vms-dec: kill boot-console newline spam (operator's echoed RETURNs) + type-during-boot regression gate - #850
Merged
Merged
Conversation
…ssion gate The boot-to-login console showed blank-line "newline spam" scattered through the boot output on both x86_64 and VAX. Root cause is NOT the software emitting newlines -- it is the OPERATOR'S OWN RETURN KEYSTROKES ECHOING. tools/vms_login.c console_login() has an OPA0: "wake-on-RETURN" (vms-2213): it prints nothing and blocks until the operator presses RETURN before showing "Username:". During the slow boot no prompt is visible, so the operator naturally hammers RETURN. The console tty is in cooked/ECHO mode, so the kernel echoes each RETURN at type-time as a blank line, mixed into the boot output. The existing tcflush() discards the leftover keystrokes but cannot un-print the blank lines the tty already echoed -- that residual is the spam. Fix: clear ECHO on STDIN for the duration of the wake window and restore it just before the real "Username:" prompt (after the tcflush). ECHO gates INPUT echo only, so boot OUTPUT is untouched and the typed username still echoes normally -- but the wake keystrokes mashed during boot no longer print. The wake's original banner-ordering rationale is now stale (vms-1fb moved the banner to print from PID 1 before run_startup()); removing the wake entirely is the faithful end state but risks a Username:/STARTUP.COM-tail interleave and re-exposing the empty-username machine-gun the tcflush guards, so it is left as a follow-up. This rung keeps the wake but silences the echo -- the guaranteed fix for the reported spam. Also removes the redundant `$ SHOW TIME` from STARTUP.COM (it emitted a stray bare date line mid-boot; the banner already prints the date; the oracle boot capture shows none). Regression coverage CI structurally lacked: every existing boot harness waits for "Username:" and only THEN feeds input, so none provokes the echo. New tests/qemu/test_console_boot_no_newline_spam.sh boots the real runtime, TYPES RETURNs DURING the boot (before the prompt), and asserts no run of echoed blank lines precedes "Username:" while login still works. Wired as ctest console_boot_no_newline_spam_e2e and a ci.yml console-newline-spam-e2e job. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…UT re-enables at prompt Interactive proof exposed that ECHO-off scoped to LOGINOUT's wake window caught almost none of the spam: the boot console log shows JOB_CONTROL forks LOGINOUT only at STARTUP.COM's tail (the final %RUN-S-PROC_ID line), so by the time console_login() runs, the operator has already mashed RETURN throughout the long boot and the cooked-mode console tty has already echoed every one of those keystrokes as a blank line. Longest echoed blank-line run measured 16 before, and still 8 with the LOGINOUT-only ECHO-off -- not fixed. PID 1 owns the console for the entire boot, so the echo must be silenced there. boot_console_disable_echo() (src/ovmx_init/ovmx_init.c) clears ECHO on /dev/console at the start of the flagless boot (and, on the conversational path, right after SYSBOOT> hands over -- SYSBOOT> itself must keep echoing). termios is per-tty device state shared across the exec/fork chain to the same console, so it persists until LOGINOUT re-enables ECHO right before "Username:" (console_login now forces ECHO on at the prompt instead of restoring a saved state). ECHO gates input echo only; boot OUTPUT is untouched. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
baron-3dl
added a commit
that referenced
this pull request
Aug 28, 2026
…ce parity, SHOW USERS de-fab (#858) Bumps OVMX_PRODUCT_VERSION and os-release V0.5-7 -> V0.5-8. 14 commits since V0.5-7. Distributed Lock Manager — the cross-node ladder tops out at a real GRANT: - #849 vms-e8f1/vms-17c DLM rung-2 (H4): the first REAL cross-node $ENQ GRANT — node B holds a lock on A's behalf for A's CSID, $ENQ returns SS$_NORMAL over live SCS (no longer INV-6 "grants nothing"). The distributed lock manager now actually locks across nodes. - #845 vms-209 DLM harness H3 — a cross-node $ENQ reaches node B's real executive - #843 vms-4bd0 DLM harness H2 — two real-executive QEMU nodes complete the full VMS$VAXcluster join - #842 vms-534 DLM harness H1 — two real-executive nodes exchange the 0x6007 HELLO over a socket netdev - #840 vms-4b6 DLM harness rung H0 — SCSD.EXE composes with a real executive - #841 docs Alpha cross-node DLM wire oracle — observed SCS transport + documented GRANT semantics (Rule 8) Alpha co-release parity — authenticated login + the shared SHOW battery: - #852 vms-f2c Alpha DCL/SHOW acceptance parity — the same shared 11-command battery x86_64 runs, now on qemu-system-alpha - #847 vms.ko guards BG fork-inherit tracepoints behind CONFIG_TRACEPOINTS (Alpha P0 modpost fix) Authenticity (INV-6 de-fabrication): - #839 vms-6a1 SHOW USERS fails honestly when the executive is absent — no more per-process fabricated user list Boot console fidelity: - #850 vms-dec kill boot-console newline spam (the operator's echoed RETURNs) + a type-during-boot regression gate Networking (layered-product promotion): - #851 vms-67f TCP/IP Services promoted to a first-class layered product — build plan + roadmap (1.0 blocker) Docs / ledger: - #745 Alpha C-RTL archive DECIDED — Option A (operator ruling 2026-08-23) - #709 vms-da0 OpenVMS GCC port × OVMX faithful-surface gap analysis - #838 reconcile the release block for the V0.5-7 tag (INV-LEDGER) QA'd under KVM boot-to-login on the workshop host with the full SHOW acceptance battery VMS-faithful; boot console clean (no newline flood) and SHOW USERS honest. Release notes are generated at tag time by tools/gen_release_notes.py (INV-LEDGER single-ledger); the roadmap narrative block + public site are the conductor's reconcile (INV-0/INV-LEDGER). Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
baron-3dl
added a commit
that referenced
this pull request
Aug 28, 2026
…(dark since #850) The job name added today by #850 (vms-dec) contained an unquoted mid-value colon ('... before Username: (vms-dec)'), which is invalid YAML. GitHub Actions could not parse ci.yml, so EVERY run of it — on main and every branch — completed with ZERO jobs (no Build & Test, no harnesses, nothing); the only checks still firing were the separate Ledger-drift and CodeQL workflows. Quoting the value restores the whole workflow. Pre-existing project-wide breakage, surfaced while wiring the H5 CI job (which could not run until ci.yml parsed). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
baron-3dl
added a commit
that referenced
this pull request
Aug 28, 2026
… (block-then-grant on the requester) (#875) * vms-6ca: DLM H5 executive core — requester-side GRANT RECEIVE + deferred-grant report The cross-node contention semantics (#873) proved block-then-grant on a single real /dev/vms. This adds the two executive halves the async-reply SCS wire needs: - MASTER side: vms_lock_dlm_xnode_deq now REPORTS the queued cross-node waiter that a release flipped to granted (its requester CSID + original req_lkid + master handle + granted mode), through the fields a DEQ otherwise leaves 0, so the daemon can WIRE a deferred GRANT to the requester without a second probe. The master lock entry now carries the requester's own lock handle (req_lkid). - REQUESTER side: VMS_DLM_OP_GRANT is implemented (was SS$_UNSUPPORTED). A GRANT / queued-reply the master sent back completes an executive-resident ORIGIN record — the requester-side proxy of the outstanding request, on its own list, never touched by the local lock manager. Its granted mode is set ONLY from what the master genuinely sent over SCS: a queued-reply (mode NL) leaves it pending, a deferred GRANT (mode EX) flips it NL->EX. GETLKI falls through to it, so the status flip is observable on the REQUESTER node. INV-6: genuine executive state, no fabricated grant. BLKAST as a receive op stays SS$_UNSUPPORTED — the BLKAST wire is deferred honestly on this rung (the block-then-grant round-trip is proven without it). test_syssvc_dlm_xnode.c extended to prove both halves against a real /dev/vms (x86_64 + Alpha LP64): the deferred-grant report on the block-then-grant $DEQ, and the requester-side queued->granted origin flip. vms.ko builds clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * vms-6ca: DLM H5 SCS wire — queued-reply + deferred-GRANT delivery over the live VC The scsd daemon now carries the async DLM replies over the real SCS wire, so the block-then-grant completes on the REQUESTER node across the network — not just in the master's local executive (#873). Node B (master): the GRANT frame it sends back now carries the granted mode honestly — a queued-reply carries NL (the requester stays genuinely pending), a grant carries the granted mode — plus the master's lock handle, so the requester can $DEQ the holder. On a cross-node $DEQ that flips a queued waiter to granted, B reads the executive's deferred-grant report and WIRES an unprompted deferred GRANT (SS$_NORMAL, the granted mode) to that requester (SCSD-I-DLMDEFER). Node A (requester, armed by OVMX_DLM_H5): drives block-then-grant over the wire — holds RESONE EX (#1), sends a second incompatible $ENQ (#2) that QUEUES on B, dispatches B's queued-reply into its OWN executive so #2's origin record is genuinely PENDING (GETLKI->NL, SCSD-I-DLMPEND), releases the holder (#1), and on B's deferred GRANT dispatches it into its executive — the origin record FLIPS NL->EX (GETLKI->EX, SCSD-I-DLMH5FLIP). The status flip is read from A's real executive, driven only by what the master sent over SCS. INV-6: no fabricated wire reply or grant; the BLKAST wire stays deferred (the holder releases on its own). scsd builds clean; vmsscs unit tests green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * vms-6ca: DLM H5 two-node QEMU harness + CI job — block-then-grant over the wire Extends the H4 two-node real-/dev/vms harness to H5. Both nodes boot vms.ko and complete the VMS$VAXcluster join; node A is armed OVMX_DLM_ENQ=RESONE OVMX_DLM_H5=1 and drives the block-then-grant sequence over the live SCS wire: holds RESONE EX, a second incompatible $ENQ QUEUES on node B (B WIREs a queued-reply -> A's requester origin record PENDING, SCSD-I-DLMPEND), A releases the holder, node B WIREs the deferred GRANT off that real $DEQ (SCSD-I-DLMDEFER), and A's origin record FLIPS NL->EX (SCSD-I-DLMH5FLIP granted_mode=EX). H5 PASS asserts the status flip on the REQUESTER node A across the wire, plus B's deferred-grant wire — read from the nodes' own SCSD logs, never fabricated (INV-6). New Dockerfile.dlm-harness-h5 + init_dlm_h5.sh + run_dlm_harness_h5.sh; new dlm-harness-h5 CI job (path-filtered on the DLM sources + harness files); the existing dlm_harness filter already covers vms_lock.c + src/vmsscs/**. Shell + YAML syntax validated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * vms-6ca: DLM H5 — record the async-reply wire + requester-side completion in the compat ledger docs/compat/facilities/cluster-dlm.yaml (single-ledger source, INV-LEDGER): new cluster-dlm$async-reply-wire item for the H5 rung — the master WIREs the queued-reply + deferred GRANT over SCS, the requester-side GRANT RECEIVE completes an executive-resident origin record, and the NL->EX flip is observed on the requester. Notes the BLKAST wire deferred honestly and multi-peer deferred-grant routing as a later rung. Summary updated; H5 evidence points at the two-node harness. YAML validated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * vms-6ca: regenerate compat surface register for the H5 async-reply-wire item Derived docs/compatibility-surface.md re-rendered from docs/compat/*.yaml via tools/compat/render_compat.py (INV-LEDGER: yaml is source, md is generated). 407 items now catalogued. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ci: quote the job name with a mid-value colon — repairs ci.yml parse (dark since #850) The job name added today by #850 (vms-dec) contained an unquoted mid-value colon ('... before Username: (vms-dec)'), which is invalid YAML. GitHub Actions could not parse ci.yml, so EVERY run of it — on main and every branch — completed with ZERO jobs (no Build & Test, no harnesses, nothing); the only checks still firing were the separate Ledger-drift and CodeQL workflows. Quoting the value restores the whole workflow. Pre-existing project-wide breakage, surfaced while wiring the H5 CI job (which could not run until ci.yml parsed). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * vms-6ca: register the H5 client sender in the send-site census + repair H0's stale selftest op Two fixes surfaced by re-enabling ci.yml: 1. scs_send_sites census: the new scsd_dlm_client_send_op() sender (node A's contending $ENQ + holder $DEQ) is added to the CHOKED half of the SEND SITE TABLE in scsd.c; the scsd_dlm_srv_msg_input entry now notes the deferred GRANT it also wires. test_scsd_send_sites: 109 checks, 0 failures. 2. DLM Harness H0 selftest: it drove a DEQ expecting SS$_UNSUPPORTED (2296), but rung 3 (#873, vms-904c) made DEQ real — a DEQ of an unknown handle now returns SS$_IVLOCKID (8484), so H0 had been red since #873 (hidden by the dark CI). The side-effect-free "executive reached, honest 2296" probe now uses BLKAST, whose receive op still honestly returns SS$_UNSUPPORTED (its wire is deferred, vms-6ca) and mutates no lock state. No run/init/ci grep change needed — still rc=2296 PASS. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
The bug (operator-reported, x86_64 + VAX)
The boot-to-login console showed obnoxious blank-line newline spam scattered through the boot output. Root cause is not the software emitting newlines — the boot output is clean. It is the operator's own RETURN keystrokes echoing.
tools/vms_login.cconsole_login()has an OPA0: "wake-on-RETURN" (vms-2213): it prints nothing and blocks until the operator presses RETURN before showingUsername:. During the slow boot no prompt is visible, so an operator naturally mashes RETURN several times. The console tty is cooked/ECHO, so the kernel echoes each RETURN at type-time as a blank line, mixed into the boot narration. The existingtcflush()discards the leftover keystrokes but cannot un-print the blank lines the tty already echoed.Why the "obvious" fix (ECHO-off in LOGINOUT) is insufficient — proven interactively
I first scoped ECHO-off to
console_login()'s wake window. Interactive proof showed it caught almost none of the spam: the console log provesJOB_CONTROLforks LOGINOUT only at STARTUP.COM's tail (the final%RUN-S-PROC_IDline), so by the timeconsole_login()runs the operator has already mashed RETURN throughout the long boot and the tty has already echoed every one. Longest echoed blank-line run: 16 before, still 8 with LOGINOUT-only ECHO-off.PID 1 owns the console for the entire boot, so the echo must be silenced there.
boot_console_disable_echo()(src/ovmx_init/ovmx_init.c) clears ECHO on/dev/consoleat the start of the flagless boot (and, on the conversational path, right afterSYSBOOT>hands over —SYSBOOT>itself must keep echoing). termios is per-tty device state shared across the exec/fork chain to the same console, so it persists until LOGINOUT re-enables ECHO right beforeUsername:(console_login()now forces ECHO on at the prompt). ECHO gates input echo only; boot output is untouched.Also removes a redundant
$ SHOW TIMEfromSTARTUP.COM(it emitted a stray bare date line mid-boot; the banner already prints the date; the oracle boot capture shows none).Interactive proof (x86_64, real vms.ko over qemu-system-x86_64), 15 RETURNs mashed during boot
BEFORE (origin/main) — longest blank-line run = 16:
AFTER (this PR) — longest blank-line run = 1 (the two legit boot blanks), despite the same 15 RETURNs:
No echoed blank lines; no stray date line;
Username:clean; SYSTEM logs in and the typed username echoes (ECHO restored).Regression coverage CI structurally lacked
Every existing boot harness waits for
Username:and only then feeds input, so none provokes the echo. Newtests/qemu/test_console_boot_no_newline_spam.shboots the real runtime, types RETURNs DURING the boot (before the prompt), and asserts no run of echoed blank lines precedesUsername:while login still works. It measures the longest consecutive blank-line run in the pre-Username:segment:Wired as ctest
console_boot_no_newline_spam_e2eand aci.ymlconsole-newline-spam-e2ejob (sameOVMX_QEMU_FULL_E2E=1opt-in convention asdcl-acceptance-e2e; SKIP treated as hard failure).Both arches
The fix is entirely in shared userland: VAX LOGINOUT cross-compiles from the same
tools/vms_login.c(tools/cross-vax/build-loginout-vax.sh) and VAX STARTUP.EXE/PID 1 from the samesrc/ovmx_init/ovmx_init.c(tools/cross-vax/build-ovmx-init-vax.sh).open("/dev/console")+ termios ECHO are POSIX, available under NetBSD-vax. No new TU, so no VAX build-enum updates. x86_64 verified interactively; VAX applies identically by construction.Regression check
test_job_control_console.shon the fixed image: login + every console-behavior assertion passes (36/1). The one failure (OPERATOR.LOG missing '^%OVMX-I-VMSFS, ') is identical on origin/main (verified) — a pre-existing, unrelated kmsg-bridge/VMSFS assertion (likely stale post vms-165 vmsfs retirement), not touched by this change.Follow-up (noted, not shipped here)
Removing the wake entirely (faithful oracle behavior: straight to
Username:) risks aUsername:/STARTUP.COM-tail interleave and re-exposing the empty-username machine-gun thetcflushguards. Left as a follow-up rung; this PR keeps the wake and kills the spam.🤖 Generated with Claude Code