Kernel: the facts say whether the list of Runs was read in full
Closes the fifth story of the epic "Epic: nine gaps in the Kernel, found in review" (#29): the facts did not say whether the list of Runs was read in full. Every ceiling is counted from Runs, and that list stops at 1,000 for a query (L-53). A list cut short could hide a Run in progress, or one that counts toward a ceiling, and an item would be admitted.
What changes
-
schemas/facts.schema.jsonrequirescomplete.runs. The port sets it on each item from its one read of the list each pass.examples/facts.json,facts()intests/support.pyandfacts()insim/world.pyset it. The counter-exampleexamples/invalid/facts.no-completeness-for-runs.jsonis rejected. The two other facts counter-examples gain the flag, so each stays wrong in one way only. -
Following the architect's ruling on the issue, the existing rule I-20 covers it, and no second rule is added.
-
incomplete()fails closed, as the review asked. It used to judge only the flags present, by truthiness, so a missing flag,"false","no"or1counted as a whole list and could admit past the run ceiling. It now reads every name interms.READ_IN_FULL, the flags the schema requires, and anything that is not exactly true is incomplete. This is howmergeableis read, and it followskernel/AGENTS.md: a fact read from outside is never given a default. Thetests/support.pybuilder now matters: withoutruns: True, every test defers. -
kernel/derive.pyreads incompleteness after a merged or closed item, and such an item keeps its State. The list of Runs is read once a pass for every item. Read first, a short list would leave every merged and closed item deferring. This is the same reasoning as the merge state in #68. It applies to every list, because nothing about a merged or closed item is decided from a list. -
tests/test_decide.py:test_incomplete_facts_never_converge_or_admitcoversrunsand asserts both sides of the boundary. With the facts whole the outcome isact(reviewed) oradmit(not reviewed). With any one list short it isdefer, reasonfacts_incomplete, and that list is the evidence.- New
test_a_flag_that_is_not_exactly_true_is_incomplete: a missing key,"false","no","true",1,0andNoneeach defer, for each list. So does a missing or malformedcomplete. - New
test_the_kernel_reads_every_flag_the_facts_schema_requiresholdsREAD_IN_FULLto the schema. - New
test_incomplete_facts_are_read_after_a_merged_or_closed_itempins the order.
-
sim/world.pygains a fault,a_run_list_stops_short, listed insim/grounding.py. It cuts the list of Runs short, oldest first, and marks it. The invariants hold on 300 seeds. -
tools/mutants.pygains three mutants:- "a list of Runs read short is trusted" (
incomplete()skipsruns) - "a flag that is not exactly true counts as whole"
- "incomplete facts are read before a merged or closed item"
36 of 36 killed.
- "a list of Runs read short is trusted" (
-
Documents:
- The design's §3.3 row for
completenamesruns. The paragraph after it says a flag is whole only if exactly true, why a short list of Runs defers (I-13, I-20), and why a merged or closed item does not. - L-53 names the test and the counter-example for the list of Runs. The list of items still waits on
adapters/. - Decision 0002 gains the counter-example, the new test and a row for the order.
kernel/AGENTS.mdsays a new flag incompletegoes interms.pytoo.
- The design's §3.3 row for
Acceptance criteria (from "Kernel: two smaller gaps in what it is given")
-
complete.runsis required in the facts schema, the example,tests/support.pyandsim/world.py. Counter-example:examples/invalid/facts.no-completeness-for-runs.json. -
test_incomplete_facts_never_converge_or_admitalso coversruns: outcomedefer, reasonfacts_incomplete. Its mutant makesincomplete()skipruns. The simulator gains a fault that cuts the list short. - Criterion 3,
minItems: 1onrequired_lenses.deterministic, landed in #70. - Design §3.3
complete; L-53 names the test.
Left open, on purpose
- The order now covers every list, not only
runs. A special case forrunsalone was possible; one rule for every list seemed simpler. The review accepted it. - The simulator's lane asks the Kernel again, with the full list, before a Run starts. So the new fault shows the rule, a deferral on a short list, but not the harm, a Run admitted past a ceiling. The boundary cases and the mutants hold the harm.
a_run_list_stops_shortnames no trial in section 6, so it is listed as unverified. Whether GitHub's list says it was cut short, or the port must work that out, is foradapters/. L-53 records a query that came back as a success with no data.- The list of items saying whether it is whole (the second half of L-53) waits on
adapters/.
Checks and reviews
make verifyandpython3 -m tools.mutantspass on agit archivecopy, which avoids the nested worktrees of #64.- The tests were written first.
- The order test failed until
derive.pychanged. - The counter-example was accepted, and so failed
check_examples, until the schema changed. - Both fail-closed tests failed until
incomplete()changed: a missingreviewsflag with a standing approval was enqueued. - The
runscase of the I-20 test passed throughout, becauseincomplete()already read every flag present; its mutant shows the test now holds that.
- The order test failed until
- The second model family's read is the Gemini code review and the other bot reviewers on this pull request, as the Maintainer directed. Not merged or enqueued; the Maintainer merges.
Closes #39
🤖 Generated with Claude Code
Summary by CodeRabbit
- Bug Fixes
- Open items now remain undecided when the run list is missing, malformed, or marked incomplete, preventing incomplete information from being treated as a final state.
- Merged and closed items retain their existing state even when other fact lists are incomplete.
- Documentation
- Clarified how completeness of run information affects state decisions.