A defer-side boundary should not compose when its owner is not on the roster #309

Closed
opened 2026-08-19 01:41:44 +00:00 by coilyco-ops · 1 comment
Member

Reported from the sirens-dowel lane, which runs SIRENS_ECHO_ROLE=engineer as the only agent in its Discord guild. Kai's read: that deployment should be loading no boundaries at all. Having gone through the model, I think that is right, and I think the model already contains the reason.

What the roster says a boundary is

From docs/ownership.md:

Every boundary names the role holding the other side with a required owner. ... The owner is a relationship, not authority.

validateBoundaryOwners enforces it as a relationship in both directions - an owner receives the body by owning it, and loading fails if an owner also declares it, "since that would place one role on both sides."

So the defer side of a boundary is a routing rule. internal/person/data/boundary-modify-live-system/boundary.kdl:

boundary "modify-live-system" skill="boundary-modify-live-system" owner="ops"
  summary="DevOps changes running systems, other roles observe and hand the action over"

"Hand the action over" - to ops.

Where that stops being true

Engineer owns nothing and defers both:

role-engineer      boundary "modify-live-system" "seek-external-validation"

On a single-seat deployment there is no ops and no exec. The relationship the boundary describes has one participant. So both bodies resolve to "hand this to a role that is not present", which is not routing - it is a stop with no continuation. The agent reads a rule about a colleague it does not have.

That is not the boundary being wrong. It is the boundary being composed into a roster it does not apply to.

The evidence that it already bites

The sirens-echo lane worked around it in prose rather than in composition. .agents/skills/sirens-dowel/references/site-work.md:

The composed identity above carries a boundary that hands changes to running systems over to DevOps. That boundary does not reach these verbs. ... Where the composed boundary and this file disagree about the site, this file wins.

I wrote that, and writing it is the tell. When a deployment has to ship a local file saying "ignore the shipped doctrine above," the doctrine was composed into the wrong place. And that override is scoped to site verbs only, so the general case is still unopposed: an agent told to defer live-system changes, in a room with nobody to defer to, hedges. On a livestream lane whose whole point is to be interesting rather than neutral, that is a direct cost.

sirens-echo#1008 makes roster:core eager, so these bodies are now at full weight in every prompt rather than merely named on the card. That sharpens the problem rather than causing it - the card named them either way - but it is worth stating plainly since I opened that PR.

Shape of the fix

The schema already permits a role with no declared boundaries: role-creator ships that way today. So this is not a new capability in the role model, it is a composition-time question - is the owner present in this deployment's roster?

Candidates, roughly in order of how well they match the existing model:

  1. Compose against a declared seat set. The caller tells agent-compose which roles are actually deployed. A defer-side boundary whose owner is absent does not compose. Zero new concepts: it is the existing owner relationship, evaluated instead of assumed. A single-seat launch gets no defer-side boundaries and still gets everything it owns.
  2. An explicit solo/standalone compose flag. Simpler, less precise. It answers Dowel but says nothing about a two-seat deployment that has engineer and ops but no exec, which option 1 handles correctly for free.
  3. A demo-lane role with no boundaries. Cheapest, and wrong in the durable sense - it forks the roster to encode a deployment fact.

I favour 1. It says something true that the roster currently only assumes, and it degrades correctly at every roster size rather than only at one.

Not requesting this before the livestream

The demo is 2026-08-19 11:00 PT. This is a shipped tool, pinned into dev-base, which then has to reach the image and the deployment. That chain is not one to start the night before a live recording, and the lane is currently working. Filing it for after.

Reported from the `sirens-dowel` lane, which runs `SIRENS_ECHO_ROLE=engineer` as the only agent in its Discord guild. Kai's read: that deployment should be loading no boundaries at all. Having gone through the model, I think that is right, and I think the model already contains the reason. ## What the roster says a boundary is From `docs/ownership.md`: > Every boundary names the role holding the other side with a required `owner`. ... **The owner is a relationship, not authority.** `validateBoundaryOwners` enforces it as a relationship in both directions - an owner receives the body by owning it, and loading fails if an owner also declares it, "since that would place one role on both sides." So the defer side of a boundary is a routing rule. `internal/person/data/boundary-modify-live-system/boundary.kdl`: ``` boundary "modify-live-system" skill="boundary-modify-live-system" owner="ops" summary="DevOps changes running systems, other roles observe and hand the action over" ``` "Hand the action over" - to `ops`. ## Where that stops being true Engineer owns nothing and defers both: ``` role-engineer boundary "modify-live-system" "seek-external-validation" ``` On a single-seat deployment there is no `ops` and no `exec`. The relationship the boundary describes has one participant. So both bodies resolve to "hand this to a role that is not present", which is not routing - it is a stop with no continuation. The agent reads a rule about a colleague it does not have. That is not the boundary being wrong. It is the boundary being **composed into a roster it does not apply to**. ## The evidence that it already bites The sirens-echo lane worked around it in prose rather than in composition. `.agents/skills/sirens-dowel/references/site-work.md`: > The composed identity above carries a boundary that hands changes to running systems over to DevOps. **That boundary does not reach these verbs.** ... Where the composed boundary and this file disagree about the site, **this file wins.** I wrote that, and writing it is the tell. When a deployment has to ship a local file saying "ignore the shipped doctrine above," the doctrine was composed into the wrong place. And that override is scoped to site verbs only, so the general case is still unopposed: an agent told to defer live-system changes, in a room with nobody to defer to, hedges. On a livestream lane whose whole point is to be interesting rather than neutral, that is a direct cost. sirens-echo#1008 makes `roster:core` eager, so these bodies are now at full weight in every prompt rather than merely named on the card. That sharpens the problem rather than causing it - the card named them either way - but it is worth stating plainly since I opened that PR. ## Shape of the fix The schema already permits a role with no declared boundaries: `role-creator` ships that way today. So this is not a new capability in the role model, it is a composition-time question - **is the owner present in this deployment's roster?** Candidates, roughly in order of how well they match the existing model: 1. **Compose against a declared seat set.** The caller tells agent-compose which roles are actually deployed. A defer-side boundary whose owner is absent does not compose. Zero new concepts: it is the existing `owner` relationship, evaluated instead of assumed. A single-seat launch gets no defer-side boundaries and still gets everything it owns. 2. **An explicit solo/standalone compose flag.** Simpler, less precise. It answers Dowel but says nothing about a two-seat deployment that has `engineer` and `ops` but no `exec`, which option 1 handles correctly for free. 3. **A demo-lane role with no boundaries.** Cheapest, and wrong in the durable sense - it forks the roster to encode a deployment fact. I favour 1. It says something true that the roster currently only assumes, and it degrades correctly at every roster size rather than only at one. ## Not requesting this before the livestream The demo is 2026-08-19 11:00 PT. This is a shipped tool, pinned into dev-base, which then has to reach the image and the deployment. That chain is not one to start the night before a live recording, and the lane is currently working. Filing it for after.
Author
Member

Duplicate of #304, which was filed earlier today on the same gap and has better detail on the request parser. Folded the distinct part of this - Kai's broader "no boundaries at all" directive, and a roster-presence alternative to boundary-omit - into a comment there. Closing.

Duplicate of #304, which was filed earlier today on the same gap and has better detail on the request parser. Folded the distinct part of this - Kai's broader "no boundaries at all" directive, and a roster-presence alternative to `boundary-omit` - into a comment there. Closing.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-flight-deck/agent-compose#309
No description provided.