Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
4b6eb6c
engine: make canonicalize idempotent for quoted idents
bpowers May 16, 2026
0acbdc6
engine: resolve subscripted self-reference to its real name
bpowers May 16, 2026
9cd0e3d
engine: preserve flow subscripts in stock-flow decomposition
bpowers May 16, 2026
5abc816
engine: resolve synthetic net-flow rate per element
bpowers May 16, 2026
46a3fe6
engine: split dependency-graph machinery into db_dep_graph
bpowers May 16, 2026
b026331
engine: extract per-variable lowering into db_var_fragment
bpowers May 17, 2026
d34c5e3
engine: add array_producing_vars condition-2 accessor
bpowers May 17, 2026
7e25d06
docs: update tech-debt
bpowers May 18, 2026
5cd68fc
engine: replace phantom design-doc citations in comments
bpowers May 18, 2026
6e221e4
doc: add element-level cycle resolution design plan
bpowers May 18, 2026
fe09d9f
doc: add element-level cycle resolution implementation plan
bpowers May 18, 2026
fa93e4a
engine: promote scc_components to production pub(crate) primitive
bpowers May 18, 2026
615337a
engine: add ResolvedScc/SccPhase and resolved_sccs payload
bpowers May 18, 2026
12d8d07
engine: resolve single-variable self-recurrence SCCs in dt cycle gate
bpowers May 18, 2026
3315e5d
engine: tighten genuine same-element self-cycle to CircularDependency…
bpowers May 18, 2026
5d8c6f0
engine: re-point dt cycle consistency harness to element invariant
bpowers May 18, 2026
7241d41
engine: assert byte-stable per-element run order (AC1.4)
bpowers May 18, 2026
f9c0abd
engine: correct phase_element_order rationale and clarify element-cyc…
bpowers May 18, 2026
1351afb
doc: phase 2 init combined-fragment representability spike
bpowers May 18, 2026
7172f68
engine: extract init_walk_successors, share the init relation
bpowers May 18, 2026
07b513b
engine: init-phase per-element relation and verdict
bpowers May 18, 2026
2149ab7
doc: revise phase 2 subcomponent B for symbolic-ref architecture (GH …
bpowers May 18, 2026
9773534
engine: rebuild SCC element-graph verdict on symbolic refs (multi-mem…
bpowers May 18, 2026
74d9419
engine: interleave members' symbolic segments into one combined PerVa…
bpowers May 18, 2026
b45e381
doc: insert phase 2 task 5b (multi-member SCC dependency-graph consum…
bpowers May 18, 2026
f059c4d
engine: consume multi-member resolved SCCs in dependency graph (SCC-a…
bpowers May 18, 2026
c18a496
engine: inject combined SCC fragment in assemble_module (dt+init)
bpowers May 18, 2026
3218ba2
engine: ref.mdl multi-variable recurrence simulates (AC2.1)
bpowers May 18, 2026
912bbd7
engine: interleaved.mdl element interleave simulates (AC2.2)
bpowers May 18, 2026
f0af97f
engine: transition inter-variable-cycle test; add init-recurrence fix…
bpowers May 19, 2026
220b478
engine: byte-stable combined fragment; corpus regression gate green (…
bpowers May 19, 2026
4f7cf87
engine: phase 2 review doc-accuracy fixes (no logic change)
bpowers May 19, 2026
a122fd1
doc: reconcile phase 3 to phase 2 symbolic accessor (GH #575 follow-t…
bpowers May 19, 2026
caa57c4
engine: loud-safe fallback for unsourceable in-SCC nodes (AC3.2, AC3.3)
bpowers May 19, 2026
cee5d06
engine: source synthetic-helper symbolic fragment from parent implici…
bpowers May 19, 2026
0baaee1
engine: helper-bearing recurrence simulates via parent-sourcing (AC3.1)
bpowers May 19, 2026
f0edf50
doc: reconcile test-requirements AC3 rows with phase 3 symbolic accessor
bpowers May 19, 2026
a82dff2
engine: VECTOR SORT ORDER genuine Vensim 0-based indices (AC5)
bpowers May 19, 2026
00f25d1
doc: phase 5 VECTOR ELM MAP base+stride resolution spike
bpowers May 19, 2026
889bfb8
engine: VECTOR ELM MAP genuine Vensim base+full-source (AC6)
bpowers May 19, 2026
bceeb94
engine: harden VECTOR ELM MAP full_source_len roundtrip + strict-slic…
bpowers May 19, 2026
6f83c43
doc: expand phase 6 task 3 with element-level lagged-read strip (C-LE…
bpowers May 19, 2026
1183899
engine: element-level lagged-read strip in symbolic SCC graph; re-ver…
bpowers May 19, 2026
d32bd62
doc: add phase 6 tasks 4-5 for #580 latent compile bugs
bpowers May 19, 2026
b25dc06
engine: group-mapped subscript translation in temp-arg-helper extract…
bpowers May 19, 2026
505fc4f
doc: reconcile phase 6 task 4 to as-built #580 Bug A fix
bpowers May 19, 2026
ad432fb
engine: arrayed-GF dependency stub in isolated per-variable recompile…
bpowers May 19, 2026
dacc436
doc: reconcile phase 6 task 5 to as-built #580 Bug B fix
bpowers May 19, 2026
95757c9
doc: add phase 6 task 6 for #582 cross-fragment GF de-dup
bpowers May 19, 2026
871d112
engine: cross-fragment graphical-function de-duplication (#582)
bpowers May 19, 2026
7a90c6e
doc: add phase 6 task 7 for #583 temp recycle fix
bpowers May 19, 2026
b091084
engine: match monolithic temp recycling in fragment concatenation (#583)
bpowers May 19, 2026
e69278d
doc: add phase 6 tasks 8-9 for AC7.3 NaN clusters
bpowers May 19, 2026
c466732
engine: include INITIAL-backed module outputs in the initials runlist…
bpowers May 19, 2026
3cc709f
engine: arrayed VECTOR SORT ORDER per-slice 0-based ranks (AC5/AC7.3 …
bpowers May 19, 2026
19b03a4
doc: add phase 6 task 10 for :NA: sentinel root-cause fix
bpowers May 19, 2026
70f8f74
engine: represent Vensim :NA: as the finite sentinel -2^109, not NaN
bpowers May 19, 2026
9f49160
engine: C-LEARN incremental structural-gate test (AC7.1-7.3, AC7.5)
bpowers May 19, 2026
2d2fab6
doc: add phase 6 task 11 for #363 codegen panic->Err (AC7.5)
bpowers May 19, 2026
59f0112
engine: convert codegen PREVIOUS-subscript panic to typed Err (#363, …
bpowers May 19, 2026
b0d0823
engine: re-point clearn LTM-discovery test to clean compile; retire c…
bpowers May 19, 2026
63f2c00
engine: clarify GF-block dedup boundary-marker comment (phase 6c review)
bpowers May 20, 2026
356a601
doc: add phase 7 task 5 for per-element GF mapping fix
bpowers May 20, 2026
6157354
engine: map per-element graphical functions by element name, not Arra…
bpowers May 20, 2026
01496d6
doc: phase 7 comparator -- :NA:-aware + near-zero-robust
bpowers May 20, 2026
8775ae9
engine: harden ensure_vdf_results -- AC8.2 guards + :NA:/near-zero co…
bpowers May 20, 2026
3eca135
engine: un-stub simulates_clearn -- residual excluded + tracked (AC8.…
bpowers May 20, 2026
80fd531
engine: commit clearn-residual exactness test; fix phase-7c review do…
bpowers May 20, 2026
9f9041f
doc: update engine context for element-cycle resolution
bpowers May 20, 2026
3c09683
doc: index element-cycle-resolution plan; test-requirements finalizat…
bpowers May 20, 2026
e3e4890
engine: note per-ident vs per-cell C-LEARN match rate (final review)
bpowers May 20, 2026
d7f8f13
docs: add test plan for element-cycle-resolution
bpowers May 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
- [test-requirements.md](implementation-plans/2026-04-05-server-rewrite/test-requirements.md) -- AC-to-test mapping for execution validation
- [implementation-plans/2026-05-13-macros/](implementation-plans/2026-05-13-macros/) -- 7-phase plan implementing Vensim `:MACRO:` support: datamodel/serialization foundation, MDL & XMILE import/export, compile-time expansion, multi-output materialization, and hero-corpus validation
- [test-requirements.md](implementation-plans/2026-05-13-macros/test-requirements.md) -- AC-to-test mapping for execution validation
- [implementation-plans/2026-05-18-element-cycle-resolution/](implementation-plans/2026-05-18-element-cycle-resolution/) -- 7-phase plan resolving element-level recurrence cycles so the C-LEARN hero model compiles via the incremental path, runs to FINAL TIME, and matches genuine Vensim within 1%: single/multi-variable SCC element-acyclicity resolution, synthetic-helper sourcing, VECTOR SORT ORDER/ELM MAP genuine semantics, the C-LEARN structural gate (plus a stack of unmasked assembly/import/`:NA:`/per-element-GF fixes), and numeric finalization
- [test-requirements.md](implementation-plans/2026-05-18-element-cycle-resolution/test-requirements.md) -- AC-to-test mapping for execution validation

## Security

Expand Down
581 changes: 581 additions & 0 deletions docs/design-plans/2026-05-18-element-cycle-resolution.md

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
# Element-Level Cycle Resolution — Phase 4 Implementation Plan

**Goal:** `VECTOR SORT ORDER` returns genuine-Vensim **0-based** permutation
indices (not 1-based); every fixture that encoded the 1-based bug is corrected
to genuine Vensim.

**Architecture:** A one-token VM fix (`i + 1` → `i`) plus comment correction,
then rewrite every Simlin-authored fixture/test that baked in the 1-based
output. This is a **purely numeric concern, independent of cycle resolution**
(`array_producing ∩ C-LEARN's cycle = ∅`), but it lies on C-LEARN's numeric
path (C-LEARN's target-sorting uses `VECTOR SORT ORDER`), so it is sequenced
before the C-LEARN numeric finalization.

**Tech Stack:** Rust (`simlin-engine`) `vm.rs` opcode, `array_tests.rs`,
`tests/compiler_vector.rs`, `.dat` fixture.

**Scope:** Phase 4 of 7. **Independent of Phases 1-3.**

**Codebase verified:** 2026-05-18 (branch `clearn-hero-model`). Genuine
0-based semantics confirmed by Ventana Systems' official Vensim documentation
(VECTOR SORT ORDER: "The returned vector contains the zero based index number
for the elements in sorted order") **and** by real Vensim DSS 7.3.4 reference
output `test/test-models/tests/vector_order/output.tab` (`SORT ORDER[*]` range
`0..n-1`, contains `0` — impossible for a 1-based permutation).

---

## Design deviations (verified — these override the design doc)

1. **The design's `array_tests.rs` module references are scrambled.** The
design lists "`vector_builtin_promotes_active_dim_ref_* ~4145`",
"`mod dimension_dependent_scalar_arg_tests ~4217`", "`mod
arrayed_except_hoisting_tests ~3984`". Verified reality:
- `vector_builtin_promotes_active_dim_ref_*` ARE at ~4145 but inside
`mod flag_split_tests` (declared `array_tests.rs:4086`).
- `mod dimension_dependent_scalar_arg_tests` is at `array_tests.rs:4217`
(correct).
- `mod arrayed_except_hoisting_tests` is at `array_tests.rs:3589` and has
**no** VSO assertion (it is VEM-only — Phase 5). The design's intended
target at ~3984 is actually `mod different_builtin_override_tests`
(declared `array_tests.rs:3976`), which asserts 1-based VSO at lines
`4010`/`4032`. Use `different_builtin_override_tests`; **drop**
`arrayed_except_hoisting_tests` from Phase 4 scope.
2. **`tests/compiler_vector.rs` is MISSING from the design's Phase 4
component list** and has **five** VSO tests asserting 1-based output that
will break under the 0-based fix. They MUST be corrected in Phase 4.
3. **`Opcode::Rank` (vm.rs ~2407-2450) is correctly 1-based** (genuine Vensim
`RANK` is 1-based, confirmed by the same `output.tab`) — it is a distinct
opcode; **do NOT touch it**.
4. **Ties:** Ventana docs are silent on `VECTOR SORT ORDER` tie-breaking
(sibling `VECTOR RANK` doc says ties are "arbitrary"). The current VM uses
Rust's stable `sort_by` (`vm.rs:2390-2398`), which is deterministic and
byte-stable — **keep stable sort** (satisfies the design's determinism
requirement; "consistent with genuine Vensim" = not contradicting any
documented behavior, since Vensim leaves ties unspecified).
5. **`vector_simple` is MDL-only** (`vector_simple.mdl` + `vector_simple.dat`;
no `.xmile`). `vector_simple.dat` is ASCII text (tab-separated
`time<TAB>value`, rows for t=0 and t=1) — the `Read` tool's binary
heuristic misfires on `.dat`; use `cat -A`/`od -c` to view, edit as text.
It is consumed by `simulates_vector_simple_mdl` (`tests/simulate.rs:767-770`,
NOT `#[ignore]`, NOT in any `TEST_MODELS` list) via `ensure_results`
(absolute eps `2e-3`); it currently **passes** only because the `.dat` was
hand-authored to the buggy 1-based values, so the VM fix and the `.dat`
rewrite must land together.

---

## Acceptance Criteria Coverage

### element-cycle-resolution.AC5: VECTOR SORT ORDER genuine Vensim semantics
- **element-cycle-resolution.AC5.1 Success:** `VECTOR SORT ORDER([2100,2010,2020], ascending)` yields the 0-based permutation `[1,2,0]` (matching genuine Vensim).
- **element-cycle-resolution.AC5.2 Success:** Descending direction yields the correct 0-based permutation; ties preserve stable order consistent with genuine Vensim.
- **element-cycle-resolution.AC5.3 Edge:** The Simlin-authored fixtures that encoded 1-based output (`array_tests.rs` cases, `vector_simple.dat` `l`/`m`) are corrected to genuine Vensim and pass.

---

## Testing conventions

TDD: correct the test's expected literals (the test IS the spec for the new
behavior) — write the corrected expectation, watch it fail against the
still-buggy VM, then apply the VM one-token fix and watch it pass. Unit tests:
`array_tests.rs` (declared `#[cfg(test)] mod array_tests;` in `lib.rs`) and
`tests/compiler_vector.rs` (`--features file_io` if required by that test
file). End-to-end: `tests/simulate.rs::simulates_vector_simple_mdl`. Verify
via `git commit` (pre-commit 180s cap, never `--no-verify`). All Phase 4 tests
are tiny — no `#[ignore]`.

---

<!-- START_TASK_1 -->
### Task 1: VM — `VECTOR SORT ORDER` emits 0-based indices

**Verifies:** element-cycle-resolution.AC5.1, element-cycle-resolution.AC5.2

**Files:**
- Modify: `src/simlin-engine/src/vm.rs:2386` (`indexed.push((val, i + 1));` → `indexed.push((val, i));`)
- Modify: `src/simlin-engine/src/vm.rs:2373` (comment `// Collect (value, 1-based-index) pairs` → 0-based)
- Modify: `src/simlin-engine/src/vm.rs:2358-2361` (replace the "intentional asymmetry" / "matches Vensim's VECTOR SORT ORDER semantics" comment with the correct 0-based semantics + citation)

**Implementation:**
- Change the single token at `vm.rs:2386`: `i + 1` → `i`. The loop variable
`i` (`vm.rs:2377`, `for i in 0..size`) is the 0-based element ordinal; the
result write at `vm.rs:2400-2402` (`temp_storage[temp_off + i] = orig_idx as f64`)
is a flat positional write unaffected by the value change.
- Direction handling (`vm.rs:2390-2398`: `direction == 1` ascending else
descending; Rust stable `sort_by`) is **already correct** — do not change.
- Rewrite the `vm.rs:2358-2361` comment to state the genuine semantics: VECTOR
SORT ORDER returns a 0-based permutation (position `i` holds the source
index of the `i`-th element in sorted order); `direction > 0` ascending,
otherwise descending; ties are stable (deterministic; Vensim leaves ties
unspecified). Cite the genuine-Vensim ground truth:
`test/test-models/tests/vector_order/output.tab` (real Vensim DSS 7.3.4,
`SORT ORDER[*]` range `0..n-1`) and Ventana's official VECTOR SORT ORDER
reference ("zero based index number ... in sorted order"). Note that prior
design docs `docs/design-plans/2026-02-27-vm-vector-ops.md` and
`2026-03-10-close-array-gaps.md:253` encoded the now-disproven 1-based
assumption and are superseded.

**Testing:**
This task's behavior is verified by Tasks 2-4 (they correct the expected
literals to 0-based and must pass once this token changes). No new VM unit
test is added here beyond what Tasks 2-4 already assert (the AC5.1/AC5.2
spec is exactly those expectations); adding a redundant VM-internal test
would test wiring, not behavior.

**Verification:**
Run: `cargo build -p simlin-engine` — compiles.
(Tasks 2-4 run the assertions; do not commit a known-red suite — sequence so
Task 1's token change and Tasks 2-4's expectation corrections are committed
together if pre-commit would otherwise be red. Practically: implement Tasks
1-4, then a single `git commit`.)
**Commit:** (folded into Task 4's commit — see note)
<!-- END_TASK_1 -->

<!-- START_TASK_2 -->
### Task 2: Correct `array_tests.rs` VSO expectations

**Verifies:** element-cycle-resolution.AC5.3, element-cycle-resolution.AC5.1, element-cycle-resolution.AC5.2

**Files:**
- Modify: `src/simlin-engine/src/array_tests.rs` — the following VSO-asserting cases (all currently 1-based):
- `mod flag_split_tests` (decl 4086): `vector_builtin_promotes_active_dim_ref_monolithic` (line `4155`: `&[2.0, 3.0, 1.0]`) and `vector_builtin_promotes_active_dim_ref_vm` (line `4166`: `&[2.0, 3.0, 1.0]`). Model `vals[DimA]=[30,10,20]`, `VECTOR SORT ORDER(vals,1)` (asc). Genuine 0-based ⇒ `&[1.0, 2.0, 0.0]`.
- `mod different_builtin_override_tests` (decl 3976): `different_builtin_override_monolithic` (line `4010`: `(vals[2] - 3.0).abs() < 1e-9`) and `different_builtin_override_vm` (line `4032`: same). `source[D]=[10,20,30]`, override elem "3" = `vector_sort_order(source[*],1)`. Genuine 0-based VSO of `[10,20,30]` asc = `[0,1,2]`, slot 2 ⇒ `2.0`. (Leave `vals[0]`/`vals[1]` — those are VEM defaults, Phase 5.)
- `mod dimension_dependent_scalar_arg_tests` (decl 4217): `assert_vso_dim_dep_results` (lines `4239`/`4244`/`4249`: `vals[0]==2.0`,`vals[1]==3.0`,`vals[2]==2.0`) → genuine `[1.0, 2.0, 1.0]`; `vso_nested_direction_varies_by_dimension_vm` (lines `4284`/`4289`/`4294`: `12.0`/`13.0`/`12.0`, model `10+vso`) → `[11.0,12.0,11.0]`; `vso_except_direction_varies_by_dimension_vm` (lines `4322`/`4335`: `vals[0]==2.0`,`vals[2]==2.0`; `vals[1]==999.0` override unchanged) → `vals[0]=1.0,vals[2]=1.0`. Update the explanatory comments (4224-4228, 4320, 4332-4333) to 0-based.

**Implementation:**
Recompute each expected literal as the genuine 0-based permutation per the
verified per-case derivations above (ascending: position `i` = source index
of the `i`-th smallest; descending: of the `i`-th largest; `dir > 0`
ascending, else descending). Update accompanying comments that narrate
"1-based"/"rank" to the 0-based gather semantics.

**Testing:** These corrected cases ARE the AC5.* spec; they must fail against
the pre-Task-1 VM and pass with the Task-1 token fix.

**Verification:** Run: `cargo test -p simlin-engine vector_builtin_promotes_active_dim_ref different_builtin_override dimension_dependent_scalar_arg` — pass (with Task 1 applied).
<!-- END_TASK_2 -->

<!-- START_TASK_3 -->
### Task 3: Correct `tests/compiler_vector.rs` VSO expectations

**Verifies:** element-cycle-resolution.AC5.3

**Files:**
- Modify: `src/simlin-engine/tests/compiler_vector.rs`:
- `vector_sort_order_a2a_produces_correct_results` (line `27`: `&[2.0, 3.0, 1.0]`) → `&[1.0, 2.0, 0.0]`
- `vector_sort_order_a2a_produces_correct_values_monolithic` (line `40`: `&[2.0, 3.0, 1.0]`) → `&[1.0, 2.0, 0.0]` (update comment line ~33)
- `vector_sort_order_a2a_produces_correct_values_vm` (line `50`: `&[2.0, 3.0, 1.0]`) → `&[1.0, 2.0, 0.0]`
- `nested_vector_sort_order_inside_sum_in_array_context_monolithic` (line `202`: `&[6.0, 6.0, 6.0]`) → `&[3.0, 3.0, 3.0]` (update comment line ~196: `SUM([1,2,0])=3`)
- `nested_vector_sort_order_inside_sum_in_array_context_vm` (line `212`: `&[6.0, 6.0, 6.0]`) → `&[3.0, 3.0, 3.0]`

**Implementation:**
All five use `vals[D]=[30,10,20]`, `VECTOR SORT ORDER(vals,1)` (asc) ⇒ genuine
0-based `[1,2,0]`; the two `SUM` cases sum that to `3.0`. Apply the literal +
comment corrections.

**Testing:** Corrected expectations are the spec; fail pre-Task-1, pass after.

**Verification:** Run: `cargo test -p simlin-engine --features file_io --test compiler_vector` — pass (with Task 1).
<!-- END_TASK_3 -->

<!-- START_TASK_4 -->
### Task 4: Correct `vector_simple.dat` `l`/`m` columns + commit Phase 4

**Verifies:** element-cycle-resolution.AC5.3, element-cycle-resolution.AC5.1, element-cycle-resolution.AC5.2

**Files:**
- Modify: `test/sdeverywhere/models/vector_simple/vector_simple.dat` — the `l` and `m` rows (both the t=0 and t=1 rows)

**Implementation:**
Model: `DimA: A1,A2,A3`; `h[DimA]=2100,2010,2020`;
`l[DimA]=VECTOR SORT ORDER(h[DimA],ASCENDING)` (`ASCENDING==1`);
`m[DimA]=VECTOR SORT ORDER(h[DimA],0)` (descending). Genuine 0-based:
- `l` (ascending of `[2100,2010,2020]`): sorted `2010(idx1),2020(idx2),2100(idx0)`
⇒ `l[a1]=1, l[a2]=2, l[a3]=0` (currently `2,3,1`).
- `m` (descending): `2100(idx0),2020(idx2),2010(idx1)` ⇒
`m[a1]=0, m[a2]=2, m[a3]=1` (currently `1,3,2`).
Rewrite **both** the t=0 and t=1 rows for `l[a1..a3]` and `m[a1..a3]`
identically (constant over time). Preserve the exact `.dat` tab/line format
(edit as text via `cat -A`/an editor; do not reformat other columns).

Then commit Phase 4 as one unit (Tasks 1-4 together — the VM token change and
all expectation/fixture corrections must land in the same commit so
pre-commit's `cargo test` is green):

**Verification:**
Run: `cargo test -p simlin-engine --features file_io simulates_vector_simple_mdl` — passes against corrected `.dat`.
Run: `git commit -m "engine: VECTOR SORT ORDER genuine Vensim 0-based indices (AC5)"`
— pre-commit runs fmt/clippy/`cargo test` (180s cap); all Phase 4 tests
(`array_tests` VSO cases, `compiler_vector` VSO tests, `simulates_vector_simple_mdl`)
green.

**Commit:** `engine: VECTOR SORT ORDER genuine Vensim 0-based indices (AC5)`
<!-- END_TASK_4 -->

---

## Phase 4 Done When

- `VECTOR SORT ORDER` emits 0-based permutation indices; `[2100,2010,2020]`
ascending ⇒ `[1,2,0]`, descending correct, ties stable (Task 1 — AC5.1,
AC5.2).
- Every Simlin-authored fixture that encoded 1-based output is corrected to
genuine Vensim and passes: `array_tests.rs` VSO cases,
`tests/compiler_vector.rs` VSO tests, `vector_simple.dat` `l`/`m` (Tasks
2-4 — AC5.3).
- `Opcode::Rank` untouched (genuine Vensim RANK is 1-based).
- Full engine suite green under the 3-minute `cargo test` pre-commit cap.
Loading
Loading