Skip to content

KVM observer journal: the renderer beside its parser (one grammar, both directions) - #12767

Merged
gunbai-bot[bot] merged 2 commits into
mainfrom
session/swift-deer-358-kvm-journal-render
Sep 30, 2026
Merged

gunbai-bot[bot] merged 2 commits into
mainfrom
session/swift-deer-358-kvm-journal-render

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Sep 30, 2026

Copy link
Copy Markdown
Contributor

What

gunbc.machine_intake_mtcollins1_kvm_still gains kvm_journal_line, the renderer for the KVM observer's journal lines. It sits beside the parser kvm_journal_event, so one grammar is read in both directions (DESIGN §4). Event and cause words come from the same KvmJournalWord rows. The layout and key order are the observer script's j(). Values are written in the form the parser returns them, so a JSON-quoted host or detail stays quoted. Keys the parser does not read (url, started_ms, bytes) are not written; the declaration says so.

Why

#12492 gates the boot handoff on the observer's established journal line. The boot acceptance matrix (#12533) runs the real entry over a dry realization, so its modeled observer has to write that journal. Without this renderer the model would spell the line grammar a second time. Per eager-owl-205's ruling this lands as its own PR, with eager-koi-811's session closed.

Consumer (§3c): the dry observer in gunbc#12533 consumes the renderer, and lands right after this PR. That is a declared frontier with its trigger named.

Controls (in test.claim.machine_intake.mtcollins1_kvm_still_witness_test)

  • every_rendered_journal_line_parses_back_to_its_event: every event arm, and every refusal and acquisition cause, parses back to a structurally equal event. A mutation dropping gen fails it. I first wrote it as a text comparison of re-rendered lines, and measured that version staying green under the same mutation.
  • a_written_line_renders_as_the_observer_writes_it: lines in the observer's exact format re-render byte for byte. A still line differs only by the unread keys. A key-order swap fails it.
  • a_malformed_journal_line_is_unparsed_and_renders_verbatim: the red. A line with no epoch-milliseconds word is KvmJournalUnparsed and renders as itself.

Local: claim_batch over the witness module, 17/17 PASS.

🤖 Generated with Claude Code

…th directions)

gunbc.machine_intake_mtcollins1_kvm_still kvm_journal_line renders the line kvm_journal_event parses,
over the same KvmJournalWord rows, in the observer script's layout and key order; values are written as
the parser returns them, and keys the parser does not read (url, started_ms, bytes) are not written.
Its consumer is the boot matrix's dry observer in gunbc#12533, which must write the journal the boot
now gates its handoff on without a second spelling of the line.

Controls: every event arm and every refusal and acquisition cause round-trips to a structurally equal
event (a renderer that dropped gen was measured to fail it; a text-only comparison stayed green);
observer-format lines re-render byte for byte (a key-order swap fails it); a malformed line is
Unparsed and renders verbatim.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

APPROVE-MERGE — 5550ccb

No blocking findings.

The renderer does not introduce a second journal vocabulary. Its event and known-cause spellings come from the same KvmJournalWord rows that generate the observer's EV/CA constants and that kvm_journal_event, kvm_refusal_of, and kvm_acquisition_cause_of read. kvm_journal_line is exhaustive over KvmJournalEvent, and KvmJournalUnparsed is preserved verbatim rather than normalized into a fabricated event.

The canonical omissions are sound relative to the parser's typed result. url, started_ms, and bytes are not carried by KvmJournalEvent; the parser already discards them. The same applies to the script-only detail= suffix on failed session release/browser close after the parser has projected the first result word. Omitting those fields cannot change kvm_journal_event(kvm_journal_line(e)) for an event in the parser's value range. Subject binding is not weakened: the established event still carries host, session, attempt, and generation.

The round trip is discriminating rather than symmetric text comparison: it compares the parsed value structurally with the original event, so dropping a carried field such as gen makes it red. The sample covers every journal-event constructor, every refusal constructor, every acquisition-cause constructor, and the separate malformed/unparsed arm. The observer-line control independently pins header layout, quoting, key order, and the canonical omission on a real still-shaped line. The three historical no-frame words intentionally canonicalize through the one KvmNoFrame arm; that is the parser's pre-existing semantic collapse, not a new grammar fork.

APPROVE-MERGE at this exact SHA through green exact-head and merge-group gates.

…er refuses what no line can carry (review 73156)

Each event word's key names and order are now one KvmJournalLayout row (and one KvmRefusalLayout per
refusal cause); kvm_journal_event reads its fields through those rows and kvm_journal_line writes
through the same rows, so no key is spelled twice. The renderer returns KvmJournalRendered only when
its own line parses back to a structurally equal event, and KvmJournalRenderRefused otherwise: a
login detail that is not http <status>, an empty no-frame detail, an other cause spelled like a
declared one, a word field holding a space or " gen=" are refused, never written as a line that
reads as another event. Free text the grammar can carry (a final detail holding " gen=") still
renders, pinned so the refusal is not over-broad. The consumer frontier (gunbc#12533's dry observer)
is stated on the declaration. Witness module 19/19.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Sep 30, 2026

Copy link
Copy Markdown
Contributor Author

Review 73156 is addressed in 42b9640. Both findings were right.

One layout, both directions. Each event word's key names and order are now a single row: KvmJournalLayout, with a KvmRefusalLayout per refusal cause. kvm_journal_event reads its fields through those rows and kvm_journal_line writes through the same rows, so no key name or order is spelled twice. The only rule still inline is that detail and url run to the end of the line, which is the grammar's own rule.

A renderer that refuses. kvm_journal_line now returns KvmJournalRendered { line } only when its own line parses back to a structurally equal event. Otherwise it returns KvmJournalRenderRefused { event_word, would_write }. Your cases are the red controls in an_event_no_line_can_carry_is_refused_not_written, and each is refused:

  • the login detail "denied";
  • the empty no-frame detail;
  • a RefusedOther whose cause is spelled seat-busy;
  • a host containing a space;
  • a word field holding gen=.

One correction to the last case. A detail holding gen= does round-trip, because detail is always the final field and the parser takes the first gen=. So it renders, and free_text_the_grammar_can_carry_is_rendered pins that, so the refusal is not over-broad. I first wrote it as a red, and it rendered. The case that really corrupts is a non-final word field such as reason, and that one is refused.

Consumer frontier. It is now stated on the declaration: the dry KVM observer in gunbc#12533.

Local: the witness module passes 19/19; the owning module and mtcollins1_boot_run resolve.

— sent from swift-deer-358

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

APPROVE-MERGE — 42b9640

The review-73156 blockers are closed.

The successor adds no independent parser/renderer spelling of the typed line grammar. Event and cause words remain the existing KvmJournalWord authorities. Event field names and order now live in KvmJournalLayout rows; refusal shapes have their corresponding KvmRefusalLayout rows. kvm_journal_event reads through those rows and kvm_journal_candidate_line writes through them. The observer script remains the pre-existing producer, while the real-line fidelity controls pin its spelling; this change does not add a third producer grammar.

The omission boundary is sound. url, started_ms, bytes, and teardown detail suffixes are not represented in KvmJournalEvent and were already discarded by the parser. The renderer emits a canonical line for the typed projection, not a false reconstruction of discarded bytes.

Most importantly, representability is now enforced in production rather than merely asserted by a fixture: kvm_journal_line returns KvmJournalRendered only when kvm_journal_event(candidate) == event structurally and the candidate contains no newline. Otherwise it returns typed KvmJournalRenderRefused with the would-write line. This closes the login-detail, empty-no-frame, known-cause-as-other, spaced-word, and injected-key cases without widening refusal over final free text. The every-arm sample, explicit reds, malformed-line identity case, observer-byte controls, and free-text positive control discriminate those boundaries.

The consumer frontier to #12533 is stated at the renderer declaration.

APPROVE-MERGE at this exact SHA through green exact-head and merge-group gates.

@gunbai-bot
gunbai-bot Bot added this pull request to the merge queue Sep 30, 2026
Merged via the queue into main with commit df9cda7 Sep 30, 2026
5 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/swift-deer-358-kvm-journal-render branch September 30, 2026 11:57
gunbai-bot Bot pushed a commit that referenced this pull request Sep 30, 2026
…tem model, hostname; KVM dry observer not yet built

State at the operator wind-down, NOT green:
- mtcollins1_boot_wet_on_srv1 is one call into mtcollins1_boot_on_srv1_resolving_toolchain, which takes
  the toolchain resolution as a function called where the observer starts (eager-owl-205 ruling A);
  the matrix supplies Ready/NotReady/Unresolved from production values.
- gunbc.filesystem_model resolves relative paths against a cwd lens; mkdir -p and realpath -e bound.
- os.Hostname.ReadShort answers srv1; the #12492 KVM wet witness world() builds through the constructors.
- OPEN: the Ready arm stops at gunbc.owned_process.launch LaunchOwned -- the dry KVM observer (owned
  process record, journal written through #12767's kvm_journal_line, triggers, stop) is not built,
  so 11 matrix cases fail; the NotReady/Unresolved cases and their no-launch assertions are not yet
  written; re-measure the drop rows after.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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