Repository navigation
Conversation
… (DR-0037) Resolves #8409 with Konstantin's proposal: keep ICANN+PRIVATE, no runtime fetch, and fail closed with no eTLD+1; drop "two verifiers running different PSL versions are non-conformant against each other" and the library names; refresh through dependency updates. Step 3 of Discovering an agent's signing keys is the one home, and R3a step 1, L2, the threat table, and the trust.json grantee description point to it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Ladon verdict: Escalate to human review
Escalate — gated path touched without required approval, plus a Breaking-class governance question.
This PR relaxes the cross-verifier PSL pinning requirement and ratifies DR-0037. The diff modifies static/schemas/source/trust/v1/trust.json, which is under the hard, path-based approval gate (gated_paths: true). The current review_decision is REVIEW_REQUIRED, not APPROVED, so the gate is NOT satisfied and the outcome must be escalate (decision table row 2).
Additionally, this is a normative spec relaxation that reverses a previously-stated requirement — a governance/ratification decision that per the repo's "ratification is a human act" rule is never auto-approved without review_decision: APPROVED. Both triggers point to the same place: a human/CODEOWNERS reviewer must sign off.
Medium findings
- specs/capabilities-brand-url.md:384 — Sibling design specs (capabilities-brand-url.md:325,384; brand-identity-trust-split.md:149) still assert the "pinned PSL snapshot" requirement DR-0037 now reverses. Coherence follow-up; not blocking on its own.
No critical/high findings: schema change is description-only and coherent with L2 docs, no oneOf/wire-shape change, changeset present and correctly scoped. The remaining concern is purely the approval gate.
Escalation reasons
static/schemas/source/trust/v1/trust.jsonis under the gated-paths approval gate andreview_decisionisREVIEW_REQUIRED— human/CODEOWNERS review required before merge.- Normative spec relaxation reversing a prior requirement (DR-0037) — ratification is a human act.
Medium findings
- specs/capabilities-brand-url.md:384 — Sibling design specs still assert the "pinned PSL snapshot" requirement DR-0037 reverses
Why human review
- static/schemas/source/trust/v1/trust.json is under the gated-paths hard approval gate and review_decision is REVIEW_REQUIRED (not APPROVED) — human/CODEOWNERS review required
- Normative spec relaxation reversing a prior requirement and ratifying DR-0037 — ratification is a human act, not auto-approvable
- This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/trust/v1/trust.json (modified) matches
static/schemas/source/**) and the current GitHub review decision is 'REVIEW_REQUIRED', not APPROVED. This is a hard gate enforced in code — Ladon cannot auto-approve until a human/CODEOWNERS approval is recorded, regardless of how clean the diff is.
There was a problem hiding this comment.
Ladon verdict: Escalate to human review
Escalate — gated path touched without required approval.
This PR modifies static/schemas/source/trust/v1/trust.json, which matches the deterministic hard approval gate (static/schemas/source/**). gated_paths is true and review_decision is REVIEW_REQUIRED (not APPROVED), so per decision rule row 2 the outcome must be escalate — human/CODEOWNERS approval is required before this can merge.
No blocking code findings: the reviewer found a clean, coherent spec/governance change dropping the cross-verifier PSL-pinning requirement in favor of a bundled, never-fetched-at-runtime list, ratified in new record DR-0037. Changeset is present and correctly typed patch (trust.json is experimental, the change only relaxes a conformance requirement, a pinned snapshot still conforms); the schema edit is description-only (no wire-shape change, so no schema↔docs drift); DR-0037's partial supersession of DR-0023 is accurate; all live normative surfaces updated consistently; fail-closed reasoning sound and the runtime-fetch ban retained.
The change itself is non-breaking (a relaxation, not a breaking wire change), but the gated-path approval gate is unsatisfied regardless. A real human/CODEOWNERS approval lifts this gate.
Escalation reasons:
static/schemas/source/trust/v1/trust.jsonis under the hard approval gate (static/schemas/source/**) andreview_decisionisREVIEW_REQUIRED, notAPPROVED— human/CODEOWNERS review required.
Why human review
- Modifies static/schemas/source/trust/v1/trust.json (gated path static/schemas/source/**) while review_decision is REVIEW_REQUIRED, not APPROVED — human/CODEOWNERS approval required to satisfy the hard approval gate.
- This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/trust/v1/trust.json (modified) matches
static/schemas/source/**) and the current GitHub review decision is 'REVIEW_REQUIRED', not APPROVED. This is a hard gate enforced in code — Ladon cannot auto-approve until a human/CODEOWNERS approval is recorded, regardless of how clean the diff is.
Ladon's coherence finding on #8702. capabilities-brand-url.md's revision log stays as history. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@KonstantinMirin, this is your #8409 proposal, recorded as DR-0037. Could you review and approve? It needs a human approval: the description-only edit to |
There was a problem hiding this comment.
Ladon verdict: Escalate to human review
Escalate — hard approval gate not yet satisfied.
This PR modifies static/schemas/source/trust/v1/trust.json, which matches the gated path glob static/schemas/source/**. Per the deterministic hard approval gate (decision rule row 2), gated_paths: true AND review_decision: REVIEW_REQUIRED (not APPROVED) forces escalation — human/CODEOWNERS approval is required before this can merge, regardless of how clean the diff is.
The reviewer's delta is clean: 29 lines across 2 files, both coherence cleanups for DR-0037 (PSL bundled, not pinned). DR-0037 frontmatter fills in the merged PR number (metadata-only); brand-identity-trust-split.md:146 aligns the last "pinned PSL snapshot" straggler to the "bundled with the verifier, never fetched at runtime" wording and cites DR-0037. No wire-shape change, no schema↔docs drift, no changeset-scope issue, no contradiction of governance precedent. No Critical/High/Medium findings.
This is a sticky escalation consistent with the prior decision: the gated-path hard gate remains unsatisfied. Once a human/CODEOWNERS approval is recorded (review_decision → APPROVED), this clean diff can fall through to approve.
Escalation reasons
- Modifies
static/schemas/source/trust/v1/trust.json(gated pathstatic/schemas/source/**) whilereview_decisionisREVIEW_REQUIRED, notAPPROVED— human/CODEOWNERS approval required to satisfy the hard approval gate.
Why human review
- Modifies static/schemas/source/trust/v1/trust.json (gated path static/schemas/source/**) while review_decision is REVIEW_REQUIRED, not APPROVED — human/CODEOWNERS approval required to satisfy the hard approval gate.
- This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/trust/v1/trust.json (modified) matches
static/schemas/source/**) and the current GitHub review decision is 'REVIEW_REQUIRED', not APPROVED. This is a hard gate enforced in code — Ladon cannot auto-approve until a human/CODEOWNERS approval is recorded, regardless of how clean the diff is.
KonstantinMirin
left a comment
There was a problem hiding this comment.
Hi Brian,
Thanks for picking this up. The decision reads right, and the R3a, step 3, and trust.json edits match what I proposed in #8409. Two places still say "pinned", and the record overstates three things. Each fix is a line or two.
Still says pinned
security.mdx:1454-1455. The verifier quickstart sample still callsetldPlusOne(host, PINNED_PSL_SNAPSHOT). I'd drop the second argument:const agentEtld1 = etldPlusOne(new URL(agentUrl).hostname); // step 3, bundled PSL const brandEtld1 = etldPlusOne(new URL(brandJsonUrl).hostname);
accounts-and-agents.mdx:380. "as registrable domains under the same snapshot" should be "under the same list".
Also at security.mdx:1428, "that step 3 above requires" sits in step 3 of the quickstart itself, so it reads as a self-reference. A link is clearer: "that step 3 of Discovering an agent's signing keys requires".
What the record overstates
-
"Fails closed" holds for trust records, but not for the
brand_json_urlorigin binding. Saynp.appjoins the PRIVATE section. A verifier with the older list givesalice.np.appandbob.np.appthe same eTLD+1. If Alice's brand.json listsbob.np.app/mcp, step 3 passes withoutauthorized_operators[], and step 6 takes Bob's keys from his origin. That is the shared-tenancy case step 3 exists to close.The decision still stands. Every verifier behaved this way before the listing, and the gap closes when the verifier updates. A pinned snapshot would keep it open until the next release. The DR and the changeset should say this rather than "fails closed" in general. The threat row in
agent-identity-3-3.mdis fine, because it covers trust records only.- DR rationale, after "which also fails closed": "The
brand_json_urlorigin binding goes the other way. An older list gives two tenants of a newly listed platform one eTLD+1, so the binding passes for them withoutauthorized_operators[]until the verifier updates. Every verifier behaved that way before the listing, and a pinned snapshot would keep the gap open until the next release." - Changeset: "A verifier whose list lacks a newly added PRIVATE suffix fails closed" becomes "On the trust-record path, a verifier whose list lacks a newly added PRIVATE suffix fails closed."
- DR rationale, after "which also fails closed": "The
-
"Two lists disagree only on suffixes added to, or removed from, the PRIVATE section." I wrote it that way in #8409, and it isn't quite right. The ICANN section changes too, through second-level suffixes under ccTLDs, for example the
.bdupdate in October 2025 andorg.ao,edu.ao, andgov.aoin 2024. A new TLD changes nothing, because the PSL default rule already treats an unlisted TLD as a suffix. "mostly in the PRIVATE section" fixes it, and the argument holds for both sections. -
"AdCP publishes no PSL snapshot and has no PSL conformance vectors."
static/test-vectors/adagents-discovery-redirects.jsonhas four PSL vectors:well-known-multi-label-tld-same-domain-followedandwell-known-multi-label-tld-cross-domain-refused(co.uk), andwell-known-private-suffix-cross-tenant-refusedandwell-known-private-suffix-same-tenant-followed(github.io). They're fine, because every list agrees on those suffixes. I'd write "AdCP publishes no PSL snapshot and no snapshot-specific vectors; the PSL vectors inadagents-discovery-redirects.jsonuse suffixes every list agrees on."
DR-0023 note
- DR-0026 and DR-0036 each mark the record they amend in part: DR-0023 carries
*Amended by DR-0026: …*, and DR-0019 carries*Amended by DR-0036: …*. DR-0023 needs the same for R3a step 1, for example after the design-spec paragraph at line 43: "Amended by DR-0037: R3a step 1 uses a Public Suffix List bundled with the verifier and refreshed through dependency updates; AdCP names no snapshot."
Server integration tests (3/4) failed in "Install dependencies" before any test ran, so a rerun should clear it.
Once these are in, I'll approve.
- Quickstart sample drops PINNED_PSL_SNAPSHOT; the step 3 pointer links to Discovering an agent's signing keys instead of reading as a self-reference. - L2: domains compare "under the same list". - DR-0037: lists differ mostly, not only, in the PRIVATE section; the brand_json_url origin binding passes for two tenants of a newly listed platform until the verifier updates; the adagents-discovery-redirects PSL vectors use suffixes every list agrees on. - Changeset scopes "fails closed" to the trust-record path. - DR-0023 carries the Amended by DR-0037 note. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks @KonstantinMirin. All six are in 7f75030, using your wording:
The PR body is updated to match. The earlier CI failures were in "Install dependencies", and this push reruns everything. |
There was a problem hiding this comment.
Ladon verdict: Escalate to human review
Escalate — hard approval gate not satisfied.
This PR modifies static/schemas/source/trust/v1/trust.json, which matches the gated glob static/schemas/source/** (gated_paths: true). The current review_decision is REVIEW_REQUIRED, not APPROVED. Per decision rule row 2, a gated path without a recorded human/CODEOWNERS approval MUST escalate — regardless of how clean the diff is.
The reviewer found no Critical/High/Medium findings: the DR-0037 governance amendment (PSL bundled, not pinned) is coherent across the changeset, L1/L2 docs, and DR-0023/DR-0037. The security.mdx cross-reference anchor verifies, schema↔docs coherence holds (trust.json grantee description matches the "bundled list" wording), and the patch changeset is defensible for a normative relaxation with no wire-shape change. There are no fresh blocking findings — but the gate is deterministic and does not lift on diff cleanliness.
This also carries forward the prior escalate posture (same gated-path trigger), which remains correct because the approval requirement is still unmet.
Escalation reasons
static/schemas/source/trust/v1/trust.jsonis under a hard approval gate (static/schemas/source/**) andreview_decisionisREVIEW_REQUIRED, notAPPROVED. Human/CODEOWNERS approval is required before this can merge.
Why human review
- Modifies static/schemas/source/trust/v1/trust.json (gated path static/schemas/source/**) while review_decision is REVIEW_REQUIRED, not APPROVED — human/CODEOWNERS approval required to satisfy the hard approval gate.
- This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/trust/v1/trust.json (modified) matches
static/schemas/source/**) and the current GitHub review decision is 'REVIEW_REQUIRED', not APPROVED. This is a hard gate enforced in code — Ladon cannot auto-approve until a human/CODEOWNERS approval is recorded, regardless of how clean the diff is.
Closes #8409, taking @KonstantinMirin's proposal from that thread: drop the cross-verifier PSL pinning requirement instead of building infrastructure for it.
Decision (DR-0037)
brand_json_urlquickstart (the Python one was wrong anyway).Why: lists differ only in suffixes added or removed between them, mostly in the PRIVATE section. On the trust-record path, a verifier with an older list derives the platform's trust record, which doesn't list the tenant, so the claim fails closed. The
brand_json_urlorigin binding goes the other way: an older list gives two tenants of a newly listed platform one eTLD+1 until the verifier updates. That's how every verifier behaved before the listing, and a pinned snapshot would keep the gap open until the next release. A shared snapshot also makes every verifier equally stale for a release cycle and costs a vendored list, SDK changes, vectors, and upkeep.Changes
security.mdx: step 3 of Discovering an agent's signing keys is the one home for the rule. The quickstart step 3 and Web Bot Auth identities step 1 now point to it.specs/agent-identity-3-3.md: R3a step 1 wording and the "PSL drift" threat row.L2/accounts-and-agents.mdxand the trust.jsongranteedescription (description only): "pinned snapshot" becomes "Public Suffix List".governance/decisions/DR-0037: amends DR-0023 in part (R3a's "pinned, dated" wording), and DR-0023 carries the Amended by DR-0037 note.brand-identity-trust-split.mdorigin binding, and the quickstart sample (noPINNED_PSL_SNAPSHOT).This relaxes a requirement, so every existing implementation stays conformant; an SDK that pins a snapshot still conforms. After merge, the SDK tracking issues adcontextprotocol/adcp-client#3379, adcontextprotocol/adcp-client-python#1562 and adcontextprotocol/adcp-go#590 close with no code changes.
🤖 Generated with Claude Code