feat(org): copy credential binding CB0 and CB1 (#1873) #1940

Merged
jason.woltje merged 2 commits from org-cb01 into refactor 2026-11-11 20:51:25 +00:00
Owner

Copy credential binding, rows CB0 and CB1 of docs/plans/2026-11-11_copy-credential-binding-design.md (#1873), as ruled 11-11 (Q1 org.hire entry, owner-only approval, no new right; Q2 copyBindings and CB0 to CB5 as written; Q3 archive discards).

  • CB0: each registry entry gets an incarnation (legacy entries get one at their first binding proposal, under the registry lock); copyId, source, definition pin and binding generation; a pure resolver where effective = role intersect approved, and only a bound, matching, unshadowed record resolves.
  • CB1: copyBindings in the org file holds ids, scope names, project ids and integers only. applyCopyBindingDecision is its only writer, behind a module-private capability every other commit is fenced against. A binding is an owner-only kind of hire decision: only the chief raises it; no autonomy level, resolver agent, member right or tester resolves it. Digest, expiry, single use, revision, generation, incarnation and definition pin are rechecked before any effect. A bind writes pending and an unbind writes the unbound tombstone; receipts carry paths only.
  • Nothing writes bound yet, so no copy launches with a binding (CB2/CB3). The org service and the Console update path keep copyBindings server-held. Eight new refusal codes with next steps. Nothing in roles/ or contracts/.

Tests: each acceptance test fails on BASE. Final lane gate at this head: 554 files, 5573/0; test-config.sh and test-task.sh exit 0.

Review: build (Opus) 1 P2 + 5 P3, security (daybreak-blue) 2 P2, all fixed in one round; security re-check approved. Rebased three times onto refactor; the fix commit is identical in range-diff, the CB0/CB1 commit differs only in upstream context lines in broker.mjs and runtime.mjs. Lead check: 44 files on ebe2af86d (the lane's copy-bindings tests, webui org-admin, and every bus, organization and business test that reads hire-decisions, org-registry, organization, org-service, organization-config or copy-bindings), 563/0.

Copy credential binding, rows CB0 and CB1 of docs/plans/2026-11-11_copy-credential-binding-design.md (#1873), as ruled 11-11 (Q1 org.hire entry, owner-only approval, no new right; Q2 copyBindings and CB0 to CB5 as written; Q3 archive discards). - CB0: each registry entry gets an incarnation (legacy entries get one at their first binding proposal, under the registry lock); copyId, source, definition pin and binding generation; a pure resolver where effective = role intersect approved, and only a bound, matching, unshadowed record resolves. - CB1: `copyBindings` in the org file holds ids, scope names, project ids and integers only. `applyCopyBindingDecision` is its only writer, behind a module-private capability every other commit is fenced against. A binding is an owner-only kind of hire decision: only the chief raises it; no autonomy level, resolver agent, member right or tester resolves it. Digest, expiry, single use, revision, generation, incarnation and definition pin are rechecked before any effect. A bind writes `pending` and an unbind writes the `unbound` tombstone; receipts carry paths only. - Nothing writes `bound` yet, so no copy launches with a binding (CB2/CB3). The org service and the Console update path keep `copyBindings` server-held. Eight new refusal codes with next steps. Nothing in roles/ or contracts/. Tests: each acceptance test fails on BASE. Final lane gate at this head: 554 files, 5573/0; test-config.sh and test-task.sh exit 0. Review: build (Opus) 1 P2 + 5 P3, security (daybreak-blue) 2 P2, all fixed in one round; security re-check approved. Rebased three times onto refactor; the fix commit is identical in range-diff, the CB0/CB1 commit differs only in upstream context lines in broker.mjs and runtime.mjs. Lead check: 44 files on ebe2af86d (the lane's copy-bindings tests, webui org-admin, and every bus, organization and business test that reads hire-decisions, org-registry, organization, org-service, organization-config or copy-bindings), 563/0.
jason.woltje added 2 commits 2026-11-11 20:51:18 +00:00
CB0: registry incarnation minted at reserve (legacy entries get one at
the first binding proposal, under the registry lock); copyId, source
and definition pin, binding generation; a pure resolver where
effective = role intersect approved and only a bound, matching,
unshadowed record resolves.

CB1: copyBindings in the organization file (ids, scope names, project
ids and integers only). applyCopyBindingDecision is its only writer,
behind a module-private capability every other commit is fenced
against. A binding is an owner-only subtype of the hire decision:
only the chief raises it, no autonomy level, resolver agent, member
right, tester or reader resolves it. Digest, expiry, single
consumption, revision, generation, incarnation and definition pin are
rechecked before any effect; a bind writes pending, an unbind the
unbound tombstone, receipts are paths only. Nothing writes bound, so
nothing launches on a binding yet (CB2/CB3). The org service and the
Console update path keep copyBindings server-held. Eight new refusal
codes with next steps.
Security review P2s:
- A binding proposal keeps only its structured request fields. The
  free-text reason is never written to the private proposal or covered
  by its digest.
- A root copy's receipts are checked at prepare, at check, and again
  under the organization lock before the write and before publication.
  A copy removed, replaced or unreadable since boot refuses with
  instance-fired, copy-stale or root-policy-unreadable.

Build review P2:
- A root copy's admitted projects come from the project unions,
  recomputed from the current document and the boot's root agents. A
  project that excludes the copy, or whose union refuses, is never in
  reach; a request naming it refuses with credential-scope-exceeded.

Build review P3s: tests for proposal-time shadowing, the loader's
copyBindings validation, a pending record that covers every service,
a stricter path check on the refusal table, and refusal codes on every
bare rejects in the binding tests.
jason.woltje merged commit 5dbd7e72d3 into refactor 2026-11-11 20:51:25 +00:00
Sign in to join this conversation.