jcp-orchestrate: background-agent orchestrator profile mapping + seal budget denials #6

Merged
dcharlot merged 2 commits from jcp/orchestrate-profile-mapping into main 2026-07-12 22:36:51 -04:00
Owner

Records the background-agent orchestrator pattern as a JCP profile and hardens the crate that models it.

  • MAPPING.md + examples/background_agents.rs: map the pattern (tracker to branch to dispatch to PR, agents in isolated containers, local-handoff CLI as MCP server, BYO subscription, event-triggered automations, chat/forge mention bindings) onto the reconcile loop, the Sandbox S0-S7 rungs its container model sits low on, the Joule Table seams its surfaces never carried, and the JCP grant its credential model stops short of. De-named by capability, matching how the module doc treats the abstract shape.
  • Conformance fix: dispatch() pre-filtered over-budget harnesses in routing, so JCP’s joule ceiling fired without sealing a receipt — enforcement with no audit trail. Denials are now decided and sealed by the runtime before failover; two regression tests pin it; the example goes 6 to 7 sealed decisions.

Verified on the rebased base: 8 tests pass, clippy --all-targets clean, example runs 7/7 receipts verifying.

🤖 Generated with Claude Code

Records the background-agent orchestrator pattern as a JCP profile and hardens the crate that models it. - `MAPPING.md` + `examples/background_agents.rs`: map the pattern (tracker to branch to dispatch to PR, agents in isolated containers, local-handoff CLI as MCP server, BYO subscription, event-triggered automations, chat/forge mention bindings) onto the reconcile loop, the Sandbox S0-S7 rungs its container model sits low on, the Joule Table seams its surfaces never carried, and the JCP grant its credential model stops short of. De-named by capability, matching how the module doc treats the abstract shape. - Conformance fix: `dispatch()` pre-filtered over-budget harnesses in routing, so JCP’s joule ceiling fired without sealing a receipt — enforcement with no audit trail. Denials are now decided and sealed by the runtime before failover; two regression tests pin it; the example goes 6 to 7 sealed decisions. Verified on the rebased base: 8 tests pass, clippy --all-targets clean, example runs 7/7 receipts verifying. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
MAPPING.md records what this crate ingests: the background-agent orchestrator
pattern (tracker -> branch -> dispatch -> PR, coding agents in isolated
containers, local-handoff CLI doubling as an MCP server, BYO subscription,
event-triggered automations, chat/forge mention bindings). The pattern is
commodity; what no deployed instance produces is a signed, energy-accounted,
verifiable receipt of what ran, under whose authority, for how many joules.

The doc maps the pattern onto the reconcile loop, the Sandbox S0-S7 rungs its
container model sits low on (~S2/S3; the step up is an S5 microVM plus
sandbox-tee::energy), the Joule Table seams its UX surfaces never carried, and
the JCP grant its credential model stops short of (authentication vs authority)
- then scopes the frontier the category leaves empty.

examples/background_agents.rs drives it end to end: two backends handle
`implement` and the fleet fails over when the first exhausts its joule budget; a
`review` backend flakes twice and lands on the third attempt, charged for every
attempt; a `deploy` task is refused at routing because no backend holds that
capability. Six sealed decisions, all verifying under the steward key.

Tests and clippy --all-targets clean.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
The joule ceiling is JCP's flagship enforcement, and the spec's contract is that
every decision is sealed, allow and deny alike. dispatch() did not honour that.
route() pre-filtered out any harness whose remaining budget could not cover the
task's quote, so an over-budget harness never reached runtime.decide() -- the
ceiling fired, the loop failed over, and no receipt recorded that it had. The
enforcement happened; the audit of it did not.

Replace route() with candidates(), which filters on capability only. dispatch()
now offers the task to each granted harness in turn, letting the runtime make and
seal the decision -- so a harness that cannot pay is denied on the record before
the loop fails over to one that can. Denied dispatches are still not debited
(Runtime::decide only debits on allow), so per-harness joule totals are unchanged.

One refusal deliberately seals nothing: a task whose kind no registered harness
holds. There is no grant to decide against, and JCP seals decisions about a
grant, not the absence of one. It is recorded denied in the RunReport instead.
Module doc and MAPPING.md now state both cases precisely rather than claiming a
blanket allow-and-deny seal.

Two regression tests: budget_denials_are_sealed_not_silently_skipped (the deny
lands in the ledger, verifies under the steward key, and is not debited) and
ungranted_kind_seals_nothing. All six pre-existing tests pass unchanged. The
background_agents example now shows 7 sealed decisions, up from 6 -- the seventh
being the budget denial that used to disappear.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Sign in to join this conversation.
No reviewers
No labels
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
Transaction-Science/open-standards!6
No description provided.