You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Scope: the actual cutover this track's own completion criterion (design/tracks/the-ir.md
§5) names — bynk-emit/src/emitter.rs and bynk-emit/src/emitter/lower.rs (plus the smaller AST
importers listed below) switched from walking bynk_syntax::ast to reading bynk-emit::ir's
already-built IrItem/IrExpr/IrStmt (P6.0–P6.14). No emitter behaviour changes as a result of this issue — it proposes the slice order only.
Realises: an ordered slice decomposition for the cutover, each slice independently mergeable
against emitter.rs/emitter/lower.rs's ordinary unrelated traffic (§3.1's per-slice freeze
decision), each cut as its own increment-proposal sub-issue of Phase 6 — The IR (spine) #1137 when its turn comes.
What this issue is, and is not
Per #1137's own convention (the IrItem::Agent/Service/Capability/Provider scoping issues — #1169, #1171, #1173, #1174 — each a placeholder settled before its own P6.x implementation issue), this is scoping, not an increment proposal itself. No code changes here. Each numbered slice below
becomes its own Closes #<n> proposal against this doc once its predecessors have landed.
Grounded findings
emit_project (emitter.rs:261) already splits per CommonsItem kind, one loop each — Type/Event (→ emit_type, emit.rs:19), free Fn (→ emit_free_fn, emitter.rs:504), then a
combined loop at emitter.rs:357-376 dispatching Capability/Provider/Service/Agent to emit_capability/emit_provider/emit_service/emit_agent (emit.rs:1083/1118/1247/2500). This
maps close to one-to-one onto IrItem's own variants — the natural axis to slice on. The complication:
~8-10 smaller exhaustive-match helpers scattered through emitter.rs (collect_external_references
and friends, emitter.rs:1718-2148; import collection, 882-999/1571-1793; agent-registry reset, 383-397) each need their per-kind arm touched by whichever slice converts that kind — small, but not
zero, per-slice overhead.
emitter/lower.rs's dispatch (lower_expr:926, emit_statement:523) is separable by expression
kind — most arms already call a dedicated lower_* helper independently swappable to read IrExpr
instead of Expr. Every lower_* function keeps its existing Lowered { pre, expr } return shape
(T2.1/R6.2, untouched) — only the argument type and internal dispatch change, per the-ir.md §3.7's own
"cutover changes what it reads, not what it returns" framing. LowerCtx is threaded through nearly
every call, so a slice converting one expression kind still needs an adapter at sibling call sites that
haven't converted yet — workable, not a hard blocker.
The R6.5 defect names a concrete stake for the Agent slice. Production block_writes_state
(emitter.rs:727) recognises a store write only via a bare-identifier name match
(ExprKind::Ident(id) at the receiver, emitter.rs:730-731) — a locally-shadowed name or non-identifier
receiver shape is silently miscategorised (missed write → implicit commit wrapper skipped; live data
loss). The IR's body_writes_state (ir/lower.rs:1040) already classifies correctly via the checker's
resolved Callee::Store, with regression coverage pinning exactly the shadowing case
(commit_shape_read_only_for_a_locally_shadowed_store_field_name, ir/lower.rs:5413) that block_writes_state cannot avoid. Converting Agent/Service handler-commit-shape emission is what
lets block_writes_state be deleted in favour of the CommitShape the IR already computes
(IrItem::Agent/IrHandler, P6.8/P6.9) — this closes a real, currently-shipping defect, not just a
structural cleanup.
The 9 ast_importers files are not uniform-sized work:
File
AST coupling
Slice treatment
emitter/wrangler.rs, emitter/runtime_use.rs
Trivial (2 and 4 type refs)
One standalone sweep — near-zero risk, shrinks the probe fast
emitter/serialisation.rs
Substantive but single-kind (Type/TypeShape-driven JSON codec)
Known probe limitation, already documented — not a new gap.ast_importers's own doc comment
(xtask/src/greenfield_status.rs, above AST_IMPORTER_EXCEPTIONS, added at #1184's review) already
states the probe reaching 0 proves no remaining file spells bynk_syntax::ast directly — it does not
prove every IrItem field is AST-free (ir.rs itself still holds Arc<TypeDecl>, HandlerKind, Refinement etc. in IrItem-adjacent fields), and a file reached only via use super::* (e.g. emit.rs, which never spells bynk_syntax::ast literally but is the most AST-coupled file in the
crate through emitter.rs's re-exported use) is invisible to the probe by construction. Flagging
here only so slice reviewers don't read "9 → 0" as a stronger claim than the probe's own doc comment
already disclaims.
Decisions
[DECISION A] Slice order (Recommended: as below). Order by ascending emitter-side special-casing,
so the cutover pattern is proven on the plainest kind first and the riskiest kind (Service) is last,
by which point the pattern is well-exercised:
Type/Fn — plainest, longest-baked IR (P6.1/P6.6). emitter/serialisation.rs rides along.
emitter/wrangler.rs + emitter/runtime_use.rs — standalone trivial sweep, any point after (1).
Capability/Provider — smallest remaining IrItem variants, no handler/commit-shape surface.
Agent — claims the R6.5 fix as its stake; emitter/workers.rs/emitter/workers_entry.rs
partially ride along or immediately follow (both depend on agent dispatch shapes).
Service — most special-cased (protocol variants, CORS/security/limits PolicyIr, emit_make_surface/cross-context surface assembly, WebSocket DO-method generation at emit.rs:3631-3990). emitter/workers_entry.rs's route/fetch generation finishes trailing this.
project.rs cleanup — once (1)–(5) land, whatever AST coupling remains here is residue, not new
work; small closing slice.
project/tests_emit.rs — last; depends on all prior machinery being IR-native to convert cleanly.
[DECISION B] Actor (Recommended: out of scope, no slice). Settled as a deliberate non-build
decision (#1172) — no IrItem::Actor variant exists or is planned. Any ActorDecl reference
remaining in emitter.rs/project.rs/emitter/workers*.rs after slices (1)–(7) is expected residue
under that settled decision, not a gap this track needs to close.
Risks & mitigations
emitter.rs/emitter/lower.rs are hot files (39/54 commits in 30 days at the-ir.md's own last
measurement) → per-slice freeze only (§3.1, already settled), never track-wide.
Partial conversion means both AST-walking and IR-reading code paths coexist mid-track → each slice's
own PR should assert byte-identical emitted output for its converted kind (differential test against main), the same discipline P6.0–P6.14's additive slices already used for "no emission-behaviour
change."
Probe can read a false "closer to 0" without real progress if a slice spells around bynk_syntax::ast via use super::* the way emit.rs already does → each slice's PR should state
its ast_importers delta explicitly, not just rely on the number.
Done when
Slices (1)–(7) above are each cut as their own increment-proposal sub-issue of Phase 6 — The IR (spine) #1137, in this order
(re-scoping any slice as it's cut is expected and fine — this is the candidate decomposition, not a
locked plan, per design/tracks/README.md step 3).
design/tracks/the-ir.md §6 is updated to reference this decomposition once accepted.
Summary
design/tracks/the-ir.md§5) names —
bynk-emit/src/emitter.rsandbynk-emit/src/emitter/lower.rs(plus the smaller ASTimporters listed below) switched from walking
bynk_syntax::astto readingbynk-emit::ir'salready-built
IrItem/IrExpr/IrStmt(P6.0–P6.14). No emitter behaviour changes as a result ofthis issue — it proposes the slice order only.
ast_importersreads 9, unchanged since this track opened (9 Aug); the IR hasbeen built purely additively the whole way through, with zero
crate::irreferences anywhere inemitter.rs/emitter/*.rsas ofmain@7f5115ee(confirmed in the-ir.md: settle §5's completion criterion for emitter/lower.rs's own string output (Q7, #1175) #1183). The-ir.md §3.7 named thisproposal a scoping placeholder blocked on
IrItem::Provider(P6.x candidate: IrItem::Provider — model the Bynk/External dispatch #1174) and the probe redefinition(Redefine the ast_importers probe so it can meaningfully reach 0 for this track #1176) — both landed (P6.14: assemble IrItem::Provider (ProviderBody) in bynk-emit::ir #1186, Redefine ast_importers so it can meaningfully reach 0 for phase 6 #1184). Nothing structural blocks scoping it now.
against
emitter.rs/emitter/lower.rs's ordinary unrelated traffic (§3.1's per-slice freezedecision), each cut as its own increment-proposal sub-issue of Phase 6 — The IR (spine) #1137 when its turn comes.
What this issue is, and is not
Per #1137's own convention (the
IrItem::Agent/Service/Capability/Providerscoping issues —#1169, #1171, #1173, #1174 — each a placeholder settled before its own P6.x implementation issue),
this is scoping, not an increment proposal itself. No code changes here. Each numbered slice below
becomes its own
Closes #<n>proposal against this doc once its predecessors have landed.Grounded findings
emit_project(emitter.rs:261) already splits perCommonsItemkind, one loop each —Type/Event(→emit_type,emit.rs:19), freeFn(→emit_free_fn,emitter.rs:504), then acombined loop at
emitter.rs:357-376dispatchingCapability/Provider/Service/Agenttoemit_capability/emit_provider/emit_service/emit_agent(emit.rs:1083/1118/1247/2500). Thismaps close to one-to-one onto
IrItem's own variants — the natural axis to slice on. The complication:~8-10 smaller exhaustive-match helpers scattered through
emitter.rs(collect_external_referencesand friends,
emitter.rs:1718-2148; import collection,882-999/1571-1793; agent-registry reset,383-397) each need their per-kind arm touched by whichever slice converts that kind — small, but notzero, per-slice overhead.
emitter/lower.rs's dispatch (lower_expr:926,emit_statement:523) is separable by expressionkind — most arms already call a dedicated
lower_*helper independently swappable to readIrExprinstead of
Expr. Everylower_*function keeps its existingLowered { pre, expr }return shape(T2.1/R6.2, untouched) — only the argument type and internal dispatch change, per the-ir.md §3.7's own
"cutover changes what it reads, not what it returns" framing.
LowerCtxis threaded through nearlyevery call, so a slice converting one expression kind still needs an adapter at sibling call sites that
haven't converted yet — workable, not a hard blocker.
The R6.5 defect names a concrete stake for the
Agentslice. Productionblock_writes_state(
emitter.rs:727) recognises a store write only via a bare-identifier name match(
ExprKind::Ident(id)at the receiver,emitter.rs:730-731) — a locally-shadowed name or non-identifierreceiver shape is silently miscategorised (missed write → implicit commit wrapper skipped; live data
loss). The IR's
body_writes_state(ir/lower.rs:1040) already classifies correctly via the checker'sresolved
Callee::Store, with regression coverage pinning exactly the shadowing case(
commit_shape_read_only_for_a_locally_shadowed_store_field_name,ir/lower.rs:5413) thatblock_writes_statecannot avoid. ConvertingAgent/Servicehandler-commit-shape emission is whatlets
block_writes_statebe deleted in favour of theCommitShapethe IR already computes(
IrItem::Agent/IrHandler, P6.8/P6.9) — this closes a real, currently-shipping defect, not just astructural cleanup.
The 9
ast_importersfiles are not uniform-sized work:emitter/wrangler.rs,emitter/runtime_use.rsemitter/serialisation.rsType/TypeShape-driven JSON codec)Typeslice, not its ownemitter/workers.rs,emitter/workers_entry.rsService+Agent-shaped Workers dispatch/entrypoint)Agent+Service, don't lead themproject.rsEmitProjectCtxassembly, touches every kind)project/tests_emit.rs.bynktest/suite/integrationdeclarations — not test scaffolding despite the name)emitter.rs/emitter/lower.rsmachinery directlyKnown probe limitation, already documented — not a new gap.
ast_importers's own doc comment(
xtask/src/greenfield_status.rs, aboveAST_IMPORTER_EXCEPTIONS, added at #1184's review) alreadystates the probe reaching 0 proves no remaining file spells
bynk_syntax::astdirectly — it does notprove every
IrItemfield is AST-free (ir.rsitself still holdsArc<TypeDecl>,HandlerKind,Refinementetc. inIrItem-adjacent fields), and a file reached only viause super::*(e.g.emit.rs, which never spellsbynk_syntax::astliterally but is the most AST-coupled file in thecrate through
emitter.rs's re-exporteduse) is invisible to the probe by construction. Flagginghere only so slice reviewers don't read "9 → 0" as a stronger claim than the probe's own doc comment
already disclaims.
Decisions
[DECISION A] Slice order (Recommended: as below). Order by ascending emitter-side special-casing,
so the cutover pattern is proven on the plainest kind first and the riskiest kind (
Service) is last,by which point the pattern is well-exercised:
Type/Fn— plainest, longest-baked IR (P6.1/P6.6).emitter/serialisation.rsrides along.emitter/wrangler.rs+emitter/runtime_use.rs— standalone trivial sweep, any point after (1).Capability/Provider— smallest remainingIrItemvariants, no handler/commit-shape surface.Agent— claims the R6.5 fix as its stake;emitter/workers.rs/emitter/workers_entry.rspartially ride along or immediately follow (both depend on agent dispatch shapes).
Service— most special-cased (protocol variants, CORS/security/limitsPolicyIr,emit_make_surface/cross-context surface assembly, WebSocket DO-method generation atemit.rs:3631-3990).emitter/workers_entry.rs's route/fetch generation finishes trailing this.project.rscleanup — once (1)–(5) land, whatever AST coupling remains here is residue, not newwork; small closing slice.
project/tests_emit.rs— last; depends on all prior machinery being IR-native to convert cleanly.[DECISION B]
Actor(Recommended: out of scope, no slice). Settled as a deliberate non-builddecision (#1172) — no
IrItem::Actorvariant exists or is planned. AnyActorDeclreferenceremaining in
emitter.rs/project.rs/emitter/workers*.rsafter slices (1)–(7) is expected residueunder that settled decision, not a gap this track needs to close.
Risks & mitigations
emitter.rs/emitter/lower.rsare hot files (39/54 commits in 30 days at the-ir.md's own lastmeasurement) → per-slice freeze only (§3.1, already settled), never track-wide.
own PR should assert byte-identical emitted output for its converted kind (differential test against
main), the same discipline P6.0–P6.14's additive slices already used for "no emission-behaviourchange."
bynk_syntax::astviause super::*the wayemit.rsalready does → each slice's PR should stateits
ast_importersdelta explicitly, not just rely on the number.Done when
(re-scoping any slice as it's cut is expected and fine — this is the candidate decomposition, not a
locked plan, per
design/tracks/README.mdstep 3).design/tracks/the-ir.md§6 is updated to reference this decomposition once accepted.Part of #1137.