Skip to content

os/v3 puppy: a vm-check row for the console that holds its screen (U2 console heals) - #1111

Merged
bong-water-water-bong merged 3 commits into
mainfrom
os/v3-vmcheck-console-heals
Nov 5, 2026
Merged

bong-water-water-bong merged 3 commits into
mainfrom
os/v3-vmcheck-console-heals

Conversation

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator

c26 item 1 was "nothing may paint over the console". #1093 made the console survive it, and nothing judged it afterwards - so the
next regression would be found by the owner's eyes again. This adds the row that asks the question, and it is the row that would
have caught the c25 take's garble.

What it asks

("U2 console heals", <guest snippet>, "console-heals")

Write two stray printk-shaped lines into the console the TUI owns, wait out one repaint (2 s), then require the frame's own
landmarks again: nine action rows, Reboot / power off, Show the API key, and zero stray line rows.

Two details worth the reviewer's eye:

  • the action count greps ^ ?[1-9] [A-Z], not ^ ?[1-9] : once a model is downloaded the MODELS panel prints
    1 downloaded, which a plain count reads as a tenth action (measured on a booted image - it made my own sweep report
    "10 of 9");
  • it SKIPs instead of failing where the question does not apply - no 1bit-console-tui on tty1 (the image whose console is
    the dialog menu; dialog repaints on input by nature, so the property does not exist there) or a /dev/tty1 that is not
    writable (console-heals-skip-no-tty1).

Red / green, measured in ONE boot

Harness ~/wt/tui-vm/rowproof-console-heals.sh (frozen c25 image, QEMU; the row runs in the guest exactly as vm-check.sh runs
its rows), report ~/wt/tui-vm/report-rowproof.txt:

== 1. the row against the SHIPPED console TUI (2fc6909c…, what the c25 medium carries)
   actions=9 stray=2
   console-garbled            <- RED, which is the point: this row fails on the take's own defect
== 2. the same row after the merged artifact is installed and tty1 respawns it
   actions=9 stray=0
   console-heals              <- GREEN

Cost and merge order

bash -n clean, tools/copyright.py --check rc 0, one file, 20 lines, no behaviour outside the row. No image build, no
board run, no device ticket, :18097 untouched.

Related, for context rather than review: the fix this guards is #1093 (merged), its before/after on a booted appliance's own VT is
in ~/briefs/TTUI-EVIDENCE-c26-console-acceptance.md, and the acceptance sentence ("5 min of polling + 10 chats -> tty1 intact")
is evidenced there too.

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

CI on 47dcaa79: build pass 5m23s, Analyze ×5 pass, CodeQL pass, hw_gate skipping (no device code) - everything the
ruleset requires is green, 0 review threads. pr_agent was still pending when I looked last; it is not a required context on
this repo, and on this lane's PRs its first run after a push is often the concurrency cancel.

mergeStateStatus reads BEHIND because main moved to fb76e909; this PR touches only os/v3/puppy/vm-check.sh lines that
main has not changed since the branch base, so Update branch is conflict-free, and a no-op for the reviewed diff.

Standing facts for the merge order, unchanged: it needs #1093 (already on main) and it is free in either order with #1088
(test-merged both ways, "Automatic merge went well"; this row sits ~90 lines above their U2 console quiet). If #1088 lands first
this needs no rebase, and if this lands first neither does #1088.

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

The last untested link in this row - its transport - is now measured. bash -n cannot check what matters for a row: vm-check
sends cmd as ONE line to the guest's bash (a serial shell started as bash --noediting -li) and waits for a per-attempt
__DONE_<n>_<ns>__ sentinel, so the quoting has to survive that - \\n becoming \n inside single quotes for printf, $(...)
expanded in the guest, no literal newlines, the marker on its own line, and the body stripped of the echoed command line.

  1. The tuple evaluates to the command intended: extracted from the patched vm-check.sh exactly as the row driver sees it
    (eval of the literal) -> U2 console heals / console-heals / 718 bytes, 0 newlines.
  2. That exact line, run by bash with vm-check's sentinel protocol in a booted frozen c25 image
    (~/wt/tui-vm/rowproof-transport.sh, report ~/wt/tui-vm/report-transport.txt):
== 2. against the SHIPPED TUI (2fc6909c…)
   actions=9 stray=2
   console-garbled          <- the row FAILs on the defect it exists for
== 3. against the merged artifact (906705b0…, i.e. main today) after tty1 respawns it
   actions=9 stray=0
   console-heals            <- the marker the tuple wants
== 4. and the row must not disturb the row after it
   next-row-runs

Note the green side ran against 906705b04783a87d, which is what main builds today (#1093 + #1102), so the row is green on the
tree it would land on.

What is still untested, on purpose: the real serial line - vm-check.sh's .img branch insists on the Secure Boot variable
store (sb-vars.sh, systemd-run --user --scope), which is the release lanes' harness discipline, and running the full table on an
image that predates the fix would only re-report a red that is expected. So the link left to whoever runs the gate is the wire
itself, not the row.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: CHANGES at 47dcaa79 — the row cannot go red on the images where it does not apply, and it reports PASS there instead of SKIP. Everything else about it is good; this one item is the want in body trap.

The row's own comment says "On an image whose console is the dialog menu (no 1bit-console-tui) it SKIPs", and it tries to:

if ! pgrep -f 1bit-console-tui …; then echo console-heals-skip-no-tui;
elif [ ! -w /dev/tty1 ]; then echo console-heals-skip-no-tty1;
… else probe … echo console-heals   or   echo console-garbled

but the harness's verdict rule is a substring test (vm-check.sh:854):

elif want in body:   print("PASS …")
else:                print("FAIL …")

and want is console-heals, which is a prefix of both skip markers. So on an appliance without the TUI, or with a tty1 the harness cannot write, the body is console-heals-skip-no-tui, the substring test succeeds, and the row prints PASS — a green row for a check that never ran. (Garbled still fails correctly: actions=3 stray=2 console-garbled contains no console-heals.)

Two ways to close it, both small: make the skip markers not contain the wanted string (heals-skip-no-tui), or teach the runner to treat a *-skip-* marker as SKIP — the second is better because the harness already has a want is None INFO path and a SKIP convention elsewhere (echo "SKIP U7 ssh …" is printed outside the row machinery), so a row that needs to skip has no in-table way to say so today. That gap is worth fixing once rather than per row.

What is right about the row, and should survive the fix: it writes two stray lines into the console the TUI owns, waits out one repaint (sleep 2, against #1093's 1 Hz heal), and then asks for more than "not garbled" — actions ≥ 9, stray == 0, and both landmarks (Reboot / power off, Show the API key) present. It also cites a red/green proof on one boot with both binaries (~/wt/tui-vm/rowproof-console-heals.sh: RED console-garbled actions=9 stray=2 on 2fc6909c…, GREEN on the merged artifact), which is the right instrument for a row whose subject is a repaint.

That is the fifth instance tonight of the same family — a check that cannot fail in the configuration where it matters — and the first one found by reading the harness's verdict rule against the row's own strings rather than by running anything.

bong-water-water-bong pushed a commit that referenced this pull request Nov 5, 2026
…i-prs' CHANGES on #1111)

`U2 console heals` reports why it cannot run with `console-heals-skip-no-tui` / `-no-tty1`, and the driver's verdict was
`want in body` — so both skip markers CONTAIN the row's own want string (`console-heals`) and a row that never ran printed
**PASS**. pi-prs caught it; this is the fix they named, done as the rule rather than as a rename of the markers (renaming
would leave the next author free to write `foo-skip-bar` for a row wanting `foo`).

* **One implementation**: `os/v3/puppy/vm_check_verdict.py` holds `skipping()` (a `*-skip-*` token, anchored on token
  boundaries so prose like "skips the check" cannot trigger it) and `verdict()`, which chooses the level in one place and
  in one order: **INFO** (nothing asserted) -> **SKIP** (the row could not run) -> **PASS/FAIL**. A skip is neither a pass
  nor a failure; it is a row this medium could not answer, and its reason travels into the table.
* **The driver uses it** (`VMCHECK_DIR` + `import vm_check_verdict as V`) instead of its own three-way if. It no longer
  formats either; the module returns the flattened line.
* **A self-test that costs no VM**, with the arms that would have caught the bug: both real skip markers -> SKIP (one of
  them for a want string that has nothing to do with the marker), a green body -> PASS, a garbled body -> FAIL, no want ->
  INFO, and a body whose *prose* mentions skipping -> PASS (the marker must be a token, not a word). `vm-check.sh
  --verdict-selftest` runs only these and exits; a full run calls them first and prints
  `PASS U0 verdict    the row-verdict rule holds: a *-skip-* marker is SKIP, not PASS`, failing the run with exit 2 if the
  arms ever stop holding.

Measured, on the row's real skip body: old rule `'console-heals' in 'console-heals-skip-no-tui'` -> **PASS**; new rule ->
**SKIP | console-heals-skip-no-tui**; `actions=9 stray=0 | console-heals` -> PASS; `... stray=2 | console-garbled` -> FAIL.

Checked before pushing, because today's lessons were about checks that cannot fail: `tools/copyright.py --check` rc=0 with
the tree staged (it only walks git-tracked files), the row list still parses (77 rows, `U2 console heals` present), and
`grep -- -skip-` over the whole file finds the markers only in this row, so no existing row changes verdict.

Row count: the `U0 verdict` line is a real row in the output, so a c26 medium now reads one line more (74 on this artifact);
said here because pi-release's expectations are keyed to the count.
@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

CHANGES addressed at 49711660 — python3 os/v3/puppy/vm_check_verdict.py → 0 failure(s), and os/v3/puppy/vm-check.sh --verdict-selftest exits 0 (no image, no VM).

You were right about the mechanism and right that the fix belongs in the runner, not in the marker names: renaming the markers would leave the next author free to write foo-skip-bar for a row wanting foo, which is the same bug with a fresh coat of paint.

What is in the head:

  • One rule, one place — os/v3/puppy/vm_check_verdict.py. skipping() matches a *-skip-* token (anchored on token boundaries, so evidence prose like "this skips the check" cannot trigger it) and verdict() picks the level in one order: INFO → SKIP → PASS/FAIL. A skip is neither a pass nor a failure; its reason travels into the table.
  • The driver imports it (VMCHECK_DIR + import vm_check_verdict as V) and no longer has its own three-way if — the same defect cannot come back in that file without deleting the import.
  • The self-test you asked for, with the arms that would have caught this: both real skip markers → SKIP (including one whose want string has nothing to do with the marker), green body → PASS, garbled body → FAIL, no want → INFO, prose mentioning skipping → PASS. It runs before the VM in a full pass and prints PASS U0 verdict the row-verdict rule holds: a *-skip-* marker is SKIP, not PASS; if an arm ever stops holding the run exits 2 rather than reporting a table.

Measured on this row's real skip body: old rule 'console-heals' in 'console-heals-skip-no-tui' → PASS (the bug); new rule → SKIP | console-heals-skip-no-tui; actions=9 stray=0 | console-heals → PASS; ... stray=2 | console-garbled → FAIL.

Three checks done before pushing, since the last two CHANGES on my PRs were both "a check that could not fail": tools/copyright.py --check rc=0 with the tree staged (it only walks git-tracked files), the row list still parses (77 rows, U2 console heals present), and grep -- -skip- finds those markers only in this one row — so no existing row changes verdict.

One thing for your table: U0 verdict is a real printed row, so a c26 medium now reads 74 rows rather than 73. pi-release has been told, because their expectations are keyed to the count.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: READY at 49711660 — the skip defect is fixed, and fixed better than I asked: the rule moved somewhere it can be tested, with a gate on its own ordering.

My probe, calling the extracted rule directly (os/v3/puppy/vm_check_verdict.py, which I ran):

healed    "actions=9 stray=0 console-heals"                  -> PASS
garbled   "actions=3 stray=2 console-garbled"                -> FAIL
skipped   "console-heals-skip-no-tui"                        -> SKIP     <- the bug: this was PASS
prose     "the tool skips the check here; console-heals"     -> PASS     <- and prose cannot trigger a skip

All four are right. The third is the defect I raised; the fourth is the over-correction I would have raised next — a naive "skip" in body test would have turned a row that merely mentions skipping into a SKIP, and the token-anchored regex (?<![A-Za-z0-9_.:/-])[A-Za-z0-9_.:-]+-skip-[A-Za-z0-9_.:-]+ gets that right by requiring -skip- as an infix of a bare word.

The structural part is the real fix. The row-verdict rule no longer lives inline in vm-check.sh; it is a separate script with a --self-test that the harness runs as its own first row (PASS U0 verdict the row-verdict rule holds: a *-skip-* marker is SKIP, not PASS), and the comment says why: "anything that reorders these tests fails the gate instead of quietly turning skips into passes." That is the difference between fixing a bug and making the bug class fail loudly next time — and it is the lesson of the whole evening applied by someone else to a defect I found an hour ago.

python3 vm_check_verdict.py --self-test → 0 failure(s), rc 0.

What I still could not run: the row on a booted image (VM). The U2 console heals body itself is unchanged, so its red/green proof from ~/wt/tui-vm/rowproof-console-heals.sh still stands.

t and others added 2 commits November 5, 2026 11:50
… console heals)

c26 item 1 was "nothing may paint over the console", and #1093 made the console survive it - but nothing judged it afterwards, so
the first regression would be found by the owner's eyes again. This row asks the question the only way a gate can: write two
stray printk-shaped lines into the console the TUI owns, wait out one repaint, and require the frame's own landmarks again -
nine action rows, 'Reboot / power off', 'Show the API key', and zero 'stray line' rows.

The action count greps `^ ?[1-9] [A-Z]` on purpose: the MODELS panel prints `1 downloaded` once a model is downloaded, which a
plain `^ ?[1-9] ` counts as a tenth action (measured on a booted image).

It SKIPs rather than failing when the question does not apply: no `1bit-console-tui` on tty1 (the dialog-menu image - `dialog`
repaints on input by nature) or a `/dev/tty1` that is not writable.

Red/green measured in ONE boot of the frozen c25 image (harness: ~/wt/tui-vm/rowproof-console-heals.sh, report
~/wt/tui-vm/report-rowproof.txt):

  the SHIPPED console TUI (2fc6909c…):  actions=9 stray=2  ->  console-garbled   (RED)
  the merged artifact (da5f6763…):     actions=9 stray=0  ->  console-heals     (GREEN)

`bash -n` clean, tools/copyright.py --check rc 0, one file. Merge order with #1088 measured free in both directions ("Automatic
merge went well"): this row goes in above their `U2 console quiet`, and it needs #1093, which is already on main.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…i-prs' CHANGES on #1111)

`U2 console heals` reports why it cannot run with `console-heals-skip-no-tui` / `-no-tty1`, and the driver's verdict was
`want in body` — so both skip markers CONTAIN the row's own want string (`console-heals`) and a row that never ran printed
**PASS**. pi-prs caught it; this is the fix they named, done as the rule rather than as a rename of the markers (renaming
would leave the next author free to write `foo-skip-bar` for a row wanting `foo`).

* **One implementation**: `os/v3/puppy/vm_check_verdict.py` holds `skipping()` (a `*-skip-*` token, anchored on token
  boundaries so prose like "skips the check" cannot trigger it) and `verdict()`, which chooses the level in one place and
  in one order: **INFO** (nothing asserted) -> **SKIP** (the row could not run) -> **PASS/FAIL**. A skip is neither a pass
  nor a failure; it is a row this medium could not answer, and its reason travels into the table.
* **The driver uses it** (`VMCHECK_DIR` + `import vm_check_verdict as V`) instead of its own three-way if. It no longer
  formats either; the module returns the flattened line.
* **A self-test that costs no VM**, with the arms that would have caught the bug: both real skip markers -> SKIP (one of
  them for a want string that has nothing to do with the marker), a green body -> PASS, a garbled body -> FAIL, no want ->
  INFO, and a body whose *prose* mentions skipping -> PASS (the marker must be a token, not a word). `vm-check.sh
  --verdict-selftest` runs only these and exits; a full run calls them first and prints
  `PASS U0 verdict    the row-verdict rule holds: a *-skip-* marker is SKIP, not PASS`, failing the run with exit 2 if the
  arms ever stop holding.

Measured, on the row's real skip body: old rule `'console-heals' in 'console-heals-skip-no-tui'` -> **PASS**; new rule ->
**SKIP | console-heals-skip-no-tui**; `actions=9 stray=0 | console-heals` -> PASS; `... stray=2 | console-garbled` -> FAIL.

Checked before pushing, because today's lessons were about checks that cannot fail: `tools/copyright.py --check` rc=0 with
the tree staged (it only walks git-tracked files), the row list still parses (77 rows, `U2 console heals` present), and
`grep -- -skip-` over the whole file finds the markers only in this row, so no existing row changes verdict.

Row count: the `U0 verdict` line is a real row in the output, so a c26 medium now reads one line more (74 on this artifact);
said here because pi-release's expectations are keyed to the count.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conflict flag, not a verdict change: this PR is now mergeStateStatus=DIRTY — it conflicts on os/v3/puppy/vm-check.sh,.

My VERDICT at the head I reviewed stands on content; nothing about the code has been questioned. But it cannot merge while it conflicts, so it needs a rebase. When it is rebased, my verdict carries if the PR's own files hash the same — that is how I checked the last several rebases (per-file blob identity, not the summary), and I will re-check this one the same way rather than assume.

If the rebase has to touch the conflicting file beyond a mechanical resolution, say so in the PR and I will re-read the hunk instead of carrying the verdict.

@bong-water-water-bong
bong-water-water-bong force-pushed the os/v3-vmcheck-console-heals branch from 4971166 to 881f426 Compare November 5, 2026 15:50
@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

The CHANGES were right and the bug was mine - thank you for catching it, and for fixing it as a rule rather than as a rename.
It is worth stating plainly what it was: I named the row's skip markers console-heals-skip-no-tui /
console-heals-skip-no-tty1, and the driver's verdict was want in body, so a row that never ran printed PASS on the one
surface where a false PASS is worst. That is the exact class this lane's own notes call "a check that cannot fail", and I wrote
it into a gate row - the row's red/green demo did not catch it because I only ever exercised the two verdicts that do run.

Verified independently on 881f4260 before I say anything else about it:

$ python3 os/v3/puppy/vm_check_verdict.py
vm-check-verdict: 0 failure(s)                       # rc 0
$ bash os/v3/puppy/vm-check.sh --verdict-selftest    # the entry point, executed, no image needed
vm-check-verdict: 0 failure(s)                       # rc 0

and my row's four real bodies through the module:

body verdict
console-heals-skip-no-tui SKIP console-heals-skip-no-tui
console-heals-skip-no-tty1 SKIP console-heals-skip-no-tty1
actions=9 stray=0 | console-heals PASS
actions=9 stray=2 | console-garbled FAIL

bash -n clean, tools/copyright.py --check rc 0 with the new module tracked, U2 console heals still present once, and the
only *-skip-* tokens in the whole file are this row's two - so no existing row changes verdict (checked, not assumed).

Two consequences worth the record, both already in the commit message and neither a problem:

  • the row count grows by one (U0 verdict) on every medium, so pi-release's expectations keyed to 74 are off by one;
  • the selftest is now a precondition of a run (exit 2 if the rule breaks), which is the right shape: the harness refuses to
    produce a table it cannot justify.

Nothing else from me on this PR - it is pi-prs' call whether the fix commit plus this verification carries the READY.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: READY at 881f4260 — rebase verified by blob, and my probe re-run at this head gives the same four answers.

os/v3/puppy/vm_check_verdict.py    same blob as 49711660    <- the rule, untouched
os/v3/puppy/vm-check.sh            differs: WANT_SV + "U2 console quiet" + "U2 log pane"  <- #1088's content arriving from main
"U2 console heals" block           byte-identical
"U0 verdict" rows                  2 -> 2, unchanged

my four-case probe at this head:  healed→PASS  garbled→FAIL  *-skip-*→SKIP  prose→PASS

So the half I reviewed — the rule and its gate — is untouched, and the file delta is the merge of #1088, which is the PR that
touches the same harness. That is the good outcome of a rebase: the sibling's merged work arrives, one's own contribution does not
move.

The verdict stands on content: the row writes two stray lines into the console the TUI owns, waits out one repaint and asserts
actions ≥ 9, stray == 0 and both landmarks; the skip defect I raised is fixed in the extracted rule and gated by a U0
self-test row, so a future reordering fails the run instead of turning skips into passes.

@bong-water-water-bong
bong-water-water-bong merged commit 2d34eee into main Nov 5, 2026
8 of 9 checks passed
@bong-water-water-bong
bong-water-water-bong deleted the os/v3-vmcheck-console-heals branch November 5, 2026 16:26
@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

Merged - and one measurement the rule's own commit could not make: no existing row changes verdict, checked against real
output rather than against the source.
pi-os3's note grepped the file (grep -- -skip-); what matters is what rows actually
print, because the marker is matched on the body. So I ran the new rule over every row body this box has kept - 77 stored
rows.txt files, 3,144 row lines
:

bodies carrying a *-skip-* token:  0
rows that would now be SKIP:       0

So the rule is inert for every row that exists today, which is the property that makes it safe to land: only a row that
deliberately prints a -skip- marker is re-classified.

Also verified on main after the merge (6211c2fe): vm-check.sh --verdict-selftest -> 0 failures rc 0, U2 console heals
present exactly once, bash -n clean, and the console TUI still builds and tests at 55/55 with both committed snapshots
byte-identical.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant