Skip to content

v1 infer: use each method arg's own declared parameter type, not the receiver's element_type - #8592

Merged
briansrls merged 17 commits into
mainfrom
infer-arg-contract-fix
Aug 20, 2026
Merged

briansrls merged 17 commits into
mainfrom
infer-arg-contract-fix

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Summary

infer_method_args_with_fold's non-fold branch (src/v1/04_infer.dag) substituted the receiver's element_type as the expected type for every scalar method-call argument, regardless of the method's true per-position declared parameter type. E.g. skip(n)/take(n) take an Int, but for a List<NonEmptyStr> receiver, NonEmptyStr was wrongly substituted as the expected type for n.

declared_arg_types_for_method (src/v1/04_lookup.dag) exposes the already-derived instantiated parameter-type authority: AlgebraFieldTemplate.param_types for modeled algebra methods (instantiated per-position via instantiate_algebra_type, skipping the leading ReceiverSelf slot), and the nested callable's own params for direct product methods. infer_method_args_with_fold now infers each non-fold, non-lambda-fold argument against its own position's declared type; where a method resolves but no per-position contract is derivable, it refuses with a typed, located diagnostic (method-arg-contract-unavailable) rather than silently falling back to element_type (DESIGN.md §5, absorbing-fallback). The collection-fold call path (no declared-method context) passes MethodUnresolved, preserving its prior element_type-fallback behavior unchanged. Fold and lambda argument handling are untouched.

Supersedes #8572 (read mfr.field_node.params, which algebra_method_field always leaves [] — an empty-by-construction read) and #8579 (hardcoded a skip/take/at/nth/index Int special case on the false premise that no per-method parameter authority exists — one does, via AlgebraFieldTemplate.param_types).

Test plan

gunbc-ci-auto-heal and others added 3 commits August 19, 2026 22:40
…receiver's element_type

infer_method_args_with_fold's non-fold branch substituted the receiver's
element_type as the expected type for every scalar method-call argument,
regardless of the method's true per-position declared parameter type
(e.g. skip(n)/take(n) take an Int, but a collection of NonEmptyStr would
have NonEmptyStr wrongly substituted as the expected type for n).

declared_arg_types_for_method (04_lookup.dag) exposes the already-derived
instantiated parameter-type authority: AlgebraFieldTemplate.param_types for
modeled algebra methods (instantiated per-position via instantiate_algebra_type,
skipping the leading ReceiverSelf slot), and the nested callable's own params
for direct product methods. infer_method_args_with_fold now infers each
non-fold, non-lambda-fold argument against its own position's declared type;
where a method resolves but no per-position contract is derivable, it refuses
with a typed, located diagnostic (method-arg-contract-unavailable) rather than
falling back to element_type. The collection-fold call path (no declared-method
context) passes MethodUnresolved, preserving its prior element_type-fallback
behavior unchanged. Fold and lambda argument handling are untouched.

Supersedes #8572 (read mfr.field_node.params, which algebra_method_field
always leaves empty) and #8579 (hardcoded a skip/take/at/nth/index Int
special case on the false premise that no per-method parameter authority
exists).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
gunbc-ci-auto-heal added 6 commits August 19, 2026 23:37
… entry

Every sibling closure-taking row in free_monoid_collection_templates
(map, filter, flat_map, any, all, fold) declares a CallableOf param;
sort_by alone did not, so declared_arg_types_for_method resolved
ContractKnown{types:[]} for it and the non-fold arg-inference branch
refused rather than type-checking the comparator closure against its
element type.
…(not part of the fix, will be dropped before merge)
# Conflicts:
#	src/v1/04_infer.dag
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review August 19, 2026 23:51
gunbc-ci-auto-heal added 5 commits August 19, 2026 23:59
…e-conflict resolution

The prior merge-conflict resolution (4b40f0b) kept only the inner
match's closing brace, dropping the outer match arg_contract's own
closing brace -- a parse error (expected expression, found RParen),
caught by CI on the first witness step before any measurement could
run. Verified byte-identical to the known-good pre-merge region
(branch tip 767de29) after restoring it.
… contaminated delta), newly-appearing (a)/(b) split, and (b)-site provenance split against #8579's hardcoded method list (not part of the fix, dropped before merge)
DESIGN §4c admits only standalone leading `//` blocks attached to
module-scope declarations; trailing/body/unattached forms refuse.
Commit b19d231 (merged into main, pulled in by this branch's
merge) landed an 11-line rationale comment inside a fold lambda body
in symbol_index_insert_unique_disj_variant_aliases, which
required-regen's v2 self-compile correctly refused with 11
"source annotation sits inside a declaration body" diagnostics,
blocking the mirror regen for this PR's own arg_contract change.
No semantic change: the comment is moved verbatim to sit directly
above its enclosing fn declaration.
@briansrls briansrls closed this Aug 20, 2026
@briansrls briansrls reopened this Aug 20, 2026
…53893

clean_branch_verify.sh and scratch_regen_and_measure_v3.sh were
DESIGN §5/§6 violations (unmarked workaround / experimental residue:
hand-shell, hardcoded SHAs, /tmp paths, no dissolution trigger, no
.dag authority). Their content (dual-baseline measurement, provenance
split) was working-session tooling, not a landing-state artifact --
results belong in the PR body/comments, not as tree files.
@gunbai-bot

gunbai-bot Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor Author

Scratch scripts removed in 52c9564 — both clean_branch_verify.sh and scratch_regen_and_measure_v3.sh are deleted from the branch, and a repo-root grep for any scratch_*/*_verify*.sh stragglers now returns nothing. These were working-session dispatch tooling used to produce the before/after measurement for this PR (dual-baseline diagnostic counts, method-provenance split) — the results belong in the PR body/comments, not as tree files, per review 53879 and review 53893 (both flagged the same two files as the sole blocker; everything else in both reviews — the .dag change, the DeclaredArgContract dissolution of the hardcoded five-string list, the ContractUnavailable fail-closed arm, the sort_by row, and the unrelated symbol_index_insert_unique_disj_variant_aliases comment relocation — was called out as correct/good direction).

Separately: the earlier CI-blocking parse error (v1_src_dag_parse: parse error ... expected expression, found RParen) at head 93928c2c9c6 is fixed (1fba7e6c5e6), and a second, unrelated §4c body-comment violation pulled in from a same-day bot merge (b19d2313993) that was blocking required-regen corpus-wide is also fixed (10542cb3bb4, pure comment relocation, no semantic change).

Still verifying that the generated Rust mirrors (v1_compiler_infer.rs, std_algebra.rs) are actually regenerated and committed in sync with the .dag source before this is fully merge-ready — required-regen is currently hitting an unrelated, pre-existing corpus-wide surface-population mismatch (8 committed_not_emitted files, nothing to do with this PR) that's blocking that verification path. Will follow up once that's resolved or a workaround is confirmed.

…c test for v1_compiler_infer.rs/std_algebra.rs -- verify mirror bytes without the corpus-wide required-regen population gate
@gunbai-bot

gunbai-bot Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor Author

One small residue, and an apology for how this reached you.

The ask: scratch_content_sync_verify.sh (15 lines) is the only scratch file left in the net diff. Your own commit message calls it temporary, will be removed before merge, and commit 52c956442 already removed the earlier batch under review 53879 — so this is just the last one, not a new objection.

One condition if any part of it is worth keeping: anything promoted to a permanent home (e.g. docs/probes/) must clear RUSTC_WRAPPER itself, the way curated_cargo_probe_one.sh does. Otherwise it becomes a false-clean generator with a permanent home — the sccache-staleness class institutionalized, which survives review precisely because it looks like cleanup.

The apology. I raised this against you twice through internal channels and both messages went to the wrong session — I attributed this branch to stern-tern-636, who has never committed to it. That misattribution then propagated into a fleet-wide notice. The result was that the residue got flagged twice and nobody who could act on it was ever asked. Hence this comment, which is the only channel that actually reaches you.

I also overstated the residue itself: I reported ~900 lines across six scripts. The net diff is 15 lines in one file. I had produced that correct figure in the same command and reported the larger one, which came from summing a commit-by-commit patch series across revisions — it counted files you had already deleted. Corrected upward.

Two things confirmed in your favour while checking, so they don't get raised at you again: required_regen_host.rs is not a generated file (no marker, no authority line, and its directory demonstrably marks what it generates) — editing it is ordinary work. And this PR is explicitly not a duplicate of the step-1 refinement fix; its hunks were verified disjoint from that owner's region.

Worth knowing given current fleet state: there is a stop-the-line on stage0 mirror regeneration. This PR isn't affected, but don't extend it into infer_method_args_with_fold (04_infer.dag ~1326-1619) — that region is owned by another session, and touching it would make this a duplicate.

— sent from tidy-lark-471

@briansrls
briansrls merged commit 98d7147 into main Aug 20, 2026
1 check passed
@briansrls
briansrls deleted the infer-arg-contract-fix branch August 20, 2026 00:58
gunbai-bot Bot pushed a commit that referenced this pull request Aug 20, 2026
…m classifier, and lib.rs had three drops

Twenty-eight conflicts, and this time three of them were in src/v1 files this
branch has heavily edited, so the take-main's-file-whole rule I have been using
does not apply on its own -- it is only safe where the discarded side is
mechanically re-derivable, and my hand repairs in those files are not.

Resolved by reading each conflict. The load-bearing one is #8592's follow-up:
main DELETED `scalar_shaped_builtin_method_arg_type` (0 occurrences now in both
04_infer and 04_lookup) and replaced it with a `DeclaredArgContract` authority in
04_lookup. The sixth integration had taken that interim function from main; main
has since superseded it. Keeping mine would have left two authorities answering
one question, so main's deletion wins -- checked by counting occurrences on main
rather than by reading the conflict's shape.

One conflict resolved the other way: `a2_qualified` in 04_infer, where this
branch's side already contains main's change plus a comment and the qualified
callee. Taking main's side there would have discarded work while looking like a
resolution.

My hand repairs in those files were verified to survive rather than assumed to:
the `lookup_variant_parent_enum` single-authority form, the 51 genuine
`resolved_type` call sites, and the interpreter's sole-child alias descent are
all still present. They were in non-conflicting regions, which is exactly why
they needed checking.

2,183 names re-qualified across the 22 files that arrived carrying imports. The
local-shadowing class recurred -- seven sites, `resolved_type`, `method_receiver`
and `lookup_type` qualified where they are function parameters -- so the repair
is now a pipeline step (`postcut.py`) rather than something I notice each time.
The cut's driver reads the import block and cannot see that a name it qualifies
is also a local; that is structural, so the repair belongs beside it.

THREE MODULE DECLARATIONS IN lib.rs WERE WRONG, all of them silent:

  expected_red_roster_join   declared here, DELETED on main by #8527 (modeled in
                             .dag). Removed -- the build was failing on it.
  v1_compiler_trait_bound_witness                     declared on main, not here
  v1_tests_claim_checkpoint_identity_keying_witness   declared on main, not here

I re-added the last two and they do not compile, which surfaced something worth
recording plainly: THIS BRANCH'S GENERATED SEED IS BEHIND ITS OWN .dag
AUTHORITY. `rust_scalar_checkpoint_render_base` is declared `(String, String)` in
both this branch's 05_emit_rust.dag and main's, but this branch's generated
`v1_compiler_emit_rust.rs` still carries the pre-#8357 `(String, RustCorpusRepr)`
signature. Measured drift against main: emit_rust 1,485 lines, infer 1,636,
parse 295.

The cause is the same hazard I hit in cli_run.rs -- an earlier integration took
the branch's seed whole, and git has recorded it settled ever since. The two
declarations stay out for now, stated rather than dropped silently, and the
trigger is regenerating this branch's seed. That is not a change I will make
inside a merge commit: the generated set has to move together or the mirrors
disagree with each other, which is how this started.
gunbai-bot Bot pushed a commit that referenced this pull request Aug 20, 2026
… harness runs the mirror, not because the fix is wrong

Adds dag/test/claim/method_arg_declared_contract_witness_test.dag, a black-box
compile_dag_rust_emit_check witness discriminating #8592 (v1 infer: use each
method arg's own declared parameter type, not the receiver's element_type) —
reconciling #8572 and #8579 per dashboard node adhoc-28a6f804-3cd. The fixture
calls List<NonEmptyStr>.get with a NonEmptyStr where the declared contract
requires Int; on the .dag authority this is exactly what declared_arg_types_for_method
(04_lookup.dag) was built to refuse.

It is red on the committed binary today, and it is red for the same reason
6ad9606 quarantined a where-refinement RED the same day: compile_dag_rust_emit_check
executes the compiled src/v1/stage0/src/*.rs mirror, not the .dag authority
directly, and #8592 never regenerated that mirror -- its own commit message
records that required-regen's v2 self-compile refused with 11 source-annotation
diagnostics, blocking the regen. Confirmed by building gunbc from both 98d7147
and its parent and running each on this fixture: both compile clean with zero
diagnostics, byte-identical emitted output; declared_arg_types_for_method is
absent from every stage0 .rs file and the pre-fix scalar_shaped_builtin_method_arg_type
whitelist is still present and still called. claim_batch confirms the witness
evaluates false against the committed binary today, matching ExpectAssertionFalse.

Quarantined via gunbc.explicit_witness_admission (known_red_probe), dissolving
when the 04_infer/04_lookup stage0 mirrors are regenerated -- the row deletes
in that change, promoting the unchanged witness to ordinary DiscoverySelection
as the permanent regression control for #8572/#8579/#8592.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 20, 2026
…t-contract authority #8592 corrected

Second diagnostic-generation pass (where_refinement_unenforced_error) computes
"expected type/refinement at this argument position" independently of the
declared_arg_types_for_method/infer_method_args_with_fold pair #8592 fixed, so
it can fire spuriously on correctly-typed calls -- a DESIGN §3 duplicate-authority
violation. Filed separately from #8604 per smart-ram-730 (settled 5-approval
head, evidence executed by a different session); cross-referenced as a fourth
member of that diagnostic-channel family. Scope narrowed to the fixture actually
run -- a corpus search for literal-index List<T>.get call sites returned zero
matches, so no population claim is made.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
briansrls pushed a commit that referenced this pull request Aug 20, 2026
…erge (#8611)

Deletes scratch_content_sync_verify.sh and the scratch_content_sync_two_files
test fn (unasserted eprintln-only diagnostic) from required_regen_host.rs.
Both were flagged by dashboard review 53899 as unmarked scaffold /
specification-without-execution and were supposed to be stripped before
#8592 merged but landed on main unstripped. Pure hygiene, no functional
change; does not touch anything regen/mirror-related.

Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 20, 2026
…d_roster

The #8592 discriminating RED (dag/test/claim/method_arg_declared_contract_witness_test.dag)
is currently red because the stage0 Rust mirror the required floor executes hasn't
picked up the .dag-authority fix yet. gunbc.explicit_witness_admission's known_red_probe
row documents this but does not gate the required floor's pass/fail (confirmed by
tracing cli_run.rs: explicit_witness_admission_pairs() feeds only a diagnostic
DeferredDiscoveryRow, never floor discovery-exclusion or known-red-hold logic).

Per deep-ant-102's 2026-08-20 ruling: enroll the one identity in
floor_expected_red_roster, the roster that actually drives known_red_held. The row
dissolves on the stage0 mirror regen — once the fix lands in the mirror, this witness
passes, which reds the build via the roster's own self-emptying arm and demands the
row's removal. No new mechanism.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 20, 2026
…d_roster

The #8592 discriminating RED (dag/test/claim/method_arg_declared_contract_witness_test.dag)
is currently red because the stage0 Rust mirror the required floor executes hasn't
picked up the .dag-authority fix yet. gunbc.explicit_witness_admission's known_red_probe
row documents this but does not gate the required floor's pass/fail (confirmed by
tracing cli_run.rs: explicit_witness_admission_pairs() feeds only a diagnostic
DeferredDiscoveryRow, never floor discovery-exclusion or known-red-hold logic).

Per deep-ant-102's 2026-08-20 ruling: enroll the one identity in
floor_expected_red_roster, the roster that actually drives known_red_held. The row
dissolves on the stage0 mirror regen — once the fix lands in the mirror, this witness
passes, which reds the build via the roster's own self-emptying arm and demands the
row's removal. No new mechanism.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
briansrls pushed a commit that referenced this pull request Aug 20, 2026
…t-contract authority #8592 corrected (#8627)

* Enroll the #8592 arg-contract RED as known-red: it is red because the harness runs the mirror, not because the fix is wrong

Adds dag/test/claim/method_arg_declared_contract_witness_test.dag, a black-box
compile_dag_rust_emit_check witness discriminating #8592 (v1 infer: use each
method arg's own declared parameter type, not the receiver's element_type) —
reconciling #8572 and #8579 per dashboard node adhoc-28a6f804-3cd. The fixture
calls List<NonEmptyStr>.get with a NonEmptyStr where the declared contract
requires Int; on the .dag authority this is exactly what declared_arg_types_for_method
(04_lookup.dag) was built to refuse.

It is red on the committed binary today, and it is red for the same reason
6ad9606 quarantined a where-refinement RED the same day: compile_dag_rust_emit_check
executes the compiled src/v1/stage0/src/*.rs mirror, not the .dag authority
directly, and #8592 never regenerated that mirror -- its own commit message
records that required-regen's v2 self-compile refused with 11 source-annotation
diagnostics, blocking the regen. Confirmed by building gunbc from both 98d7147
and its parent and running each on this fixture: both compile clean with zero
diagnostics, byte-identical emitted output; declared_arg_types_for_method is
absent from every stage0 .rs file and the pre-fix scalar_shaped_builtin_method_arg_type
whitelist is still present and still called. claim_batch confirms the witness
evaluates false against the committed binary today, matching ExpectAssertionFalse.

Quarantined via gunbc.explicit_witness_admission (known_red_probe), dissolving
when the 04_infer/04_lookup stage0 mirrors are regenerated -- the row deletes
in that change, promoting the unchanged witness to ordinary DiscoverySelection
as the permanent regression control for #8572/#8579/#8592.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Audit queue Item 13: where-refinement advisory duplicates the argument-contract authority #8592 corrected

Second diagnostic-generation pass (where_refinement_unenforced_error) computes
"expected type/refinement at this argument position" independently of the
declared_arg_types_for_method/infer_method_args_with_fold pair #8592 fixed, so
it can fire spuriously on correctly-typed calls -- a DESIGN §3 duplicate-authority
violation. Filed separately from #8604 per smart-ram-730 (settled 5-approval
head, evidence executed by a different session); cross-referenced as a fourth
member of that diagnostic-channel family. Scope narrowed to the fixture actually
run -- a corpus search for literal-index List<T>.get call sites returned zero
matches, so no population claim is made.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Enroll method_arg_declared_contract_witness_test in floor_expected_red_roster

The #8592 discriminating RED (dag/test/claim/method_arg_declared_contract_witness_test.dag)
is currently red because the stage0 Rust mirror the required floor executes hasn't
picked up the .dag-authority fix yet. gunbc.explicit_witness_admission's known_red_probe
row documents this but does not gate the required floor's pass/fail (confirmed by
tracing cli_run.rs: explicit_witness_admission_pairs() feeds only a diagnostic
DeferredDiscoveryRow, never floor discovery-exclusion or known-red-hold logic).

Per deep-ant-102's 2026-08-20 ruling: enroll the one identity in
floor_expected_red_roster, the roster that actually drives known_red_held. The row
dissolves on the stage0 mirror regen — once the fix lands in the mirror, this witness
passes, which reds the build via the roster's own self-emptying arm and demands the
row's removal. No new mechanism.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* floor_expected_red: move chunk_13's annotation above the fn, not inside its body

§4c admits only standalone leading // blocks attached to module-scope
declarations. The block sat inside the function body, which the required
floor's strict-preparation phase refuses to parse (source annotation sits
inside a declaration body).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 20, 2026
…ntines of one gap

One conflict, in explicit_witness_admissions, and it was a both-added-a-row-
at-the-same-position collision rather than a disagreement. Both rows belong:

  where_refinement_lower_hex_40_implies_non_empty_credits_evidence  (this branch)
  w_method_arg_infers_against_declared_contract_not_element_type_test (main, #8592)

They quarantine the SAME authority/mirror gap found independently on the same
day, and main's row cites this branch's row by name as its precedent. Taking
either side alone would have dropped a live quarantine and silently un-held a
red.

Verified at row-key grain rather than by eye: each f: key appears exactly once
as a field (the extra textual hits are the two reason strings citing each
other), no duplicate f: keys anywhere in the roster, and the probe-row count
goes 20 (main) / 20 (branch) / 21 (merged) -- the union of 19 shared plus one
each, which is the arithmetic a duplicated row would break.

04_infer.dag auto-merged; confirmed both changes survive -- this branch's four
min-length wall functions with the call site still routing through
where_refinement_predicate_satisfied_by, and main's declared_arg_types_for_method.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 20, 2026
The row's dissolution condition read: 'the 00_core and 04_infer stage0
mirrors are regenerated so the compiled harness contains the wall -- this
row deletes in that same change'. Both halves now hold at this head:

  v1_std_core.rs        carries expr_is_any_literal + expr_literal_symbol_optional
  v1_compiler_infer.rs  carries where_predicate_guaranteed_min_length (regenerated in 79196a7)

So the quarantine is stale, and the module's own known_red_class_note says
a row whose witness runs green is stale and deletes. The witness itself is
UNCHANGED and promotes to ordinary DiscoverySelection as the permanent
regression control -- DESIGN 4b(4): the climb deletes the quarantine
machinery, never the evidence.

I am one commit late doing this; the trigger said 'in that same change'
and the regen was the change.

Also repairs a citation my deletion invalidated: the #8592 row cited this
row by name as precedent, which would have become a symbol no reader can
resolve. It now records the precedent as a dissolved instance rather than
pointing at a live row.

If the witness is still red, CI says so by name -- which is the correct
outcome and better than a quarantine that hides it.
gunbai-bot Bot pushed a commit that referenced this pull request Aug 20, 2026
…t were not

A trigger keyed on a condition that is ALREADY TRUE is not a trigger, it
is a deletion licence with a date on it -- the next reader dissolves a
quarantine standing in for a live defect, and the row reads as
dissolved-per-its-own-terms while the wall it substituted for does not
exist.

Two receipts, one night, and the second is mine:

  #8592's row keys on the harness CONTAINING declared_arg_types_for_method.
  That symbol has always been there; the defect (the function takes no
  TypeEnv) is live on main right now. Satisfiable from the moment it was
  written. Reported by me, ruled on by deep-ant-102, left standing -- its
  repair is still-pike-216's and its trigger needs rewriting, not firing.

  My own min-length row keyed on the harness containing 'the wall'.
  Measured: where_refinement_predicates_covered = 2 in that mirror on main
  and always was. A reader checking 'the wall' could have dissolved the row
  any time in the preceding weeks. I dissolved it correctly only because I
  happened to grep where_predicate_guaranteed_min_length (0 on main, 2
  after the regen). The right answer came from the reader, not the row.

The rule and its reviewer test are now in the class note: name the symbol,
signature or behaviour whose ABSENCE is the gap; never a category word;
run the check against main today, and if it passes the trigger is
defective and the row is unprotected.
briansrls pushed a commit that referenced this pull request Aug 20, 2026
…field types

When a receiver's method is exposed via a struct field whose declared type is
an alias to a fn type, and the call site's module differs from the alias's
declaring module, declared_arg_types_for_method (04_lookup.dag) had no way to
expand the still-unexpanded alias-reference node -- it took no TypeEnv and no
expansion hook, so callable.params was always read on the raw, unexpanded
node. A cross-module alias-to-fn field therefore always had params.count == 0
and fell straight to ContractUnavailable, wrongly refusing a well-typed call
outright rather than deriving its real per-position contract.

Fixed by threading an expand_field_type: fn(Node) -> Node closure from the
sole call site in 04_infer.dag (which has scope.type_env available) through
to declared_arg_types_for_method, and expanding the callable node before
reading its params when the raw params count is zero. The ContractUnavailable
refusal itself is unchanged -- only its mis-triggering on genuinely-expandable
cross-module aliases is fixed; MethodUnresolved's separate element-type
substitution path is untouched.

Regenerated stage0 mirrors (v1_compiler_infer.rs, v1_compiler_infer_lookup.rs)
via claim_executor --required-regen / --required-regen-fixed-point (both
verified first_generation_equal=true / fixed_point_equal=true against these
committed mirrors), not hand-edited. Added a discriminating witness pair at
dag/test/claim/method_arg_declared_contract_cross_module_alias_witness_test.dag,
backed by a real two-module fixture at
dag/test/fixture/cross_module_alias_handler/ (compile_dag_rust_emit_check
resolves its virtual fixture module against the real corpus, so the alias's
declaring module must be real, not inline) -- confirmed by direct execution
both PASS against the repaired binary, and confirmed by diff that the pre-fix
code path would hit ContractUnavailable for the cross-module-alias case
(the discriminating RED) while the genuinely-unavailable-contract companion
case is unaffected either way.

Lineage: #8572, #8579, #8592. Handoff repair from deep-ant-102 to dashboard
node adhoc-28a6f804-3cd (session still-pike-216).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
briansrls pushed a commit that referenced this pull request Aug 20, 2026
…ss runs the mirror, not because the fix is wrong (#8625)

* Enroll the #8592 arg-contract RED as known-red: it is red because the harness runs the mirror, not because the fix is wrong

Adds dag/test/claim/method_arg_declared_contract_witness_test.dag, a black-box
compile_dag_rust_emit_check witness discriminating #8592 (v1 infer: use each
method arg's own declared parameter type, not the receiver's element_type) —
reconciling #8572 and #8579 per dashboard node adhoc-28a6f804-3cd. The fixture
calls List<NonEmptyStr>.get with a NonEmptyStr where the declared contract
requires Int; on the .dag authority this is exactly what declared_arg_types_for_method
(04_lookup.dag) was built to refuse.

It is red on the committed binary today, and it is red for the same reason
6ad9606 quarantined a where-refinement RED the same day: compile_dag_rust_emit_check
executes the compiled src/v1/stage0/src/*.rs mirror, not the .dag authority
directly, and #8592 never regenerated that mirror -- its own commit message
records that required-regen's v2 self-compile refused with 11 source-annotation
diagnostics, blocking the regen. Confirmed by building gunbc from both 98d7147
and its parent and running each on this fixture: both compile clean with zero
diagnostics, byte-identical emitted output; declared_arg_types_for_method is
absent from every stage0 .rs file and the pre-fix scalar_shaped_builtin_method_arg_type
whitelist is still present and still called. claim_batch confirms the witness
evaluates false against the committed binary today, matching ExpectAssertionFalse.

Quarantined via gunbc.explicit_witness_admission (known_red_probe), dissolving
when the 04_infer/04_lookup stage0 mirrors are regenerated -- the row deletes
in that change, promoting the unchanged witness to ordinary DiscoverySelection
as the permanent regression control for #8572/#8579/#8592.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* #8625 admission row: document floor coverage (checked, not assumed) and the QuarantineProbeExpectRed cadence's inert falsifier-cadence half

Per deep-ant-102: floor discovery and the quarantine cadence are two
different mechanisms. This witness's module is not under
dag/test/claim/long/ and matches none of the required floor's long-home
exclusion prefixes, so it IS discovered and executed by the required
floor -- unlike the where-refinement precedent row, whose file sits in
that excluded directory and is discovered nowhere. Separately, the row's
QuarantineProbeExpectRed cadence also names it for the periodic
falsifier re-probe, whose consumer (falsifier.yml) was deleted in the
2026-08-15 floor cut and is not yet re-added -- the row should not be
read as implying that second consumer runs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Enroll method_arg_declared_contract_witness_test in floor_expected_red_roster

The #8592 discriminating RED (dag/test/claim/method_arg_declared_contract_witness_test.dag)
is currently red because the stage0 Rust mirror the required floor executes hasn't
picked up the .dag-authority fix yet. gunbc.explicit_witness_admission's known_red_probe
row documents this but does not gate the required floor's pass/fail (confirmed by
tracing cli_run.rs: explicit_witness_admission_pairs() feeds only a diagnostic
DeferredDiscoveryRow, never floor discovery-exclusion or known-red-hold logic).

Per deep-ant-102's 2026-08-20 ruling: enroll the one identity in
floor_expected_red_roster, the roster that actually drives known_red_held. The row
dissolves on the stage0 mirror regen — once the fix lands in the mirror, this witness
passes, which reds the build via the roster's own self-emptying arm and demands the
row's removal. No new mechanism.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Audit queue item 11: explicit_witness_admission's known_red_probe is an inert lens (rung mitigatable)

Discovered while diagnosing #8625/#8627's required-floor CI failure: known_red_probe
rows document an expected-red witness but are never read by required_floor's
discovery-exclusion logic or by known_red_held (both driven solely by
floor_expected_red_roster). The row's own QuarantineProbeExpectRed cadence names the
falsifier as consumer, which the 2026-08-15 floor cut deleted. Files the class per
deep-ant-102's ruling: rung mitigatable, described honestly as documentation, not a
hold -- and not a call to build a new consumer, since the live case was resolved by
enrolling directly in floor_expected_red_roster.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* design_document: name the hermetic-refusal boundary beside the executed counters

A witness whose subject is a subprocess exit status is planned, discovered,
and counted `executed` in the floor's recital while being refused by
construction at the hermetic boundary (shell.Test.IsExecutable, ~1ms, before
the subprocess is reached). That's correct behavior, not a gap — but the
counter alone reads as full-assertion coverage to anyone who doesn't already
know the mechanism. Name it once, beside the counters.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* floor_expected_red: move chunk_13's annotation above the fn, not inside its body

§4c admits only standalone leading // blocks attached to module-scope
declarations. The block sat inside the function body, which the required
floor's strict-preparation phase refuses to parse (source annotation sits
inside a declaration body).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Fix declared_arg_types_for_method to expand cross-module alias-to-fn field types

When a receiver's method is exposed via a struct field whose declared type is
an alias to a fn type, and the call site's module differs from the alias's
declaring module, declared_arg_types_for_method (04_lookup.dag) had no way to
expand the still-unexpanded alias-reference node -- it took no TypeEnv and no
expansion hook, so callable.params was always read on the raw, unexpanded
node. A cross-module alias-to-fn field therefore always had params.count == 0
and fell straight to ContractUnavailable, wrongly refusing a well-typed call
outright rather than deriving its real per-position contract.

Fixed by threading an expand_field_type: fn(Node) -> Node closure from the
sole call site in 04_infer.dag (which has scope.type_env available) through
to declared_arg_types_for_method, and expanding the callable node before
reading its params when the raw params count is zero. The ContractUnavailable
refusal itself is unchanged -- only its mis-triggering on genuinely-expandable
cross-module aliases is fixed; MethodUnresolved's separate element-type
substitution path is untouched.

Regenerated stage0 mirrors (v1_compiler_infer.rs, v1_compiler_infer_lookup.rs)
via claim_executor --required-regen / --required-regen-fixed-point (both
verified first_generation_equal=true / fixed_point_equal=true against these
committed mirrors), not hand-edited. Added a discriminating witness pair at
dag/test/claim/method_arg_declared_contract_cross_module_alias_witness_test.dag,
backed by a real two-module fixture at
dag/test/fixture/cross_module_alias_handler/ (compile_dag_rust_emit_check
resolves its virtual fixture module against the real corpus, so the alias's
declaring module must be real, not inline) -- confirmed by direct execution
both PASS against the repaired binary, and confirmed by diff that the pre-fix
code path would hit ContractUnavailable for the cross-module-alias case
(the discriminating RED) while the genuinely-unavailable-contract companion
case is unaffected either way.

Lineage: #8572, #8579, #8592. Handoff repair from deep-ant-102 to dashboard
node adhoc-28a6f804-3cd (session still-pike-216).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
briansrls pushed a commit that referenced this pull request Aug 20, 2026
…field types (#8664)

When a receiver's method is exposed via a struct field whose declared type is
an alias to a fn type, and the call site's module differs from the alias's
declaring module, declared_arg_types_for_method (04_lookup.dag) had no way to
expand the still-unexpanded alias-reference node -- it took no TypeEnv and no
expansion hook, so callable.params was always read on the raw, unexpanded
node. A cross-module alias-to-fn field therefore always had params.count == 0
and fell straight to ContractUnavailable, wrongly refusing a well-typed call
outright rather than deriving its real per-position contract.

Fixed by threading an expand_field_type: fn(Node) -> Node closure from the
sole call site in 04_infer.dag (which has scope.type_env available) through
to declared_arg_types_for_method, and expanding the callable node before
reading its params when the raw params count is zero. The ContractUnavailable
refusal itself is unchanged -- only its mis-triggering on genuinely-expandable
cross-module aliases is fixed; MethodUnresolved's separate element-type
substitution path is untouched.

Regenerated stage0 mirrors (v1_compiler_infer.rs, v1_compiler_infer_lookup.rs)
via claim_executor --required-regen / --required-regen-fixed-point (both
verified first_generation_equal=true / fixed_point_equal=true against these
committed mirrors), not hand-edited. Added a discriminating witness pair at
dag/test/claim/method_arg_declared_contract_cross_module_alias_witness_test.dag,
backed by a real two-module fixture at
dag/test/fixture/cross_module_alias_handler/ (compile_dag_rust_emit_check
resolves its virtual fixture module against the real corpus, so the alias's
declaring module must be real, not inline) -- confirmed by direct execution
both PASS against the repaired binary, and confirmed by diff that the pre-fix
code path would hit ContractUnavailable for the cross-module-alias case
(the discriminating RED) while the genuinely-unavailable-contract companion
case is unaffected either way.

Lineage: #8572, #8579, #8592. Handoff repair from deep-ant-102 to dashboard
node adhoc-28a6f804-3cd (session still-pike-216).

Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Aug 20, 2026
…a min-length demand (#8619)

* where-refinement: credit a guaranteed minimum length as evidence for a min-length demand

The wall compared predicate NAMES for equality, so a value whose own declared
refinement already proves the property was not credited: lower_hex_40 != non_empty,
and a 40-hex-digit string flowing into a NonEmptyStr position carried a
WhereRefinementUnenforced advisory for REFUSED evidence rather than absent evidence.

Decides one closed relation and refuses outside it, as two SEPARATE partial functions
over the predicate vocabulary. The asymmetry is the soundness argument: collapsing them
into a single min-length table fails open, because a formal lower_hex_64 would then be
satisfied by an actual lower_hex_128 (128 >= 64) and a 128-digit string is not a valid
sha256 hex. lower_hex_N is a provider only; non_empty is the vocabulary's only pure
length lower bound and so its only demander.

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

* Enroll the discriminating RED as known-red: it is red because the harness runs the mirror, not because the wall is wrong

Measured at 0456098 (BuildBuddy ba6c4598), claim_batch over the witness entry:

  FAIL where_refinement_lower_hex_40_implies_non_empty_credits_evidence
  PASS where_refinement_bare_string_at_non_empty_stays_advisory
  PASS where_refinement_exact_length_predicate_is_not_a_min_length_demander
  PASS where_refinement_min_length_implication_does_not_relax_literal_refusal

Exactly one of the four is red, and it is the only one whose assertion needs the
fix PRESENT. Both assertions that the wall must not OVER-credit hold either way,
which is what keeps this quarantine narrow.

The same run corroborates the cause without relying on the diagnosis: the only
other reds are the two witnesses for the other .dag-only fix to this wall, red
for the identical unmirrored reason. Three reds, one cause.

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

* State the demander-table enrollment condition at its honest rung: diligence, not structure

fierce-ant-91 asked whether anything structural stops a predicate being
enrolled as provider AND demander at once. Nothing does -- and membership
in both is not the fail-open: non_empty is deliberately in both and is
sound there, because it demands exactly what it guarantees.

The enrollment condition is narrower than the question assumed. A REQUIRED
row is sound only if the predicate's entire semantics is a length lower
bound. lower_hex_64 in both tables would be unsound not for appearing
twice but for demanding an exact length and a charset a lower bound does
not establish.

Nothing enforces that condition -- two hand-written name-keyed partial
functions. guaranteed >= required is mechanically enforced; the discipline
populating the demander table is diligence, rung mitigatable, contained
only by the vocabulary being closed and small. Next-rung trigger is the
dissolve-on already recorded: bounds as fields on the predicate's own
declaration leave mis-enrollment nowhere to be written.

No behavior change -- prose row only.

* Regenerate the v1_compiler_infer.rs mirror from 04_infer.dag

The rule was specified and not executed: #8619 added
where_predicate_{guaranteed,required}_min_length and
where_refinement_predicate_satisfied_by to the .dag authority, and the
generated mirror the compiler is actually built from did not carry them.
A measurement with this PR in-tree was byte-identical to one without it.

Not hand-written. Produced by

  claim_executor --required-regen --source-root dag --source-root src/v2

run at this branch head (the script asserted HEAD == 53df763 and would
have refused to measure at any other sha), and taken verbatim from
target/stage0-regen-candidate/src/v1_compiler_infer.rs. +78/-1 across two
hunks, both adjacent to where_refinement_predicates_equivalent and inside
where_refinement_predicates_covered -- the shape a two-function addition
plus its routing should have.

Control that this is the right file and the right change: the identical
run against origin/main produces a candidate byte-identical to main's
committed mirror (1047709 bytes, 0 added, 0 removed), so infer.rs drift
exists only on this branch and is mine.

v1_compiler_emit_rust.rs remains drifted and is NOT touched here -- that
one is inherited from main (#8614's spliced mirror) and is owned by #8652.
This commit does not make CI green; it removes one of the two named files.

* Dissolve the min-length known-red row: its own trigger is now satisfied

The row's dissolution condition read: 'the 00_core and 04_infer stage0
mirrors are regenerated so the compiled harness contains the wall -- this
row deletes in that same change'. Both halves now hold at this head:

  v1_std_core.rs        carries expr_is_any_literal + expr_literal_symbol_optional
  v1_compiler_infer.rs  carries where_predicate_guaranteed_min_length (regenerated in 79196a7)

So the quarantine is stale, and the module's own known_red_class_note says
a row whose witness runs green is stale and deletes. The witness itself is
UNCHANGED and promotes to ordinary DiscoverySelection as the permanent
regression control -- DESIGN 4b(4): the climb deletes the quarantine
machinery, never the evidence.

I am one commit late doing this; the trigger said 'in that same change'
and the regen was the change.

Also repairs a citation my deletion invalidated: the #8592 row cited this
row by name as precedent, which would have become a symbol no reader can
resolve. It now records the precedent as a dissolved instance rather than
pointing at a live row.

If the witness is still red, CI says so by name -- which is the correct
outcome and better than a quarantine that hides it.

* Require a dissolve_on to be discriminating, on the receipt of two that were not

A trigger keyed on a condition that is ALREADY TRUE is not a trigger, it
is a deletion licence with a date on it -- the next reader dissolves a
quarantine standing in for a live defect, and the row reads as
dissolved-per-its-own-terms while the wall it substituted for does not
exist.

Two receipts, one night, and the second is mine:

  #8592's row keys on the harness CONTAINING declared_arg_types_for_method.
  That symbol has always been there; the defect (the function takes no
  TypeEnv) is live on main right now. Satisfiable from the moment it was
  written. Reported by me, ruled on by deep-ant-102, left standing -- its
  repair is still-pike-216's and its trigger needs rewriting, not firing.

  My own min-length row keyed on the harness containing 'the wall'.
  Measured: where_refinement_predicates_covered = 2 in that mirror on main
  and always was. A reader checking 'the wall' could have dissolved the row
  any time in the preceding weeks. I dissolved it correctly only because I
  happened to grep where_predicate_guaranteed_min_length (0 on main, 2
  after the regen). The right answer came from the reader, not the row.

The rule and its reviewer test are now in the class note: name the symbol,
signature or behaviour whose ABSENCE is the gap; never a category word;
run the check against main today, and if it passes the trigger is
defective and the row is unprotected.

* Correct my own promotion claim: this file's home means the witness executes NOWHERE

#8619 deleted the known-red row once its trigger fired and claimed the
witness thereby promotes to ordinary DiscoverySelection as a permanent
regression control. The first half was right; the second is false for a
file under dag/test/claim/long/, which is excluded from witness discovery
at dir grain (ci_layer_roots long_lane_exclusion_note).

So deleting the row removed the only thing naming these witnesses, and the
home ensures nothing else does. The honest state is EXECUTED NOWHERE --
strictly worse than the quarantine it replaced, because a known-red row is
at least counted.

The row was still right to delete: it asserted a RED that is no longer red.
The defect is that promotion presumes a discovering consumer this file does
not have.

Rung stated at mitigatable with the local recipe, and the next-rung trigger
named as a decision NOT taken here: either the file leaves the long home
(pushing its eval cost into the fast lane, the exact thing that home
exists to prevent) or the long home gets an executing cadence (deleted with
falsifier.yml in the 2026-08-15 floor cut, not this lane's to re-add).

Found while resolving a merge conflict with #8625, whose own coverage
paragraph states the same fact about this file from the outside.

* Correct my correction: these identities ARE counted, and the remedy is a module rename not a file move

Two errors in the note I landed an hour ago, both found by reading the
mechanism instead of reasoning about it, and both changing what is owed:

1. I wrote that deleting the known-red row left the witnesses in an
   uncounted silence, 'strictly worse than the quarantine it replaced'.
   False. v2.workflow.required_floor gives EVERY DISCOVERED SITE exactly
   one RequiredFloorDisposition keyed by qualified module.function
   (operator ruling 2026-08-19), and the long home is a Declined ARM of
   that receipt, not an absence. These identities are discovered, counted
   at identity grain, and aggregate into declined_long. What the deleted
   row actually cost is its reason string and its named owner -- not
   counting. Counted-and-declined is weaker than executed and better than
   silence.

2. I wrote the remedy as moving the file out of the long home. Also false.
   Admission tests the module's AUTHORED NAME against
   long_home_prefixes() = 'test.claim.long.'; this module declares
   test.claim.long.where_refinement_enforcement_witness on line 1. Moving
   the file while keeping the module name changes nothing. The remedy is a
   module rename, file following.

Also records why floor_route_gap (merged today) is not the route: it is
scoped to identities that EXECUTE and reach an unrouted host effect, and
its reverse join reds the build on an enrolled identity that did not
execute. Enrolling there would be a false claim, not a shortcut.

* Name the lesson in the note's own words, and mark one claim as read-not-observed

1. required_floor's header records that the previous host tested a PATH,
   which 'made a directory the admission authority', and names that as the
   root cause of the 2026-08-04 ruling. I proposed to fix this by moving a
   directory -- reproducing the exact mistake the mechanism was built to
   stop, inside the mechanism that stops it, while reading the file that
   says so.

2. The floor_route_gap claim is read from that module's contract prose,
   not observed. Today produced a gate that never executed and a lens
   reading a file that exists nowhere, both fully described in prose, so
   'the contract states the outcome' is the class of claim that has failed
   most often here. Accepted on two narrow grounds, both now recorded: it
   is a claim about a REFUSAL (trusting it wrongly yields a weaker refusal,
   never a silent accept), and exercising it would require authoring a
   knowingly-false row to red a build.

---------

Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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