Skip to content

Before trusting an empty sweep, break something the sweep should catch - #9139

Closed
gunbai-bot[bot] wants to merge 7 commits into
mainfrom
session/bright-wren-428
Closed

gunbai-bot[bot] wants to merge 7 commits into
mainfrom
session/bright-wren-428

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Aug 24, 2026 •

Copy link
Copy Markdown
Contributor

Rehome the finding as a qualitative brief, and delete the census the bankruptcy ruling forbids

#9132 merged six minutes after #9139 was filed, deleting docs/probes whole under
the operator ruling "less measuring, more fixing" and its rule: name the
instrument, never transcribe its output. This branch predated that, so the merge
left my two files as the only survivors in a bankrupted directory -- silently
resurrecting it. Both are removed.

The 71-row per-module census TSV is deleted outright rather than rehomed. It is
exactly what the ruling bankrupts: a transcribed table with no instrument
attached, stale the moment the compiler changes, and there is now no directory
in which it should exist.

The 177-line measurement document is replaced by a 60-line brief in docs/briefs,
because what survives a measurement bankruptcy is the qualitative finding, not
the run that produced it. The raw counts are gone; the mutation is described so
anyone can re-derive it. It is filed as a companion to instrument-traps, whose
"a false absence is worse than a false green" it answers with the one cheap
mechanical remedy that class has:

Before trusting an empty sweep, break something the sweep should catch.

The finding itself is unchanged. The incomplete-header premise -- that partial
headers are ALREADY BROKEN, each a live refusal -- is falsified. Every
src/v2/compiler module compiles alone at zero blocking, and deleting
v2.compiler.compile's ENTIRE 33-line import header still produces zero, against
an undefined-name control that refuses immediately. The sweep was measuring
closure membership, not headers; sleek-ant-767 reached the same conclusion the
same day from the construction side. The premise was not satisfied, it was
unmeasurable by the method chosen -- and without the planted red those two are
indistinguishable.

No repair PR is opened. A 47-header change would have had no red before and none
after: unverifiable by construction, DESIGN §4b's decoration, and colliding with
integration/namespace-cut, which deletes the same headers corpus-wide.

Co-Authored-By: Claude Opus 5 noreply@anthropic.com

gunbc-ci-auto-heal and others added 3 commits August 24, 2026 21:29
…ports deleted, still 0 blocking

The brief asked this lane to finish an incomplete-header sweep over the
remaining src/v2/compiler modules, on the premise that a partial import header
is ALREADY BROKEN -- each one a live refusal when compiled alone, as
v2.compiler.program_assembly was in #9083. The premise does not hold, and the
reason is not that the headers are complete.

The universe is 70 .dag files under src/v2/compiler (42 top-level, 27
self_host/, 1 manual/), not the 47 the brief named. All 70 were measured
entry-scoped, each against a gunbc built from the same tree in the same remote
dispatch. 69 report 0 blocking errors. The one exception,
manual/retry_eagain_bash.dag with 1, is a file-transport emission gap in
extdeps.cloud.gcp.gcp -- a different defect with a different owner, named and
excluded rather than folded in.

So the sweep returns empty. The finding is that the empty carries no
information, and one command separates the two readings of it. 00_compile.dag
carries a 33-line header; four arms on one binary, one entry, one dispatch:

  A  baseline                    0 blocking, 472 advisory
  B  ALL imports stripped        0 blocking, 510 advisory
  C  undefined name planted      2 blocking, 472 advisory
  D  restored                    0 blocking, 472 advisory

C is the positive control and it refuses, so the instrument is not inert. B is
the finding: a module whose import header has been deleted in its entirety
compiles alone with zero blocking errors. The 33 import statements contribute
nothing to whether it resolves; their whole measurable effect is 38 more
non-blocking advisories. This is the pool-fallback mechanism the 2026-08-24
probe describes, seen from the deletion side, and it independently reproduces
sleek-ant-767's construction-side result that closure membership rather than the
import statement admits a bare call.

No 47-header repair PR is opened, for two reasons either of which suffices. It
would be unverifiable by construction -- no red before, no red after -- which is
the DESIGN §4b decoration failure: permanently green, carrying no information,
worse than absent because it would be cited afterwards as coverage.  And
integration/namespace-cut deletes headers corpus-wide, so it is throwaway work
by construction.

Three instrument defects are recorded because each produced a clean-looking zero
before any measurement had been taken: a missing required --output-dir that made
all 70 invocations a clap error, a --target dag choice that reported unrelated
file-transport emission gaps as blocking, and a head -200 filter that truncated
20 of 70 results ahead of their summary line. The transferable rule is stated in
the probe: before trusting an empty sweep, break something the sweep should
catch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…bankruptcy ruling forbids

#9132 merged six minutes after #9139 was filed, deleting docs/probes whole under
the operator ruling "less measuring, more fixing" and its rule: name the
instrument, never transcribe its output. This branch predated that, so the merge
left my two files as the only survivors in a bankrupted directory -- silently
resurrecting it. Both are removed.

The 71-row per-module census TSV is deleted outright rather than rehomed. It is
exactly what the ruling bankrupts: a transcribed table with no instrument
attached, stale the moment the compiler changes, and there is now no directory
in which it should exist.

The 177-line measurement document is replaced by a 60-line brief in docs/briefs,
because what survives a measurement bankruptcy is the qualitative finding, not
the run that produced it. The raw counts are gone; the mutation is described so
anyone can re-derive it. It is filed as a companion to instrument-traps, whose
"a false absence is worse than a false green" it answers with the one cheap
mechanical remedy that class has:

  Before trusting an empty sweep, break something the sweep should catch.

The finding itself is unchanged. The incomplete-header premise -- that partial
headers are ALREADY BROKEN, each a live refusal -- is falsified. Every
src/v2/compiler module compiles alone at zero blocking, and deleting
v2.compiler.compile's ENTIRE 33-line import header still produces zero, against
an undefined-name control that refuses immediately. The sweep was measuring
closure membership, not headers; sleek-ant-767 reached the same conclusion the
same day from the construction side. The premise was not satisfied, it was
unmeasurable by the method chosen -- and without the planted red those two are
indistinguishable.

No repair PR is opened. A 47-header change would have had no red before and none
after: unverifiable by construction, DESIGN §4b's decoration, and colliding with
integration/namespace-cut, which deletes the same headers corpus-wide.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gunbai-bot gunbai-bot Bot changed the title The header sweep returns empty, and the empty is uninformative: 33 imports deleted, still 0 blocking Before trusting an empty sweep, break something the sweep should catch Aug 24, 2026
gunbc-ci-auto-heal and others added 2 commits August 24, 2026 22:46
…ded by presence not contents

The first version of this brief generalised from one planted red and got the
conclusion wrong. Dropping ONE used import from v2.compiler.compile changed
nothing, so it concluded headers contribute nothing to resolution and the
instrument was blind to the question. Both halves were wrong.

Dropping imports one at a time, three of nine refuse by name and location:
emit, eval (two names) and program_assembly all produce "not found in scope".
The header is load-bearing; parse was simply an arm whose provider stayed
reachable.

Pushed further the arms resolve into one predicate, measured on ONE binary with
each state applied and reverted: complete header green; header missing one entry
REFUSES; header absent entirely green; and header carrying a SINGLE line naming
a symbol the file never uses produces 71 blocking errors -- unresolved types as
well as unresolved calls. Adding one inert line to a green file breaks it;
deleting that line, leaving no header, restores it.

So the regime is switched by the PRESENCE of any import line, not by its
contents. No header means whole-pool resolution and you get everything; any
header means declared-closure resolution and you get exactly what you named.
The U the dispatching brief originally named follows with no further hypothesis
-- green, blocking, green -- and it is one mechanism rather than three.

The empty sweep was therefore not blindness. The tree is clean because #9083
repaired the last broken instance, and the instrument sees the class fine.

The transferable rule survives and is better evidenced, because it caught its
own author: what corrected the wrong conclusion was running more planted reds
instead of shipping the tidy one. The brief now carries that history rather than
tidying it away, and adds the sharper lesson underneath it -- a planted red that
fires correctly still licenses only one conclusion, and where a mechanism has
several regimes, one arm samples one regime.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…eded, not that it was correct

The regime table's third row is where the wrong-provider risk lives, and the
table as written invites reading its green as clearance. Where a name has more
than one declarer in the pool, binding the wrong one is green at every aggregate
grain -- a blocking count cannot distinguish found-the-right-name from found-a-
name.

Records the sound way to settle it (a site whose wrong bind cannot typecheck --
match on a sibling arm the other candidate lacks, turning an identity question
into a colour question) and the unsound way, which is the one worth warning
about because it looks rigorous: inferring provider identity from emitted
artifacts. Emission is measured to re-decide some calls from their leaf spelling,
so two different resolved providers with the same leaf name emit the same bytes.
A difference in emitted bytes proves divergence; agreement proves nothing, and
the false negative points toward 'safe'.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

The failing witnesses check on this PR is inherited from main, not caused by this branch.

This PR's entire diff is +103 lines of prose in one file under docs/briefs/. It touches no .dag, no Rust, and nothing under dag/.

The failure is identical on main — same subject hash, same four errors, same file:

required-ci: floor refused: subject=f292d7dafd1458df modules_resolved=3889 modules_excluded=4
dag/gunbc/systemctl_show_read.dag:80:5: error: undefined variable 'systemctl_show_property_path'
dag/gunbc/systemctl_show_read.dag:81:5: error: undefined variable 'systemctl_show_property_service'
dag/gunbc/systemctl_show_read.dag:97:7: error: function 'systemctl_show_property_read_ssh_argv' not found in scope
dag/gunbc/systemctl_show_read.dag:110:7: error: function 'systemd_property_capture_from_outcome' not found in scope

main run 32784719807 @ 05c627fd6 fails the same way; this PR's run 32786322882 @ 96414f2 is the same failure arriving through the merge-with-main that PR runs test.

Cause, for anyone else who lands here: #9057 deleted the four helpers while converting the property reads, and #9062 added systemctl_show_load_state_* callers that still reference them. Neither is wrong alone; the collision strands the load-state siblings.

Already owned — not being fixed here: #9147 (diagnosis) and #9146 (repair) are both open on it. This PR needs no change and will go green once one of those lands.

— sent from bright-wren-428

gunbc-ci-auto-heal and others added 2 commits August 24, 2026 23:42
…s silence was nearly filed as a compiler defect

Two additions, both from the same session as the specimen and both stronger than
the header sweep that prompted the brief.

THE RULE. Six times in one session an instrument returned empty and the empty
was not a measurement: a missing required flag, a wrong target, a truncating
filter, a fixture the runner could not see, a filter matching neither diagnostic
nor refusal, and a malformed fixture whose refusal the same filter dropped. Every
one failed silently toward good news. The pattern under them is not carelessness:

  An instrument that cannot represent the answer returns empty, and empty is
  indistinguishable from "nothing was there."

That is a property of building instruments faster than they can be validated,
which is the normal condition of investigative work -- so the remedy is
structural (plant the red), not attentional. Four of the six were output filters,
which earns its own corollary: narrowing the channel to the shape you expect
makes every unexpected shape -- a refusal, an argument error, a crash -- arrive
as silence.

THE NEAR-MISS, which is why the sixth is written out rather than counted. A
malformed fixture blanked, and the blankness was read as a GRAMMAR AMBIGUITY: a
nullary variant in scrutinee position silently reinterpreted as a record literal,
two readings of one text with no refusal on either side. That would be a real
defect and it was one edit away from being filed as one. Re-run with the filter
removed, the compiler refuses -- typed, located, fail-closed:

  module index refused: 1 unparseable .dag source(s)
    <probe>.dag:110-112: expected expression, found FatArrow

There is no ambiguity and no silent reinterpretation. The substrate did exactly
what DESIGN §5 requires; the only defect was the filter between the refusal and
the reader. A blank output is consistent with "the compiler said nothing wrong"
and with "the compiler refused and I could not hear it", and those have opposite
owners. Attributing an instrument's silence to its subject is how a clean
mechanism acquires a bug report it did not earn.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
'Narrow your filter and unexpected shapes arrive as silence' names the symptom.
The mechanism is that a grep for `^error|blocking` is not a VIEW of the output,
it is a HYPOTHESIS ABOUT the output -- and it discards exactly the cases where
the hypothesis is wrong. That is actionable in a way 'check your instruments' is
not, because it says which artifact to distrust.

Generalises past greps to any flag suppressing a channel a conclusion is about
to be drawn from: a quiet push that hides a rejection leaves the author claiming
content that was never delivered. Framing credited to smart-ram-730, who arrived
at it from a -q on a push while I arrived at it from four blanked sweeps.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@briansrls briansrls closed this Aug 25, 2026
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