From 46df3d4a31949b42fe024b80a89984fcb90a031a Mon Sep 17 00:00:00 2001 From: Nick Gomez <122398915+nick-inkeep@users.noreply.github.com> Date: Fri, 9 Oct 2026 11:40:46 +0000 Subject: [PATCH] Report truthful push and round results, with records and metrics (#6034) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add the U-records slice spec for truthful push and round results The gate-placement unit that makes push and round results say what happened: D31's outcome classes per step, one result marker per run, round records, NOT-RUN for missing toolchains, the clean-tree precondition, the metrics script, the contract's matrix reach and the flake-admission and doctrine documents. Records the delegated decisions with their reasons and the items that drop out. * Record the decomposition's decisions in the U-records spec Add DR-15: a supervisor hands INKEEP_GATE_RESULT_FILE only to a child supervisor whose result it reads and removes it from every other child, because supervisors pass their environment on and a leaked value would let fixture supervisors inside a test step overwrite the outer result. Also record that plan queries keep their exits and print no marker, that a heuristic kill under a required CI home is reported while an observed kill blocks (the push's exit rule is unchanged), that step records carry the outcome reason as outcomeReason because reasonCode already names the selection reason there, and that none of the prelude edits adds a runner to the hook. * [US-001] R1: Add the shared gate outcome module Add scripts/gate-outcome.mjs, a zero-dependency module that every push and round supervisor will share, and its paired test. - classifyStep applies the step precedence in order: a signal Node observed, the supervisor's own interruption, a bare 130, 137 or 143 as a heuristic kill, 0 as pass, 77 as not-run only when the child's own output carries a column-0 NOT-RUN: line or a not-run marker (otherwise a defect with reason unmarked-not-run), a missing or non-executable binary as not-run with reason spawn-failed, and any other status as a defect that keeps its native status. - runOutcome derives the run class (defect, then not-run, then killed, then pass), its exit (0, 1, 77, 128+N, or the bare status of a heuristic kill), incomplete with the killed step ids when a kill follows the first defect, reported reds that leave the class alone, and the summed child bytes. exitFor gives each class its exit, not-applicable 0 included. - formatMarker and parseMarker write and read the INKEEP_GATE_RESULT_V1 line: one line of compact JSON holding only the result fields, with string values limited to repository-relative tokens so no absolute path or environment value reaches it. The reader takes the last column-0 marker and ignores indented ones. - emitResult writes the result to INKEEP_GATE_RESULT_FILE when it is set and prints no marker; otherwise the marker is the last stderr line. A parent takes the recorded class only when the recorded exit equals the status it observed and agrees with that class. createResultFile and childEnv give a nested supervisor a fresh file and strip an inherited one from every other child. - observeChild streams a child's stdout and stderr to the supervisor's sinks byte for byte, counts the bytes and collects the column-0 NOT-RUN: and marker lines. It waits for the child's close, so output larger than spawnSync's buffer arrives whole, and it keeps draining the child when a sink fails, so a reader that goes away neither hangs nor crashes the supervisor. The marker write tolerates a broken stderr for the same reason. The test runs the real CLI e2e install reporter and reads its nested not-run marker. * [US-002] R6: Exit with a killed test batch's signal status The paired-test runner turned every batch that died by a signal into exit 1, so a push read a killed batch the same way as a failing test. runBatch now returns 128 plus the signal number (143 for SIGTERM, 137 for SIGKILL) and still names the signal on stderr, with the memory-pressure hint for SIGKILL. An unknown signal keeps exit 1. runBatches combines its batch and tree-integrity statuses so that a verdict outranks a kill: the first non-zero status that is not a signal status wins, in the existing order (tree-mutating batch, parallel batch, then the two tree checks), and a signal status is returned only when nothing produced a verdict. A test failure in the other batch, residue in the tree, or an unreadable git status under CI therefore keeps its own exit when a batch was also killed. Without a kill every combination returns what it returned before. The comment sentence saying signal deaths stay 1 on purpose is removed because it is no longer true. Tests: a batch whose real child dies by SIGTERM exits 143; the SIGKILL case now expects 137; per-order subtests for a kill beside a pass and a kill beside a verdict; residue after either batch and an unreadable status under CI still win over a kill. Each new case except one fails against the anchor runner for the behavioural reason; the exception (parallel killed, tree-mutating failed) already returned 1 there and is kept as a preservation check. Node 24's node --test handles SIGTERM and SIGINT itself and exits 1, so in practice only SIGKILL or a crash reaches the runner as a signal death. * [US-003] R7: Report a missing subtree install as a NOT-RUN line The Open Knowledge and discord-linear-sync wrappers now print "NOT-RUN: