Skip to content

Decide whether Filesystem service operations are transport-bound before repairing the two emitter path defects - #8858

Merged
briansrls merged 2 commits into
mainfrom
session/still-badger-464
Aug 22, 2026
Merged

briansrls merged 2 commits into
mainfrom
session/still-badger-464

Conversation

@briansrls

@briansrls briansrls commented Aug 22, 2026 •

Copy link
Copy Markdown
Contributor

The question came first

The brief posed a binary — are Filesystem operations bound to a fixture handler (in which case teaching the emitter a real path would break the one thing it does correctly), or is the emitted code an attempted transport (in which case the two reported defects are real template defects)?

Neither. Established by compiling a three-operation transport file fixture through gunbc compile at all three targets and reading the output, rather than by reading the templates:

target emitted for Write(path, content)
Rust declares -> Result<(bool), _>, returns Ok(content) — a String
Go declares (struct{ bool }, error), returns string, calls os.ReadFile without importing os, and path := redeclares the parameter
Python body at the wrong indent, Tuple unbound

Every operation — Write, Delete, List, WriteOwnerOnly — emits a read, ignores the declared path: template and its own path argument, and Write drops content entirely.

Not a fixture binding, positively: nothing binds base_path to a fixture root (Rust defaults ".", Python requires it from the caller, Go has no constructor at all). And the same operations are consumed as real filesystem effects through the interpreter, which reads the declaration correctly — dispatch_file substitutes the path template and dispatches on verb. A fixture handler that returns the wrong type and cannot be built is not serving a fixture.

The root

Not three renderer defects — semantic information loss at the dispatch boundary. emit_unified_transport_dispatch takes:

render_rest:  fn(String, Node, Int, Map<...>)
render_shell: fn(String, Node, Int, Map<...>)
render_file:  fn(String, Int)          <-- no transport node
render_local: fn(String, Int)

The declaration carries a verb, a path template, input bindings and an output contract. The dispatch supplies a name and an indent depth. No file renderer could read path: or verb: however it was written — one signature defect wearing three costumes. There was a third copy beyond the two in the brief: Go.

This removes no capability

There was never a working file emission to remove. Emitted code that fails to typecheck in Rust, fails to compile in Go for two independent reasons, and binds an undefined name in Python is the absence of the capability, currently spelled as output rather than as a refusal. The class climbs from below-floor fabrication (§5) to a typed, located, counted refusal.

The repair

One refusal, minted before target-specific rendering in emit_artifact, so one authority serves all three targets:

TransportEmissionNotModeled { transport_kind, service, operation, declaring_module, target, missing_realization_fact, span }

A module declaring a file-transport operation emits no file and yields a counted diagnostic. Counted is the point (§5) — a refusal whose frequency is observable is how we learn a real consumer arrived; its absence is why this decayed unnoticed.

The dispatch arm still refuses rather than being deleted: is_local_transport is defined as "not rest, not shell, not file", so removing the arm would route a file transport into render_local and fabricate a direct function call by omission.

The census mirrors the dispatch's rest → shell → file precedence rather than testing is_file_transport alone, so the two agree by construction rather than by coincidence (§3).

Severity: mechanism confirmed, no victim

  • Production reach: zero. Six operations across two modules, no emission site, no witness asserting these strings, zero hand-maintained callers under src/v1/stage0/src/bin/.
  • Mechanism reach: nonzero. The fixture in the new witness executes the path — something plainly reached this code to produce those three outputs.

Next-rung trigger (§4b(2) — waiting on a named event, not stalled)

The class climbs when a real consumer needs a file transport emitted, and the refusal is what reports that day. The repair is then the §3 one: interface shape and transport are two facts, so emitters bind a realization handler rather than each inlining one.

Threading the path alone does not close it, and the trigger says so in its own text — the deleted renderers also dropped content and returned a String against a declared bool, neither of which is a path problem. The interface must carry the verb, the resolved path template, the operation input bindings, the payload/content input, the declared output type, and the failure/effect semantics.

Deliberately unbuilt today (§6, displaced cost): building the full binding for a surface with no consumer is the purity trap.

Evidence, by execution

Discriminator witness (dag/test/claim/transport_emission_not_modeled_witness_test.dag), run in both directions. The RED arm is executed, not reasoned: the same four rows were run against a claim_batch built from a detached origin/main worktree — a compiler with no such wall, whose v1_std_core.rs contains zero occurrences of TransportEmissionNotModeled.

row main (no wall) this branch
three file ops refuse with exactly 3 FAIL PASS
rest + shell refuse with 0 PASS PASS
rest + shell clean of all blocking diagnostics PASS PASS
mixed module refuses only the file operation FAIL PASS

The two discriminators go red on the baseline and green here. Rows 2 and 3 passing on both sides is the correct result, not a weakness: they are positive controls whose job is to stay green, and one that flipped would mean the dispatch had been broken for every transport. Without them the file cannot distinguish "the file arm refuses" from "the dispatch is broken for everything". The mixed row pins the refusal to the operation, so a wall that poisoned siblings goes red there while the file-only row stays green. The outcome was predicted before the run rather than read back from it.

The witness stays enrolled after the climb (§4b(4)) — deleting the evidence with the machinery would recreate specification-without-execution one rung up.

required-regen: drift is exactly the six mirrors of the six edited .dag modules — no more, no less. Mirrors installed from <candidate>/src/ with cp, never hand-edited.

Emitted artifacts read directly, not assumed: TransportEmissionNotModeled present in v1_std_core.rs; emit_file_call / emit_py_file_call / emit_go_file_call at zero across all three emitter mirrors.

Seed projection receipt, re-derived rather than carried forward (as compiler_diagnostic_seed_projection_note requires): cli_run.rs fn census flat at 847 on both main and this branch; numstat 7 added / 0 removed; 0 added lines declaring a fn. The variant is blocking, so is_interpreter_blocking_diagnostic's _ => true is correct and no compile_clean_diagnostic_is_advisory entry is owed.

Also confirmed by execution: the annotation-grain refusal fired on this change's own first draft (five hard diagnostics for a // block inside a declaration body, which DESIGN §4c does not admit) and was fixed by moving it to module grain.

Two notes for reviewers

An instrument hazard worth knowing. gunbc compile --source-dir X is silently ignored whenever any --source-root is passed (main.rs: else if let Some(dir) = source_dir), and adding --source-root src/v1 does not help either — v1 modules land in the name-census-only bucket, indexed but not compiled. A deliberately undefined symbol planted in 05_emit.dag produced zero new diagnostics under both invocations. There is no gunbc compile invocation that typechecks src/v1; the regen path is the instrument. Whole-tree resolve over dag + src/v2 sits at ~26.4k diagnostics on green main — baseline corpus red, never a signal about a change.

A stale figure I did not touch. compiler_diagnostic_seed_projection_note records a cli_run.rs fn census of 747; the command it names now yields 847 on main. That figure certifies a different lane's diff, so I re-derived my own rather than overwriting another lane's receipt — flagging it rather than silently fixing or ignoring it.

🤖 Generated with Claude Code

… dispatch dropped the declaration, three targets copied the result

`transport file` operations emitted code that does not compile in any target.
Measured by compiling a three-operation fixture through rust, python and go:

  Rust   `write` declares -> Result<(bool), _> and returns Ok(content), a String
  Go     declares (struct{ bool }, error), returns string, calls os.ReadFile
         without importing "os", and `path :=` redeclares the parameter
  Python body at the wrong indent, Tuple unbound

Every operation -- Write, Delete, List, WriteOwnerOnly -- emitted a READ,
ignored the declared `path:` template AND its own `path` argument, and Write
dropped `content` entirely. That is DESIGN section 5's fabricated plausible
output: below the ladder, not a low rung on it.

THE ROOT IS SEMANTIC INFORMATION LOSS AT THE DISPATCH BOUNDARY, not three
renderer defects. emit_unified_transport_dispatch handed `render_file` only
(op_name, depth) -- alone among the transport arms in NOT receiving the
transport node -- so no renderer could read `path:` or `verb:` however it was
written. The declaration carries a verb, a path template, input bindings and an
output contract; the dispatch supplied a name and an indent depth. The three
target copies (Rust emit_file_call, Python emit_py_file_call, Go
emit_go_file_call) are downstream of one defect rather than three peers, which
is why all three are deleted rather than the Rust one repaired.

THIS REMOVES NO CAPABILITY. There was never a working file emission to remove;
the absence was spelled as output instead of as a refusal. The class climbs
from below-floor fabrication to a typed, located, counted refusal.

The refusal is minted ONCE, before target-specific rendering, in emit_artifact:
a module declaring a file-transport operation emits NO file and yields
TransportEmissionNotModeled { transport_kind, service, operation,
declaring_module, target, missing_realization_fact, span }. Counted is the
point (section 5): a refusal whose frequency is observable is how we learn a
real consumer arrived. The dispatch arm still refuses rather than being deleted
-- is_local_transport is DEFINED as "not rest, not shell, not file", so
removing the arm would route a file transport into render_local and fabricate a
direct function call by omission.

The census mirrors the dispatch's rest -> shell -> file precedence rather than
testing is_file_transport alone, so the two agree by construction rather than
by coincidence.

SEVERITY: mechanism confirmed, no victim. Production reach is zero -- six
operations across two modules, no emission site, no witness asserting these
strings, and zero hand-maintained callers under src/v1/stage0/src/bin.
Mechanism reach is NONZERO: the fixture in the new witness executes the path.

NEXT-RUNG TRIGGER (section 4b(2) -- waiting on a named event, not stalled): the
class climbs when a real consumer needs a file transport emitted, and the
refusal is what reports that day. The repair is then the section 3 one --
interface shape and transport are two facts, so emitters bind a realization
handler rather than each inlining one. THREADING THE PATH ALONE DOES NOT CLOSE
IT: the deleted renderers also dropped `content` and returned a String against
a declared bool, neither of which is a path problem. Deliberately unbuilt today
(section 6, displaced cost): building the binding for a surface with no
consumer is the purity trap.

EVIDENCE, by execution:
  - discriminator witness, 4/4 PASS: three file ops refuse with exactly 3;
    rest+shell refuse with 0; rest+shell clean of ALL blocking diagnostics;
    a mixed module refuses ONLY the file operation. The last row pins the
    refusal to the operation, so a wall poisoning siblings goes red there while
    the file-only row stays green. It stays enrolled after the climb
    (section 4b(4)): deleting the evidence with the machinery would recreate
    specification-without-execution one rung up.
  - required-regen: drift is exactly the six mirrors of the six edited .dag
    modules, no more; mirrors installed from the candidate, never hand-edited.
  - emitted artifacts read directly: TransportEmissionNotModeled present in
    v1_std_core.rs; emit_file_call / emit_py_file_call / emit_go_file_call at
    zero across all three emitter mirrors.
  - seed projection receipt re-derived, not carried forward: cli_run.rs fn
    census FLAT at 847 on both main and this branch; numstat 7 added / 0
    removed; 0 added lines declaring a fn. The variant is blocking, so
    is_interpreter_blocking_diagnostic's `_ => true` is correct and no
    compile_clean_diagnostic_is_advisory entry is owed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review August 22, 2026 02:24
@gunbai-bot

gunbai-bot Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

CI red is pre-existing on main, not this change — and the floor executed this PR's witness

witnesses failed with 16 red sites. None is caused by this PR, and the four new rows passed on the real floor.

Failure-set parity, at identity grain rather than by count. The 16 failures on this PR are set-identical to main's at the merge base 90986d1946 (gh run 32542017600, itself a failure). Symmetric difference in both directions is empty:

in MINE but not MAIN:  (none)
in MAIN but not MINE:  (none)

All 16 are non-exhaustive pattern match on: OccurrenceId { value: N } in v2.test.claim.body_lowering.statement_let_bind and v2.test.claim.fold_lowering — unrelated to transports or diagnostics. Main's last two heads (90986d1946, 67437fcbe9) are both red; 77ced016ef was the last green.

The floor counters show this PR's witness ran and passed:

main 90986d1946 this PR delta
planned 10425 10429 +4
passed 10102 10106 +4
failed 16 16 0
known_red_held 206 206 0
route_gap_held 101 101 0

+4 planned and +4 passed, with failures flat — exactly the four rows of test.claim.transport_emission_not_modeled_witness, which also appears in the routed module list. Since planned == executed == terminal, every routed site received a verdict, so the four are accounted for in passed rather than skipped.

That is stronger evidence than the local run reported in the description: these rows executed under the required floor on CI, not just under a local claim_batch.

I am not merging (temporary policy: operator merges manually). Flagging that main is red at HEAD as a separate matter, since it is not this PR's to fix and it affects anything else merging today.

— sent from still-badger-464

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