Conversation
…vms-1d9)
Phase 0.5 hard barrier: the merged Kernel Executive CI job (vms-e4d) only
COPYs src/kernel/ + tests/qemu/ into its initramfs, so every test drives
/dev/vms with raw ioctls. An adversary proved that reverting a userspace
syssvc file (src/libvms/syssvc/sys_event.c) to its pre-change stub left
the harness byte-identical green -- every Phase 1/3 item is userspace
wiring the harness cannot see at all.
Adds test_syssvc_lock, statically linked against the REAL src/libvms
(musl, same OVMX_STATIC mode distro/Dockerfile.bootable already uses) and
built into the initramfs alongside the raw-ioctl test_kmod_* programs. It
calls the public sys$enq/sys$enqw/sys$deq entry points across a real
fork()'d second process and, empirically (podman build+run against real
QEMU/vms.ko):
- GREEN with production sys_lock.c: 11 suites passed, 0 failed.
- RED after reverting sys$enq/sys$enqw to an always-succeeds stub (same
defect shape as the sys_event.c regression): test_syssvc_lock's
cross-process NOQUEUE-denial and post-release-grant assertions fail
(10 suites passed, 1 failed) while every test_kmod_* stays green --
proving the ioctl tests are structurally blind to this class of bug
and the new test is not.
- GREEN again after restoring sys_lock.c.
Also:
- src/libvms/include/lksdef.h: promotes sys_lock.c's private LKSB
struct to a public header (zero behavior change) -- external callers
had no way to build the lksb parameter sys$enq/sys$enqw/sys$deq
require.
- tests/qemu/CMakeLists.txt: builds test_syssvc_lock against real
/dev/vms when present; ctest SKIP (exit 77), never a fake PASS, when
it is not (every dev/CI container -- Rule 9, Docker is not a runtime).
- .github/workflows/ci.yml: updates the kernel-executive negative-
control job's exact suite-count assertion (3 passed/7 failed -> 3
passed/8 failed), empirically re-measured against a real
NEGATIVE_CONTROL=1 build+run -- test_syssvc_lock also depends on
/dev/vms and joins the "fails honestly when absent" bucket.
Found and flagged, not fixed (out of this item's scope): src/libvms/include/lckdef.h
duplicates starlet.h's LCK$M_* flag constants with DIFFERENT, stale
values (e.g. LCK$M_NOQUEUE 0x8 vs. starlet.h's oracle-pinned 0x4) --
see the file-header comment in test_syssvc_lock.c and this item's
returned findings.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Rebased onto current origin/main (past vms-e4d) and fixed the three
merge-blockers an adversary found against round 2, all verified against
real podman build+QEMU runs (never just code-read):
B1 - THE CAPABILITY WAS NOT GENERAL. tests/qemu/Dockerfile named exactly
one binary twice (`--target test_syssvc_lock`, `cp .../test_syssvc_lock`),
so the next test_syssvc_*.c a Phase 1/3 item adds would build, ctest-SKIP
fine locally, and never reach the QEMU initramfs. Fixed:
- tests/qemu/CMakeLists.txt now globs test_syssvc_*.c and registers each
automatically via qemu_syssvc_add_test(), collecting every target name
into a GLOBAL property and exposing a single `qemu_syssvc_tests` custom
target that depends on all of them.
- tests/qemu/Dockerfile builds `--target qemu_syssvc_tests` (not a named
binary) and copies build-static/bin/test_syssvc_* by glob into the
initramfs.
- Proved generality empirically: added a throwaway test_syssvc_dummy.c
with NO Dockerfile/CMakeLists.txt edit, podman-built, and confirmed it
ran inside QEMU ("test_syssvc_dummy: 1 passed, 0 failed", FINAL RESULTS
12/0). Removed the dummy and reran -- back to 11/0, matching the new
ci.yml assertion below. init.sh's existing `/tests/test_syssvc_*` glob
already handled the run side; only the build/copy side was hardcoded.
- Added a suite-count assertion to the POSITIVE kernel-executive CI job
(previously only the negative-control job pinned a count), so a test
that silently stops being built/staged/run can no longer stay green.
B2 - THE NO-SILENT-FALLBACK PROOF WAS CIRCULAR. test_syssvc_lock bailed at
its own vms_kif_open() bootstrap and exited SKIP(77) before any sys$ call
was made, so sys_lock.c's SS$_NOSUCHDEV return path (do_enq/sys$deq) was
never actually exercised -- constraint #2 was satisfied by code reading.
Fixed: when bootstrap fails, the test now calls the PUBLIC sys$enqw and
sys$deq entry points directly (vms_kif_open() is idempotent on failure, so
this drives the real ensure_kif_open()-fails branch in sys_lock.c) and
CHECKs the returned status AND the LKSB's own status field both equal
SS$_NOSUCHDEV. A failed check now returns exit 1 (real FAIL), not a masked
77. Proved the gate can go red: injected a defect in do_enq() (fake
SS$_NORMAL success instead of SS$_NOSUCHDEV when /dev/vms is absent),
rebuilt+ran the negative-control image, watched the new assertions FAIL
("test_syssvc_lock: 1 passed, 2 failed"), then reverted and reran green.
B3 - lksdef.h WAS PRESENTED AS VMS-AUTHENTIC. Rewrote the header comment
per CLAUDE.md Rule 8: explicitly labeled an OVMX design choice, not a VMS-
published layout, citing the oracle finding that SYS$LIBRARY:STARLET.MLB
has no $LKSB macro at all (%LIBRAR-W-NOMTCHFOU) -- there is nothing
authentic to pin the byte layout against.
Also (low priority, honesty over fixing): documented in
tests/qemu/CMakeLists.txt that the ctest registration of test_syssvc_lock
SKIPs in 100% of environments where ctest runs, and is invoked directly by
init.sh (not through ctest) inside QEMU -- it buys build-graph inclusion
and an honest SKIP, not coverage, despite appearing in the ctest listing.
Verified via podman (docker is absent on this host; podman reproduces CI
exactly):
- Positive job: FINAL RESULTS 11 suites passed, 0 suites failed.
- Negative-control job: FINAL RESULTS 3 suites passed, 8 suites failed;
new no-silent-fallback CHECKs all PASS (SS$_NOSUCHDEV asserted, not a
string this program authored).
- Injected-defect run: new CHECKs FAIL as expected, proving the gate can
trip; reverted and reran green.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…e-count floor)
F1: Dockerfile, distro/Dockerfile.bootable, and tests/qemu/Dockerfile all
`COPY . <dest>` the full build context with no .dockerignore, so any local
build-*/ tree, .git history, or stray artifact in the working copy lands in
the image byte for byte -- slow, fat, and a disclosure risk. Reproduced from
this exact working copy (build-ci/, build-docker/, build-test/,
build-verify/, .git, docs/, tracking/, third-party/ all present on disk).
Added a repo-root .dockerignore excluding VCS/agent-state/historical-doc
directories verified (by grep across all CMakeLists.txt and all three
Dockerfiles) to be unread by any build step. Confirmed via `podman build`
+ exec that /src/repo no longer contains build-ci, .git, docs, tracking, or
third-party, and that all three Dockerfiles (root, bootable, qemu) still
build and smoke-test clean.
F2: the round-3 kernel-executive CI job hard-pinned
'11 suites passed, 0 suites failed', so the very next item that legitimately
adds test_syssvc_event.c would raise the true count to 12 and turn CI red
for succeeding -- defeating the glob-based generality vms-1d9 exists to
build. Replaced the exact pin with three checks that only go red when a
suite is REMOVED or FAILS, never when one is ADDED: zero-failures, a floor
of >=11 passed, and presence of every named suite's init.sh header line.
Proved both directions against real QEMU runs (not just regex review):
- Removed tests/qemu/test_kmod_access.c, rebuilt, ran in QEMU for real:
output showed '10 suites passed, 0 suites failed'; new check goes RED
(floor check) and independently RED (named-suite check, verified with
the count artificially padded back to 11 to isolate that layer).
- Restored test_kmod_access.c; added a genuine throwaway
test_syssvc_throwaway.c (deleted before this commit), rebuilt with zero
Dockerfile/CMakeLists edits, ran in QEMU for real: output showed
'12 suites passed, 0 suites failed'; new check stays GREEN.
- Rebuilt the final tree (no throwaway file) and reran in QEMU: baseline
'11 suites passed, 0 suites failed' unchanged, new check GREEN.
- Reran the negative-control image (NEGATIVE_CONTROL=1): unchanged
'3 suites passed, 8 suites failed', RC=1 -- untouched by this change.
Everything else the round-3->4 adversarial review found (SS$_NOSUCHDEV
2680 vs oracle 2312, lckdef.h bit-value drift, zero production callers of
vms_kif_register(), the QEMU gate's blindness to src/vmsdcl, only the lock
manager reachable) is pre-existing debt, already filed separately, and is
untouched here.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… (vms-1d9)
Round 4 fixed two findings and introduced four. This undoes that damage and
closes the one gap that was never gated. Every claim below is proven by a real
podman build + QEMU boot, not by inspection.
G1 .dockerignore no longer excludes CLAUDE.md. Round 4's exclusion broke this
epic's OWN Rule 9 standing gate inside every image built from the repo root:
tests/integration/test_runtime_target.sh greps CLAUDE.md, and
`ctest -R runtime_target_gate` went red in the image while CI stayed green
(CI only ran ctest on the host checkout) -- a silently broken guardrail.
Now passes in-image.
G2 .dockerignore no longer excludes third-party/, which src/imgact/test/
run_tcc_{native,rms,object_native,selfhost}.sh and src/vmslink/mk_tcc.sh
hard-require. The whole list is narrowed to non-source state only, and it is
now validated by RUNNING the suite inside the resulting image rather than by
grepping the build files -- the method that missed both of the above.
G3 The suite gate is strong in both directions with nothing maintained by hand.
Round 3 pinned an exact tally (red on a legitimate addition); round 4
replaced it with a floor plus a hand-maintained name list whose own comment
said it is not updated on addition, leaving every future suite unprotected.
init.sh now prints a machine-readable per-suite verdict carrying the
binary's real exit status, and CI derives the expected suite set from
`ls tests/qemu/test_*.c`. Suite ADDED -> green; suite DROPPED -> red;
suite FAILS -> red. A monotone floor on the number of suite SOURCES catches
outright deletion, which a derived set cannot see.
G4 The negative-control job gets the same treatment. Its exact 3/8 tally pin
turned red when a legitimate test_syssvc_*.c was added (proven: 3/9).
G5 The decisive one. A real silent fallback in sys_lock.c (SS$_NORMAL instead
of SS$_NOSUCHDEV when /dev/vms is absent, in do_enq and sys$deq) left the
FINAL RESULTS accounting BYTE-IDENTICAL -- 3 passed / 8 failed, RC 1 -- and
every assertion in both jobs still passed. Cause: init.sh funnels exit 77
(honest skip) and exit 1 (assertion failure) into one counter, and CI pinned
only the total, so a per-process fake that reports success was invisible to
the entire gate. The negative control now asserts that every test_syssvc_*
suite exits exactly 77, which holds only when its device-absent
SS$_NOSUCHDEV assertions all passed. Re-injecting that exact fallback now
turns the job RED; reverting restores green (identical image SHA).
Unchanged: test_syssvc_lock.c, tests/qemu/CMakeLists.txt, sys_lock.c, lksdef.h.
The proven core -- a QEMU test linking the real libvms catching a userspace
defect all eight raw-ioctl suites miss -- was not touched, and was re-verified:
deleting one kstat_to_ss() line turns test_syssvc_lock red while all 8
test_kmod_* suites stay rc=0.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…(vms-1d9) GitHub runs `run:` steps under `bash -e`, and `grep -c` exits 1 on an empty set, so an empty derived suite list would have aborted the step with no diagnostic instead of reaching the explicit source-count floor below it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
DO NOT MERGE — HELD BY THE ORCHESTRATOR (2026-07-29). CI is green and the PR is mergeable; it is still not safe to merge, for two independent reasons.
Prior rounds' genuine wins on this branch are recorded and should be preserved when it is re-cut: the QEMU test linking the real libvms catches a userspace defect all eight raw-ioctl Full state and next steps: |
|
CLOSED BY TRIAGE 2026-07-29. Not a rejection of the capability — a rejection of this diff. Two independent disqualifiers, both from this PR's own hold comment and both still true:
Closing rather than leaving it green-and-mergeable behind a comment: a DO-NOT-MERGE comment is a bet that every future agent skims the thread. The branch |
…x (10 items) (#158) * vms-c9c: negative-control diagnostic prints the condition, not an inferred cause rc!=77 (and rc!=0) for test_syssvc_* only means "77 was not reached" -- it has two distinct causes (a fabricated success, or an unrelated assertion failure), and the old message asserted the first as fact. Proven false on PR #46 (run 30725753152): both fabricated-success assertions passed, the real defect was DCL.EXE crashing. Now the message states the ambiguity and pastes the suite's own FAIL line(s) so the reader attributes from evidence already in the same output. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * vms-86a: shard the per-facility negctl job to fit CI under concurrent load Root cause (measured, rd vms-86a trail): the job ran all 58 manifest defects sequentially in ONE job -- 27m solo, 50m under moderate CI load, >60m and timeout-killed with three PRs in flight. Raising timeout-minutes was rejected (flaky-test rule): it hides the margin problem, it doesn't fix it. Splits the per-facility loop into 6 independent matrix shard jobs, each running ~1/6 of `facility_defects.sh list` (partitioned by NR%6, so it tracks the manifest as it grows/shrinks -- never a hand-maintained sublist). Each shard still runs the SAME positive control and the SAME per-defect equality check (red set EXACTLY require_fail+knock_on_fail, attribution, blind-suite gaps) the single job did, just over a subset. A new aggregate job (keeping the ORIGINAL job name for branch-protection/ doc continuity) unions every shard's emitted execution record and runs the full-manifest comparison against the committed tests/qemu/facility_negctl_observed.tsv in both directions -- the exact check the single-job driver ran on a full run, just over the union instead of one sequential execution. Verified: the 6-way NR%6 partition covers the manifest exactly (58/58, no gaps, no dupes); reconstructing the union from the real committed record and running fnr_compare against it passes; dropping one shard's rows from the union is correctly caught as a mismatch. Both existing static selftests (facility_defects.sh selftest, facility_record_negctl.sh) still pass unmodified. actionlint clean except pre-existing style-level shellcheck notes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * vms-b3b: key the facility-negctl red-set equality on (suite, text), not text alone run_facility_negctl.sh's per-defect equality (check 6) compared bare assertion text against require_fail/knock_on_fail, discarding the suite attribution fail_map() already carries (`cut -f2-`). MEASURED: the text "child: a LOCAL flag set by the parent is NOT visible here (local clusters stay per-process)" -- named by bind-client-no-register, expected from test_syssvc_ef_mproc.c (in that defect's suites_red) -- is also printed verbatim by test_kmod_eflag_mproc.c, which is NOT in suites_red. Under the old equality, a red from either suite satisfied the requirement, so a red from the wrong suite could mask the right suite's own red going missing. Fix: tests/qemu/facility_negctl_equality.sh's fne_scope_map() scopes the observed (suite, text) rows to the defect's suites_red glob (or "(harness)") before the text comparison runs, so a same-text red from an out-of-scope suite can no longer stand in for the suite the manifest actually named. Swept the whole manifest at the same normalisation facility_defects.sh's own selftest uses: every require_fail/knock_on_fail text in every defect is still found within its own suites_red-scoped sources except this one already measured case -- the fix does not narrow any other defect's requirement. tests/qemu/facility_negctl_equality_negctl.sh is the negative control (no QEMU needed): it pins the real collision as still-grounded, proves a red from the right suite still satisfies the requirement, and proves a same-text red from the wrong suite (test_kmod_eflag_mproc) no longer does -- reproducing the driver's own comparison shape end to end. Registered as ctest facility_negctl_equality (label "harness", no container/QEMU). * vms-41b: root rule's header clause requires a NON-static declaration The census credited any function prototyped in a header the build compiles as a root (rule 2, "exported API surface"), because the P-record reading never carried the static/extern qualifier. MEASURED exploit: a dead helper declared AND defined `static` in a multi-includer header (dcl_cmd.h, included by 9 TUs) bought a root exactly like the earlier two-edit recipes this gate already closed -- a `static` declaration can never be an exported entry point, since each includer gets its own private symbol. Fix: call_edges() now tags each P record static|extern, and root rule 2 only seeds from non-static declarations in non-TU files. Verified by hand against the prior recipe (now rc=1, naming vms_kif_chkpriv) and against the pristine tree (unchanged, rc=0). Added negative control 48 to pin it; all 42 controls in test_kif_caller_census_negctl.sh pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * vms-d33: close the header-residency root-rule loophole in the kif census Rule 2 of the census's call graph grants a root to "every product function prototyped in a header the build compiles" -- correct for a genuinely exported symbol, but the (origin file, name) tagging that tells a `.c` translation unit's private static from an extern definition only fired when the origin was itself one of the compiled TUs. A header never is, so a `static` function whose declaration AND body both lived directly in a compiled header (e.g. src/vmsdcl/include/dcl/dcl_cmd.h) fell through untagged and landed on the same bare-name node an actually-exported symbol gets -- granting root status, and therefore a product path, to a function with internal linkage that could never be called from outside its own translation unit. MEASURED before the fix: two edits (a static declaration+body in dcl_cmd.h, plus retiring vms_kif_chkpriv's OVMX-UNWIRED token) bought rc=0 at 44/32/12, one extra root (731 -> 732). Fixed by tracking header-resident static definitions independent of the per-TU tagging and excluding them from rule 2's grant. Pristine tree unaffected (731 roots, 1547 reached, 31/44 unchanged) because the loophole requires a function that additionally carries a standalone forward declaration -- a shape no existing static-inline header helper in the tree has. The same two-edit recipe is now rc=1, naming vms_kif_chkpriv. Captured as negative control 48 in test_kif_caller_census_negctl.sh (42 passed, 0 failed, no regressions across all pre-existing controls). This closes one purely-static loophole in vms-d33's "product path, not execution" question -- it does not close vms-d33 itself. A genuinely extern function declared in a header and defined in one .c file is still a root whether or not it is ever called at runtime, and is still indistinguishable here from a real caller nobody exercises -- that gap is execution, not linkage, and needs the per-assertion runtime-attribution instrument's groundwork (docs/design-runtime-attribution.md, residual R7) before it can close. Documented as a disclosed residual, not claimed closed, in both the gate's header comment and the design doc addendum. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * vms-cb5: $SETUAI's SYSPRV test comes from the executive, not the caller's own PCB Round 5 of the Phase 3 security review, against origin/main c871334. sys$setuai -- the one service that rewrites SYSUAF.DAT, UAI$_PWD included -- guarded itself with: struct vms_pcb *pcb = vms_pcb_get(); if (pcb && !(pcb->cur_privs & PRV$M_SYSPRV)) return SS$_NOPRIV; Two ways through. vms_pcb_get() returns NULL for a process that never called vms_pcb_init(), so `pcb &&` made the condition false and NO privilege test ran at all. And where a PCB did exist the mask was pcb->cur_privs, which sys$setprv writes for the calling process with no validation -- the caller's own claim about itself. The test now reads the row the executive holds for the process (vms_kif_getjpi_self), the same source tools/vms_authorize.c uses since vms-b2e, and refuses when that read does not come back (Rule 9: no absent-executive branch). Also fixes the rewrite's UIC write-back base. parse_uaf_line() reads the two UIC fields with strtoul(..., 8) after vms-e60; this fprintf still printed them with %u, so rewriting any record whose UIC digits differ between the bases changed that account's UIC. USER1 ships 200|202 and would have been written 128|130. tests/qemu/test_syssvc_setuai.c drives all of it against a real /dev/vms: a caller with no PCB, a caller with an authenticated non-SYSPRV identity, a caller whose own PCB claims SYSPRV over an executive row that does not, and the SYSPRV positive that keeps the three refusals from being blanket. The SYSUAF.DAT evidence is read by the parent -- a process that neither authenticated nor wrote. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * vms-38c: re-measure runtime attribution post vms-2b2, fix stale anchors vms-2b2 closed: all 16 wired vms_ioctl_* handlers are now MEASURED (25/33 total, 8 UNPROBED = the OVMX-UNWIRED exempt set). Re-measuring the register against that finds 8 of 10 OVMX-EXECUTIVE claims MEASURED, exactly 2 still UNMEASURED: sys$readef and sys$setef. Root cause is NOT unprobed handlers -- vms_ioctl_readef/setef are each measured-dependent elsewhere (test_syssvc_ef_ local, test_kmod_eflag, test_kmod_bind) -- it's a suite-scope mismatch: the defects that mutate their WASSET/WASCLR status word never redden an assertion in test_syssvc_ef_mproc.c, the suite cited as these two claims' own proof. Fixes landed: - test_userspace_service_register.sh: the UNMEASURED branch now distinguishes "handler measured elsewhere, suite mismatch" from "handler unprobed anywhere" instead of always citing the now-closed vms-2b2 as the reason. The stale "2 of 10 measured" / "9 of 33 handlers" comment block is replaced with a re-derivable description instead of a count that will drift again. - facility_attribution.sh selftest checks 3 & 5 hardcoded vms_ioctl_wflor as a "known unprobed" anchor. vms-2b2's own follow-up (vms-2ed) later gave it real coverage in that exact suite, which silently broke the selftest (a stale hardcoded fact, the same mistake class this file argues against). Now derives the anchor from `handlers` output each run. - facility_attribution_negctl.sh control B hit the same staleness (the recorded 2-edit sys$wflor buy no longer represents an unpaid claim, since wflor is now honestly measured in that suite). Control B now detects that organic graduation and falls through to a fresh, currently-live equivalent: one ignored call added to sys$readef's own already-declared EXECUTIVE proof does not flip its standing UNMEASURED to MEASURED -- the adversarial round this item required, run against current data instead of a resolved case. Not enforced: a pristine tree would still red 2 of 10 claims, so the register stays report-only per the item's done-condition. Verified: register (rc=0), register negctl (49/49), facility_attribution selftest (6/6), facility_ attribution_negctl (8/8), facility_defects selftest, facility_record_negctl (25/25). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * vms-05e7: close the composed rename+shared-.inc census exfiltration The census's third definition reading (vms-e2b) namespaced its unrestricted region read to `vms_kif_` names, to tell an exfiltrated interface wrapper apart from vms_syscall.h's 47 static inline syscall stubs. That name filter left an escape: exfiltrate a wrapper's body into a .inc shared with a second product TU (defeating the private-origin rule) AND rename it out of the vms_kif_ namespace (defeating the name filter). MEASURED before this change: 7 edits, universe 44->43, rc=0, PASS -- a silent shrink. Fix: call_edges() now tracks the `inline` keyword alongside `static` and tags a defs-mode static definition "static-inline" when both are present. A new fourth definition-reading term reads the interface TU's full region with no name filter, excluding only "static-inline" definitions -- the tell that separates vms_syscall.h's generic stubs (all `static inline`, verified) from a real wrapper's body (plain `static`, verified against vms_kif.c's own kif_bind/kif_call/etc.). The recipe now reds naming the renamed entry point instead of silently leaving the universe. Added negative control 48 reproducing the full 7-edit recipe; all 42 existing controls stay green; pristine tree rc=0, universe unchanged at 44. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * vms-cb5: test_syssvc_setuai bootstraps the device table before resolving SYSUAF SYSUAF_PATH is a VMS filespec; vmsfs_to_linux_path() cannot resolve it until the system device is in this process's device table, which is what every shipped image does at startup. Without it the suite failed on a missing file instead of on $SETUAI's privilege test, so its refusals would have been explained by the wrong thing. The resolved path is printed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * vms-cb5: negative control setuai-sysprv-caller-declared, and the suite's logical-name bootstrap VMS_SYSUAF_PATH is "SYS$SYSTEM:SYSUAF.DAT", so resolving it needs the logical name table as well as the device table. MEASURED before this: the path resolved to /vms/sysuaf.dat and the suite failed on a missing file instead of on $SETUAI's privilege test. The control deletes the mask test and nothing else -- the state $SETUAI was in for every caller with no PCB. It names the three refusals in require_fail and the file-unchanged check in knock_on_fail, with the reason. facility_defects.sh selftest PASS; coverage PASS (59 defects >= floor 58, all anchored, 27 suites named). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * vms-e90: teach divider-integrity detector to recognize table separator rows src/vmsscs/include/scs_mscp_srv.h:601 is a legitimate markdown-style comment table ("header offset | size | field" / "---|------|---...") added by vms-4e31 (ddce7ec) to document the SCA block-transfer header layout, not a corrupted divider. The FUSED_RE detector was matching the dash run and flagging the rest of the row as fused-onto-line text. Fix by shape, not by allowlist: a tail made up of nothing but '|' and divider characters (a table separator row's remaining cells) is exempted, the same way a '*/' comment closer already is. Real fusion -- prose from the next comment line -- still trips the check immediately, per new test test_still_flags_fusion_immediately_after_a_table_style_run. Proof suite: 14/14 pass (was 12; added the table-row true-negative and a paired true-positive). Full-tree gate sweep: 777 files, 0 findings. * vms-cb5: $GETUAI/$SETUAI stop losing every empty SYSUAF field Found by the new suite, not by reading: test_syssvc_setuai read USER1's row back out of SYSUAF.DAT after a $SETUAI and got uic_group=202, uic_member=0 where 200 and 202 belong. parse_uaf_line() split the row with seven strtok_r(buf, "|") calls. strtok treats a RUN of delimiters as ONE, so every empty field was dropped and every field after it read one position early. Five of the six shipped rows have an empty field, so $GETUAI answered the wrong hash, the wrong UIC and the wrong privileges for those accounts, and $SETUAI wrote the misparse back. USER1||200|202|SYS$SYSDEVICE:[USERS.USER1]||TMPMBX,NETMBX -> password_hash="200", uic_group=202, uic_member=strtoul(defdir,8)=0 uic_member 0 is why this is more than a parsing bug: tools/vms_login.c does setuid(rec->uic_member), and setuid(0) is not a drop. What stops that on the shipped SYSUAF is that all four accounts this misparse gives member 0 carry no password hash and cannot authenticate (vms-08f) -- not anything here. The replacement split is the one src/libvms/rtl/sysuaf.c's sysuaf_scan() already uses, so the two readers of this file now agree by construction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * vms-ed8: close register-universe residuals #1-3 disclosed by vms-c19 Closes three of the five gaps test_userspace_service_register.sh disclosed (not claimed closed) after vms-c19: 1. A target declared under tests/, holding its own sys$ definition in a source under tests/, that is nevertheless installed. The tests/ exclusion only asked "is the compiling target declared outside tests/ AND does it compile a non-tests/ source"; a target failing both halves but shipped by install(TARGETS ...) was never asked about. Fixed by scanning every CMakeLists.txt for install(TARGETS ...) and treating a named target as a product target regardless of which directory declared it. 2. A source CMake compiles only under an option this configure leaves OFF, living outside src/ and tools/ (inside those two the glob still catches it, e.g. src/imgact/ under OVMX_IMGACT=OFF). Fixed with a mechanical scan (register_optguard.awk) for add_subdirectory() calls gated by an OFF option that resolve outside src/+tools/; the gate now REFUSES rather than silently certifying a hole, naming the option and path. 3. compile_commands.json was parsed by line shape with no defense against a PARTIAL parse (a "file" field that never reaches a matching object close would have silently dropped that entry). The parser is pulled out into tests/integration/lib/register_buildset.awk, which now counts "file" fields seen vs. objects closed and refuses on a mismatch instead of certifying a shrunk set. Each fix is measured before/after against the real gate on a sandboxed tree: the pre-fix gate PASSes while missing the minted service; the post-fix gate reds naming exactly it. register_buildset.awk's partial-parse path is also unit-tested directly against a hand-built malformed compile_commands.json, since no product-source mutation can perturb cmake's own JSON shape. Pristine tree: rc=0, universe unchanged at 88 services. Negative controls added to test_userspace_service_register_negctl.sh for all three; gate header's "WHAT REMAINS OPEN" disclosure updated to drop the two closed bullets (deleted, not reworded, per the standing prose ruling). Residuals #4 (assembly aliasing) and #5 (shared broken-build-set message prefix) are out of scope for this item and remain open. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: alice <alice@workspace.local> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…t; toolchain builds it byte-identical twice (#470) MMK.EXE now drives the PLAN for a real multi-translation-unit OVMX component — the freestanding runtime (src/libvmssys vms_string/vms_snprintf/vms_math + a driver), described by the committed MMS descrip.mms tests/toolchain/component/ OVMXRT.MMS: four TCC compiles, a LIBRARIAN archive, a LINK, in dependency order, byte-identical across two runs. Zero bash in the plan — MMK drives it. This is spine #4's single-TU parse proof scaled to a real multi-TU + library component. The OVMX-native LIBRARIAN.EXE + LINK.EXE build that component's .OLB and image BYTE-IDENTICALLY across two independent builds (cmp clean) on the real component objects, with selective member pull (2 of 3 members). LIBRARIAN zeroes the ar mtime/uid/gid fields; with TCC.EXE's proven compile determinism (run_tcc_selfhost gen2==gen3), the whole TCC->LIBRARIAN->LINK chain is reproducible — the byte-identical-twice bar for the build OUTPUT. New host ctests (both green): toolchain-mmk-component-plan (MMK_EXE) and toolchain-mmk-component-build (LIBRARIAN/LINK/OVMXDUMP on the real objects). Residual gap (spine #6, vms-d1b, the CI gate): MMK's mailbox-driven DCL EXECUTION of the plan requires a real /dev/vms (QEMU); that + first-ever TCC-in-QEMU, toolchain staging into the initramfs, spawned-DCL foreign-command setup, and the byte-identical-in-QEMU assertion are specified precisely in docs/design-self-host-spine5-mmk-component.md. No unproven/red QEMU suite is shipped (Rule 6/7). Co-authored-by: alice <alice@workspace.local> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ve (#472) Bump OVMX_PRODUCT_VERSION V0.4-2 → V0.4-3. 15 PRs since V0.4-2. Headline: the self-host toolchain now BUILDS — MMK.EXE drives real compile+link inside OVMX against a live executive. SELF-HOST #4 COMPLETE MMK.EXE genuinely drives compile+link builds vs real /dev/vms (#464 capstone). Full exec-drive substrate: async AST delivery + interruptible $HIBER (#457), IO$M_NOW (#458), DCL-over-mailbox (#460), + crash fixes #463 (32→64 ptr-width) / #464 (IO$M_NOW func-code mask). Freeze-join fix (#459). Component build host-proven (#470). UX FIDELITY SHOW CPU (#465), file protection SET/display (#467), RECALL readline-independent (#468), DCL scripting $STATUS/%X + CALL/SUBROUTINE + DECK/EOD (#469), DIRECTORY wildcards/ellipsis (#461). + swept other threads' merged work Self-host spine #5/#6 (MMK-drives-a-real-component IN QEMU) in flight. Co-authored-by: alice <alice@workspace.local> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…byte-identical, zero-bash (CI gate) (#476) * vms-d1b: self-host spine #6 — MMK drives a real TCC compile in QEMU, byte-identical, zero-bash (CI gate) The shipped MMK.EXE now drives a REAL toolchain step inside OVMX in QEMU, against a real /dev/vms: it spawns a persistent DCL over VMS mailboxes and streams a descrip.mms whose action defines a foreign command TCC :== "$..." and invokes it to compile the REAL src/libvmssys freestanding runtime TU vms_string.c to an object. DCL activates the foreign command by fork()+execve() of the staged static TCC.EXE (a plain static image is not in-process-eligible, so imgact_activate returns SS$_UNSUPPORTED and DCL forks it) — the FIRST-EVER TCC.EXE run inside QEMU and the first time MMK drives a real compiler (not a DCL builtin) end to end. The parent (which never runs a compiler) asserts the driven object is a valid ELF relocatable carrying vms_strlen and is BYTE-IDENTICAL across two independent in-guest MMK-driven builds. Zero bash in the build path. This closes spine #6 (vms-d1b, the CI gate) and the MMK-driven-EXECUTION residual of spine #5 (vms-fe4) for the COMPILE stage. - tests/toolchain/mk_tcc_static.sh: builds tinycc as a PLAIN STATIC (musl) foreign-command image (distinct from mk_tcc.sh's IMGACT-packaged self-host image) — the binary DCL fork+execve activates, no IMGACT/shareable staging. - tests/toolchain/run_tcc_static_component.sh + CMake test toolchain-tcc-static-component: host proof the static TCC.EXE compiles the real runtime TUs (vms_string/vms_snprintf/driver) to valid, byte-identical objects; asserts vms_math.c is the documented x86 tcc-blocked TU (SSE "x" inline asm). - tests/qemu/test_syssvc_mmk_build.c: the QEMU suite (extends spine #4's test_syssvc_mmk_drive.c); honest-skips 77 with no /dev/vms. - tests/qemu/Dockerfile: stages static TCC.EXE at SYS$SYSTEM, tinycc's headers + musl's stdint.h closure beside it, and the real component source. The suite plugs into the STANDING kernel-executive CI barrier (builds the image from the checked-out tree, a clean context), so the MMK-driven native build is gated on every run — no new job. - facility_defects.sh: new per-facility control mmk-build-image-not-activated — dcl_exec_foreign_command reports success WITHOUT activating the image, so the driven TCC command completes but runs no compiler; reddens exactly the suite's five object/byte-identity assertions FAST (no $HIBER wedge), attributable to the build drive alone. A DEDICATED control, not a second suite on the sp_send=0 drive control: two ~50s $HIBER wedges do not fit run_tests.sh's 120s QEMU budget in one boot. Floor 96 -> 97. Verified in QEMU on this host: kernel-executive 76/76 (mmk_build 7/7); mmk-build-image-not-activated reddens exactly the 5 object assertions with no strays and the harness completes (no timeout); executive-absent mmk_build rc=77. BUILD.COM retirement is NOT done: the full compile->archive->LINK-to-image chain in-guest remains (vms_math not tcc-compilable on x86_64; LINK needs the SYS$LIBRARY shareables staged + logical-name resolution in LINK.EXE + IMGACT activation) — the precise residual for spine #7, documented in docs/design-self-host-spine5-mmk-component.md. No red gate shipped (Rule 6/7). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * vms-d1b: fix mmk_build CI timing — wait for MMK to EXIT (single generous bound), not a 2s reap grace CI's Kernel Executive job went red from a clean build: mmk_build produced the object and echoed the marker (build-#1 assertions GREEN) but MMK had not yet finished tearing down its spawned DCL within the tight 2s REAP_GRACE, so reap1 stayed 0, the reap1 short-circuit skipped drive #2, and the completion + byte-identity assertions reddened. CI's TCG is much slower than the dev host, where reap1 was always 1. Restructure drive_build to a SINGLE generous bounded wait (40s) that drains output (detecting the marker) AND polls for MMK to exit, returning the instant MMK exits -- so a green drive costs only its real runtime and the bound is only ever hit by a genuine hang. Removes the split 10s-marker / 2s-reap phases that were sized for a fast dev host. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * vms-d1b: make mmk_build load-robust — capture proof (marker+object) instead of waiting on MMK's exit The clean-build repro showed mmk_build's remaining flake was MMK's slow self-exit under contended TCG: the compile finished, the marker was echoed and the byte-identical object was on disk, but MMK had not yet torn down its spawned DCL and exited within the bound, so the reap-based assertion reddened. MMK's exit timing is not a property this suite tests. drive_build now stops the instant the PROOF is captured -- the DCL echoed OVMXD1B:COMPILED AND the object exists on disk -- and kills MMK as cleanup rather than gating on its self-exit. A genuine mid-drive $HIBER deadlock still fails hard (no marker is ever echoed). The completion assertion is now the marker (reliable), the reap-exit assertion is dropped, and the drive-#2 short-circuit is keyed on the object (robust under load), not on MMK's exit. The negctl declared set is unchanged (the 5 object/byte-identity assertions; the marker stays green). Verified: two consecutive clean green runs (mmk_build 6/6), and mmk-build-image-not-activated reddens exactly the 5 object assertions with the marker green. (A QEMU timeout / mmk_drive reap-flake seen intermittently here is this 10-container dev host's load, not the code: on CI the harness completed and mmk_drive passed.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: alice <alice@workspace.local> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ttach() (Rule 9 gate) Integration regression on work/vms-0.5-final: the "Build & Test" job built clean but ctest went red on runtime_target_gate (#5) and, as a consequence, runtime_target_negctl (#8) -- the standing Rule 9 / INV-6 gates (tests/integration/test_runtime_target.sh). Each merged branch was green alone; the combination reddened the gate. ROOT CAUSE (merge interaction). vms-46c-sysboot-acp refactored ovmx_init.c's executive_attach(): pre-merge it was ONE function that loaded vms.ko, opened /dev/vms via the boot seam, CAPTURED the descriptor into executive_fd, HALTED if the open failed, and emitted the %OVMX-I-EXEC line inline. The refactor split that into executive_attach_silent() (capture + halt) + executive_announce() (the printf) + a thin executive_attach() wrapper that just calls the two. It did this for a real reason -- the conversational SYSBOOT> path must attach the executive BEFORE the prompt but print nothing until after it. But check 3 of the Rule 9 gate inspects the body of the function LITERALLY named executive_attach() for the descriptor capture, the terminal-halt failure branch, and the pin; after the refactor that body only delegates, so the gate reported "no ovmx_boot_open_executive() result is captured into a variable" and failed. #8's positive control re-runs #5, so it failed with it. The gate and its negctl were not touched by the merge, so they were left inspecting a function that no longer held the guarantee. FIX (code, not the gate). Restore the executive guarantee INTO executive_attach() itself -- capture, `if (executive_fd < 0)` terminal ovmx_exec_halt(), and the pinned file-static fd -- and add an `announce` parameter so the silent conversational path is preserved: executive_attach(0) attaches without the console line (deferring it to executive_announce() after SYSBOOT>), and every other caller uses executive_attach(1) for the inline announce. This keeps the guarantee in the exact function the gate reads and leaves the guarantee lines verbatim (so the negctl's line-anchored mutations still trip), while preserving vms-46c's silent-boot behaviour. test_runtime_target.sh and its negctl are UNCHANGED -- no gate weakened, no allowlist added (CLAUDE.md Rule 9). Verified by full ctest on the k3s rail (real git clone, non-dind). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ch() (Rule 9 gate) Integration regression on work/vms-0.5-final: the "Build & Test" job built clean but ctest went red on runtime_target_gate (#5) and, as a consequence, runtime_target_negctl (#8) -- the standing Rule 9 / INV-6 gates (tests/integration/test_runtime_target.sh + its negative control). Each merged branch was green alone; the combination reddened the gate. ROOT CAUSE (merge interaction). vms-46c-sysboot-acp refactored ovmx_init.c's executive_attach(). Pre-merge it was ONE function that loaded vms.ko, opened /dev/vms via the boot seam, CAPTURED the descriptor into executive_fd, HALTED if the open failed, pinned the fd, and emitted the %OVMX-I-EXEC line inline. The refactor split that into executive_attach_silent() (capture + halt) + executive_announce() (the printf) + a thin executive_attach() wrapper that just calls the two. It did this for a real reason -- the conversational SYSBOOT> path must attach the executive BEFORE the prompt (the Files-11 ACP $MOUNT needs it) yet print nothing until after it. But check 3 of the gate inspects the body of the function LITERALLY named executive_attach() for the descriptor capture, the terminal-halt failure branch, and the pin; after the refactor that body only delegates, so the gate reported "no ovmx_boot_open_executive() result is captured into a variable" and failed. The negctl was untouched by the merge, so its positive control (which re-runs the gate on the unmutated tree) failed with #5, and its 3b(h) mutation still anchored the executive_attach(void) signature. FIX (code only -- no test touched). Move the guarantee back INTO executive_attach() itself: the load, the executive_fd = ovmx_boot_open_executive() capture, the `if (executive_fd < 0)` terminal ovmx_exec_halt(), the pinned file-static fd, and the %OVMX-I-EXEC printf all live in the one function the gate reads again. The conversational path's need to defer the console line is met by a file-static executive_announce_deferred flag (set before the silent attach, announced via executive_announce() after SYSBOOT>) -- a deferral of the ANNOUNCE only; the capture+halt+pin guarantee is unconditional. Signature stays executive_attach(void), and the guarantee lines stay verbatim, so both the gate and every negctl mutation (including 3b(h), which anchors the signature) match and trip exactly as before. tests/integration/test_runtime_target.sh and test_runtime_target_negctl.sh are UNCHANGED -- no gate weakened, no allowlist added (CLAUDE.md Rule 9). Verified locally: gate PASS, negctl 31/31; full ctest re-run on the k3s rail (real git clone, non-dind) below. NOT part of this fix: dcl-integration (#117) fails on the bare builder/rail image (SET ACCOUNTING cannot write SYS$MANAGER:ACCOUNTNG.ENB with no populated VMS root) -- it fails identically on the pre-merge base commit 06e62f5, so it is a pre-existing environment artifact, not an integration regression. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… the VMS data model) + DEC C behavior-compat architecture (#995) * vms-4b5: resolve the alpha cc1 "-O0 union-pun-branch miscompile" — it is the VMS data model, not a bug Root-caused the reported alpha-dec-vms cc1 (GCC 14.2.0) "silent miscompile" of a union-type-punned branch at -O0. It is NOT a codegen fault: on alpha-dec-vms `long` is 32-bit (LLP64-shaped model, matching DEC C / VSI C on OpenVMS), so `union { double d; unsigned long u; }` puns a 64-bit double through a 32-bit member and captures only the low 32 bits. Branching that (zero-extended) value against the 64-bit constant 0x3FF0000000000000 is provably-false, which GCC correctly folds away even at -O0 (an in-range constant, or a runtime comparand, keeps the branch). Proven in the ovmx-cross-alpha-vms container: sizeof(long)==4 even at -mpointer-size=64; in-range const -> branch kept, out-of-range -> folded; unsigned long long member -> full ldq pun + cmpeq + branch codegens correctly. Fix: widen crtl_cc1fp_test.c's fpbits union to `unsigned long long`, correct the false LP64/miscompile comments, and branch ON the punned member as a positive regression (real ldq + cmpeq + branch, verified). Correct the surface-gaps register (S1.3 + item #5). The broader risk this exposed (DEC C behavior/data-model compatibility) is the subject of a new design doc. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V2jrHU9fdTTfKhB5HBQNQH * docs: DEC C behavior-compat source architecture — register + oracle, not whack-a-mole Strategic design fork for the operator (vms-da0 lane). Frames the DEC C / VSI C compatibility problem the vms-4b5 phantom bug exposed: to compile real VMS C source unchanged, OVMX must be behavior-compatible with DEC C (data model, layout, float format, pragmas, macros, extensions, linkage), and chasing individual divergences program-by-program is a tarpit. Recommends a declarative DEC C behavior register + differential oracle + authoring-time lint over the GCC 14.2.0 alpha-dec-vms base (a "DEC C personality layer"), scoped to L1 documented-behavior compat, with L2/L3 demand-gated. Surfaces two operator forks: preprocessor identity (__DECC vs __GNUC__) and how far L2 goes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V2jrHU9fdTTfKhB5HBQNQH --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…thout-valid (35→34) kernel-core/vms_cluster_api.c gets a real injected negative control (§1 35->34). Defect getsyi-csid-reported-without-valid: cluster_api_getsyi_project() forces the SYI$_NODE_CSID block always-taken (the unique `if (club->local_csid_valid)` learned-CSID guard becomes `if (1)`), so node_csid_valid is asserted with NO learned CSID — integration-note E30's exact fabrication (0 means "none assigned", never "node zero"); node_csid stays 0, only the VALID flag lies. suites_red: test_syssvc_cluster_negctl; require_fail "... node_csid_valid CLEAR -- the cluster assigned no CSID, and 0 means 'none assigned', never 'node zero'" (anchored). Static-proven (host): selftest injects + idempotent-teeth; §1 drops vms_cluster_api.c (35->34); dash -n clean. Per-defect QEMU falsification rides the batched local rail run + CI negctl shard. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HMDFjHCqxDuXgbyxNU572h
…thout-valid (35→34) kernel-core/vms_cluster_api.c gets a real injected negative control (§1 35->34). Defect getsyi-csid-reported-without-valid: cluster_api_getsyi_project() forces the SYI$_NODE_CSID block always-taken (the unique `if (club->local_csid_valid)` learned-CSID guard becomes `if (1)`), so node_csid_valid is asserted with NO learned CSID — integration-note E30's exact fabrication (0 means "none assigned", never "node zero"); node_csid stays 0, only the VALID flag lies. suites_red: test_syssvc_cluster_negctl; require_fail "... node_csid_valid CLEAR -- the cluster assigned no CSID, and 0 means 'none assigned', never 'node zero'" (anchored). Static-proven (host): selftest injects + idempotent-teeth; §1 drops vms_cluster_api.c (35->34); dash -n clean. Per-defect QEMU falsification rides the batched local rail run + CI negctl shard. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HMDFjHCqxDuXgbyxNU572h
…thout-valid (35→34) kernel-core/vms_cluster_api.c gets a real injected negative control (§1 35->34). Defect getsyi-csid-reported-without-valid: cluster_api_getsyi_project() forces the SYI$_NODE_CSID block always-taken (the unique `if (club->local_csid_valid)` learned-CSID guard becomes `if (1)`), so node_csid_valid is asserted with NO learned CSID — integration-note E30's exact fabrication (0 means "none assigned", never "node zero"); node_csid stays 0, only the VALID flag lies. suites_red: test_syssvc_cluster_negctl; require_fail "... node_csid_valid CLEAR -- the cluster assigned no CSID, and 0 means 'none assigned', never 'node zero'" (anchored). Static-proven (host): selftest injects + idempotent-teeth; §1 drops vms_cluster_api.c (35->34); dash -n clean. Per-defect QEMU falsification rides the batched local rail run + CI negctl shard. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HMDFjHCqxDuXgbyxNU572h
Round 5 of
vms-1d9(epicvms-6b8, Phase 0.5 barrier). Draft — opened primarily so GitHub Actions runs at all:ci.ymlonly fires on push-to-main or a PR against main, so rounds 1–4 of this branch have never had CI evidence. The two things only a real Actions run can show are thetimeout-minutes: 20budget on a cold runner and YAML/runner-shell validity of the new bash blocks.What this round does
The core capability is unchanged and was deliberately not redesigned: a QEMU test linking the real
libvmscatches a userspace defect that all eight raw-ioctltest_kmod_*suites miss, and thetest_syssvc_*.cglob is generic. Round 4 fixed two findings and introduced four; this undoes that damage and closes the one gap that was never gated..dockerignoreno longer excludesCLAUDE.mdctest -R runtime_target_gatenow passes in-image (was***Failed).dockerignoreno longer excludesthird-party/run_tcc_native.sh:77passes in-image3/9split, previously red, now greenG5 is the decisive one
The adversary's injected fallback in
sys_lock.c(returningSS$_NORMALinstead ofSS$_NOSUCHDEVwhen/dev/vmsis absent, in bothdo_enqandsys$deq) left the accounting byte-identical —3 suites passed, 8 suites failed, RC 1 — while all threeSS$_NOSUCHDEVassertions failed. Nothing either job asserted on changed. Root cause:init.shfunnels exit 77 (honest skip) and exit 1 (assertion failure) into the sameTOTAL_FAILcounter, and CI pinned only the total. So a per-process fake that reports success — the exact defect classvms-6b8exists to kill — passed the whole gate.init.shnow emits=== SUITE <name> rc=<exit code> ===, carrying the binary's real exit status. The negative control asserts everytest_syssvc_*suite exits exactly 77, which holds only when its device-absent assertions all passed:rc=77→sys$enqw/sys$deqreally returnedSS$_NOSUCHDEVrc=1→ a publicsys$entry point returned something else → silent fallback, REDrc=0→ claims success with no/dev/vmsat all → fake, REDInjected:
test_syssvc_lock rc=1→FAIL: ... A SILENT FALLBACK (vms-6b8's signature defect). Reverted:rc=77, green, identical image SHA6b8ebfa7bb64.G3: strong in both directions, no hand-maintained list
CI derives the expected set from
ls tests/qemu/test_kmod_*.c tests/qemu/test_syssvc_*.c. Proven with a throwawaytest_syssvc_evt.c(deleted before commit;vms-ef1owns the real one) — i.e. against a suite that did not exist when the gate was written, which is exactly the population round 4 left unprotected:12 suites passed, 0 failed, green (round 3's exact pin would have gone red)11 suites passed, 0 failed, zero occurrences of the suite → red (round 4 returnedPASS: all checks satisfied, PASS_COUNT=11here)kstat_to_ss()line deleted) → red, and all 8test_kmod_*suites stayedrc=0, re-confirming the userspace-only reachRegressions hunted beyond the named scope
.dockerignoreaffects every image built from the repo-root context, so I built all three, not just the one the item names:tests/qemu/Dockerfile✅,distro/Dockerfile.bootable✅ (the real runtime target per Rule 9 — never validated against round 4's exclusions), root legacyDockerfile✅. Full in-imagectestsweep run; only consumer ofinit.shoutput isrun_tests.sh, via theFINAL RESULTSline I did not change.Not fixed here — filed separately, do not block this
SS$_NOSUCHDEV = 2680vs the oracle's 2312 (vms-556),lckdef.h's wrongLCK$M_*values (vms-5bd), zero production callers ofvms_kif_register()(vms-9fc), the gate's blindness tosrc/vmsdcl(vms-f42), and only the lock manager being reachable so far.This round adds no VMS constant, status value or wire format, so there is nothing new requiring oracle sign-off;
rc=77is the Automake/CMakeSKIP_RETURN_CODEconvention, not a VMS value.🤖 Generated with Claude Code