Skip to content

Bare-provider gate: read bare references from the full parse; delete the byte scanner - #12609

Merged
gunbai-bot[bot] merged 7 commits into
mainfrom
session/clever-moth-264
Sep 29, 2026
Merged

gunbai-bot[bot] merged 7 commits into
mainfrom
session/clever-moth-264

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

What

The unimported-bare-provider gate (visit_bare_reference_providers) got its candidates from bare_identifier_candidates, a byte scanner with no grammar. After #12421 added a top-level fn response, every service operation's response { .. } block read as a bare reference, and unrelated PRs refused with UnimportedBareProvider. #12381 and #12542 renamed the helper, which only moved the collision.

The gate now reads each file's free names from its full parse, using the one structural reference walk (collect_node_refs). That walk is shared with the reference-edge producer through entry_resolve::parsed_file_references. bare_identifier_candidates and destructuring_bound_spans are deleted.

Why the full parse (and not the resolved set or a token reader)

  • The resolved reference set can't feed the gate. build_reference_closure_index needs a PreparedRepository, and that only exists after the gate has decided which modules to pull, so it would be circular.
  • The pool parse can't feed it either. It reads declaration headers only and skips bodies (a DESIGN §6 cost fix).
  • A token-level reference reader would be a second parser. response isn't a keyword token; the parser recognizes it by position. Classifying identifiers by grammar position means driving every production.
  • Parent ruling: option A, a per-file full parse read by collect_node_refs.

What the walk now records (BarePositions)

  • undotted: free variables, unbound ExprCall callees, record-literal types, variant constructors and type names. This is the gate's names.
  • dotted_heads: free chain heads and method receivers. The services census answers these first, so Filesystem.Write(..) still resolves as a service.
  • callees: unbound ExprCall names only, which feed call_position. The pullable check and BUILTIN_REQUIRED_SERVICE_KEYS read call_position.
  • Method names are not bare references. xs.length(), and a pipe xs |> filter(f) (which parses to the same ExprMethodCall), resolve through the receiver's type: a structural (algebra) method, else a service operation (resolve_known_method_node). They never go through a bare lookup, so no import can be owed for them. Only the method chain is kept, for the services-prefix lookup (method_chains).
  • authored_types: type names at the raw parse's authored type positions: parameter children, and inferred: Resolved for return, field, data and operation types. collect_node_refs doesn't read those slots because it was written for the prepared tree. A record field contributes its type, not its label (service output { context: T }, variant payloads), and a parameter's default value is skipped. These names are kept out of bare, so the reference-edge producer's edges are unchanged.
  • Bound callees: a callee held by an enclosing binder no longer enters bare. It names the binder, not a declaration.

Controls (bare_reference_scanner_tests, closure_edge_demand_tests)

  • The Observe Namecheap DNS through fleet convergence and approval-gated WIF #12421 specimen doesn't refuse. Two top-level fn response declarations plus a service response {} block, in both an import-less file and an import-bearing one: whole-pool admission and unimported_bare_providers both pass.
  • A genuine unimported bare reference still refuses. An import-bearing file that calls duplicated() from outside its import closure is named, with its provider.
  • None of these is counted as a reference:
    • a named-argument label, a field after ., a record-literal key, a let binder and its reads, lambda parameters, pattern leaves;
    • xs.length() and piped filter/length;
    • a service output { context: T } label, a variant payload label, a parameter default.
  • Each test has a positive control in the same source, e.g. BrowserContext in the output field is counted.
  • 43 of 43 tests in the touched modules pass. cargo clippy --all-targets -D warnings is clean.

Cost (live tree, dag + src/v2, 6984 files, BuildBuddy amd64; main measured at 88436e5 on the same runner)

main this PR
run_required_bare_reference_admission wall 38.1 s 41.2 s
peak RSS (VmHWM) 5.12 GB 5.12 GB
verdict Ok, 6984/6984 judged Ok, 6984/6984 judged

Parse trees aren't retained: each file's tree is dropped once its reference set is read. This follows the existing rule that pool-level readers don't pre-fill parse_cache.

Roster effect (floor_unimported_bare_provider_debt)

Unimported pairs over the whole pool go from 2066 (main) to 1848.

381 gone, all false positives:

163 new, all true positives the scanner missed:

kind count
data x: T annotation types (the scanner skipped them as a key position; 113 are LiveTreeDisposition) 147
constructors in value or match-arm positions (input: NodeRegistered, Conflict => ..) 9
type names in parameter or function types (fn(Finding) -> Bool, a: PublishedMockCase) 3
free length(..) calls 2
record-field value (rlm1_merge_commit: rlm1_merge_commit) 1
{BoardSerialAbsent} inside a string literal, which the grammar interpolates 1

The roster judges only route files plus ImportsFixed rows, so this PR isn't refused. A new pair refuses as Unrostered only when its file is next touched, as for every other file.

Not in this cut

annotation_erased_scan_text stays (follow-up filed: node://adhoc-fa696787-bb7). Its remaining consumers are two other byte scanners: referenced_module_paths_in_text (load's dotted-module-path closure) and module_self_declared_names. Replacing those is a separate cut.

v1 admission

gunbc.v1_maintenance_standing: this change serves the v2 floor. A false UnimportedBareProvider or AMBIGUOUS refusal on the required path blocks unrelated v2 work.

🤖 Generated with Claude Code

gunbc-ci-auto-heal and others added 2 commits September 29, 2026 09:06
…the byte scanner

The gate's candidate source (bare_identifier_candidates) was a byte scanner with no grammar,
so a service operation's `response { .. }` block read as a bare reference to any top-level
`fn response` (#12421). The gate now reads each file's free names from its full parse via
the one structural reference walk (collect_node_refs), shared with the reference-edge
producer through entry_resolve::parsed_file_references. bare_identifier_candidates and
destructuring_bound_spans are deleted.

v1 admission (gunbc.v1_maintenance_standing): serves the v2 floor. A false
UnimportedBareProvider/AMBIGUOUS refusal on the required path blocks unrelated v2 work.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…nces

A method call's name (`xs.length()`, and a pipe `xs |> filter(f)`, which parses to the same
node) resolves through the receiver's type (resolve_known_method_node), never a bare lookup,
so it is no longer a candidate. The raw-parse type reader now reads a record field's TYPE, not
its label (service `output { context: T }`, variant payloads), and skips parameter default
values. Controls added for both.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@gunbai-bot
gunbai-bot Bot added this pull request to the merge queue Sep 29, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 29, 2026
gunbc-ci-auto-heal and others added 5 commits September 29, 2026 13:31
…o longer derives

The merge group refused with RosterStale: the parsed gate reader (this PR) stopped deriving
pairs the byte scanner invented. Those pairs were never references and the files did not
change, so neither existing cause is true. Add a typed cause, NotAReference, held to the same
re-derived claim as ImportsFixed (the file exists and does not carry the pair), with its own
refusals (RetiredNotAReferenceButCarried / ...ButFileAbsent), a host decode of the new view
field, and a claim covering admission and both reds.

Retirements, measured on the merged tree with both readers:
- 329 NotAReference: carried by the old scanner, not by the parsed reader (filter 119, any 49,
  get 24, skip 23, labels, op names, response).
- 59 ImportsFixed: carried by neither reader on current main; the file changed.
No row sits on a deleted file; no ImportsFixed row is carried again.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…'s fields

The floor refused with `row not_a_reference is not a Bool (<field absent>)`: it read the
roster AT THE DIFF BASE, whose view predates the field, through the same host decode as the
head. Only the head's rows are consumed by the host (to choose which files to re-derive); the
base is read for its .dag value, which the edit judgment compares in .dag. So the base reading
no longer decodes row fields, and a base written before a view field existed stays readable.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
# Conflicts:
#	src/v2/workflow/floor_unimported_bare_provider_debt_roster.dag
…-head patch; port its same-file response() control to the parsed reader

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@gunbai-bot
gunbai-bot Bot added this pull request to the merge queue Sep 29, 2026
Merged via the queue into main with commit 6b99b26 Sep 29, 2026
5 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/clever-moth-264 branch September 29, 2026 18:13
gunbai-bot Bot pushed a commit that referenced this pull request Sep 29, 2026
…(its dissolution, #12132, landed)

The #filter bare-provider refusal that hid its verdict was already retired by #12609. On main
785934a the probe PASSES, which its own dissolution names as the row's deletion condition.
The nine algebra_receiver probes remain red (re-measured on the same main).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 29, 2026
… bare-provider gate (#12609) now reads type positions from the full parse

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 30, 2026
…ter as NotAReference

The floor refused RosterStale: the file no longer carries the pair. measure.dag has imported Time
from extdeps.units.iso_80000_3 since 2026-09-05, before the roster was seeded on 2026-09-25, so the
file did not change; the seeding reader derived an imported name as unimported, and the parsed
reader (#12609) does not. That is NotAReference -- the READER changed -- not ImportsFixed, which
would claim a file change that did not happen. This PR surfaced it by touching measure.dag.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 30, 2026
…t roster as NotAReference: Time is a Dimension variant this file declares, not a bare reference; the parsed reader (#12609) no longer derives it, and this PR touching the file made the stale row visible

Co-Authored-By: Claude Opus 5.5 (1M context) <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.

0 participants