Problem
In src/simlin-engine/src/db.rs, the thread-local flag IN_TRACKED_CONTEXT (declared around db.rs:104) is only ever read, never set to true. The guarded wrapper try_accumulate_diagnostic (db.rs:115) short-circuits to a permanent no-op whenever the flag is false:
fn try_accumulate_diagnostic(db: &dyn Db, diag: Diagnostic) {
let in_context = IN_TRACKED_CONTEXT.with(|flag| flag.get());
if in_context {
CompilationDiagnostic(diag).accumulate(db);
}
// Outside a tracked context the diagnostic is silently discarded.
}
The wrapper exists because a bare .accumulate(db) panics with "cannot accumulate values outside of an active tracked function" when called outside a #[salsa::tracked] frame (and catch_unwind is ineffective under WASM's panic = "abort"). But the entire assemble_* chain runs outside any tracked frame:
compile_project_incremental -> assemble_simulation -> assemble_module
-> compile_implicit_var_fragment / lower_implicit_var
So try_accumulate_diagnostic is a no-op for every call site on that chain. The doc comment at db.rs:111-114 already states this plainly: "Scaffolding: the flag is never set to true today, so all calls are no-ops -- assembly errors are instead returned via Result::Err..."
Consequence
Structured per-variable CompilationDiagnostics produced during assembly never reach collect_all_diagnostics, so MCP / FFI / simlin_project_get_errors consumers never see them as structured per-variable diagnostics. Two concrete instances on the dead path today:
- The pre-existing
assemble_module aggregate-Err diagnostic (db.rs:5067, the "failed to compile fragments for variables: ..." path).
- The per-helper
DimensionInScalarContext diagnostic in lower_implicit_var (db.rs:4013-4026), added during element-cycle-resolution Phase 6 Task 4 (commit b25dc06d, branch clearn-hero-model) precisely to make a lowering-stage residual legible per-helper rather than only in the opaque aggregate missing_vars string.
Both are only legible today via the compile_project_incremental Err return string, not as structured diagnostics. The real-variable path emits a structured diagnostic via accumulate_var_compile_error (which runs inside a tracked frame); the assembly path cannot reach that surface.
Why it matters
Observability / diagnostic-surfacing gap. The error is not lost — the Err is returned and the helper/variable names appear in its message, so this is not a silent miscompile. But an AI agent or CLI caller reaching for the structured per-variable error list (the canonical "what's wrong with my model?" surface) gets nothing for assembly-stage failures; they only get a single opaque aggregate string at the top level. Degrades the developer/agent debugging experience for exactly the failure modes (DimensionInScalarContext residuals, fragment-compile failures) most likely to need per-variable attribution.
Components affected
src/simlin-engine/src/db.rs: IN_TRACKED_CONTEXT (~db.rs:104), try_accumulate_diagnostic (~db.rs:115), assemble_module (~db.rs:5067), lower_implicit_var (~db.rs:4013-4026).
Possible approaches
Either:
- Wire
IN_TRACKED_CONTEXT to true around the assemble_* chain — but with care: the chain is not itself a #[salsa::tracked] query, so this needs thought about salsa accumulator semantics (which tracked frame would the accumulated values attach to, and would collect_all_diagnostics actually re-run that query and observe them?). A flag set true without a live tracked frame underneath would just re-introduce the panic the wrapper was built to dodge.
- Relocate the per-variable diagnostic emission into the tracked
compile_var_fragment-equivalent path that does run inside a tracked frame, so the structured diagnostic is produced where accumulate is legal and collect_all_diagnostics can see it.
Approach 2 is likely the cleaner fix: it keeps the no-op scaffolding honest (delete IN_TRACKED_CONTEXT and the wrapper once nothing depends on it) and emits diagnostics only where salsa supports it.
Context
Identified during element-cycle-resolution Phase 6 Task 4 (commit b25dc06d, branch clearn-hero-model). This is not a blocker for the element-cycle-resolution work, which uses the compile_project_incremental Err return directly.
Same area and same investigation as #580 (the assembly-stage fragment-compile failure itself) but a distinct, pre-existing issue: #580 is the bug; this is the structured-diagnostic-surfacing gap around it. Conceptually adjacent to #466 (LTM auto-flip warning unreachable through simlin_project_get_errors) — both are "diagnostic invisible to get_errors" — but a different mechanism (#466 is an ltm_enabled=false FFI-layer reset; this is the IN_TRACKED_CONTEXT-never-true engine scaffolding no-op).
Problem
In
src/simlin-engine/src/db.rs, the thread-local flagIN_TRACKED_CONTEXT(declared arounddb.rs:104) is only ever read, never set totrue. The guarded wrappertry_accumulate_diagnostic(db.rs:115) short-circuits to a permanent no-op whenever the flag is false:The wrapper exists because a bare
.accumulate(db)panics with "cannot accumulate values outside of an active tracked function" when called outside a#[salsa::tracked]frame (andcatch_unwindis ineffective under WASM'spanic = "abort"). But the entireassemble_*chain runs outside any tracked frame:So
try_accumulate_diagnosticis a no-op for every call site on that chain. The doc comment atdb.rs:111-114already states this plainly: "Scaffolding: the flag is never set totruetoday, so all calls are no-ops -- assembly errors are instead returned viaResult::Err..."Consequence
Structured per-variable
CompilationDiagnostics produced during assembly never reachcollect_all_diagnostics, so MCP / FFI /simlin_project_get_errorsconsumers never see them as structured per-variable diagnostics. Two concrete instances on the dead path today:assemble_moduleaggregate-Errdiagnostic (db.rs:5067, the "failed to compile fragments for variables: ..." path).DimensionInScalarContextdiagnostic inlower_implicit_var(db.rs:4013-4026), added during element-cycle-resolution Phase 6 Task 4 (commitb25dc06d, branchclearn-hero-model) precisely to make a lowering-stage residual legible per-helper rather than only in the opaque aggregatemissing_varsstring.Both are only legible today via the
compile_project_incrementalErrreturn string, not as structured diagnostics. The real-variable path emits a structured diagnostic viaaccumulate_var_compile_error(which runs inside a tracked frame); the assembly path cannot reach that surface.Why it matters
Observability / diagnostic-surfacing gap. The error is not lost — the
Erris returned and the helper/variable names appear in its message, so this is not a silent miscompile. But an AI agent or CLI caller reaching for the structured per-variable error list (the canonical "what's wrong with my model?" surface) gets nothing for assembly-stage failures; they only get a single opaque aggregate string at the top level. Degrades the developer/agent debugging experience for exactly the failure modes (DimensionInScalarContextresiduals, fragment-compile failures) most likely to need per-variable attribution.Components affected
src/simlin-engine/src/db.rs:IN_TRACKED_CONTEXT(~db.rs:104),try_accumulate_diagnostic(~db.rs:115),assemble_module(~db.rs:5067),lower_implicit_var(~db.rs:4013-4026).Possible approaches
Either:
IN_TRACKED_CONTEXTtotruearound theassemble_*chain — but with care: the chain is not itself a#[salsa::tracked]query, so this needs thought about salsa accumulator semantics (which tracked frame would the accumulated values attach to, and wouldcollect_all_diagnosticsactually re-run that query and observe them?). A flag set true without a live tracked frame underneath would just re-introduce the panic the wrapper was built to dodge.compile_var_fragment-equivalent path that does run inside a tracked frame, so the structured diagnostic is produced whereaccumulateis legal andcollect_all_diagnosticscan see it.Approach 2 is likely the cleaner fix: it keeps the no-op scaffolding honest (delete
IN_TRACKED_CONTEXTand the wrapper once nothing depends on it) and emits diagnostics only where salsa supports it.Context
Identified during element-cycle-resolution Phase 6 Task 4 (commit
b25dc06d, branchclearn-hero-model). This is not a blocker for the element-cycle-resolution work, which uses thecompile_project_incrementalErrreturn directly.Same area and same investigation as #580 (the assembly-stage fragment-compile failure itself) but a distinct, pre-existing issue: #580 is the bug; this is the structured-diagnostic-surfacing gap around it. Conceptually adjacent to #466 (LTM auto-flip warning unreachable through
simlin_project_get_errors) — both are "diagnostic invisible toget_errors" — but a different mechanism (#466 is anltm_enabled=falseFFI-layer reset; this is theIN_TRACKED_CONTEXT-never-true engine scaffolding no-op).