Skip to content

v2: declaration-grade lowering of service declarations (gen-two census wall) - #12277

Merged
gunbai-bot[bot] merged 6 commits into
mainfrom
session/still-wolf-52
Sep 25, 2026
Merged

gunbai-bot[bot] merged 6 commits into
mainfrom
session/still-wolf-52

Conversation

@gunbai-bot

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

Copy link
Copy Markdown
Contributor

Gen-two census wall (node adhoc-c537b0c6-a6e): v2 parsed service declarations but nothing lowered them, so the census retained the wrapper and refused. The first refusal was dag/extdeps/access/posix_effective_principal_read_op.dag. Shape ruled by neat-boar-16: A + B1, with the split and fail-closed condition described below.

What lands

  • v2.compiler.body_lowering_fold body_lower_service_decl lowers a service onto EXISTING connectives, with no new node kind:
    Conj { <service>: Conj { <op>: Arrow(Conj{input fields}, Conj{output fields}) } }.
    Each operation lowers to the same Arrow a function type lowers to. The graft flattens it like a record, and the symbol index sees the service, its operations and their fields. It reads from the unfolded parse subtree (it is listed in body_lower_is_deferred_lower_at_normalize) because every member is a declaration fact, not a body.
  • Two set-aside reasons, typed, located and counted apart:
    • body_lowering_reason_realization_member_set_aside: transport, service-level config (it binds the transport's endpoint and authentication; parsed since G0 grammar: service-level config blocks over v1's closed field set #12286), exit, response and mock_response. These are realization per DESIGN §3.
    • body_lowering_reason_interface_member_unmodeled: readonly / idempotent / hermetic, plus an io field's from "key" / = default tail. These ARE interface facts, and they rank for modeling on the new RFM row service_interface_member_has_no_carrier, whose trigger is a typed operation-modifier carrier.
  • A set-aside member is unreachable as lowered, by construction (re-seated on MQ-4: wrapper retention is a typed variant consumed by the normalized-tree door; the reason-scan is deleted #12234's typed BodyLowering; there is no reason scan). The lowering builds its set-aside population as a typed list (ServiceSetAside). At census grade (normalize_census, whose carrier has no route past the symbol index) the service lowers, with each member as a located advisory. On every other route body_lower_service_decl REFUSES the service as body_lowering_reason_service_realization_unreachable, with each member's own located diagnostic pending, so no stage can assume a default transport. That cause has a compile_door_cause_ownership row. normalized_tree.dag is unchanged by this PR.
  • Unreadable members refuse. A member the lowering cannot read refuses located (body_lowering_reason_service_member_unread), and an unreadable name retains the shell. An operation that declares input (or output) twice refuses located as body_lowering_reason_service_io_block_repeated. A service that declares an operation name twice refuses at the second declaration as body_lowering_reason_service_operation_repeated, rather than as an unlocated post_normalize_not_well_formed at the module root. The first full gen-two census found exactly that shape in dag/extdeps/bmc/http.dag, where GetManager is declared twice. The source fix is its own PR.
  • Grammar change (v2.extdeps.languages.dag): io_block is split into input_block / output_block. A literal terminal is captured by token class alone, so one io_block over a choice of the two words could not say which one it matched. The production identity now carries that.

Declared frontier: the service name

The name is ONE label carrying the whole declared spelling (shell.Find), not a per-segment spine. A spine collides at the module level: dag/extdeps/shell.dag has 16 services under shell, and 9 other files share a prefix. Fixing that needs a prefix merge in namespace_graft, which is load-bearing.

The cost: a dotted label hides its named parts (DESIGN §2), and a dotted reference to it does not resolve. Trigger: v2 resolving service CALLS. At that point the spine plus the graft prefix merge becomes required, and this label migrates in one transition. This is recorded on the RFM row.

Evidence

v2.test.claim.normalize.service_declaration_lowering: 10 claims, all PASS locally. Each runs from a supplied token stream and stays within the 72,300-step new-witness budget (38k–56k eval steps). Three fidelity claims pin each supplied stream to what the real tokenizer produces.

  • the census admits a posix-shaped service and indexes m.'a.P'.R;
  • the realization and unmodeled-interface counts come out apart (1 / 2);
  • full normalize refuses the same service, with both the refusal cause and the set-aside member pending;
  • control: two services sharing a prefix (s.F, s.E, the shell.dag shape) both admit with distinct labels;
  • discriminating REDs: a repeated input block, and a repeated operation name, each refuse located under their own cause.

v2.test.parse.g0_service_decl_parse_probe: the old route claim ("a parsed service is refused for retention") flipped, as intended. Per §4b(4) it is kept as two permanent controls: an empty service is admitted, and a transport-only service is refused by full normalize as service_realization_unreachable. All 19 claims in the file PASS locally.

Real file: an interpreter census of the real dag/extdeps/access/posix_effective_principal_read_op.dag gives ADMIT, realization=3, unmodeled-interface=5.

Corpus-wide counts over the 110 non-test service files are pending. An interpreter sweep is running and I'll post the result as a comment.

Native route (srv1, head 5269897): gen-one emit --entry v2.compiler.compile gets the census past posix_effective_principal_read_op.dag and every other service file ahead of the next wall. Neither service-level config nor any other service file is the first wall. The new fatal is body_lowering_reason_call_argument_unread at dag/examples/weather/weather.dag bytes 1015..1016: a fn literal passed as a call argument (#12210's class), with parse_grammar_choice_overlap_residue in the chain. That is outside this PR.

🤖 Generated with Claude Code

…o existing connectives; realization and unmodeled interface members set aside, counted; full door refuses)

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

gunbai-bot Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

Native-route evidence (srv1, via neat-boar-16, head 5269897): gen-one built from this head, then gen-one emit --entry v2.compiler.compile. The census no longer refuses dag/extdeps/access/posix_effective_principal_read_op.dag. The next file-grain wall is body_lowering_reason_call_argument_unread at dag/examples/weather/weather.dag bytes 1015..1016, in a fn body. That file has no service declaration, so the refusal belongs to the body-lowering lane and is out of this PR's scope.

@gunbai-bot

gunbai-bot Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

Corpus-wide set-aside counts over the 110 non-test files that declare a service (dag/ and src/v2):

reason members
body_lowering_reason_realization_member_set_aside (transport, exit, response, mock_response) 1013
body_lowering_reason_interface_member_unmodeled (readonly/idempotent/hermetic, io from/default tails) ≈1434

How these were measured: by a syntactic count of member spellings inside service blocks, NOT by the census. I checked the counter against the one real file the census did read: posix_effective_principal_read_op.dag, where the census reported 3 / 5, gives 3 / 5.

The interface figure is an upper bound. The lowering emits one diagnostic per io field, so a field carrying BOTH a from key and a default counts once there but twice here.

I abandoned the interpreter census sweep: at about 1.5 min for a 1.9 KB file, the ~2.5 MB population is hours of interpreter time. The instrument for exact figures is the native census, which srv1 already ran over every service file ahead of the weather.dag wall, and admitted them all.

Both populations rank for climbing: realization onto a transport-binding carrier, and interface onto the typed operation-modifier carrier (gunbc.recurring_failure_mode service_interface_member_has_no_carrier). With 1400+ interface members, set-aside rather than refusal is the right disposition, per the ruling.

— sent from still-wolf-52

gunbai-bot Bot pushed a commit that referenced this pull request Sep 25, 2026
…eps lower_list_introduction; deferral list keeps both
gunbc-ci-auto-heal and others added 4 commits September 25, 2026 06:46
…ew-witness eval-step budget 72300)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…set-aside is a typed list; census grade admits, every other route refuses by construction, no reason scan)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ering_reason_service_operation_repeated), not as an unlocated post-normalize well-formedness failure (the bmc/http.dag shape)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…the emitter admits module-item grain only; DESIGN 4c)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… the config-only route claim refuses for its set-aside realization

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

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVE at exact head 59688b3. Reviewed against the corrected contract: realization members and unmodeled interface members are two distinct typed/located set-aside classes at census grade; neither class is itself a census refusal. ServiceSetAsideKind preserves that distinction, normalize_census is the only caller admitting a non-empty set-aside population, and ordinary lowering refuses any such service with the member-specific diagnostics pending, so downstream consumers cannot assume omitted transport/interface facts. Repeated operation names refuse at the second operation node under body_lowering_reason_service_operation_repeated. The existing-connective service/operation Arrow shape and declared whole-dotted-name frontier are consistent with the stated design. Exact-head CI is green, including floor, compiler, emit-build/v2-native-cli, clippy, and aggregate witnesses.

@gunbai-bot
gunbai-bot Bot added this pull request to the merge queue Sep 25, 2026
Merged via the queue into main with commit 7736bd1 Sep 25, 2026
5 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/still-wolf-52 branch September 25, 2026 23:46
@briansrls
briansrls restored the session/still-wolf-52 branch September 25, 2026 23:54
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