feat(compass-agent): validate spawn role against the closed Manager taxonomy (RIG-3074) - #810
Open
rigel-mintaka wants to merge 1 commit into
Open
feat(compass-agent): validate spawn role against the closed Manager taxonomy (RIG-3074)#810rigel-mintaka wants to merge 1 commit into
rigel-mintaka wants to merge 1 commit into
Conversation
…axonomy (RIG-3074) Tightens and validates the role-on-spawn contract RIG-2726 (#762) wired end to end. No new proto field and no new tool param — this narrows the existing `role` value-space and enforces the closed set server-side. ### TypeScript (tool edge) - Narrow `spawnParameters.role` from a non-blank `type("string")` to the closed literal union `'supervisor' | 'owner' | 'manager'`, so the model sees the exact taxonomy in the JSON schema and an off-taxonomy or empty label is rejected structurally at the tool edge (a literal union renders into the schema; the old `.narrow` did not). The non-blank rule is no longer description-carried for `role` (it is now structural); handle and persona keep theirs. - `cli.ts`: emit one `console.error` when a role is set but its `prompts/<role>/SYSTEM.md` did not materialize, so a role-without-shipped-prompt degradation is visible instead of a silent fallback to the default block-0. ### Go server (authority) - Add `spawnableRoles` — a fixed server constant of the three roles beside `rootSupervisorRole` (a frozen product decision, not derived from the operator config bundle). - `SpawnAsAccount` validates `req.GetRole()` against it before `CreateAgent`, so an unknown or empty role is refused in-band `CodeInvalidArgument` and writes no row — and the guard sits ahead of the create/resume switch, so it covers the resume branch too. All three roles are spawnable (a spawned supervisor is parented and permitted). Rewrote the set-at-creation invariant comment: role is caller-selected but server-validated; prompt text still arrives only via the operator bundle; the store stays the provision-time source of record. ### Tests - TS: schema rejects off-taxonomy roles and accepts each of the three. - Go pgtest: empty and off-taxonomy roles rejected with `CodeInvalidArgument` and no row; each of the three accepted and threaded to the Provision wire; the idempotent-resume and crash-resume tests retry with a valid different role and still prove stored-role immutability. Every pre-existing agent-initiated spawn test that omitted a role now passes `manager` so it keeps exercising its own invariant. Verified against real Postgres (throwaway container). ### Open questions - Second creation door: `CommsService.CreateAgent` (`go/internal/comms/comms.go:146-150`) calls `store.CreateAgent` with a `ParentAgentID` but no `Role`, so it can create roleless tree nodes — which the frozen taxonomy tenet 3 and DL-new-B say cannot exist. T1 only guards `SpawnAsAccount` (the `agents_spawn_peer` path DL-new-B scopes). Closing the second door is a compass-server design fork that pairs with RIG-2673 (agent-tool exposure of `create_agent`); filed as RIG-3097 for compass-server, not fixed here. Spec-impact: none. Refs RIG-3074 Co-authored-by: Matt Wilkinson <matt@rigel.build>
|
Compass engineering docs preview: https://compass-agent-rig-3074-role.compass-eng-docs.pages.dev Deployed from |
mattwilkinsonn
approved these changes
Aug 31, 2026
rigel-mintaka
added a commit
that referenced
this pull request
Sep 1, 2026
…076)
Matt ruled the owner tier supports multiple owner levels ("middle
managers"): an `owner` may spawn a child `owner` for a coherent sub-domain,
not only child `manager`s, and owner tiers nest as deep as the domain needs.
The taxonomy already permits this (record DL-new-E multi-tree; DL-new-F made
`ManagerResolver` walk to the nearest ancestor of ANY Manager-class role
precisely so an owner-under-owner is not skipped), and the `management-trees`
skill already draws it (`department Managers [each owner]`) — but the owner
block-0 prompt named only child `manager`s on every action line. This closes
that gap so the prompt matches the frozen model.
`config/prompts/owner/SYSTEM.md`: the position, grow-subtree, coordinator,
work-loop, and operator-approval lines now name child `owner`s alongside
`manager`s, and add the role-selection rule — a coherent sub-domain that is
itself decomposable gets a child `owner`; a single function/lane gets a
`manager`. Mirrors the supervisor prompt's existing "spawn `owner`s and
`manager`s" phrasing one tier down.
`docs/concepts/agent-roles.md`: the `owner` bullet now names delegating a
sub-domain to a child `owner` (owner tiers nest), consistent with the prompt.
No code change; the bind-3 taxonomy is unchanged (RIG-3074/#810 stays as-is —
depth carries hierarchy, the role set stays exactly supervisor/owner/manager).
Spec-impact: none. Refs RIG-3076
Co-authored-by: Matt Wilkinson <matt@rigel.build>
rigel-mintaka
added a commit
that referenced
this pull request
Sep 1, 2026
…076)
Matt ruled the owner tier supports multiple owner levels ("middle
managers"): an `owner` may spawn a child `owner` for a coherent sub-domain,
not only child `manager`s, and owner tiers nest as deep as the domain needs.
The taxonomy already permits this (record DL-new-E multi-tree; DL-new-F made
`ManagerResolver` walk to the nearest ancestor of ANY Manager-class role
precisely so an owner-under-owner is not skipped), and the `management-trees`
skill already draws it (`department Managers [each owner]`) — but the owner
block-0 prompt named only child `manager`s on every action line. This closes
that gap so the prompt matches the frozen model.
`config/prompts/owner/SYSTEM.md`: the position, grow-subtree, coordinator,
work-loop, and operator-approval lines now name child `owner`s alongside
`manager`s, and add the role-selection rule — a coherent sub-domain that is
itself decomposable gets a child `owner`; a single function/lane gets a
`manager`. Mirrors the supervisor prompt's existing "spawn `owner`s and
`manager`s" phrasing one tier down. The compact-context line is now
role-agnostic ("the work lives in your subtree") so it covers child owners.
`docs/concepts/agent-roles.md`: the `owner` bullet now names delegating a
sub-domain to a child `owner` (owner tiers nest), consistent with the prompt.
`config/skills/management-trees/SKILL.md`: the compact `owner` role summary
now names delegating sub-domains to child `owner`s (it previously read "child
managers" only), matching the concepts doc and the example tree.
No code change; the bind-3 taxonomy is unchanged (RIG-3074/#810 stays as-is —
depth carries hierarchy, the role set stays exactly supervisor/owner/manager).
Spec-impact: none. Refs RIG-3076
Co-authored-by: Matt Wilkinson <matt@rigel.build>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Tightens and validates the role-on-spawn contract RIG-2726 (#762) wired end to end. No new proto field and no new tool param — this narrows the existing
rolevalue-space and enforces the closed set server-side.TypeScript (tool edge)
spawnParameters.rolefrom a non-blanktype("string")to the closed literal union'supervisor' | 'owner' | 'manager', so the model sees the exact taxonomy in the JSON schema and an off-taxonomy or empty label is rejected structurally at the tool edge (a literal union renders into the schema; the old.narrowdid not). The non-blank rule is no longer description-carried forrole(it is now structural); handle and persona keep theirs.cli.ts: emit oneconsole.errorwhen a role is set but itsprompts/<role>/SYSTEM.mddid not materialize, so a role-without-shipped-prompt degradation is visible instead of a silent fallback to the default block-0.Go server (authority)
spawnableRoles— a fixed server constant of the three roles besiderootSupervisorRole(a frozen product decision, not derived from the operator config bundle).SpawnAsAccountvalidatesreq.GetRole()against it beforeCreateAgent, so an unknown or empty role is refused in-bandCodeInvalidArgumentand writes no row — and the guard sits ahead of the create/resume switch, so it covers the resume branch too. All three roles are spawnable (a spawned supervisor is parented and permitted). Rewrote the set-at-creation invariant comment: role is caller-selected but server-validated; prompt text still arrives only via the operator bundle; the store stays the provision-time source of record.Tests
CodeInvalidArgumentand no row; each of the three accepted and threaded to the Provision wire; the idempotent-resume and crash-resume tests retry with a valid different role and still prove stored-role immutability. Every pre-existing agent-initiated spawn test that omitted a role now passesmanagerso it keeps exercising its own invariant. Verified against real Postgres (throwaway container).Open questions
CommsService.CreateAgent(go/internal/comms/comms.go:146-150) callsstore.CreateAgentwith aParentAgentIDbut noRole, so it can create roleless tree nodes — which the frozen taxonomy tenet 3 and DL-new-B say cannot exist. T1 only guardsSpawnAsAccount(theagents_spawn_peerpath DL-new-B scopes). Closing the second door is a compass-server design fork that pairs with RIG-2673 (agent-tool exposure ofcreate_agent); filed as RIG-3097 for compass-server, not fixed here.Spec-impact: none. Refs RIG-3074
Co-authored-by: Matt Wilkinson matt@rigel.build