What happened?
When a collaborator is disabled in the public roster but has a replacement identity, routing surfaces do not share one accepted contract for legacy explicit mentions, implicit/default targets, pre-resolved execution, and no-target behavior.
Concrete case:
opus.available=false
opus.successor=opus-5
opus-5.available=true
Without a central contract, the system can continue generating or persisting the legacy opus target, while individual consumers independently decide whether to redirect, warn, choose another cat, or persist a sentinel.
PR #1283 is a broad candidate implementation, but it is intentionally on HOLD pending maintainer acceptance of this focused scope.
Steps to reproduce
- Configure the roster so
opus is disabled and points to available, registered opus-5.
- Exercise each boundary:
- send a message with no explicit mention in a new thread;
- load an existing routing policy or participant containing
opus;
- explicitly send
@opus;
- invoke a system producer with pre-resolved
targetCats=['opus'];
- disable/remove the configured successor and request a guardian/default target;
- inspect public template/backfill behavior on an existing runtime catalog.
- Observe that these boundaries historically used different fallback and validation rules.
There is also a roster metadata edge in the current candidate patch: the disabled legacy opus remains lead:true, while available opus-5 is lead:false. With the current ActorResolver, that changes deep repo-watcher and health-monitor selection from the former Opus lead to codex, rather than transferring the lead role to the explicit successor.
Expected behavior / focused contract
- Explicit legacy mention:
@opus remains fail-closed. Return a structured cat_disabled warning; put canonical @opus-5 first in alternatives. Do not silently retarget explicit user intent.
- Implicit/default/persisted target: a disabled cat may resolve through exactly one explicitly configured
successor edge.
- Successor validity: the successor must be registered and available. Do not infer replacements from family or version ordering.
- Central execution admission: pre-resolved system targets must pass the same availability/successor guard before serial or parallel execution.
- No valid successor: return an explicit no-target result. Do not choose an unrelated service and do not persist
__none__ as a guardian/member identity.
- Public seed/backfill ownership: public template data may add the necessary public variant/roster metadata, but must not overwrite runtime-owned private catalog fields. Backfill must be explicit and allowlisted.
- Operational identity metadata: clarify whether lead status belongs to the retired identity or transfers to its explicit successor. For this Opus replacement, scheduler selection should not drift accidentally because the only active Ragdoll successor lost
lead metadata.
- Active prompts/UI: only current canonical generation surfaces should emit/save
opus-5; historical records should not be globally rewritten.
Acceptance criteria
Alternatives considered
- Hard-code
opus-5 in each consumer: rejected because it will drift at the next identity upgrade.
- Pick the newest available member of the same family: rejected because family/version naming is not a safe successor contract.
- Silently redirect explicit
@opus: rejected because it changes explicit user intent.
- Bulk-copy the private runtime catalog into the public seed: rejected because it would leak installation-owned aliases and runtime state.
Environment
[砚砚/gpt-5.6-sol🐾]
What happened?
When a collaborator is disabled in the public roster but has a replacement identity, routing surfaces do not share one accepted contract for legacy explicit mentions, implicit/default targets, pre-resolved execution, and no-target behavior.
Concrete case:
opus.available=falseopus.successor=opus-5opus-5.available=trueWithout a central contract, the system can continue generating or persisting the legacy
opustarget, while individual consumers independently decide whether to redirect, warn, choose another cat, or persist a sentinel.PR #1283 is a broad candidate implementation, but it is intentionally on HOLD pending maintainer acceptance of this focused scope.
Steps to reproduce
opusis disabled and points to available, registeredopus-5.opus;@opus;targetCats=['opus'];There is also a roster metadata edge in the current candidate patch: the disabled legacy
opusremainslead:true, while availableopus-5islead:false. With the currentActorResolver, that changes deeprepo-watcherandhealth-monitorselection from the former Opus lead tocodex, rather than transferring the lead role to the explicit successor.Expected behavior / focused contract
@opusremains fail-closed. Return a structuredcat_disabledwarning; put canonical@opus-5first in alternatives. Do not silently retarget explicit user intent.successoredge.__none__as a guardian/member identity.leadmetadata.opus-5; historical records should not be globally rewritten.Acceptance criteria
@opusstays fail-closed with@opus-5as the first alternative.opus-5through the same contract.mainand contains no unrelated patch-equivalent upstream commits.Alternatives considered
opus-5in each consumer: rejected because it will drift at the next identity upgrade.@opus: rejected because it changes explicit user intent.Environment
zts212653/clowder-ai900c0d68f80b9e529debe7f5fcc6f56389b9c1c3[砚砚/gpt-5.6-sol🐾]