You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Kernel: a reviewing Run that leaves a rubric criterion uncovered has not reported #16
Part of the epic "Epic: slice 0, foundations. The repo holds the line, its context is tested, and the platform facts are recorded".
Why. A rubric is the least a Role must check. The Kernel reads facts and run records, never a Result (§3.9), so the rule has two halves: apply rejects an uncovered Result, and the Kernel reads that rejection from the run record.
Done when
A pure function checks a reviewing Result against its rubric and the changed paths: every criterion that applies is met, a Finding, or not_applicable with a reason. It has its own example and counter-example; the schema alone cannot express this.
A Run whose Result fails that check ends as a failed Run of kind item, and the run-record field that says so is named.
The Kernel does not treat a required Lens as having reported on content when its Run ended that way. The boundary test is written first.
The simulator's reviewer can return an uncovered Result, and the invariants hold on the fixed seeds.
Needs. The story "Schemas for Task, Result, Effect and Disposition", for the Result's shape.
Design. §3.14, "A Result reports coverage"; §4.2, item 1; §3.9; I-37.
changed the title [-]Kernel: a reviewing Result that leaves a rubric criterion uncovered does not count[/-][+]Kernel: a reviewing Run that leaves a rubric criterion uncovered has not reported[/+]on Oct 11, 2026
Solution Architect, delegated. Builds on #150 (decisions 0025, 0026), which merges first.
1. Coverage is not a fact. The Kernel never reads a Result (§3.9). Coverage lives in the Result. The facts gain no field; the run record carries what follows from it. Why: a Result is the model's word.
2. Coverage gets its own schema now: schemas/coverage.schema.json, coverage/1. It is a list of {criterion, verdict, reason}. verdict is met, finding or not_applicable. reason is a code matching ^[a-z_]+$, or null. Why:#19 waits on trials P-13 and P-17 for usage, not coverage.
3. "Uncovered" is decided by one pure function: kernel/coverage.py, covered(rubric, coverage, findings, changed). It returns ("covered", []), ("uncovered", ids) or ("unreadable", []). A criterion applies when it has no applies_when, or when a changed path, or a rename's previous path (names), matches one of its patterns. An applying criterion is uncovered when:
it has no entry, or two;
its verdict is finding and no Finding cites it;
a Finding cites it but the verdict is not finding;
its verdict is not_applicable and the reason is not a code.
So is an entry for an id the rubric lacks. An entry for a criterion that does not apply is ignored. Why: §3.14, I-37. The evidence is criterion ids, codes apply can post.
4. Path syntax.applies_when is read with derive.matches, the one matcher. It gains one form: ** as a whole name stands for any run of names, none included. The hook's _glob learns it in the same change, and test_tools' agreement test widens to the rubric's patterns. Why:fits reads the rubric's **/*.py as one level deep, which under-applies PR-3.
5. Who is at fault.uncovered ends the Run with conclusion: failure and outcome: item. Those are the run-record fields that say so, and no new field is added. unreadable (a rubric that can't be read, or changed paths not read in full) ends it with environment. Why: a broken rubric is the Factory's fault, and it must not spend the item's attempts (I-23).
6. What the Kernel does: re-admit, bounded. A Lens has reported only through a Run on this content that ended success. After an uncovered Run the item stays verifying/awaiting_review, and the same Lens's review is admitted again. Each such Run is an attempt of review-change. After max_attempts (3) since a writer acted, attempts_exhausted is a Hold with the Run ids as evidence, needs_you. Every Run also counts toward the Run ceiling and stops under a Pause. Why: model output varies, and the existing brakes bound the retry.
7. Fails closed.
complete.runs not true: facts_incomplete (exists).
A failed reviewing Run with a null outcome is never a report. It is not an attempt, so the Run ceiling bounds it, as with approvals today.
A reviewing Run on this content that is success with a non-null outcome contradicts itself. It is the new run_unreadable: defer, needs_you, evidence the Run id. It is read where awaiting_review is read, and it takes a queued item out.
In covered, an applies_when it can't read makes the criterion apply.
Tests and mutants. Each test is written first.
Boundary test
Mutant it kills
test_decide::test_a_review_run_that_failed_has_not_reported (failure, timed out and cancelled, each item; a later success reports)
The example is examples/coverage.json, covered against config/rubric-pr-review.json and the paths it names. The counter-example is examples/invalid/coverage.a-criterion-that-applies-left-out.json: valid to the schema, refused by covered. tools/check_examples.py runs covered over both.
Simulator. On fault seeds, ending() sometimes gives an uncovered review: failure/item, and no thread opens (I-5). There is no # GitHub: marker, because this is the Factory's own behaviour. Three invariants:
an approval or a merge has a successful review of that content by every required model Lens (I-37);
a thread comes only from a successful review;
uncovered review Runs since a writer acted are at most max_attempts.
test_the_seeds_serve_a_review_that_left_a_criterion_uncovered must reach both the re-admission and attempts_exhausted.
Decision record.docs/decisions/0030-a-reviewing-run-that-leaves-a-criterion-uncovered-has-not-reported.md. It replaces nothing. Its Boundaries rows name the tests above. Its waiting rows:
No lower limit for reviews: an uncovered review keeps the existing limit of three attempts per content before a Hold. A separate limit can follow if the cost shows in practice.
Activity
[-]Kernel: a reviewing Result that leaves a rubric criterion uncovered does not count[/-][+]Kernel: a reviewing Run that leaves a rubric criterion uncovered has not reported[/+]don-petry commentedon Oct 17, 2026
Working rulings (overturnable in review)
Solution Architect, delegated. Builds on #150 (decisions 0025, 0026), which merges first.
1. Coverage is not a fact. The Kernel never reads a Result (§3.9). Coverage lives in the Result. The facts gain no field; the run record carries what follows from it. Why: a Result is the model's word.
2. Coverage gets its own schema now:
schemas/coverage.schema.json,coverage/1. It is a list of{criterion, verdict, reason}.verdictismet,findingornot_applicable.reasonis a code matching^[a-z_]+$, or null. Why: #19 waits on trials P-13 and P-17 for usage, not coverage.3. "Uncovered" is decided by one pure function:
kernel/coverage.py,covered(rubric, coverage, findings, changed). It returns("covered", []),("uncovered", ids)or("unreadable", []). A criterion applies when it has noapplies_when, or when a changed path, or a rename's previous path (names), matches one of its patterns. An applying criterion is uncovered when:findingand no Finding cites it;finding;not_applicableand the reason is not a code.So is an entry for an id the rubric lacks. An entry for a criterion that does not apply is ignored.
Why: §3.14, I-37. The evidence is criterion ids, codes
applycan post.4. Path syntax.
applies_whenis read withderive.matches, the one matcher. It gains one form:**as a whole name stands for any run of names, none included. The hook's_globlearns it in the same change, andtest_tools' agreement test widens to the rubric's patterns. Why:fitsreads the rubric's**/*.pyas one level deep, which under-applies PR-3.5. Who is at fault.
uncoveredends the Run withconclusion: failureandoutcome: item. Those are the run-record fields that say so, and no new field is added.unreadable(a rubric that can't be read, or changed paths not read in full) ends it withenvironment. Why: a broken rubric is the Factory's fault, and it must not spend the item's attempts (I-23).6. What the Kernel does: re-admit, bounded. A Lens has reported only through a Run on this content that ended
success. After an uncovered Run the item staysverifying/awaiting_review, and the same Lens's review is admitted again. Each such Run is an attempt ofreview-change. Aftermax_attempts(3) since a writer acted,attempts_exhaustedis a Hold with the Run ids as evidence,needs_you. Every Run also counts toward the Run ceiling and stops under a Pause. Why: model output varies, and the existing brakes bound the retry.7. Fails closed.
complete.runsnot true:facts_incomplete(exists).successwith a non-null outcome contradicts itself. It is the newrun_unreadable: defer,needs_you, evidence the Run id. It is read whereawaiting_reviewis read, and it takes a queued item out.covered, anapplies_whenit can't read makes the criterion apply.Tests and mutants. Each test is written first.
test_decide::test_a_review_run_that_failed_has_not_reported(failure, timed out and cancelled, eachitem; a later success reports)test_decide::test_a_review_that_succeeded_with_a_fault_is_unreadabletest_decide::test_item_faults_exhaust_attempts(exists; its runs arereview-change)test_coverage::test_a_criterion_that_applies_must_be_coveredtest_coverage::test_a_renamed_files_old_path_makes_a_criterion_applytest_coverage::test_not_applicable_needs_a_reason_codenot_applicableneeds no reasontest_coverage::test_a_finding_verdict_needs_a_finding_that_cites_itfindingneeds no Findingtest_coverage::test_an_unreadable_rubric_is_unreadable_never_coveredtest_tools::the agreement test, with****read within one nameThe example is
examples/coverage.json, covered againstconfig/rubric-pr-review.jsonand the paths it names. The counter-example isexamples/invalid/coverage.a-criterion-that-applies-left-out.json: valid to the schema, refused bycovered.tools/check_examples.pyrunscoveredover both.Simulator. On fault seeds,
ending()sometimes gives an uncovered review:failure/item, and no thread opens (I-5). There is no# GitHub:marker, because this is the Factory's own behaviour. Three invariants:max_attempts.test_the_seeds_serve_a_review_that_left_a_criterion_uncoveredmust reach both the re-admission andattempts_exhausted.Decision record.
docs/decisions/0030-a-reviewing-run-that-leaves-a-criterion-uncovered-has-not-reported.md. It replaces nothing. Its Boundaries rows name the tests above. Its waiting rows:applycallscoveredbefore any Effect (harness/);adapters/);result/1embedscoverage/1(Schemas for Task, Result, Effect and Disposition #19).Design §3.10's
itemrow gains "a reviewing Result left a criterion uncovered".Follow-ups
result/1takescoverage/1by$ref.covered.Taken as working rulings (the Maintainer may overturn them in review):
tools/hooks/protected.py(the**path syntax) and the two simulator files. Since Kernel: a change to the Factory's own rules or a Lens's inputs is reviewed by a model Lens #135, every change to a protected path is reviewed by every model Lens.kernel/coverage.pyjoins the protected paths.don-petry commentedon Oct 17, 2026
Decision record renumbered to 0029 (#146 needs no record, so the numbers close up). Merge order follows the numbers.