Skip to content

Anti-drift architecture for normative guarantees + two Tier-1 security fixes#5833

Open
bokelley wants to merge 2 commits into
mainfrom
security-audit-adcp-protocol
Open

Anti-drift architecture for normative guarantees + two Tier-1 security fixes#5833
bokelley wants to merge 2 commits into
mainfrom
security-audit-adcp-protocol

Conversation

@bokelley

@bokelley bokelley commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Follow-up to the 2026-07 AdCP protocol security audit. The audit's through-line was that AdCP's strongest guarantees are stated in prose but diluted at the layer that enforces them — a MUST with no schema backing, a reference snippet never executed, a fact hand-copied across docs that drifted. This PR lands the enforcement scaffold plus the two mechanical Tier-1 fixes, each shipped with the check that would have caught it.

Anti-drift architecture (specs/spec-anti-drift.md)

Principle: make the enforcement layer the source of truth; push each check to the cheapest deterministic layer; reserve the governing agent for judgment calls.

  • Normative-statement registry (static/registry/normative-statements/) — every security MUST/claim tagged by enforcement layer + status, so "prose MUST with no backing" becomes countable.
  • Coverage linter (scripts/check-normative-coverage.cjs) — validates the registry, fails when an enforced entry's linked check is missing, and enforces a --min-enforced one-way floor (adding a gap never fails; losing an enforced statement does).
  • Offline doctest lane (scripts/run-doctests.cjs) — runs ​```lang doctest blocks deterministically; the lane the existing live-agent snippet suite couldn't be for pure-logic bugs.
  • Blocking CI gate (.github/workflows/normative-guarantees.yml).

Tier-1 fixes (each flips its registry row to enforced)

  • example_useadcp_use in the request-signing reference verifier (docs/building/by-layer/L1/security.mdx). Dead code that silently disabled the key-purpose separation check. Guarded by a doctest.
  • intent added to the governance-phase enum so a buyer can express the intent-phase check the spec already mandates (the token MUST carry phase: "intent"). Guarded by tests/governance-phase-enum.test.cjs + changeset.

Reviews addressed

Ran through code-reviewer and security-reviewer. Applied: scrubbed the doctest child env + dropped the shell runner + permissions: contents: read (executes PR-authored code in CI); wired the enum guard into CI; switched the ratchet to a --min-enforced count so cataloguing a gap isn't blocked; sanitized the registry notes to state the rule/fix rather than ship exploit recipes to a public repo; added a class check and a resolve-under-ROOT guard to the linter; added NS-GOV-004 for the wire-behaviour MUST the enum test doesn't cover.

Remaining Tier-1 findings (design decisions, tracked)

Not mechanical — each needs a design call: #5826 (verify_brand_claim key→brand binding), #5827 (report_plan_outcome budget attestation), #5828 (rights_constraint verification), #5829 (content-digest on spend calls), #5830 (TMP privacy claim). Rolls up to #3925.

Incidental

One unrelated commit escapes a pre-existing <5% in specs/spec-guardian.md (unpublished; MDX couldn't parse it, tripping the local docs preflight). One-char change, renders identically.

Verification

Precommit passed (4380 unit tests, typecheck). Doctest lane, enum guard, and coverage linter all green. Schema rebuild clean.

🤖 Generated with Claude Code

bokelley and others added 2 commits July 7, 2026 04:46
…security findings

From the 2026-07 AdCP protocol security audit. The recurring finding was a
guarantee stated in prose but not enforced at the layer that should hold it, so
this lands the enforcement scaffold and two mechanical fixes with their guards.

New anti-drift primitives:
- specs/spec-anti-drift.md — RFC: gap analysis + layer-ownership model
- static/registry/normative-statements/ — registry of security MUSTs/claims
  tagged by enforcement layer + status, with a coverage linter
- scripts/check-normative-coverage.cjs — linter + dashboard + --min-enforced
  one-way floor (fails when an enforced statement is lost, not when a gap is added)
- scripts/run-doctests.cjs — offline doctest lane; runs `lang doctest` blocks in
  a scrubbed env, refuses shell blocks (executes PR-authored code in CI)
- .github/workflows/normative-guarantees.yml — blocking gate (permissions: read-only)

Tier-1 fixes (each flips its registry row to enforced):
- example_use -> adcp_use in the request-signing reference verifier — dead code
  that disabled the key-purpose separation check; guarded by a doctest
- add `intent` to the governance-phase enum so a buyer can express the
  intent-phase check the spec already mandates; guarded by
  tests/governance-phase-enum.test.cjs + changeset

Remaining Tier-1 findings are design decisions tracked in #5826-#5830.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pre-existing defect (unrelated to the anti-drift work on this branch): MDX reads
`<5` as a JSX tag with an invalid name and fails to parse, which trips the local
Mintlify broken-links pre-push preflight. The file is not published (absent from
docs.json) so CI never caught it. One-character escape; renders identically.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@aao-release-bot aao-release-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Argus is not auto-reviewing this PR because it modifies protected paths that require human review (.changeset/fix-governance-phase-intent.md, .github/workflows/normative-guarantees.yml, static/schemas/source/enums/governance-phase.json, static/schemas/source/governance/check-governance-request.json). A human reviewer should review and merge this PR; Argus will resume on subsequent PRs once these changes land on main.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant