Skip to content

Emitter: an effectful fold step is realized as a loop in the enclosing async frame (native broker class E) - #13154

Merged
gunbai-bot[bot] merged 10 commits into
mainfrom
session/loyal-gull-749
Oct 4, 2026
Merged

gunbai-bot[bot] merged 10 commits into
mainfrom
session/loyal-gull-749

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Native broker wave 2D (program: gentle-dove-36), class E: an effectful call inside a fold step emitted .await? into a synchronous closure (rustc E0728).

Re-derivation (DESIGN §6b)

fold is a bounded Loop. Iterator::fold(init, |acc, x| …) is one realization of it, and that realization assumes a pure step: the closure is its own synchronous frame. The call arm decides .await? by the one effect authority (v1.compiler.infer_items item_is_effectful_callee, plus is_typed_service_call_receiver for service ops), and the enclosing fn is already async because it reaches that effect. So the defect is not the await. It is the closure: an effectful step belongs in the enclosing frame, where .await and ? mean what they mean everywhere else in the fn (an effect's refusal propagates out of the fold as it would out of a let). This is the same move as the effectful tail-call lowering (a loop over a mutable state slot in the caller's frame), applied to the Loop that fold already is.

Change (src/v1/05_emit_rust.dag, emit_rust_fold_method_call)

  • rust_expr_reaches_awaited_call asks, over the step's subtree, exactly the two predicates that write an .await?. It mints no new effect authority.
  • When the step reaches one, emit_rust_effectful_fold_loop emits { let mut __fold_acc[: T] = init; for __fold_elem in iter { let acc = __fold_acc; let x = __fold_elem; __fold_acc = { body }; } __fold_acc }. The body is emitted by the ordinary expression emitter against the same lambda scope; take_owned is applied when the closure path would apply it.
  • Pure steps keep the .fold(init, closure) realization unchanged. The closure string is now built only on that arm.
  • rust_fold_safe_acc_type: the unit-element accumulator rule (Option<()> etc. → _) is hoisted so both realizations share it. The first probe of the loop arm annotated the raw Option<()> and produced expected Option<String>, found Option<()> in gunbc.package_delivery seed_npm_cache_from_admitted; sharing the rule removed it.
  • Stage0 mirror v1_compiler_emit_rust.rs comes from claim_executor --required-regen (the only drift reported); the second pass is a fixed point (REGEN2_EXIT=0).

Control: //gunbc/instruments:native-emission-controls (emitted, built, RUN)

The hand-written stage0 test is deleted. Per gentle-dove-36's ruling, the control lives in the shared label. Cases in gunbc.instruments.native_emission_controls: control_tally_absent_reads folds Filesystem.Read over three paths under a root no host provisions, into a record accumulator (the pending_escalations shape). Its cases are effectful_fold_step_counts_every_refused_read (=3) and the reds effectful_fold_step_red_seen_counts_elements (=3) and effectful_fold_step_red_empty_keeps_init (=0).

  • Before (driver binding present, fold rule absent): exit 2, EmittedCompilerBuildFailed first_error=error[E0728]: await is only allowed inside async functions and blocks. That is the broker's defect.
  • After: exit 0, every roster case held, warning_count=0 under -D warnings.

Depends on #13180 (the NativeClaimDriver Filesystem binding, its own PR as ruled). That branch is merged into this one rather than stacked, because a PR whose base is not main gets no CI. Once #13180 lands, this diff reduces to the fold rule and its cases.

Broker probe delta

Two arms, built and probed in one remote dispatch with the local-only 1B hoist, keyed by module and normalized message. At fd30a50 the count went 1082 → 1073 with this rule plus #13147 (disjoint files). This rule's share: −5 E0728, in approval_decision_store (the brief's site), command_runner, and package_delivery ×3. No new error identities. On the merged head 6be3086 the probe shows 1082. Main has moved since; the E0728 identities above are absent there too.

Not covered: the remaining E0728s are a different class

gunbc.auth.approval_store_receipt store_receipt_answer (×3, which the brief listed under class E) and gunbc.host_cli_dependency first_absent_host_cli_dependency do not await inside a fold step. They pass an effectful function value to a pure higher-order fn: slot: fn() -> EscalationSlot thunks into store_receipt_answer_over, and cons: fn(A, T) -> A into v2.std.algebra fold_list. The function type carries no effect, so the callee is emitted sync, and no emitter-local rule can make that right without effect-carrying function types. That is a language-layer gap, reported to gentle-dove-36 rather than patched.

🤖 Generated with Claude Code

Brian Searls and others added 3 commits October 3, 2026 19:54
…g async frame

Fold handed its step to Iterator::fold as a synchronous closure, so an effectful
callee's `.await?` landed inside it (rustc E0728). The step now runs as a `for`
loop over a mutable accumulator when it reaches an awaited call, asked of the
same two authorities that write the await (item_is_effectful_callee and
is_typed_service_call_receiver). Pure folds keep the closure realization.

Control: src/v1/stage0/tests/effectful_fold_step_emitted_rust.rs emits, rustc-
compiles and runs an effectful fold with a record accumulator (RED before,
green after). Stage0 mirror via claim_executor --required-regen; second pass
is a fixed point.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ee (required-regen; second pass is a fixed point)

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

gunbai-bot Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor Author

On the advisory in review 75067 (a receipt for the hand-written Rust test):

The receipt is a deferral. The test exists only because the shared emitted-and-run control label //gunbc/instruments:native-emission-controls (#13144, lane 2A) is not on main yet, and stacking on it would leave this PR with no CI. Once #13144 lands, lane 2D (loyal-gull-749, node adhoc-1eb08b07-ad6) moves this case into gunbc.instruments.native_emission_controls as a NativeClaimDriver case. That label emits, builds and runs it as .dag, with no hand Rust. The same change then deletes src/v1/stage0/tests/effectful_fold_step_emitted_rust.rs. Until then it follows its sibling named_filter_emitted_rust route (#13137), with the rust_unit_tests_off_the_merge_path rung named in its header.

On the noted limitation (a nested non-fold closure that awaits): agreed, it is not a regression. It belongs to the effectful-function-value class (fold_list(cons: fn…) and the thunk arguments in approval_store_receipt), which is escalated as a language-layer decision rather than an emitter rule.

— sent from loyal-gull-749

@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.

NO-LAND at this head, for one integration reason only. The lowering itself looks correct: effectful fold steps belong in the enclosing async frame, the pure .fold(..) arm stays unchanged, the effect test reuses the existing await authorities, and the broker delta removes the five E0728 identities without creating new ones. CI is green.

But this PR is based on 4998418, which is the merge commit of #13144. Therefore the stated deferral for src/v1/stage0/tests/effectful_fold_step_emitted_rust.rs is no longer true: //gunbc/instruments:native-emission-controls already exists on this base and is explicitly the shared authority for emitter-rule controls. Please move this effectful-fold specimen into gunbc.instruments.native_emission_controls as emitted/build/run cases with declared roster identities, delete the hand-written Rust integration test, run the shared label, and re-request. This is the same consolidation rule applied to #13137.

Brian Searls and others added 3 commits October 4, 2026 00:10
…ds the filesystem_io handler when the report demands it

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Brian Searls and others added 2 commits October 4, 2026 00:32
…ld control into native-emission-controls and delete the hand-written test
…d-written test); stage0 mirror regenerated

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 Oct 4, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Oct 4, 2026
Brian Searls and others added 2 commits October 4, 2026 05:52
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 Oct 4, 2026
Merged via the queue into main with commit f4e5ddb Oct 4, 2026
4 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/loyal-gull-749 branch October 4, 2026 09:51
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