Skip to content

docs(distribution): correct the review-credential visibility facts - #276

Merged
kyle-sexton merged 6 commits into
mainfrom
fix/review-credential-visibility-facts
Jul 26, 2026
Merged

kyle-sexton merged 6 commits into
mainfrom
fix/review-credential-visibility-facts

Conversation

@kyle-sexton

@kyle-sexton kyle-sexton commented Jul 26, 2026 •

Copy link
Copy Markdown
Member

Summary

distribution/REVIEW-CREDENTIAL.md classifies standards and claude-code-plugins as private, "confirmed firsthand". Both are public. Re-verified against the live GitHub API on 2026-07-26:

Repository Classified as Actual
standards private public
claude-code-plugins private public
ci-workflows public public ✓
dotfiles, provisioning, github-iac, medley private private ✓

Two consequences, in severity order.

1. The document's premise is void. Its entire rationale is that mounting private standards content into a review agent moves the confidentiality boundary from "who can read standards" to "who can read the review output". With standards public there is no such boundary. A native-reference mount of a public repo needs no credential at all — so the App this document classifies may be unnecessary, not merely scoped too widely.

2. Its scope and storage lists would leak secrets into public repositories. They name standards and claude-code-plugins as private targets. Wiring the org-secret visibility list as written would make both STANDARDS_REVIEW_APP_* secrets resolvable in a public repository's workflow runs — violating this document's own rule, two paragraphs later, that they are "never resolvable in a public-repo workflow run".

Nothing is provisioned (Status: classified, not provisioned), so nothing is exposed today. This closes the gap before anything is created.

What this change does and does not do

  • Adds a CAUTION block with the verified table and both consequences, stating plainly that the section must not be provisioned from and that the requirement should be re-derived from scratch — possibly to "no credential needed".
  • Leaves the superseded scope and storage lists unedited, deliberately, so a re-derivation sees exactly what was proposed rather than inheriting a silently patched plan.
  • Rewrites the surrounding prose so the general principle (a mount of private content into a publicly-visible review agent needs a scoped credential) stands on its own, separate from the now-false claim about which repos are private.
  • Retains the republication limits. They read as confidentiality controls, but the prompt-injection bullet — an attacker-controlled diff directing the agent to reproduce mounted content — is independent of repository visibility and keeps its full force. Removing them alongside the void premise would have been the easy mistake.

This does not decide whether the credential should exist. That is a design question for whoever re-derives it, and the document now says so instead of implying the answer.

Cross-doc reconciliation

Per distribution/governance-process.md's "Cross-doc reconciliation before a normative-doc change merges", stated explicitly rather than implied:

Searched the tracked tree for every site asserting the same concept — git grep -nE "private (target|consumer|caller|repo)s?|enrolled private|whole-file-managed private". Four sites carried the stale claim and all four are reconciled in this PR:

Site Was Now
distribution/REVIEW-CREDENTIAL.md two repos classified private corrected, with verification date and recheck trigger
distribution/README.md:141 "enrolled private targets" "enrolled targets" — an adoption list, not a visibility class
distribution/sync-manifest.test.sh:384 "each enrolled private consumer" "each enrolled consumer"
distribution/sync-manifest.test.sh:557 "four whole-file-managed private consumers" "four whole-file-managed consumers"

The README.md and test.sh errors pre-date this PR — claude-code-plugins was already public before this document was touched — but the duty to reconcile attaches to the change correcting the underlying fact, so they are fixed here rather than deferred.

Nothing else in the repository now contradicts the corrected fact. The remaining matches were checked individually and are correct as written: components/runner-policy/README.md and distribution/README.md:172 describe private repositories generically (conditional behaviour for selfHostedCi: true consumers) without asserting any named repository's visibility; lychee.toml and .github/dependabot.yml configure tooling against private repos as a class.

Test plan

  • typos — clean.
  • markdownlint-cli2 — 0 errors.
  • gitleaks, editorconfig — clean (pre-commit hook run).
  • Every visibility claim re-verified individually via gh api repos/melodic-software/<repo> --jq .visibility rather than carried over from the document.

Related

No linked issue.

Found while reviewing the runner-policy contract approval for ci-workflows@e295107 (#275). That approval gates these same two secrets out of every governed caller via allowedSecrets, which is what prompted checking whether the credential's own classification still held. It did not.

REVIEW-CREDENTIAL.md classified `standards` and `claude-code-plugins` as
private, "confirmed firsthand". Both are public — re-verified against the
live GitHub API on 2026-07-26. `dotfiles`, `provisioning`, `github-iac`,
and `medley` are private as stated; `ci-workflows` is public as stated.

Two consequences, in severity order.

The document's premise is void. Its rationale is that mounting private
`standards` content into a review agent moves the confidentiality boundary
from "who can read standards" to "who can read the review output". With
`standards` public there is no such boundary, so the App this document
classifies may be unnecessary rather than merely scoped too widely.

Its scope and storage lists would leak secrets into public repositories.
They name `standards` and `claude-code-plugins` as private targets, so
wiring the org-secret visibility list as written would make both
STANDARDS_REVIEW_APP_* secrets resolvable in a public repo's workflow
runs — violating this document's own rule that they are never resolvable
in a public-repo workflow run.

Nothing is provisioned, so nothing is exposed today; this closes the gap
before anything is created. The superseded lists are left unedited under
an explicit caution so a re-derivation can see what was proposed rather
than inheriting a silently patched plan.

The republication limits are retained: the prompt-injection control is
independent of repository visibility and keeps its full force.

Found while reviewing the runner-policy contract approval for
ci-workflows@e295107 (#275), which gates these same two secrets out of
every governed caller.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Jul 26, 2026 •

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 44s —— View job


Review

  • Gather context (REVIEW.md, CLAUDE.md)
  • Read the PR diff
  • Review changed file
  • Post findings

The change is technically sound and well-scoped. The editorial approach — adding a prominent CAUTION block, leaving the superseded lists intact for re-derivation, and disentangling the prompt-injection control from the now-void confidentiality rationale — is the right call. No blocking issues.

One nit in the retained text:

The republication limits preamble (lines 106–110) correctly explains that the bullets are kept for the prompt-injection control, not confidentiality. But the second bullet was left fully verbatim, and it still says:

the prompt-injection-via-diff class, where an attacker-controlled diff in the calling repo tries to use the mounted private tree as an exfiltration channel

Line 122–124 — standards is now public, so "private tree" is a factual error in a bullet that is otherwise correctly retained. The preamble contextualizes the confidentiality loss but doesn't fix this phrase. Unlike the frozen scope/storage lists (deliberately superseded), this bullet is kept as a live control, which means it should read correctly. "mounted tree" or "mounted standards tree" would be accurate.

Fix this →

Observations (no action required):

  • The abstract principle paragraph (lines 56–62) still says "Mounting private content into a review agent…" — intentionally general for future applicability. The trailing sentence on lines 64–66 correctly anchors it to the current standards situation. Readable as written.
  • The Classification section's scope and storage entries (lines 82–98) name standards and claude-code-plugins as private targets and define org-secret visibility accordingly — deliberately left unedited per the PR description. The CAUTION block's instruction to re-derive from scratch is the right guard rather than patching these piecemeal.
  • "private calling repo" in the document header (line 3) refers to the callers (dotfiles, provisioning, etc.), not to standards itself — still accurate.

The CAUTION block's language is clear and its two-consequence ordering (void premise first, secret-leak risk second) matches the actual severity. No findings on correctness or security; the nit above is the only real edit worth making before merge.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 41e5d8eb9b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread distribution/REVIEW-CREDENTIAL.md Outdated
Comment thread distribution/REVIEW-CREDENTIAL.md Outdated
Comment thread distribution/REVIEW-CREDENTIAL.md Outdated
…serted

Review found the correction had been applied to the site in front of it
rather than to every site the fact governs — the same failure the fact
itself documents.

Two other places still described the runner-policy enrollment set as
private while it contains the public `claude-code-plugins`:
distribution/README.md's consumer handoff, and the sync-manifest test's
assertion label. The enrolled set is correct; only the adjective was
wrong, so the wording now says what the list actually is — an adoption
list, not a visibility class.

Adds repository visibility to the review triggers. Visibility is mutable,
and a stale firsthand claim is precisely what invalidated this
classification once already, so the claim now carries a verification date
and a copy-paste recheck command instead of resting on its own authority
(conventions/engineering/documentation-and-citations.md: time-bound
external claims need a recheck trigger).

Rewrites the retained republication limits around output integrity rather
than access boundaries. With `standards` public no review output can reach
an audience that could not already read the cited criteria, so framing
them as confidentiality controls preserved the premise the change had just
retired. The prompt-injection-via-diff control is the part that survives,
and it survives on its own terms.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Jul 26, 2026 •

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 35s —— View job


Review

  • Gather context (REVIEW.md, CLAUDE.md)
  • Read the full PR diff (origin/main...HEAD)
  • Review changed files
  • Post findings

The second commit (6f81c9b) reconciles the visibility fact across all three files — distribution/README.md now describes the enrolled list as an adoption list, not a visibility class, with an inline note that claude-code-plugins is public; distribution/sync-manifest.test.sh drops "private" from the assertion label; and distribution/REVIEW-CREDENTIAL.md gains the Republication limits preamble reframing those controls around output integrity and the new Review-triggers paragraph with a recheck script. All three Codex P2 findings are now closed.

One nit carried from the prior review:

The prompt-injection bullet at REVIEW-CREDENTIAL.md#L125 still reads:

…where an attacker-controlled diff in the calling repo tries to use the mounted private tree as an exfiltration channel

standards is public. "Private tree" is a factual error in a bullet that is otherwise correctly retained as a live control. The preamble added in this commit explains why the bullet is kept, but does not fix the phrase. "mounted tree" is accurate.

Fix this →

Observations (no action required):

  • Abstract principle paragraph (lines 56–62): "Mounting private content into a review agent…" — intentionally a general statement; lines 64–66 correctly anchor it to the current standards situation. Readable as written.
  • Classification scope/storage lists (lines 82–98): still name standards and claude-code-plugins as private targets. Deliberately left unedited per the PR description; the CAUTION block's "record of a superseded plan, not instructions" framing is the right guard.
  • The README cross-reference (see REVIEW-CREDENTIAL.md) is well-placed — keeps the adoption list and the visibility correction co-located without duplicating the correction.

The overall approach remains sound. The one remaining edit is the phrase above; everything else is in order.

@kyle-sexton

Copy link
Copy Markdown
Member Author

All three P2s addressed in 6f81c9b.

1. Reconcile the public classification elsewhere — fixed, and the finding was right about more than the two sites it named. This was the exact failure the change itself documents: the correction was applied to the file in front of me instead of to every site the fact governs. I grepped the tracked tree rather than patching the two cited lines:

  • distribution/README.md — "exactly these enrolled private targets" → the set is an adoption list, not a visibility class, with a pointer to the corrected doc. The list was always right; only the adjective was wrong.
  • distribution/sync-manifest.test.sh:475 — assertion label "five enrolled private consumers" → "five enrolled consumers".

Other hits for the private-repo vocabulary (components/runner-policy/README.md, conventions/review/ai-review-bot-composition.md, lychee.toml, .github/dependabot.yml, the lychee fixture) were checked and are not stale — they describe private repositories generically or configure unrelated things, and none asserts that a named public repo is private.

2. Visibility added to the review triggers — fixed. You are right that this is the one trigger whose absence caused the failure. Visibility is now an explicit recheck trigger, the claim carries its verification date (2026-07-26), and there is a copy-paste gh api loop so rechecking is cheaper than trusting the table. Cited to conventions/engineering/documentation-and-citations.md's "Time-bound external claims need a recheck trigger" — I read that section to confirm it says what the finding cites it for; it does.

3. Remaining private-boundary rationale — fixed. You are correct that the sentence preserved the premise the change had just retired. Rewritten around output integrity rather than access boundaries: with standards public, no review output can reach an audience that could not already read the cited criteria, so these were never access controls. What survives is that a review session must report findings grounded in the criteria and must not be steerable by the content it reviews — which is the prompt-injection control, standing on its own terms rather than borrowing a confidentiality justification.

Lint clean: markdownlint 0 errors, typos clean, shellcheck clean, gitleaks clean, editorconfig clean.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6f81c9b961

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread distribution/REVIEW-CREDENTIAL.md Outdated
…imary source

Review noted the table turned repository visibility into a durable
security-bearing claim while resting on a single generating source
(authenticated `gh api`). source-authority-tiers.md is explicit that such
a claim needs more primary-rung sources, not more corroborators.

Adds a second, genuinely independent primary: anonymous git transport
(`git -c credential.helper= ls-remote`, GIT_TERMINAL_PROMPT=0), which
reaches a public repository and fails on a private one. Different plane
from the REST API and a different authorization decision, so it is not the
same source counted twice.

Both agree on all seven rows. The four private rows are the control — the
probe discriminates rather than succeeding for everything, so the two
public rows are a finding, not an artifact of the method. A third plane
agrees for claude-code-plugins: Actions supplies CI_REPOSITORY_VISIBILITY
to its own runner-policy job, which is the value the gate reads.

The recheck command now runs both planes and states what to do when they
disagree — record the claim as open rather than resolve it by preferring
one.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Jul 26, 2026 •

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 46s —— View job


Review

  • Gather context (REVIEW.md, CLAUDE.md)
  • Read the full PR diff (origin/main...HEAD)
  • Review changed files
  • Post findings

The third commit (d2ca0fe) addresses the Codex P2 on corroboration. The approach is correct.

Corroboration assessment — Codex P2 resolved:

The CAUTION block now cites two independent primary-rung sources:

  1. Authenticated REST API (gh api repos/melodic-software/<repo> --jq .visibility)
  2. Anonymous git transport — git -c credential.helper= ls-remote with GIT_TERMINAL_PROMPT=0 GIT_ASKPASS=true

These are genuinely independent: different protocols, different authorization decisions (authenticated identity vs. unauthenticated reachability). The document correctly notes they are "not the same source twice." A third plane is cited for claude-code-plugins specifically (GitHub Actions CI_REPOSITORY_VISIBILITY: public) as a bonus, not as a required corroborator.

The control group (four private repos that return unreachable — private) demonstrates the probe discriminates rather than vacuously succeeding. Without it, both public rows could be an artifact of the tool. That's the right epistemic move.

The recheck script is well-constructed: both planes in a single loop, side-by-side output, and the surrounding prose explicitly states "if they diverge, the claim is uncorroborated at any count." The GIT_TERMINAL_PROMPT=0, GIT_ASKPASS=true, and credential.helper= combination is defensively correct for unauthenticated probing.

The citation "requires more primary sources for those, not more corroborators" is a precise reading of source-authority-tiers.md's security-bearing durable claim requirement. The document gets this right.

One nit — third notice, still unaddressed:

REVIEW-CREDENTIAL.md#L143:

…where an attacker-controlled diff in the calling repo tries to use the mounted private tree as an exfiltration channel

standards is public. "Mounted private tree" is a factual error in the prompt-injection bullet — which is explicitly kept as a live control, not frozen alongside the superseded scope/storage lists. A live control should read accurately. "Mounted tree" is correct.

This was flagged in both prior reviews. The preamble added in commit 6f81c9b explains why the bullet is retained; it does not fix this phrase.

Fix this →

Observations (no action required):

  • The CAUTION block's opening claim — "two independent primary-rung sources" — is accurate and correctly applies the source-authority-tiers.md framing for security-bearing durable claims.
  • The abstract principle paragraph (lines 74–80) retains "Mounting private content…" as an intentionally general statement; lines 82–84 correctly anchor the current situation. Readable as written.
  • Classification scope/storage lists (lines 100–116): still name standards and claude-code-plugins as private targets. Correctly left unedited per the PR's stated approach; the CAUTION block is the right guard.
  • README cross-reference is well-placed: the adoption list correction and the pointer to REVIEW-CREDENTIAL.md co-locate the visibility fix without duplicating it.

The overall three-commit arc is sound. The one remaining edit is the phrase above.

@kyle-sexton

Copy link
Copy Markdown
Member Author

Fourth finding addressed in d2ca0fe.

Corroborate the durable visibility classification — you were right, and the convention you cited says something stronger than "add a corroborator".

source-authority-tiers.md states that a claim "entering durable content, gating an irreversible action, or bearing on security or identity needs more primary-rung sources, not more corroborators — corroboration protects against one source being unrepresentative; it does not protect against every source being wrong." My table was one primary (authenticated gh api) presented as settled. Adding secondhand corroboration would not have fixed that.

Second primary added — anonymous git transport:

git -c credential.helper= ls-remote https://github.com/melodic-software/<repo> HEAD

with GIT_TERMINAL_PROMPT=0 / GIT_ASKPASS=true. It reaches a public repository and fails on a private one. Different plane from the REST API and a different authorization decision, so it is not the same source counted twice.

Both agree on all seven rows:

Repository Authenticated API Anonymous transport
standards public reachable — public
claude-code-plugins public reachable — public
ci-workflows public reachable — public
dotfiles private unreachable — private
provisioning private unreachable — private
github-iac private unreachable — private
medley private unreachable — private

The four private rows are the control. Without them the probe proves nothing — a method that returns "public" for everything would produce the same two public rows. They discriminate, so the finding is a finding and not an artifact.

A third plane agrees for claude-code-plugins: Actions supplies CI_REPOSITORY_VISIBILITY: public to that repo's own runner-policy job, which is the value the gate itself reads.

The recheck command in the review-triggers section now runs both planes, and states what to do when they diverge — record the claim as open rather than resolve it by preferring one, per the same convention's "a claim where the retrieved sources disagree is not corroborated at any count".

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d2ca0fe46b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread distribution/REVIEW-CREDENTIAL.md
Comment thread distribution/REVIEW-CREDENTIAL.md Outdated
…ming it

Review is right that the three observation planes are one source, not
three: authenticated REST, anonymous git transport, and the Actions-supplied
visibility value all read GitHub's repository state, and
source-authority-tiers.md counts sources sharing an upstream pool once.

Conceding rather than patching. Repository visibility is a fact GitHub
owns; no independent pool exists to corroborate it from, so the floor of
one primary plus two independent corroborators is unmeetable for this class
of claim, not merely unmet here. Labelling three planes as independent
sources was the overclaim.

The text now says what the evidence is worth: three planes buy protection
against observation error — stale credential context, cached value,
mistyped repository — which is the realistic failure mode, and buy nothing
against GitHub being wrong about its own repositories, which is not a
failure mode because that state is the fact.

Also ungates the open questions. They were gated on an App the caution
block says not to provision, which deadlocks the re-derivation that block
asks for. With `standards` public an anonymous checkout mounts the same
tree, so --add-dir visibility, SDK rule loading, default tool grants, and
OAuth quota are all pilotable now; only private-marketplace authentication
remains genuinely credential-dependent.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Jul 26, 2026 •

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 39s —— View job


Review

  • Gather context (REVIEW.md, CLAUDE.md)
  • Read the full PR diff (origin/main...HEAD)
  • Review changed files
  • Post findings

The fourth commit (6907197) closes both Codex P2s from the prior round. Both closures are correct.

Codex P2 — corroboration overclaiming — resolved:

The CAUTION block now says outright: "These are one source, not three, and the claim does not meet this repository's corroboration floor." It then explains why the floor is unmeetable for this class of claim — repository visibility is a fact GitHub owns; no independent pool exists outside GitHub to corroborate it from. The commit doesn't try to manufacture additional sources; it correctly characterizes the limit and explains what multi-plane probing does buy (protection against observation error, not against GitHub being wrong about its own state). That is the right application of source-authority-tiers.md for a fact with only one authoritative owner.

Codex P2 — pilots gated on the obsolete App — resolved:

The Open Questions section is rewritten to un-gate the pilots. It now states that with standards public most pilots no longer depend on the App — an anonymous checkout reaches the same tree — and that gating them on an App the CAUTION block says not to provision "would deadlock the re-derivation it asks for." Private-marketplace authentication is correctly identified as the one genuinely credential-dependent question.

One nit — fourth notice:

REVIEW-CREDENTIAL.md#L156:

…where an attacker-controlled diff in the calling repo tries to use the mounted private tree as an exfiltration channel

standards is public. The prompt-injection bullet is explicitly retained as a live control, not frozen alongside the superseded scope/storage lists. A live control that now reads incorrectly is worth fixing. "Mounted tree" is accurate.

This has appeared in all three prior reviews. The fourth commit addressed the Codex P2s but not this phrase.

Fix this →

Observations (no action required):

  • The document header (line 3) still says "a private calling repo's CI job" — this refers to the callers (dotfiles, provisioning, etc.) which remain private. Still accurate.
  • The abstract principle paragraph (lines 87–97) says "Mounting private content into a review agent…" — intentionally general; lines 95–97 correctly anchor the current situation. Readable as written.
  • Classification scope/storage lists (lines 113–129): left unedited per the stated approach; the CAUTION block is the right guard.
  • The corroboration explanation is intellectually honest and correctly applies the standard's own reasoning rather than gaming a count. That is exactly the right move when the floor is structurally unmeetable.

No blocking findings. The one remaining edit is the phrase above.

@kyle-sexton

Copy link
Copy Markdown
Member Author

Both addressed in 6907197. Taking the second as a concession rather than patching around it.

Supply evidence from independent upstream pools — you are right, and I have stopped claiming otherwise.

Authenticated REST, anonymous git transport, and the Actions-supplied CI_REPOSITORY_VISIBILITY all read GitHub's repository state. Under source-authority-tiers.md's "two sources are one source when they share an upstream pool", that is one source, not three. Labelling them independent was an overclaim, and adding a fourth reader of the same pool would not fix it.

But the fix is not to find independent pools — there are none. Repository visibility is a fact GitHub owns. No other authority knows it. So the floor of one primary plus two independent corroborators is unmeetable for this class of claim, not merely unmet here. The document now says exactly that, and says what the three planes actually buy:

  • protection against observation error — stale credential context, cached value, mistyped repository — which is the realistic failure mode;
  • nothing against GitHub being wrong about its own repositories, which is not a failure mode, because that state is the fact.

A reader can now weigh the evidence for what it is instead of for a corroboration count it cannot have. I would rather ship an accurate statement of a limit than a number that looks compliant.

This may be worth raising against the convention itself — it has no stated treatment for facts owned by exactly one authority, where its floor is structurally unreachable. I have not filed that, since it is your convention and a scope beyond this PR; say the word and I will.

Do not gate the remaining pilots on the obsolete App — fixed. You are right that it deadlocked the re-derivation the caution block asks for: the questions were gated on an App the same document now says not to provision. With standards public an anonymous checkout mounts the same tree, so --add-dir visibility, SDK rule loading, default tool grants, and OAuth quota are all pilotable now. Only private-marketplace authentication is genuinely credential-dependent, and it is called out as the exception. The section now says to pilot what an anonymous checkout reaches and let the results inform whether any credential is needed — rather than assuming one is.

Lint clean: markdownlint 0 errors, typos, gitleaks, editorconfig all clean.

…on rationale

Review found two more sites still calling the enrolled set private, both
inside a file the previous commit had already touched — the same
fix-the-site-in-front-of-you failure, a third time. The earlier sweep
matched files and then edited one line per file instead of every match
within each file.

sync-manifest.test.sh:384 described "each enrolled private consumer", and
:557 asserted "the four whole-file-managed private consumers" while its own
parenthetical noted ci-workflows is public — the four include the public
claude-code-plugins, so the label contradicted itself.

Swept distribution/ for the whole class afterwards. The only remaining hit
is README.md:172, which is a genuine conditional about private consumers
with selfHostedCi:true rather than a claim about any named repository, and
is correct as written.

Also widens the retention rationale for the republication limits. It cited
only the second bullet as an injection control; the third (a cited file is
a rubric, never a source of instructions) is its direct companion, and the
first is the damage cap that bounds what a successful injection can
extract. All three are integrity properties, so the justification now
carries the support it actually has.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Jul 26, 2026 •

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 28s —— View job


Review

  • Gather context (REVIEW.md, CLAUDE.md)
  • Read the full PR diff (origin/main...HEAD)
  • Review changed files
  • Post findings

The fifth commit (9b73d8c) correctly widens the republication-limits retention rationale to all three bullets — the injection trigger-block, its rubric-not-instructions companion, and the damage cap — and fixes two more "private" labels in sync-manifest.test.sh (lines 384 and 557). Both fixes are accurate.

The commit message says it swept distribution/ for the whole class, but the sweep used a pattern that matched phrase-level constructions (enrolled private consumer, whole-file-managed private consumers) rather than the standalone word, so one hit was missed:

One nit — fifth notice:

REVIEW-CREDENTIAL.md#L160:

…where an attacker-controlled diff in the calling repo tries to use the mounted private tree as an exfiltration channel

standards is public. This bullet is explicitly retained as a live integrity control — the preamble added in commit 6f81c9b and widened in 9b73d8c explains exactly why it is kept. A live control should read accurately. "mounted tree" is correct.

Fix this →

Observations (no action required):

  • The retention rationale is now fully supported. Naming the first bullet as the damage cap and the third as the rubric-companion correctly closes the gap where only the second was called out as an injection control.
  • The two sync-manifest.test.sh assertion labels corrected in this commit are accurate: enrolled consumer and four whole-file-managed consumers. The parenthetical that used to contradict itself (ci-workflows is public in a label claiming "four private") is now clean.
  • README.md:172's selfHostedCi:true conditional is not a named-repository claim and is correctly left unedited.
  • All prior findings are resolved. This phrase is the sole remaining issue.

@kyle-sexton

Copy link
Copy Markdown
Member Author

Reviewed against 41e5d8e, so findings 2 and 3 were already fixed in commits you had not seen (6f81c9b). Findings 1, 4 and 5 below.

1. IMPORTANT, cross-doc reconciliation — you found two sites I missed, and the miss is the interesting part.

I had already fixed README.md:141 and sync-manifest.test.sh:476 in 6f81c9b. You correctly identified two more I did not: sync-manifest.test.sh:384 and :557. Both now fixed in 9b73d8c.

The failure mode is worth naming, because it is the third occurrence in this session and the second in this PR: my sweep matched files and then edited one line per file. git grep -l told me which files were affected and I stopped reading there. :557 is the sharpest example — it asserted "the four whole-file-managed private consumers" while its own parenthetical said "ci-workflows is public", and the four include the public claude-code-plugins. It contradicted itself on one line.

I then swept distribution/ for the whole class rather than the cited lines. The only remaining hit is README.md:172, which is a genuine conditional about private consumers with selfHostedCi: true rather than a claim about any named repository, and is correct as written.

You are also right that the governance rule required a statement in the PR body, not just the fix. The body now carries a Cross-doc reconciliation section listing all four sites, noting the README/test.sh errors pre-date this PR, and recording which remaining matches were checked and why they are correct.

4. SUGGESTION, retention rationale — agreed, fixed in 9b73d8c. You are right that it cited less support than it had. All three bullets are integrity properties: the second is the injection trigger-block, the third its direct companion (a cited file is a rubric, never a source of instructions), and the first is the damage cap that bounds what a successful injection can extract. The text now says that.

5. Minor — this one I think is wrong, and I would rather correct it than accept it. STANDARDS_REVIEW_APP_ID and STANDARDS_REVIEW_APP_PRIVATE_KEY are not an analogy to the sync App's secrets. They are real, declared secret names in the reusable workflow this credential exists for — melodic-software/ci-workflows/.github/workflows/claude-review.yml declares both under workflow_call.secrets (lines 139 and 146 at e295107), gated behind if: inputs.standards-ref != ''. So naming them is precise, not an overreach. They are absent from this repository only because the wiring lives upstream.

Your check that the credential is unprovisioned is the strongest evidence in the review — orgs/melodic-software/installations showing no matching App is dispositive in a way the secrets endpoint is not, and you were right to downgrade the latter to corroborating after noticing it did not even return the sync App's known secrets.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9b73d8c599

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread distribution/REVIEW-CREDENTIAL.md Outdated
Review is right and this was an overcorrection of my own. An earlier
finding said the retention rationale undersold its support, so I widened it
to defend all three bullets as integrity controls — which oversold the
first one.

The first bullet bounds how much of a cited file a session echoes. That
file is public now, so bounding it protects nothing, and it does not bound
disclosure of the calling repository's content, its secrets, or the
session's tool actions — which is where the exposure actually sits once an
injection succeeds. Calling it a damage cap implied a protection it does
not provide.

All three bullets are still retained, now for the two different reasons
they actually have: the second and third are the injection controls and
hold regardless of visibility; the first is review-output discipline, so
findings stay grounded and terse rather than quoting rubric at the reader.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@kyle-sexton

Copy link
Copy Markdown
Member Author

Fixed in e088407 — and this one was my overcorrection, not a leftover.

Your earlier suggestion said the retention rationale undersold its support, so I widened it to defend all three bullets as integrity controls. That oversold the first one, and you caught it in the same PR.

You are right about what it actually bounds: the first bullet limits how much of a cited file a session echoes. That file is public now, so bounding it protects nothing — and it does not bound disclosure of the calling repository's content, its secrets, or the session's tool actions, which is where the exposure sits once an injection succeeds. "Damage cap" implied a protection it does not provide.

All three bullets are still retained, now for the two different reasons they actually have:

  • Second and third — injection controls. Block the trigger; refuse to treat a cited file as instructions rather than a rubric. Both hold regardless of repository visibility, and they are why the section survives at all.
  • First — review-output discipline, explicitly not a security control. Findings stay grounded and terse instead of quoting rubric at the reader. The text now says that outright, so nobody reads it as protection it isn't.

That is three rounds where the correct move was to weaken a claim rather than defend it: the corroboration count, the pilot gating, and now this. Worth noting since the pattern is mine, not the document's.

@claude

claude Bot commented Jul 26, 2026 •

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 31s —— View job


Review

  • Gather context (REVIEW.md, CLAUDE.md)
  • Read the full PR diff (origin/main...HEAD)
  • Review changed files
  • Post findings

The sixth commit (e088407) correctly addresses the Codex P2 from the prior round — the "damage cap" claim is removed, and the preamble now clearly distinguishes the two separate reasons the three bullets are retained: the first as review-output discipline only, the second and third as actual injection controls. The framing is accurate and the commit message explains the reasoning well.

One nit — sixth notice, still unaddressed:

REVIEW-CREDENTIAL.md#L168:

…where an attacker-controlled diff in the calling repo tries to use the mounted private tree as an exfiltration channel

standards is public. This bullet is the injection trigger-block — one of the two bullets explicitly called out in e088407's own preamble as an injection control that is "retained, for two different reasons." A control retained as a live integrity mechanism should read accurately. "mounted tree" is correct.

This has appeared in every prior review round (commits 41e5d8e, 6f81c9b, d2ca0fe, 6907197, 9b73d8c) without being addressed. The preamble in e088407 again correctly explains why the injection controls are kept, but still does not fix this phrase.

Fix this →

Observations (no action required):

  • The preamble rewrite in e088407 is the right shape: the damage-cap framing implied a protection the first bullet does not provide (it bounds output from a now-public file, not disclosure of private caller state or secrets). "Review-output discipline" is the accurate characterization.
  • The injection-control framing for the second and third bullets is unchanged and correct. Both hold regardless of visibility.
  • All prior findings from this review arc are resolved. This phrase is the only remaining issue.

@kyle-sexton
kyle-sexton merged commit 82255bc into main Jul 26, 2026
1 check passed
@kyle-sexton
kyle-sexton deleted the fix/review-credential-visibility-facts branch July 26, 2026 17:21

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e088407a34

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +36 to +40
> **These are one source, not three, and the claim does not meet this
> repository's corroboration floor.** Under
> [`source-authority-tiers.md`](../conventions/engineering/source-authority-tiers.md)
> sources that "share an upstream pool" count once, and all three read GitHub's
> repository state. Repository visibility is a fact GitHub *owns*; no

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Leave the under-corroborated visibility claim open

The fresh evidence in this revision is the explicit concession that all three observations count as one source and therefore do not meet the repository's corroboration floor, yet the following table and downstream edits still treat the visibility classification as settled durable security guidance. Either keep the classification and resulting credential decision open until the stated floor is met, or amend the source-authority convention to define and justify an exception for upstream-owned state; declaring the rule unmeetable does not itself waive it.

AGENTS.md reference: AGENTS.md:L25-L28

Useful? React with 👍 / 👎.

> unedited so the re-derivation can see exactly what was proposed; they are a
> record of a superseded plan, not instructions.

The native-reference mount is **forbidden on any public calling repo**.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Scope the public-caller prohibition to private mounts

When a public caller such as claude-code-plugins uses the distributed review instructions, this absolute prohibition still forbids its native-reference mount even though this change establishes that the mounted standards source is public and needs no credential. The following rationale only applies when the mounted content is private, so qualify the prohibition accordingly; otherwise operators can disable a valid public-source review path based on a confidentiality boundary that lines 95–97 say no longer exists.

Useful? React with 👍 / 👎.

Comment on lines +71 to +73
> boundary that no longer exists. A native-reference mount of a public repo
> needs no credential at all, and the App this document classifies may be
> unnecessary rather than merely scoped too widely.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reconcile the distribution overview with the no-credential result

This new conclusion that mounting public standards needs no credential leaves distribution/README.md:22-24 contradicting it: the distribution entry point still says a private caller uses a separate read-only credential for exactly this mount. Readers starting from the README can therefore continue designing or provisioning the obsolete App without reaching the caution here; update that overview to describe the classification as superseded or unresolved.

AGENTS.md reference: AGENTS.md:L29-L32

Useful? React with 👍 / 👎.

kyle-sexton added a commit that referenced this pull request Jul 27, 2026
…ntial (#278)

## What

- **REVIEW.md**: restructured into mutually exclusive lane-scope
sections — `## Code-review lane scope` (audit-logging + atomicity
always-checks) and `## Security lane scope` (the four `blocking`
always-checks). Deleted the report-stage filtering sections (`## Do not
report`, `## Cap the nits`) per Anthropic's Sonnet-5 harness-effect
guidance. `## Severity`, `## Depth`, and `blocking` tag semantics
unchanged.
- **distribution/REVIEW-CREDENTIAL.md**: re-derivation #264 asked for,
on top of #276's corrected visibility facts — with `standards` public no
consumer needs the credential (anonymous checkout reaches the same
tree); the `--add-dir` subagent-visibility open question marked
empirically resolved; provisioning stays deferred behind github-iac
governance.

Closes #264

## Related

- #276 — corrected the visibility facts this re-derivation builds on
(merged 2026-07-26).
- melodic-software/ci-workflows
`docs/topics/claude-review-lanes/PLAN.md` — the approved implementation
plan; this PR is its Phase 1. Phase 2's model-switch PR is gated on the
five downstream `review-instructions` sync PRs this merge triggers.
- melodic-software/claude-code-plugins#289 — carries the verification
annex #264 drew from.

## Notes

- **Independent verification (fresh-context agent, 7/7 criteria PASS + 1
blocking flag, fixed in 50b4969):** the first cut asserted the security
lane consumes this file (it runs from its own security-only prompt and
never reads it) and made the security-findings exclusion unconditional —
which would have suppressed the four `blocking` checks on the five repos
whose only reviewer is the code-review lane until the Phase 3 fleet
rollout. The intro now records scope ownership rather than wiring, and
the exclusion is gated on a `claude-security-review` workflow existing
in the repo — self-resolving as the rollout proceeds, no coverage
window.
- Deviation from the plan's original premise: the plan predates #276 and
framed the re-derivation as "claude-code-plugins is public →
ineligible". #276 established `standards` itself is public, which
supersedes per-repo eligibility — the re-derivation records that no
credential is needed at all under current state. Direction (defer
provisioning) unchanged.
- Deviation: the plan said "update `## Review triggers`" in
REVIEW-CREDENTIAL.md; left untouched — verified the existing triggers
already cover both credential-return cases (visibility change;
open-question resolution).
- Known loss: the deleted "Do not report" section was the only REVIEW.md
mention of `conventions/review/overlays/`; overlays still reach plugin
surfaces via `conventions/review/README.md`.
- Follow-up (ci-workflows Phase 2): `claude-review.yml`'s default prompt
says "review for … security"; with this split that wording should name
the lane and defer security scope per this file.
- `review-instructions` is a managed component in 5 repos and
locally-owned in medley; medley content-equivalence is a Phase 5
follow-up in the plan above.
- Cross-doc reconciliation swept: no other doc cites the deleted
sections; `conventions/review/README.md`'s `blocking` crosswalk
statements still hold against the restructured file.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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