Skip to content

approvals: an overlay teammate cannot be scoped, so it silently holds the company's widest grant #619

Description

@oxoxDev

Problem

OverlayAgent (src/ports/types.rs:2104) carries only id, name, role, description. There is no tools field, so an operator-added teammate cannot be scoped at all.

Both the harness and the console resolve that absence to the same thing — the widest grant the company has:

// src/harness/mod.rs:2014
fn overlay_agent_to_manifest(overlay: &OverlayAgent) -> ManifestAgent {
    ManifestAgent { id, role, description, tier: None, tools: Vec::new(), budget_usd_daily: None }
}

src/server/ops/team_agent.rs:346 mirrors it deliberately — "no per-agent tool line: it holds the company's standard grant". Empty tools then falls through agent_effective_grants to the full company allow. That inheritance rule is #264 working as designed and is not what this issue disputes.

The gap is narrower: a manifest teammate can be scoped with a tools line in company.toml; an overlay teammate has nowhere to write one. Every overlay teammate holds everything the company holds, permanently.

Why it matters now rather than later

add_agent is declared Reach::Nothing (src/policy/consequence.rs:169) and sits in INTRINSIC_TOOLS (src/harness/steps.rs:491), so it is always present and never asks. A model can therefore mint a teammate that holds the company's full grant with no approval anywhere in the path.

That is tolerable only while every write still parks per call. It stops being tolerable the moment #560 lands a broader policy tier or #563 lands durable allow rules: an overlay teammate would silently inherit the widest standing grant in the company, and there would be no way to express "this one is read-only". The scoping hole should close before, or with, whichever of those lands first.

Scope

  1. Add an optional tools field to OverlayAgent, serde-additive (skip when empty) so existing company records serialise byte-identically.
  2. Thread it through overlay_agent_to_manifest and the team_agent.rs projection in lockstep — if they drift, the console shows a grant the harness does not honour, which is the exact failure feat: an agent has no detail view — cannot be opened, read, or edited #264 exists to prevent.
  3. Decide what add_agent may set. Recommendation: a model-minted teammate defaults to no wider than the minting agent's own effective grant, rather than to the company's.
  4. Console: the teammate detail view should state where a teammate's grant came from — an explicit line, or inherited company allow — so an operator can tell a scoped teammate from an unscoped one by looking.

Out of scope

The empty-means-inherit rule itself (#264). That is correct and stays. This issue is only about being able to write a non-empty value for an overlay teammate.

Metadata

Metadata

Assignees

Labels

cluster:approvalsHuman-in-the-loop boundary, policy, and approval surfacesenhancementNew feature or requestpriority: p2Soon. Real but survivable — a rough edge, a gap, a thing that will bite later.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions