fix: audit repository scope coverage #49
No reviewers
Labels
No labels
attention
blocked
blocker:ci-red
blocker:conflict
blocker:drill-pending
blocker:unrequested
bug
claimed
documentation
enhancement
epic
merge-next
needs-ruling
needs-triage
offsite
post-merge
ready
release
scope:ci
scope:cli
scope:docs
scope:manifests
scope:packaging
stale
state:addressing
state:bots-reviewing
state:building
state:needs-human
No milestone
No project
No assignees
4 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: heavy-duty/stoke#49
Loading…
Reference in a new issue
No description provided.
Delete branch "build/48-scope-coverage"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Refs #48
Summary
Acceptance criteria
.gitignore,assets/logo-mark.svg, and the seventest/*.test.jsfiles.scope:*names remain in both config files and two-way parity is machine-enforced.CONTRIBUTING.md'sscope:*section corresponds tolabels.conf: the same five names(this issue adds and removes none), and each row's Covers cell describes the same path set
as that row's
labels.confdescription — the three rewritten rows updated,scope:cliandscope:manifestsuntouched. Formatting is not a mismatch: §3 is a human-readablerestatement, byte-equality was never #46's contract, and zero of the five rows are
byte-equal today (measured on
main; see the 13:41Z comment).npm test && npm run check:governanceis green.Worklog
fix: audit repository scope coverageto WIP: fix: audit repository scope coverage📣 round answered at head
d84062af54WIP: fix: audit repository scope coverageto fix: audit repository scope coverage🔎 reviewing head
d84062af54Ran in a detached worktree at this head (
npm cifirst)..gitignore,assets/logo-mark.svg, and the seventest/*.test.jsfiles.scope:cli/scope:manifestsuntouched — settled..ceremony/+ rootAGENTS.mduntouched) — settled, diff empty.Verdict next.
🔎 reviewing head
d84062af54progress:
🔎 reviewing head
d84062af54Approve — head
d84062af54659f9e0acdbbb1ff3f525c4cc43441.Reviewed the whole PR at this head in a detached worktree (
npm cifirst, per the phantom-failure trap this repo has bitten me with before). All six pre-merge criteria of #48 are met, and I verified each by running it rather than by reading.What I ran
npm testnpm run check:governancegovernance: 4 identities resolved; 5 scope rows valid— success line unchanged (AC4).gitignore,assets/logo-mark.svg, and the seventest/*.test.jsfiles (AC1)git add -N newsurface/thing.txtgovernance: tracked paths have no scope mapping: newsurface/thing.txttest/governance.test.jsagainstorigin/main'slabeler.ymlnot ok 9 - repository scope mapping covers every tracked path except the ruled residue— it fails, so it tests coverage and not the old globs (AC5)labeler.ymlonlyscope names only in labeler.yml: scope:extrascope:manifests→scope:datainlabels.confonlyscope names only in labels.conf: scope:data; scope names only in labeler.yml: scope:manifests— the direction that was blind before this PR is now caught (AC2)git diff --name-only origin/main..HEAD -- .ceremony/ AGENTS.mdThe 7b result is the one that matters most: #48's 13:26Z amendment measured that a
labels.conf-side rename was undetectable, and that replacing L123's frozen glob list would have opened the other direction too. Both directions now exit non-zero naming the offending names, and the coverage assertion replacing L123 is provably not vacuous.AC3 — each rewritten description names its globs and nothing else:
scripts/+release workflow+package manifests+changelog+fragments ↔scripts/**,.forgejo/workflows/release.yml,package.json,package-lock.json,CHANGELOG.md,changelog.d/**;.forgejo/workflows/+.github/+.ceremony/↔ the same three globs; root Markdown+docs/↔*.md,docs/**.AC6 — hand-checked, since #46 recorded that nothing automates the
CONTRIBUTING.mdleg: same five names in all three files, the three rewritten rows describe the same path sets as theirlabels.confrows, andscope:cli/scope:manifestsare untouched (the diff changes exactly three table rows). Correspondence, not byte-equality, as the 13:41Z amendment ruled.AC7 correctly left unticked, and
Refs #48is the right keyword — the only other issue number in the body is#46's contract, preceded by "never", so no closing keyword precedes a number anywhere.Glob semantics, checked against the pinned consumer
I read ceremony
0.6.3'sactions/labels-scope/labels-scope.shat its Forgejo tag (notmain, and not the GitHub tree of the same name). Its contract —**crosses/,*and?do not, whole path must match — agrees with Node'spath.matchesGlobon every path in this tree: I confirmed*.mdmatchesAGENTS.mdbut notdocs/DESIGN.mdor.ceremony/AGENTS.md, soscope:docsreally is root-prose-only, and.github/**/.ceremony/**cover their trees.path.matchesGloblanded in v22.5.0, under the>=22.12.0engines floor.Non-blocking nits
labels-scope.shsays explicitly "a leading dot is not special"; Node'spath.matchesGlobtreats it as special. Measured:path.matchesGlob('.github/.keep', '.github/**') === false, likewisedocs/.nojekyllunderdocs/**. The divergence runs in the safe direction — the validator would report such a file uncovered and fail loudly, where the real labeler would have scoped it — so it can only produce a false alarm, never a false coverage claim. No such path exists today. Worth a comment besidevalidateTrackedPathsso the next person to add a.nojekyllknows why the guard shouted.git ls-fileswithout-z. Withcore.quotePathat its default, a non-ASCII tracked path comes back C-quoted ("caf\303\251.md") and reads as uncovered. Same in the rewritten test at L211. Safe direction again, and no such path exists;-zor-c core.quotePath=falsewould close it.labeler.ymlbeside--configsurfaces as a rawENOENTrather than a governance-voiced message. Every other failure in this script names its cause.UNSCOPED_PATHSwith the validator, so drift between the two lists is undetected. Defensible as an independent restatement — flagging only so the choice is deliberate.test/governance.test.jsrequiresnode:child_processtwice (L3, L4).validateScopeNamescompares everylabels.confrow against the labeler keys, where #48 wrote "the set ofscope:*rows". The two readings coincide:.ceremony/LABELS.mdL225 defineslabels.confas "onename|color|descriptionrow per scope", so a non-scope row there is already out of contract. No change wanted; recording that I checked rather than assumed.What I could not verify, and what I relied on instead
Refs #48matches its post-merge shape.labels-scope; I read it at the0.6.3pin. Note for triage rather than for this PR: it readslabeler.ymlatCONFIG_REF, the base ref, so the widened map governs PRs only from the merge forward — which is exactly what #48's out-of-scope section and criterion 7 already say.success, but each individual entry reportsstate: nullon this instance, so I did not treat the badge as evidence — the table above is my own run in the worktree.git ls-filessucceeding in the workspace, which is new environmental surface. I did not run the Forgejo workflow.node:22-bookwormshipsgit, andclone.test.js/sync.test.jsalready shell out to it, so the binary is proven present; what I did not prove is thatactions/checkout@v4leaves a.gitdirectory on this runner. If a future runner ever falls back to a tarball checkout,check:governancefails closed withcannot enumerate tracked paths— loud, not silent, which is the right failure.Reviewed against #48 acceptance criteria and stoke's load-bearing constraints.
Verified
.gitignore,assets/logo-mark.svg, and the seventest/*.test.jsfiles). Checked with a Python glob probe because node is absent from this box..github/labels.confand.github/labeler.ymlcarry exactly the same fivescope:*names;CONTRIBUTING.md§3 lists the same five.labels.confrows name the path sets their globs match, andCONTRIBUTING.md§3 restates those path sets in its own voice (scope:cliandscope:manifestsuntouched).scripts/check-governance.jsnow asserts two-way name parity and unmapped-tracked-path coverage with a three-entry commented allowlist, while preserving the existing CLI contract and success line.test/governance.test.jsadds failing cases for an uncovered tracked path, a scope name only inlabeler.yml, and a scope name only inlabels.conf; the rewritten coverage test would fail against the pre-changelabeler.ymlmap..ceremony/or to rootAGENTS.md.changelog.d/48.mdis present.Could not verify
npm test && npm run check:governancecould not be run because node and npm are not installed in this box. I relied on manual code reading and the Python coverage probe above; the existing.forgejo/workflows/ci.ymlgate is expected to exercise these commands.Approve.
Verdict: approve — head
d84062af54659f9e0acdbbb1ff3f525c4cc43441, reviewed whole against #48 as amended (13:26Z and 13:41Z amendments; the PR body carries the amended criterion 6 verbatim, as triage's 13:43Z comment asked).Acceptance criteria 1–6 — verified, not opined (criterion 7 is triage's post-merge item; the
Refs #48shape is correct and no closing keyword precedes#48anywhere in the PR body):npm run check:governancegreen in a detached worktree at the head; (b) an independent cross-check sourcing ceremony 0.6.3's ownparse_labeler_config+glob_to_regexfrom the pinned tag and matching them againstgit ls-files: 42 tracked paths, every one matched except exactly.gitignore,assets/logo-mark.svg, and the seventest/*.test.jsfiles.scope:brandrow added tolabeler.ymlalone → exit 1scope names only in labeler.yml: scope:brand;scope:manifests→scope:datainlabels.confalone → exit 1 naming both offenders. No name added/removed/renamed in the diff.changelog.d/**, etc.); no path claimed that isn't matched.new-surface/uncovered.txt→ exit 1tracked paths have no scope mapping: new-surface/uncovered.txt; success output still endsgovernance: 4 identities resolved; 5 scope rows valid;--config/--api-urlflags and exit behaviour unchanged.labeler.ymlswapped in at the head →not ok 1 - repository scope mapping covers every tracked path except the ruled residue, listing.ceremony/*and the other genuinely-uncovered paths. It tests coverage, not the old glob list.labels.confdescriptions in §3's own voice;scope:cliandscope:manifestsuntouched (their §3 rows remain the byte-unequal restatement #46 shipped, which the amended criterion explicitly permits).Test plan: must-pass 1–4 all run green (3:
.ceremony/+AGENTS.mddiff empty; 4'sCONTRIBUTING.mdleg is the hand-check above). Must-fail 5–7 all demonstrated above with actual non-zero exits and named offenders. Must-fail 8 n/a — no mirror/router edits.npm test133/133.Conventions:
changelog.d/48.mdpresent, matching the house one-liner format; allowlist entries each carry their why; tracked-path enumeration viagit ls-filesas the spec demanded.Evidence worth recording: the labels job already derived
scope:ci+scope:docs+scope:packagingon this very PR — the widened map producing the honest three-scope answer in the wild, which is live-check 9's direction ahead of schedule.Non-blocking note: the guard matches with Node's
path.matchesGlob, the live consumer with 0.6.3's regex engine. I cross-checked the two on this tree's ten globs and they agree on every tracked path; the theoretical divergence edges (a barea/**matchingaitself, dotfile specialness under bare*) touch no path this repo tracks. If ceremony's engine ever changes, the cross-check is worth re-running.Environment gaps: the instance's check-runs endpoint 404s, so CI was read via the combined-commit-status endpoint (
state: success,ci / test+labels / labelscontexts at the head) — superseded anyway by the local full-suite run. Everything else was run directly at the head in a detached throwaway worktree.