Repository navigation
fix: accept the empty-state sentinel row in rotation and learnings gates - #10
Merged
Merged
Conversation
A freshly bootstrapped record is all sentinel and no rows. check-inflight.py has always skipped a row whose first cell contains "empty state"; check-rotation.py and check-learnings.py did not, so a new install's first preflight was red for the crime of having done nothing yet: FAIL: row '(empty state)': previous worker '-' not on the roster FAIL: row '(empty state)': verified provider/model receipt empty or not a provider/model pair: '-' FAIL: row '(empty state)': learning id must be exactly one id shaped lrn-<n> FAIL: row '(empty state)': field 'incident' empty or placeholder: '-' ... (9 violations) Skip the sentinel in both gates, matching the inflight convention. The skip is narrow: only a first cell containing "empty state" is exempted, and every later row is validated exactly as before. Ships green fixtures tests/fixtures/valid/ROTATION-STATE-empty.md and LEARNINGS-empty.md. ROTATION-STATE-empty-then-offroster.md carries a real off-roster row immediately after the sentinel, proving the skip does not mask a live violation. Both empty fixtures are wired into verify.yml so the empty-record path is exercised on every push. Refs #9
The verify.yml gate step added in the previous commit references records/examples/valid/, but the fixtures were only added under tests/fixtures/valid/. CI failed with: FAIL: rotation record not found: records/examples/valid/ROTATION-STATE-empty.md FAIL: learnings record not found: records/examples/valid/LEARNINGS-empty.md records/examples/valid/ is also the directory the descriptor's declared gate commands and the README gate table use, so that is the right home for these. The tests/fixtures/valid/ copies stay: those are what the unit tests load.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #9 (the gate half — not the bootstrap-script half).
Problem
A freshly bootstrapped ops record is all sentinel and no rows.
check-inflight.pyhas always skipped a row whose first cell contains
empty state. The rotation andlearnings gates did not, so a brand-new install's very first preflight came back
red for the crime of having done nothing yet:
Since the control-plane skill makes the rotation and learnings gates mandatory
during preflight of every dispatch, and section D says "a gate failure blocks
advancement", a fresh install cannot complete a compliant dispatch.
Fix
Skip the sentinel row in both gates, exactly mirroring the one-line skip already
in
check-inflight.py. The skip is deliberately narrow — only a first cellcontaining
empty stateis exempted. Every subsequent row is validated exactlyas before, which is what
test_red_sentinel_does_not_mask_a_real_violationguards.
Three of the three record gates now agree on what an empty record is.
Changes
scripts/protean-ops/check-rotation.py— sentinel skip incheck_rotation_rowsscripts/protean-ops/check-learnings.py— sentinel skip incheck_rowstests/fixtures/valid/ROTATION-STATE-empty.md— green fixturetests/fixtures/valid/LEARNINGS-empty.md— green fixturetests/fixtures/valid/ROTATION-STATE-empty-then-offroster.md— sentinelfollowed by a genuinely off-roster row; proves the skip does not mask a live
violation
tests/test_gates.py— 6 new cases (green sentinel, shipped fixture,and the red "not masked" case for each of the two gates)
.github/workflows/verify.yml— run both empty fixtures in the gate step, sothe empty-record path is exercised on every push rather than only when a
populated fixture happens to exist
CHANGELOG.md,.gitignore(__pycache__/)Verification
gate files, re-running the two sentinel tests (
FAILED (failures=2)with thenine diagnostics above), then popping the stash.
python3 -m unittest discover -s tests→ 157 tests, OK.check-rotation.py records/examples/valid/ROTATION-STATE-empty.md --roster records/examples/valid/ROSTER.txtand
check-learnings.py records/examples/valid/LEARNINGS-empty.md.gates/protean-ops/check-internal-names.py .→ clean, 73 files, 0 findings.Scope note
This fixes only the gate behaviour. It does not add the bootstrap step that
materialises live records in the first place, and it does not resolve the
underlying design question about whether an empty record should be a sentinel
row or a header-only table — both are still open on #9 and deliberately left
there for the maintainer. This PR makes the existing documented sentinel
convention work consistently; it does not pick a new one.
Reviewers: per repo convention the author does not audit their own work — this
needs an independent QA verdict before merge.