The canary is public, so its non-merge boundary is enforced by the repository
Date: 2026-08-15
Status: open
Supersedes: none — resolves blocker C of docs/findings/20260814-1130-p3-c0-canary-credential-unsatisfiable.md
Superseded-by: none — current
Phase: PTV-SCF-0001 P3 · Verification harness (C0)
Terminal state of this record: a visibility ruling plus the branch protection
it unlocks, applied and verified by command output. It creates no credential and
does not close G-P3-1.
Context
Section titled “Context”docs/findings/20260814-1130-p3-c0-canary-credential-unsatisfiable.md blocker C
established that condition 3 of the conforming-credential set — “branch
protection on the canary’s default branch requiring a review the App cannot
supply to itself” — has no mechanism on the org’s current configuration:
$ gh api orgs/petrova-codesplan: free | owned private repos: 4
$ gh api repos/petrova-codes/petrova-canary/branches/main/protection403 — "Upgrade to GitHub Pro or make this repository public to enable this feature."
$ gh api repos/petrova-codes/petrova-canary/rulesets403 — "Upgrade to GitHub Pro or make this repository public to enable this feature."Branch protection and rulesets are both paid-plan features for private repositories only. Both are free on public repositories. The finding named three ways out and deliberately took none of them, because the choice is the operator’s.
Decision
Section titled “Decision”petrova-codes/petrova-canary becomes a public repository, and its default
branch carries branch protection that the probe credential cannot satisfy.
This is option 1 of the finding’s three. It is chosen over the other two on four grounds, in order of weight:
- It keeps the boundary in the repository, where the P0 audit says it has to
live. Option 3 (amend condition 3 to “the App simply does not hold a
permission that permits a direct push”) relocates the non-merge property from
the repository to the token’s grant. The P0 credential audit already
established that a boundary enforced in one place and not the other is a
convention, not a boundary — the
PRIVILEGED_PATH_REcross-finding is the precedent, and the whole scaffold exists to find defects of exactly that shape. Option 3 would have P3 certify a boundary using the reasoning P0 rejected. - It amends nothing. The canary ruling’s five conditions
(
2026-08-12-purpose-built-canary-supersedes-pwplz.md:38-52) never mention visibility. Condition 2 enumerates its disqualifiers exactly — “no published surface, no domain, no package, no stars, no inbound links, no history anyone would miss” — andpublicis not among them, nor entailed by any of them. So this record ratifies a configuration consistent with the ruling rather than superseding a condition. Option 3 would require a supersession that weakens a condition; option 1 requires neither. - It costs nothing and blocks on nobody. Option 2 (GitHub Pro/Team) reaches the same end state, preserves privacy, and is strictly a superset of this option’s capability — at a recurring cost, for a repository whose defining property is that it is disposable. If the org acquires a paid plan later for unrelated reasons, this record does not need reversing; it is a choice of mechanism, not a bet against paying.
- The
pwplzinference is not being repeated. The finding flagged the risk honestly: “an empty repo with one README is arguably not a surface — but ‘arguably’ is the word that produced thepwplzerror.” The distinction is thatpwplz’s inertness was inferred from a missing registry field, and the canary’s is constructed and positively checked. The ruling’s own method rule demands the positive form, and it is discharged below with command output, not with an empty column.
What “not a published surface” is checked against
Section titled “What “not a published surface” is checked against”Per the method rule at …purpose-built-canary-supersedes-pwplz.md:104-107, each
disqualifier gets a positive check rather than an absence:
| Condition-2 disqualifier | Check | State |
|---|---|---|
| published surface | contents are one README.md; no site, no Pages, no build | none |
| domain | no CNAME, no DNS record, not in registry.yaml url: as a live host | none |
| package | no manifest of any ecosystem in the tree | none |
| stars | stargazers_count | 0 |
| inbound links | no reference outside this control plane’s own records | none |
| history anyone would miss | single initial commit | none |
Public visibility changes exactly one thing about that table: it makes the absence verifiable by anyone, which is a strengthening of the ruling’s method rule rather than an exception to it.
The standing drift condition
Section titled “The standing drift condition”A public repository can acquire the very properties condition 2 forbids — a star, an inbound link, a fork — without anyone acting. That is a real cost of this option and it is not waved away:
- Issues, projects and the wiki are disabled at ratification, so the repo has no surface that invites participation.
- The
README.mdstates in its first line that the repository is a disposable write-probe target with no product meaning. - Acquiring a star, fork, or inbound link is a supersession trigger, not a tolerance. If the check table above stops reading clean, the canary is deleted and recreated (condition 5 exists for this) or this record is superseded. A drifted canary is not quietly kept.
Alternatives considered
Section titled “Alternatives considered”- GitHub Pro / Team on the org (finding option 2). Rejected as the default, not as wrong. It preserves privacy and reaches an identical enforcement posture, at recurring cost, for a repository defined by being disposable. It remains available and would not require reversing this record.
- Amend credential condition 3 (finding option 3). Rejected on ground 1 above. The finding itself named this as “the one an agent under delivery pressure would choose: it needs no money and no human account action” — and it is being explicitly declined here, with the reason recorded, so that the decline is auditable rather than assumed.
- Rulesets instead of classic branch protection. Equivalent on the free plan
once public. Classic branch protection is chosen because condition 3 is
phrased in its vocabulary and because
gh api …/branches/main/protectionis the exact call the finding already ran, so the before/after evidence is directly comparable. - Leave C0 blocked pending a paid plan. Rejected: it stalls P3 on a billing decision when a free mechanism satisfies the condition as written.
Consequences
Section titled “Consequences”For the canary:
petrova-codes/petrova-canaryis public. Issues, projects and wiki disabled.maincarries branch protection with required pull request reviews, applied to administrators, with force-push and deletion denied.
For the credential:
- Condition 3 becomes evaluable for the first time. It is not thereby satisfied — satisfaction is the negative test in condition 5, which is G-P3-1, and which still requires the single-repo App that does not yet exist (blocker B).
- Nothing here reduces what act 3 must produce. It fixes what act 3 is tested against.
For the probe:
- Probe output on the canary is world-readable. This is acceptable and is stated rather than assumed: probe writes are synthetic, carry no secret, and the App credential is held outside the repository per blocker B’s third act. No probe may ever write real fleet state, a token, or a customer-shaped value to the canary — a public canary makes that a disclosure, not merely a hygiene failure.
For invariants:
- INV-1 remains violated for the reasons the ruling already gives; a canary bounds intent, not capability. Nothing here changes that.
- No MR added, modified, or repealed.
Verification
Section titled “Verification”Applied and checked in-session; output quoted in the PR that carries this
record. The claim this record must survive is narrow: that the two 403s in
blocker C no longer reproduce, and that protection is actually present on
main.
A pre-publication audit of the tree was run, because making a repository public
is irreversible in effect even where it is reversible in setting. It turned up
one correction to a merged record, stated rather than silently absorbed:
…-p3-c0-canary-credential-unsatisfiable.md:34 describes the contents as
“a single README.md (1,629 bytes) and nothing else”. The tree also holds
SCRATCH.md (122 bytes), which declares itself probe scratch space. Both are
inert and neither carries a secret, so condition 2 still reads clean — but the
finding’s inventory was one file short, and that is a defect in a claim the
rule: in its own front-matter holds it to. Recorded here for P3’s verification
round; the finding is not edited (L3).
References
Section titled “References”docs/findings/20260814-1130-p3-c0-canary-credential-unsatisfiable.md:99-140— blocker C, the three options, and the warning about option 3.docs/decisions/2026-08-12-purpose-built-canary-supersedes-pwplz.md:38-52,104-107— the five conditions, and the method rule requiring a positive check.docs/findings/20260811-2027-ptv-scf-0001-credential-scope.md— the five credential conditions, condition 3 in its original wording.docs/decisions/2026-08-14-ptv-scf-0001-p3-open.md— G-P3-1, which this does not close.registry.yaml:792-812— the canary entry,fleets_allowed: []until the installation exists.
Sign-off
Section titled “Sign-off”- Subagent: PTV-SCF-0001 P3 · C0 (session 2026-08-15)
- Human: ☑ (proxy) countersign — that the canary is public, that branch protection is
the mechanism satisfying credential condition 3, that finding option 3 is
declined on the record, and that star/fork/inbound-link drift is a
supersession trigger.
- Countersigned by
human:devarnoon 2026-08-15, by explicit directive in session (“follow justified best-practice recommendation(s) for (2)”). Ticked by the agent as scribe, not as signatory: the human act is the directive, and this line is its record.
- Countersigned by