From 583e3b54053cea5febb8920ee69de40812f0f78d Mon Sep 17 00:00:00 2001 From: mintaka Date: Mon, 31 Aug 2026 13:59:42 -0400 Subject: [PATCH 1/2] docs(server): ManagerResolver nearest-ancestor contract + proto role-comment sweep (RIG-3080) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Taxonomy T7 from the frozen manager-role-taxonomy record (RIG-3066). Two doc/spec surfaces drift under the three-role taxonomy and are corrected here before an implementer codes against them; both are comment-only and regen-neutral. - `go/internal/linearagent/routing.go`: the `ManagerResolver` seam doc said the tree walk goes "up parent_agent_id to a role=\"manager\" agent". Under the taxonomy that is wrong twice — a `manager`-only filter skips an `owner` parent (routing a domain-owned artifact past its owning tier), and every tree node is now Manager-class so the filter is vestigial. Reworded to the nearest tree ancestor (any Manager-class role). Only the interface + test fakes exist today (`NewResolver` is called only from tests), so this prevents a future implementer hardcoding `role==\"manager\"`. - `proto/compass/v1/compass.proto`: the `role` field comment said "operator-set role". After T1 the label is spawner-selected from the closed taxonomy and server-validated; the provision field stays server-authoritative (populated from the stored role, overwrites client-supplied). Swept the comment to match the T1 invariant. Verified: gofmt clean; go build ./internal/linearagent/... exit 0; go test ./internal/linearagent/... ok (routing fakes green); proto diff is comment-only (regen-neutral, confirmed no non-comment line changed). Refs RIG-3080 Co-authored-by: Matt Wilkinson jj-hooks: autofixes for compass-server/rig-3080-managerresolver-contract --- go/gen/compass/v1/compass.pb.go | 21 ++++++++++++------- go/internal/linearagent/routing.go | 4 +++- .../src/gen/compass/v1/compass_pb.ts | 21 ++++++++++++------- .../src/gen/compass/v1/compass_pb.ts | 21 ++++++++++++------- proto/compass/v1/compass.proto | 21 ++++++++++++------- 5 files changed, 55 insertions(+), 33 deletions(-) diff --git a/go/gen/compass/v1/compass.pb.go b/go/gen/compass/v1/compass.pb.go index 166f14dc8..99897e31c 100644 --- a/go/gen/compass/v1/compass.pb.go +++ b/go/gen/compass/v1/compass.pb.go @@ -2704,14 +2704,19 @@ type ProvisionAgentWorkspaceRequest struct { // it into the container // (compass-runner consumer). Empty = no persona baked (default). Persona string `protobuf:"bytes,3,opt,name=persona,proto3" json:"persona,omitempty"` - // The agent's operator-set role, selecting the container's block-0 system - // prompt at provision so it survives compaction (a system-prompt config block - // is not part of the message history a snapcompact archives). SERVER- - // AUTHORITATIVE: the Server is expected to populate this by reading - // AgentAccount.role from the store on the provision path and to overwrite any - // client-supplied value, so a caller cannot inject a role prompt — an - // invariant enforced by the server provision path (not by this wire-settable - // field). Where persona (field 3) is an APPEND overlay, role REPLACES block-0: + // The agent's role, selected at spawn from the closed taxonomy + // (supervisor/owner/manager) and server-validated, selecting the container's + // block-0 system prompt at provision so it survives compaction (a + // system-prompt config block is not part of the message history a snapcompact + // archives). The label's ORIGIN is spawner-selected: the spawn request + // carries a required label from the closed taxonomy, validated against the + // server's spawnableRoles set (CodeInvalidArgument on an + // unknown label) before it is stored. This provision field stays SERVER- + // AUTHORITATIVE: the Server populates it by reading the stored + // AgentAccount.role (the provision source of record) and overwrites any + // client-supplied value, so a caller cannot inject a role prompt via + // provision — prompt TEXT ships only in the operator-published config bundle. + // Where persona (field 3) is an APPEND overlay, role REPLACES block-0: // the label selects config/prompts//SYSTEM.md, materialized by the // Runner into the container's customSystemPrompt (compass-runner consumer). // Empty = no role (default OMP block-0). diff --git a/go/internal/linearagent/routing.go b/go/internal/linearagent/routing.go index 390c73217..9a184c446 100644 --- a/go/internal/linearagent/routing.go +++ b/go/internal/linearagent/routing.go @@ -46,7 +46,9 @@ type OwnershipIndex interface { // ManagerResolver walks a recorded authoring agent (possibly a peer) to its // owning Manager and returns that Manager's account id and home channel id. // It is its own narrow seam because no single store method spans the tree walk -// (up parent_agent_id to a role="manager" agent) AND the home-channel read; the +// (up parent_agent_id to the nearest tree ancestor — any Manager-class role, +// not a role=="manager" filter, since every tree node is now Manager-class and +// an owner parent must not be skipped) AND the home-channel read; the // driver backs it with the store's agent-tree + account reads at assembly. // store.ErrNotFound when the agent (or a walk ancestor) does not resolve. type ManagerResolver interface { diff --git a/packages/compass-agent/src/gen/compass/v1/compass_pb.ts b/packages/compass-agent/src/gen/compass/v1/compass_pb.ts index 810bbd111..d5e6b8475 100644 --- a/packages/compass-agent/src/gen/compass/v1/compass_pb.ts +++ b/packages/compass-agent/src/gen/compass/v1/compass_pb.ts @@ -1100,14 +1100,19 @@ export type ProvisionAgentWorkspaceRequest = Message<"compass.v1.ProvisionAgentW persona: string; /** - * The agent's operator-set role, selecting the container's block-0 system - * prompt at provision so it survives compaction (a system-prompt config block - * is not part of the message history a snapcompact archives). SERVER- - * AUTHORITATIVE: the Server is expected to populate this by reading - * AgentAccount.role from the store on the provision path and to overwrite any - * client-supplied value, so a caller cannot inject a role prompt — an - * invariant enforced by the server provision path (not by this wire-settable - * field). Where persona (field 3) is an APPEND overlay, role REPLACES block-0: + * The agent's role, selected at spawn from the closed taxonomy + * (supervisor/owner/manager) and server-validated, selecting the container's + * block-0 system prompt at provision so it survives compaction (a + * system-prompt config block is not part of the message history a snapcompact + * archives). The label's ORIGIN is spawner-selected: the spawn request + * carries a required label from the closed taxonomy, validated against the + * server's spawnableRoles set (CodeInvalidArgument on an + * unknown label) before it is stored. This provision field stays SERVER- + * AUTHORITATIVE: the Server populates it by reading the stored + * AgentAccount.role (the provision source of record) and overwrites any + * client-supplied value, so a caller cannot inject a role prompt via + * provision — prompt TEXT ships only in the operator-published config bundle. + * Where persona (field 3) is an APPEND overlay, role REPLACES block-0: * the label selects config/prompts//SYSTEM.md, materialized by the * Runner into the container's customSystemPrompt (compass-runner consumer). * Empty = no role (default OMP block-0). diff --git a/packages/compass-client/src/gen/compass/v1/compass_pb.ts b/packages/compass-client/src/gen/compass/v1/compass_pb.ts index 810bbd111..d5e6b8475 100644 --- a/packages/compass-client/src/gen/compass/v1/compass_pb.ts +++ b/packages/compass-client/src/gen/compass/v1/compass_pb.ts @@ -1100,14 +1100,19 @@ export type ProvisionAgentWorkspaceRequest = Message<"compass.v1.ProvisionAgentW persona: string; /** - * The agent's operator-set role, selecting the container's block-0 system - * prompt at provision so it survives compaction (a system-prompt config block - * is not part of the message history a snapcompact archives). SERVER- - * AUTHORITATIVE: the Server is expected to populate this by reading - * AgentAccount.role from the store on the provision path and to overwrite any - * client-supplied value, so a caller cannot inject a role prompt — an - * invariant enforced by the server provision path (not by this wire-settable - * field). Where persona (field 3) is an APPEND overlay, role REPLACES block-0: + * The agent's role, selected at spawn from the closed taxonomy + * (supervisor/owner/manager) and server-validated, selecting the container's + * block-0 system prompt at provision so it survives compaction (a + * system-prompt config block is not part of the message history a snapcompact + * archives). The label's ORIGIN is spawner-selected: the spawn request + * carries a required label from the closed taxonomy, validated against the + * server's spawnableRoles set (CodeInvalidArgument on an + * unknown label) before it is stored. This provision field stays SERVER- + * AUTHORITATIVE: the Server populates it by reading the stored + * AgentAccount.role (the provision source of record) and overwrites any + * client-supplied value, so a caller cannot inject a role prompt via + * provision — prompt TEXT ships only in the operator-published config bundle. + * Where persona (field 3) is an APPEND overlay, role REPLACES block-0: * the label selects config/prompts//SYSTEM.md, materialized by the * Runner into the container's customSystemPrompt (compass-runner consumer). * Empty = no role (default OMP block-0). diff --git a/proto/compass/v1/compass.proto b/proto/compass/v1/compass.proto index 129bdc962..6e02c8e70 100644 --- a/proto/compass/v1/compass.proto +++ b/proto/compass/v1/compass.proto @@ -596,14 +596,19 @@ message ProvisionAgentWorkspaceRequest { // it into the container // (compass-runner consumer). Empty = no persona baked (default). string persona = 3; - // The agent's operator-set role, selecting the container's block-0 system - // prompt at provision so it survives compaction (a system-prompt config block - // is not part of the message history a snapcompact archives). SERVER- - // AUTHORITATIVE: the Server is expected to populate this by reading - // AgentAccount.role from the store on the provision path and to overwrite any - // client-supplied value, so a caller cannot inject a role prompt — an - // invariant enforced by the server provision path (not by this wire-settable - // field). Where persona (field 3) is an APPEND overlay, role REPLACES block-0: + // The agent's role, selected at spawn from the closed taxonomy + // (supervisor/owner/manager) and server-validated, selecting the container's + // block-0 system prompt at provision so it survives compaction (a + // system-prompt config block is not part of the message history a snapcompact + // archives). The label's ORIGIN is spawner-selected: the spawn request + // carries a required label from the closed taxonomy, validated against the + // server's spawnableRoles set (CodeInvalidArgument on an + // unknown label) before it is stored. This provision field stays SERVER- + // AUTHORITATIVE: the Server populates it by reading the stored + // AgentAccount.role (the provision source of record) and overwrites any + // client-supplied value, so a caller cannot inject a role prompt via + // provision — prompt TEXT ships only in the operator-published config bundle. + // Where persona (field 3) is an APPEND overlay, role REPLACES block-0: // the label selects config/prompts//SYSTEM.md, materialized by the // Runner into the container's customSystemPrompt (compass-runner consumer). // Empty = no role (default OMP block-0). From 48a26e3f3acc4172fee11f087d0bcbcdb27b76ce Mon Sep 17 00:00:00 2001 From: mintaka Date: Mon, 31 Aug 2026 15:57:27 -0400 Subject: [PATCH 2/2] docs(proto): polish role field comment wording (RIG-3080) Review-loop polish on the ProvisionAgentWorkspaceRequest.role doc comment (three low-severity findings): reflow so "INVALID_ARGUMENT on an unknown label" is not split mid-phrase; use the Connect-canonical INVALID_ARGUMENT spelling instead of the Go-flavored CodeInvalidArgument (the comment generates into both Go and TS clients); and spell out that a role is required at spawn while the provision wire field stays optional (an empty stored role yields the default block-0), reconciling with the trailing "empty" clause. Comment-only + regen across all gen trees; no wire/field change. Refs RIG-3066 Co-authored-by: Matt Wilkinson --- go/gen/compass/v1/compass.pb.go | 21 ++++++++++--------- .../src/gen/compass/v1/compass_pb.ts | 21 ++++++++++--------- .../src/gen/compass/v1/compass_pb.ts | 21 ++++++++++--------- proto/compass/v1/compass.proto | 21 ++++++++++--------- 4 files changed, 44 insertions(+), 40 deletions(-) diff --git a/go/gen/compass/v1/compass.pb.go b/go/gen/compass/v1/compass.pb.go index 99897e31c..ec5dbf5e4 100644 --- a/go/gen/compass/v1/compass.pb.go +++ b/go/gen/compass/v1/compass.pb.go @@ -2710,16 +2710,17 @@ type ProvisionAgentWorkspaceRequest struct { // system-prompt config block is not part of the message history a snapcompact // archives). The label's ORIGIN is spawner-selected: the spawn request // carries a required label from the closed taxonomy, validated against the - // server's spawnableRoles set (CodeInvalidArgument on an - // unknown label) before it is stored. This provision field stays SERVER- - // AUTHORITATIVE: the Server populates it by reading the stored - // AgentAccount.role (the provision source of record) and overwrites any - // client-supplied value, so a caller cannot inject a role prompt via - // provision — prompt TEXT ships only in the operator-published config bundle. - // Where persona (field 3) is an APPEND overlay, role REPLACES block-0: - // the label selects config/prompts//SYSTEM.md, materialized by the - // Runner into the container's customSystemPrompt (compass-runner consumer). - // Empty = no role (default OMP block-0). + // server's spawnableRoles set (INVALID_ARGUMENT on an unknown label) before + // it is stored. This provision field stays SERVER-AUTHORITATIVE: the Server + // populates it by reading the stored AgentAccount.role (the provision source + // of record) and overwrites any client-supplied value, so a caller cannot + // inject a role prompt via provision — prompt TEXT ships only in the + // operator-published config bundle. Where persona (field 3) is an APPEND + // overlay, role REPLACES block-0: the label selects + // config/prompts//SYSTEM.md, materialized by the Runner into the + // container's customSystemPrompt (compass-runner consumer). A role is + // required at spawn; this provision field is optional and an empty stored + // role yields the default OMP block-0. Role string `protobuf:"bytes,4,opt,name=role,proto3" json:"role,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache diff --git a/packages/compass-agent/src/gen/compass/v1/compass_pb.ts b/packages/compass-agent/src/gen/compass/v1/compass_pb.ts index d5e6b8475..932b67f33 100644 --- a/packages/compass-agent/src/gen/compass/v1/compass_pb.ts +++ b/packages/compass-agent/src/gen/compass/v1/compass_pb.ts @@ -1106,16 +1106,17 @@ export type ProvisionAgentWorkspaceRequest = Message<"compass.v1.ProvisionAgentW * system-prompt config block is not part of the message history a snapcompact * archives). The label's ORIGIN is spawner-selected: the spawn request * carries a required label from the closed taxonomy, validated against the - * server's spawnableRoles set (CodeInvalidArgument on an - * unknown label) before it is stored. This provision field stays SERVER- - * AUTHORITATIVE: the Server populates it by reading the stored - * AgentAccount.role (the provision source of record) and overwrites any - * client-supplied value, so a caller cannot inject a role prompt via - * provision — prompt TEXT ships only in the operator-published config bundle. - * Where persona (field 3) is an APPEND overlay, role REPLACES block-0: - * the label selects config/prompts//SYSTEM.md, materialized by the - * Runner into the container's customSystemPrompt (compass-runner consumer). - * Empty = no role (default OMP block-0). + * server's spawnableRoles set (INVALID_ARGUMENT on an unknown label) before + * it is stored. This provision field stays SERVER-AUTHORITATIVE: the Server + * populates it by reading the stored AgentAccount.role (the provision source + * of record) and overwrites any client-supplied value, so a caller cannot + * inject a role prompt via provision — prompt TEXT ships only in the + * operator-published config bundle. Where persona (field 3) is an APPEND + * overlay, role REPLACES block-0: the label selects + * config/prompts//SYSTEM.md, materialized by the Runner into the + * container's customSystemPrompt (compass-runner consumer). A role is + * required at spawn; this provision field is optional and an empty stored + * role yields the default OMP block-0. * * @generated from field: string role = 4; */ diff --git a/packages/compass-client/src/gen/compass/v1/compass_pb.ts b/packages/compass-client/src/gen/compass/v1/compass_pb.ts index d5e6b8475..932b67f33 100644 --- a/packages/compass-client/src/gen/compass/v1/compass_pb.ts +++ b/packages/compass-client/src/gen/compass/v1/compass_pb.ts @@ -1106,16 +1106,17 @@ export type ProvisionAgentWorkspaceRequest = Message<"compass.v1.ProvisionAgentW * system-prompt config block is not part of the message history a snapcompact * archives). The label's ORIGIN is spawner-selected: the spawn request * carries a required label from the closed taxonomy, validated against the - * server's spawnableRoles set (CodeInvalidArgument on an - * unknown label) before it is stored. This provision field stays SERVER- - * AUTHORITATIVE: the Server populates it by reading the stored - * AgentAccount.role (the provision source of record) and overwrites any - * client-supplied value, so a caller cannot inject a role prompt via - * provision — prompt TEXT ships only in the operator-published config bundle. - * Where persona (field 3) is an APPEND overlay, role REPLACES block-0: - * the label selects config/prompts//SYSTEM.md, materialized by the - * Runner into the container's customSystemPrompt (compass-runner consumer). - * Empty = no role (default OMP block-0). + * server's spawnableRoles set (INVALID_ARGUMENT on an unknown label) before + * it is stored. This provision field stays SERVER-AUTHORITATIVE: the Server + * populates it by reading the stored AgentAccount.role (the provision source + * of record) and overwrites any client-supplied value, so a caller cannot + * inject a role prompt via provision — prompt TEXT ships only in the + * operator-published config bundle. Where persona (field 3) is an APPEND + * overlay, role REPLACES block-0: the label selects + * config/prompts//SYSTEM.md, materialized by the Runner into the + * container's customSystemPrompt (compass-runner consumer). A role is + * required at spawn; this provision field is optional and an empty stored + * role yields the default OMP block-0. * * @generated from field: string role = 4; */ diff --git a/proto/compass/v1/compass.proto b/proto/compass/v1/compass.proto index 6e02c8e70..e9906343b 100644 --- a/proto/compass/v1/compass.proto +++ b/proto/compass/v1/compass.proto @@ -602,16 +602,17 @@ message ProvisionAgentWorkspaceRequest { // system-prompt config block is not part of the message history a snapcompact // archives). The label's ORIGIN is spawner-selected: the spawn request // carries a required label from the closed taxonomy, validated against the - // server's spawnableRoles set (CodeInvalidArgument on an - // unknown label) before it is stored. This provision field stays SERVER- - // AUTHORITATIVE: the Server populates it by reading the stored - // AgentAccount.role (the provision source of record) and overwrites any - // client-supplied value, so a caller cannot inject a role prompt via - // provision — prompt TEXT ships only in the operator-published config bundle. - // Where persona (field 3) is an APPEND overlay, role REPLACES block-0: - // the label selects config/prompts//SYSTEM.md, materialized by the - // Runner into the container's customSystemPrompt (compass-runner consumer). - // Empty = no role (default OMP block-0). + // server's spawnableRoles set (INVALID_ARGUMENT on an unknown label) before + // it is stored. This provision field stays SERVER-AUTHORITATIVE: the Server + // populates it by reading the stored AgentAccount.role (the provision source + // of record) and overwrites any client-supplied value, so a caller cannot + // inject a role prompt via provision — prompt TEXT ships only in the + // operator-published config bundle. Where persona (field 3) is an APPEND + // overlay, role REPLACES block-0: the label selects + // config/prompts//SYSTEM.md, materialized by the Runner into the + // container's customSystemPrompt (compass-runner consumer). A role is + // required at spawn; this provision field is optional and an empty stored + // role yields the default OMP block-0. string role = 4; }