instar 1.3.1196 → 1.3.1197
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/data/standards-guard-index.json +1 -1
- package/dist/data/standards-guard-index.meta.json +2 -2
- package/dist/data/standards-registry.meta.json +1 -1
- package/package.json +1 -1
- package/scripts/standards-coverage.mjs +48 -20
- package/src/data/builtin-manifest.json +2 -2
- package/src/data/standards-guard-index.json +1 -1
- package/src/data/standards-guard-index.meta.json +2 -2
- package/src/data/standards-registry.meta.json +1 -1
- package/upgrades/1.3.1197.md +32 -0
- package/upgrades/ci-rerun-on-review.eli16.md +31 -0
- package/upgrades/side-effects/ci-rerun-on-review.md +84 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"generatedFrom": "source-tree",
|
|
4
4
|
"registrySha256": "8e6606a6722433c5ffc15b3870402283c5406083a14cdbd0e18e735731e2aae2",
|
|
5
|
-
"packageVersion": "1.3.
|
|
5
|
+
"packageVersion": "1.3.1197",
|
|
6
6
|
"guards": [
|
|
7
7
|
{
|
|
8
8
|
"ref": "docs/audits/phase-b/f10-triage.md",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"sha256": "
|
|
2
|
+
"sha256": "a4dfe2bf7d36670a4e46e566bb3eed53479031f12f38a5450f4c2badd1754192",
|
|
3
3
|
"registrySha256": "8e6606a6722433c5ffc15b3870402283c5406083a14cdbd0e18e735731e2aae2",
|
|
4
|
-
"packageVersion": "1.3.
|
|
4
|
+
"packageVersion": "1.3.1197"
|
|
5
5
|
}
|
package/package.json
CHANGED
|
@@ -604,10 +604,22 @@ function validateRootSelfWiring() {
|
|
|
604
604
|
return exactKeys(config, ['branches']) &&
|
|
605
605
|
Array.isArray(config.branches) && config.branches.length === 1 && config.branches[0] === 'main';
|
|
606
606
|
};
|
|
607
|
-
|
|
607
|
+
// `pull_request_review` added 2026-08-22 and pinned, not merely permitted.
|
|
608
|
+
// The direction guard accepts the operator's approval as proof, but CI fired
|
|
609
|
+
// on push — before any approval could exist — so approving left the check
|
|
610
|
+
// red and finished, with nothing to re-run it. `dismissed` is pinned beside
|
|
611
|
+
// `submitted` because withdrawing an approval must re-run the guard and turn
|
|
612
|
+
// the check red again: a gate that only re-evaluates toward passing is not a
|
|
613
|
+
// gate. Pinning the types means neither can be dropped silently.
|
|
614
|
+
const reviewTrigger = workflow.on?.pull_request_review;
|
|
615
|
+
const reviewTriggerWired = exactKeys(reviewTrigger, ['types']) &&
|
|
616
|
+
Array.isArray(reviewTrigger.types) && reviewTrigger.types.length === 2 &&
|
|
617
|
+
reviewTrigger.types.includes('submitted') && reviewTrigger.types.includes('dismissed');
|
|
618
|
+
if (!exactKeys(workflow.on, ['push', 'pull_request', 'pull_request_review', 'workflow_dispatch']) ||
|
|
608
619
|
!(workflow.on.workflow_dispatch === null || exactKeys(workflow.on.workflow_dispatch, [])) ||
|
|
620
|
+
!reviewTriggerWired ||
|
|
609
621
|
!eventTargetsMain('push') || !eventTargetsMain('pull_request')) {
|
|
610
|
-
errors.push('The Root self-wiring requires top-level push and
|
|
622
|
+
errors.push('The Root self-wiring requires top-level push, pull_request and pull_request_review (submitted+dismissed) CI triggers targeting main');
|
|
611
623
|
}
|
|
612
624
|
const job = workflow.jobs?.['standards-coverage'];
|
|
613
625
|
const steps = Array.isArray(job?.steps) ? job.steps : [];
|
|
@@ -666,31 +678,47 @@ function validateRootSelfWiring() {
|
|
|
666
678
|
// protected-base step's is, so a behaviour edit here is a DECLARED edit.
|
|
667
679
|
const expectedReviewRun = [
|
|
668
680
|
'set -u',
|
|
669
|
-
'
|
|
670
|
-
"
|
|
671
|
-
|
|
681
|
+
'assoc_failed=0',
|
|
682
|
+
'if [ "$EVENT_NAME" != "pull_request" ] && [ "$EVENT_NAME" != "pull_request_review" ]; then',
|
|
683
|
+
' if associated=$(gh api "repos/${GITHUB_REPOSITORY}/commits/${PUSH_SHA}/pulls" 2>/dev/null); then',
|
|
684
|
+
` match=$(SHA="$PUSH_SHA" jq -c '[.[] | select(.merge_commit_sha == env.SHA)] | if length == 1 then .[0] else empty end' <<< "\${associated:-[]}" 2>/dev/null || echo '')`,
|
|
685
|
+
' else',
|
|
686
|
+
" associated='[]'",
|
|
687
|
+
" match=''",
|
|
688
|
+
' assoc_failed=1',
|
|
689
|
+
' fi',
|
|
672
690
|
" PR=''",
|
|
673
691
|
" HEAD_SHA=''",
|
|
674
692
|
" PR_AUTHOR=''",
|
|
675
693
|
' if [ -n "$match" ]; then',
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
694
|
+
` PR=$(jq -r '.number // empty' <<< "$match" 2>/dev/null || echo '')`,
|
|
695
|
+
` HEAD_SHA=$(jq -r '.head.sha // empty' <<< "$match" 2>/dev/null || echo '')`,
|
|
696
|
+
` PR_AUTHOR=$(jq -r '.user.login // empty' <<< "$match" 2>/dev/null || echo '')`,
|
|
679
697
|
' fi',
|
|
680
|
-
|
|
698
|
+
` echo "path-b: event=\${EVENT_NAME} associated=$(jq -r 'length' <<< "\${associated:-[]}" 2>/dev/null || echo unreadable) matched-pr=\${PR:-none} assoc-failed=\${assoc_failed}"`,
|
|
681
699
|
'fi',
|
|
682
|
-
"
|
|
683
|
-
'if [
|
|
684
|
-
|
|
700
|
+
'echo "path-b: head-sha=${HEAD_SHA:-none} owner=${OWNER_LOGIN:-none}/${OWNER_TYPE:-none}"',
|
|
701
|
+
'if [ "$assoc_failed" = "1" ]; then',
|
|
702
|
+
` printf '%s' '{"fetchError":"the commit-to-pull-request association call failed"}' > "$OUT"`,
|
|
703
|
+
'elif [ -z "$PR" ]; then',
|
|
704
|
+
' jq -n --arg headSha "$HEAD_SHA" \\',
|
|
705
|
+
' --arg ownerLogin "$OWNER_LOGIN" \\',
|
|
706
|
+
' --arg ownerType "$OWNER_TYPE" \\',
|
|
707
|
+
' --arg prAuthorLogin "$PR_AUTHOR" \\',
|
|
708
|
+
" '{reviews:[], headSha:$headSha, ownerLogin:$ownerLogin, ownerType:$ownerType, prAuthorLogin:$prAuthorLogin}' \\",
|
|
709
|
+
` > "$OUT" || printf '%s' '{"fetchError":"jq could not build the review context"}' > "$OUT"`,
|
|
710
|
+
'elif reviews=$(gh api "repos/${GITHUB_REPOSITORY}/pulls/${PR}/reviews?per_page=100" 2>/dev/null); then',
|
|
711
|
+
` echo "path-b: reviews=$(jq -r 'length' <<< "$reviews" 2>/dev/null || echo unreadable)"`,
|
|
712
|
+
' jq -n --argjson reviews "$reviews" \\',
|
|
713
|
+
' --arg headSha "$HEAD_SHA" \\',
|
|
714
|
+
' --arg ownerLogin "$OWNER_LOGIN" \\',
|
|
715
|
+
' --arg ownerType "$OWNER_TYPE" \\',
|
|
716
|
+
' --arg prAuthorLogin "$PR_AUTHOR" \\',
|
|
717
|
+
" '{reviews:$reviews, headSha:$headSha, ownerLogin:$ownerLogin, ownerType:$ownerType, prAuthorLogin:$prAuthorLogin}' \\",
|
|
718
|
+
` > "$OUT" || printf '%s' '{"fetchError":"jq could not build the review context"}' > "$OUT"`,
|
|
719
|
+
'else',
|
|
720
|
+
` printf '%s' '{"fetchError":"the reviews API call failed"}' > "$OUT"`,
|
|
685
721
|
'fi',
|
|
686
|
-
"echo \"path-b: reviews=$(jq -r 'length' <<< \"${reviews:-[]}\" 2>/dev/null || echo unreadable) head-sha=${HEAD_SHA:-none} owner=${OWNER_LOGIN:-none}/${OWNER_TYPE:-none}\"",
|
|
687
|
-
'jq -n --argjson reviews "${reviews:-[]}" \\',
|
|
688
|
-
' --arg headSha "$HEAD_SHA" \\',
|
|
689
|
-
' --arg ownerLogin "$OWNER_LOGIN" \\',
|
|
690
|
-
' --arg ownerType "$OWNER_TYPE" \\',
|
|
691
|
-
' --arg prAuthorLogin "$PR_AUTHOR" \\',
|
|
692
|
-
" '{reviews:$reviews, headSha:$headSha, ownerLogin:$ownerLogin, ownerType:$ownerType, prAuthorLogin:$prAuthorLogin}' \\",
|
|
693
|
-
" > \"$OUT\" || echo '{}' > \"$OUT\"",
|
|
694
722
|
'',
|
|
695
723
|
].join('\n');
|
|
696
724
|
const expectedBaseSha = "${{ github.event.pull_request.base.sha || github.event.before || format('{0}^', github.sha) }}";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./builtin-manifest.schema.json",
|
|
3
3
|
"schemaVersion": 1,
|
|
4
|
-
"generatedAt": "2026-08-24T02:
|
|
5
|
-
"instarVersion": "1.3.
|
|
4
|
+
"generatedAt": "2026-08-24T02:50:42.124Z",
|
|
5
|
+
"instarVersion": "1.3.1197",
|
|
6
6
|
"entryCount": 202,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"generatedFrom": "source-tree",
|
|
4
4
|
"registrySha256": "8e6606a6722433c5ffc15b3870402283c5406083a14cdbd0e18e735731e2aae2",
|
|
5
|
-
"packageVersion": "1.3.
|
|
5
|
+
"packageVersion": "1.3.1197",
|
|
6
6
|
"guards": [
|
|
7
7
|
{
|
|
8
8
|
"ref": "docs/audits/phase-b/f10-triage.md",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"sha256": "
|
|
2
|
+
"sha256": "a4dfe2bf7d36670a4e46e566bb3eed53479031f12f38a5450f4c2badd1754192",
|
|
3
3
|
"registrySha256": "8e6606a6722433c5ffc15b3870402283c5406083a14cdbd0e18e735731e2aae2",
|
|
4
|
-
"packageVersion": "1.3.
|
|
4
|
+
"packageVersion": "1.3.1197"
|
|
5
5
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
`.github/workflows/ci.yml` gains a `pull_request_review` trigger (`submitted`, `dismissed`), and The Root's self-wiring contract in `scripts/standards-coverage.mjs` pins it.
|
|
9
|
+
|
|
10
|
+
The constitutional direction guard accepts the operator's approving review as proof that a registry change was authorised. CI fired on `push`, before any approval could exist, so the guard ran, correctly found none, and failed — and approving afterwards changed nothing, because the check had already finished. Approval had no event to re-run it.
|
|
11
|
+
|
|
12
|
+
The trigger alone is not the fix. A `pull_request_review` event is a THIRD event shape, and the evidence step plus the three `AUDIT_CHANGE_*` expressions each assumed exactly two. The step branched on `!= "pull_request"`, so a review event took the PUSH path, where the pull request is found by matching `github.sha` against `merge_commit_sha` — and on a review event `github.sha` is the merge ref, which matches nothing. Left alone, the trigger fires, the job runs, no pull request resolves, an empty context is written and the guard refuses: approving would have turned the check red *reliably* rather than leaving it stale. The event is handled explicitly in all four places and the branch test is pinned as a fourth regression route.
|
|
13
|
+
|
|
14
|
+
## What to Tell Your User
|
|
15
|
+
|
|
16
|
+
None — internal change (no user-facing surface).
|
|
17
|
+
|
|
18
|
+
## Summary of New Capabilities
|
|
19
|
+
|
|
20
|
+
None — internal change (no user-facing surface).
|
|
21
|
+
|
|
22
|
+
## Evidence
|
|
23
|
+
|
|
24
|
+
Observed live on PR #1960: approved at 22:03 with the standards check red and finished; a manual re-run of the same job then passed with no other change. That difference was the defect.
|
|
25
|
+
|
|
26
|
+
`scripts/standards-coverage.mjs --check` passes against the branch worktree, so the pinned literal matches the workflow rather than a description of it. `dismissed` is pinned alongside `submitted` so withdrawing an approval re-runs the guard and turns the check red again — a gate that re-evaluates only toward passing is not a gate. Ratchet suite 38/38, including the negative controls asserting that a workflow missing the required triggers FAILS; their fixtures and expected error text moved with the contract.
|
|
27
|
+
|
|
28
|
+
## Known Limits
|
|
29
|
+
|
|
30
|
+
A review EDITED in place does not re-trigger (`pull_request_review` fires on submit/dismiss). The guard binds to the head sha, so the exposure is an edited review body rather than a state change, and any new push re-runs everything via `synchronize`.
|
|
31
|
+
|
|
32
|
+
More broadly: this closes the gap for the review path only. Any other check whose inputs are not repository content has the same shape, and nothing enumerates those.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Making an approval actually do something — Plain-English Overview
|
|
2
|
+
|
|
3
|
+
## The problem in one breath
|
|
4
|
+
|
|
5
|
+
Tonight the operator approved a rulebook change and nothing happened. The check that was supposed to notice his approval had already run — minutes earlier, before he tapped — and finished red. Nothing told it to look again. It only didn't leave him stuck because someone was watching and pushed the button by hand.
|
|
6
|
+
|
|
7
|
+
## What already exists
|
|
8
|
+
|
|
9
|
+
The automated checks run when code changes. That has always been enough, because until today every input they cared about was code.
|
|
10
|
+
|
|
11
|
+
## What this adds
|
|
12
|
+
|
|
13
|
+
The checks now also run when someone approves a change, or withdraws an approval. That's it — one line saying "an approval is also a reason to look again."
|
|
14
|
+
|
|
15
|
+
## The new pieces
|
|
16
|
+
|
|
17
|
+
Nothing new is built. An existing set of checks gains one more reason to run.
|
|
18
|
+
|
|
19
|
+
## The safeguards
|
|
20
|
+
|
|
21
|
+
**Withdrawing counts too, and that's the important half.** If the operator approves and then changes his mind, the check runs again and goes back to red. A check that only re-runs when the news is good isn't a check — it would let a change of mind be quietly ignored while a stale green sat on the screen.
|
|
22
|
+
|
|
23
|
+
**The new trigger is pinned in place.** There's a guard that records the exact shape of the automated checks, so this can't be quietly removed later. If it were, the symptom would be an operator approving into silence again — the same bug, returning without a trace. Now its absence breaks the build instead.
|
|
24
|
+
|
|
25
|
+
## What ships when
|
|
26
|
+
|
|
27
|
+
Immediately, and it needs nothing from the operator. It's the missing half of the approval path that shipped an hour ago.
|
|
28
|
+
|
|
29
|
+
## What you actually need to decide
|
|
30
|
+
|
|
31
|
+
Nothing. This is a defect found on first real use, fixed in the direction of your time rather than mine.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Side-Effects Review — CI re-runs when a review is submitted or dismissed
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `ci-rerun-on-review`
|
|
4
|
+
**Date:** `2026-08-22`
|
|
5
|
+
**Author:** `echo`
|
|
6
|
+
**Second-pass reviewer:** `not required — one workflow trigger and its pinned contract`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
`.github/workflows/ci.yml` gains a `pull_request_review` trigger (`submitted`, `dismissed`), and `scripts/standards-coverage.mjs` pins that trigger in The Root's self-wiring contract.
|
|
11
|
+
|
|
12
|
+
**Found in production, on the first real use of the feature it completes.** The direction guard now accepts the operator's approving review as proof that a constitutional change was authorised. But CI fired on `push`, minutes before any approval could exist, so the guard ran, correctly found no approval, and failed. The operator then approved — and nothing happened. The check was already finished and red, with no event to re-run it. It only did not strand him because someone was watching and re-ran the job by hand.
|
|
13
|
+
|
|
14
|
+
An approval flow whose result depends on a human remembering to re-run the job is not a flow.
|
|
15
|
+
|
|
16
|
+
## Decision-point inventory
|
|
17
|
+
|
|
18
|
+
- CI trigger set — **modify** — adds the event that makes an approval re-evaluate the guard.
|
|
19
|
+
- The Root self-wiring contract in `standards-coverage.mjs` — **modify** — pins the new trigger and its two types.
|
|
20
|
+
|
|
21
|
+
No agent-runtime decision point is touched.
|
|
22
|
+
|
|
23
|
+
## 1. Over-block
|
|
24
|
+
|
|
25
|
+
`dismissed` is included deliberately and is the only arm that can newly turn a check RED. That is the point: withdrawing an approval must re-run the guard and fail it again. **A gate that re-evaluates only in the direction of passing is not a gate** — it would let an operator's change of mind be silently ignored while the stale green sat there. This is over-blocking in the correct direction and is the whole reason `dismissed` is pinned rather than merely allowed.
|
|
26
|
+
|
|
27
|
+
## 2. Under-block
|
|
28
|
+
|
|
29
|
+
`pull_request_review` fires for `submitted`/`dismissed`, so a review EDITED in place (rare) does not re-trigger. Named rather than papered over: the guard binds to the head sha, so the practical exposure is an edited review body — not a state change — which cannot flip approval either way. A `synchronize` on any new push already re-runs everything.
|
|
30
|
+
|
|
31
|
+
## 3. Level-of-abstraction fit
|
|
32
|
+
|
|
33
|
+
One trigger on the workflow that already runs the check. No new job, no polling, no bot. The alternative — a scheduled job re-running checks — would be strictly worse: slower, noisier, and it would not know what it was waiting for.
|
|
34
|
+
|
|
35
|
+
## 4. Signal vs authority compliance
|
|
36
|
+
|
|
37
|
+
Unchanged. This alters WHEN the check runs, never what it decides. The guard's authority and the ruleset's authority are untouched.
|
|
38
|
+
|
|
39
|
+
## 4b. Judgment-point check
|
|
40
|
+
|
|
41
|
+
None added. A workflow trigger is a deterministic event subscription.
|
|
42
|
+
|
|
43
|
+
## 5. Interactions
|
|
44
|
+
|
|
45
|
+
- **The direction guard's path B** is the feature this completes; without it, path B is only usable by someone manually re-running jobs.
|
|
46
|
+
- **The self-wiring contract** pins the trigger so it cannot be dropped silently. Dropping it would not fail any test otherwise, and the symptom would be an operator approving into a void — exactly the failure being fixed.
|
|
47
|
+
- **CI cost:** one extra run per review event on open PRs. Reviews are rare here (the operator is asked only for constitutional changes), so this is not a meaningful load.
|
|
48
|
+
- **The event SHAPE, found on rebase (2026-08-23) and the reason this branch is not a two-line change.** Adding a trigger gives the workflow a THIRD event shape, and three places assumed exactly two. The evidence step branched on `!= "pull_request"`, so a review event fell into the push branch, where the pull request is resolved by matching `github.sha` against `merge_commit_sha` — on a review event `github.sha` is the merge REF and matches nothing. The step would have resolved no pull request, written an empty context, and refused. The trigger added to make an approval count would have reliably rejected it, while every assertion about the trigger's presence stayed green: the event fires, the job runs, the check goes red. `AUDIT_CHANGE_KIND` / `_BASE_SHA` / `_HEAD_SHA` had the same two-shape assumption and would have handed the decision audit an EMPTY change kind — an unscoped run reporting clean. Both are fixed here and the first is pinned as a fourth regression route. This is the producer/consumer split in its exact shape: the trigger is the producer, and firing it is not the same fact as the checks handling it.
|
|
49
|
+
|
|
50
|
+
## 6. External surfaces
|
|
51
|
+
|
|
52
|
+
None. No route, no message, no notification.
|
|
53
|
+
|
|
54
|
+
## 6b. Operator-surface quality
|
|
55
|
+
|
|
56
|
+
This IS an operator-surface fix. Before: approve, and the red check stays red with no explanation. After: approve, and the check re-runs and goes green on its own.
|
|
57
|
+
|
|
58
|
+
## 7. Multi-machine posture
|
|
59
|
+
|
|
60
|
+
`unified` — trivially. A CI trigger; no state, no per-machine behaviour.
|
|
61
|
+
|
|
62
|
+
## 8. Rollback cost
|
|
63
|
+
|
|
64
|
+
The trigger, the event-shape handling in the evidence step and the three `AUDIT_CHANGE_*` expressions, plus their pinned counterparts in the contract. Reverting restores today's behaviour, in which an operator's approval requires a manual re-run to take effect — which is why the revert should not happen quietly. Reverting the event-shape handling ALONE is worse than reverting the whole change: the trigger would still fire and the check would then fail on every approval.
|
|
65
|
+
|
|
66
|
+
## Conclusion
|
|
67
|
+
|
|
68
|
+
Ship. It closes a gap found on the first real use of the approval path, in the direction of the operator's time rather than the agent's.
|
|
69
|
+
|
|
70
|
+
## Second-pass review
|
|
71
|
+
|
|
72
|
+
Ran, and it found something. Rebasing onto `main` after #1970 landed put this branch's trigger next to that change's push-path resolution for the first time, and the two together produced a third event shape neither had handled. See §5. The design question worth a second look — whether `dismissed` belongs — is answered under §1 and is the load-bearing half.
|
|
73
|
+
|
|
74
|
+
## Evidence pointers
|
|
75
|
+
|
|
76
|
+
- Observed live: PR #1960, approved at 22:03, standards check still red and finished; a manual re-run of the same job then passed with no other change. That difference is the bug.
|
|
77
|
+
- `tests/unit/standards-coverage-ratchet.test.ts` 38/38, including the negative controls that assert a workflow missing the required triggers FAILS, whose fixtures and expected error text moved with the contract.
|
|
78
|
+
- **Correction, on rebase.** An earlier version of this document cited moving the suite's population literals 88/89/89 → 89/89/89 as evidence. Those literals are GONE — #1970 removed them on `main`, because `protectedBase` is measured against the merge base and therefore depends on WHERE the test runs, so no literal can satisfy both the branch and the merged state. The rebase takes `main`'s removal. The claim is withdrawn rather than restated.
|
|
79
|
+
- The fourth regression route (`pull_request_review` folded back into the push branch) is asserted in the same suite and fails the check when applied, alongside the three routes #1970 pinned.
|
|
80
|
+
- `scripts/standards-coverage.mjs --check` run against this worktree: PASSED, so the pinned literal matches the workflow as it now stands rather than as it was described.
|
|
81
|
+
|
|
82
|
+
## Class-Closure Declaration (display-only mirror)
|
|
83
|
+
|
|
84
|
+
The class is "a check whose input can change without the check re-running." Closed for the review path specifically. NOT closed generally: any other check whose inputs are not repository content has the same shape, and nothing enumerates those. Named, not claimed.
|