Skip to content
Merged
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
c56ccd7
A transport argv identifier is never name-resolved: zero diagnostics,…
Aug 22, 2026
46dd712
Merge remote-tracking branch 'origin/main' into transport-argv-unreso…
Aug 22, 2026
5c9a6c5
Renumber the transport-argv row 28 -> 29: #8907 claimed 28 first
Aug 22, 2026
f6519d2
Merge remote-tracking branch 'origin/main' into transport-argv-unreso…
Aug 22, 2026
3be53dd
Row 29: the argv position produces a node the pipeline treats as reso…
Aug 22, 2026
5dbaf36
Merge remote-tracking branch 'origin/main' into transport-argv-unreso…
Aug 22, 2026
0fa7492
Re-trigger required CI: the prior run's failure was not attributable …
Aug 22, 2026
e6af23e
Merge remote-tracking branch 'origin/main' into transport-argv-unreso…
Aug 22, 2026
53a5921
Row 29 terminal rule: unique-or-refuse, never a token fallback, and i…
Aug 22, 2026
f36ab61
Merge remote-tracking branch 'origin/main' into transport-argv-unreso…
Aug 23, 2026
d6044a4
Merge remote-tracking branch 'origin/main' into transport-argv-unreso…
Aug 23, 2026
8312af0
Where the transport argv resolution must happen: consume the resolved…
Aug 23, 2026
dc31ce5
Merge remote-tracking branch 'origin/main' into transport-argv-unreso…
Aug 23, 2026
7f6e6c4
Merge remote-tracking branch 'origin/main' into transport-argv-unreso…
Aug 23, 2026
e76bdcc
Merge remote-tracking branch 'origin/main' into transport-argv-unreso…
Aug 23, 2026
75c269c
Merge remote-tracking branch 'origin/main' into transport-argv-unreso…
Aug 23, 2026
f6dbce4
Merge main: pick up the ArgvCommand call-site repair (#9031) that unb…
Aug 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletions docs/plans/compiler-guarantee-recovery-gap-analysis.md
Original file line number Diff line number Diff line change
Expand Up @@ -3184,6 +3184,124 @@ enforces end to end.
caused by this change, and neither is repairable in `extdeps` — coercing the 19 sites would be
editing correct source to satisfy a compiler that cannot read it, which is worse than papering over
a modelling error. Restoration trigger for each: the owning seam closing.

32. **An identifier inside a `transport shell { argv: [...] }` position is NEVER NAME-RESOLVED
at compile time — a symbol declared nowhere in the corpus produces ZERO diagnostics.**
Measured 2026-08-22 by `still-seal-394` while dissolving the `env`/`chmod` binary-path
nicknames; recorded here in its CORRECTED, WEAKER form at the measuring session's own request.

DISCRIMINATING CONTROL, same file, same run — this is what makes it a finding rather than an
observation. An undefined variable in an ordinary `fn` body reds `undefined variable`. The
identical undefined name placed in a transport argv produces no diagnostic at all. So the
silence is specific to the argv position, not a property of the run.

WHAT THE POSITION ACTUALLY DOES, read off the emitted AST rather than inferred from the
diagnostic count (three arms, one 0-diagnostic run):

- `argv: [probe_bin, "0700", "{path}"]` → `ExprVar`, `binding_kind` null, no inferred node
- `argv: ["chmod", probe_tail(path: path)]` → `ExprCall`, unresolved
- `argv: [nowhere_declared_symbol, "{path}"]` → `ExprVar`, unresolved, ZERO diagnostics

The position PARSES expressions — consistent with `clever-crab-309`'s independent finding that
a service argv can splice a function returning `List<String>` — and simply never resolves them.

THE CLAIM, STATED AT THE STRENGTH THE EVIDENCE CARRIES. The honest form is that citing a symbol
in a transport argv is **UNGUARDED**, not that it is impossible. It may resolve correctly at
realization. The first version of this finding said the transport layer *cannot* be dissolved
by citation; that was stronger than what was measured, and the measuring session retracted it
unprompted, in the direction that weakened its own result.

WHY THE CORRECTED VERSION IS WORSE, NOT BETTER. "Impossible" would at least fail loudly. What
was actually measured is that a citation written here emits as a LITERAL TOKEN with nothing
refusing — so the failure mode is a SILENTLY WRONG ARGV, not a refusal. That is below floor
(§5), not a rung on the ladder: the deficit's frequency is zero by construction because no
instrument counts it.

RUNG: outside the ladder — silent wrongness, forbidden outright rather than ranked. NOT
`mitigatable`: nothing contains the harm, because nothing observes it.

CEILING: *structurally guaranteed* — name resolution over an argv expression is the same
decidable `Node`-tree read the namespace authority already performs everywhere else. This is a
missing wiring, not an undecidable property.

THE POSITION DOES NOT MERELY SKIP A CHECK — IT PRODUCES A NODE THE PIPELINE TREATS AS
RESOLVED, and this is the half that makes the cheap fix wrong. The undeclared identifier is
admitted as `ExprVar` with `binding_kind` null and NO INFERRED NODE. So there are two failures
stacked: the loud one (nothing refuses an unknown name) and the silent one (what flows onward
is indistinguishable, to every downstream consumer, from a name that resolved). A narrow
"refuse unknown identifiers in transport argv" patch closes the loud half and leaves the silent
half exactly as it is — a null-binding node still travelling the pipeline under the name of a
resolved one. Running the existing expression-resolution and type-inference authority over the
argv expression tree closes both at once, because a node that authority produces carries its
binding by construction. Recorded because the cheap patch is the tempting one and it would
retire this row's visible symptom without retiring the row.

THE FIX MUST NOT COLLAPSE TWO DIFFERENT FACTS. The existing operation-argv note requires a
literal in the executable position because letting an operation INPUT choose the executable is
unsafe. That argument does not reach a resolved module declaration:

- program selected by a resolved declaration → allowed, a compile-time cited authority
- program selected by arbitrary runtime operation input → still refused

So the sites currently unreachable are not sites where citation is unsafe; they are sites where
a missing path refuses the safe case along with the unsafe one. A cut that preserves the
refusal uniformly would entrench the conflation rather than fix it, and would leave
`extdeps.tools.env` `env_path_resolved_program` and `extdeps.tools.chmod` `chmod_binary_path` —
declarations authored precisely to be cited — permanently uncitable at the position that needs
them. The cut must also NOT introduce a transport-specific symbol resolver: that would be an
N-th resolver beside the namespace authority (§2/§3), and it is the reuse of the existing
authority that makes this class's ceiling *structurally guaranteed* rather than merely fixable.

NEXT-RUNG TRIGGER: resolve identifiers in transport argv positions through the ordinary
name-resolution path, and refuse an unresolved one with a typed, located diagnostic. Until
then every `transport shell` argv is an unchecked string channel wearing expression syntax.

WHERE THAT RESOLUTION MUST HAPPEN, and this clause exists because the trigger above is
ambiguous between two designs whose safety differs (ratified 2026-08-23). The transport cut must
CONSUME AN ALREADY-RESOLVED EXACT CALLABLE IDENTITY carried on the node from source resolution
— `transport argv expression → ordinary source resolution → exact lookup result → type
judgment → resolved expression retained on the node → transport lowering consumes it`. It must
NOT reconstruct callable meaning from the emit environment. The reason is measured rather than
stylistic: `source_visible_names` is resolve-time only and emit reads an empty map, so the
callable wall (gunbc#8952) declares its own rung as refusing on the source→resolve path and
SILENT on emit, treating the empty map as `VisibilityUnobservable` — a compatibility fallback,
not an authored-binding verdict. A transport cut that re-ran lookup at emit grain would
therefore inherit that silent rung at the exact position this row exists to make safe, and
would do so while appearing to reuse a repaired authority. Reusing an authority means consuming
its RESULT, not re-executing it at a seam where its inputs have vanished.

BLAST RADIUS, and it is why this blocks a live program rather than sitting in a queue: it puts
roughly 15 of 46 bare-`env` sites out of scope for citation-based dissolution, covering
`extdeps/{shell,python,gunbc,rust/cargo_build,tools/npm}` and `cli_services`. Those sites are
out of scope for want of per-site live execution, NOT out of reach in principle — the
corrected claim is what makes that distinction available.

NOT CLAIMED: that any argv in the corpus is currently wrong. No instrument can answer that
today, which is the row's point. It records a blindness, not a defect count.

THE TERMINAL RULE, RATIFIED 2026-08-22, AND ITS HARD PREREQUISITE. The trigger above says
"resolve through the ordinary path"; that is necessary and, on its own, not safe, because the
ordinary path currently CHOOSES among competing authorities instead of refusing. The corrected
terminal sentence is: **a transport argv expression is lowered only from an exact, uniquely
resolved and typechecked semantic expression — zero candidates refuse, multiple candidates
refuse naming every authority, and no authored token is ever emitted as a fallback.** The
materializer's forbidden arm is stated explicitly because it is the arm that produced this row:
*resolution failed or was ambiguous → emit the authored token as text* is the silent-wrong-
output behaviour measured above, and reaching it through a REPAIRED resolver would be worse
than today's blindness, not better, because the fallback would then wear a resolution step.

So this row does not land alone. It stacks behind the callable-ambiguity repair, carried by
gunbc#8943 and cited BY PR because row numbers have already shifted twice under both rows while
they sat in review — this row was drafted as 29, main independently landed a different 29 and
30, and it is now 32. A row number is a POSITION in a file many lanes append to concurrently,
so citing one is the §3 positional-citation defect with an unusually short half-life: the
reference rots without anyone touching either row. It is: one program, two reviewable cuts, inseparable in
merge order — the resolver wall merges and turns main green FIRST, then this cut retargets onto
main, receives its first real CI run, and merges. Kept as two diffs so that a red is
attributable to exactly one population: ordinary-call ambiguities newly EXPOSED by the wall, or
transport expressions newly RESOLVED by this cut. One monolithic diff would make every red
ambiguous between them, which is a poor shape for a change whose entire subject is ambiguity.

## 12. Proposed sequencing (reconciled with the independent review; for operator sign-off)

**(2026-07-31 restructure.)** The canonical dependency order now lives in the roadmap
Expand Down
Loading