Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
# simlin-mcp's pysimlin_version_matches_latest_tag needs the
# pysimlin-v* tags (setuptools-scm makes the tag the version's
# source of truth); without them the guard skips on every run.
fetch-tags: true

- name: Install Rust toolchain
run: rustup show
Expand Down
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ This is the most expensive class of error in this repo, because review does not
- Public Rust items and non-trivial internal functions should have concise rustdoc describing purpose, key assumptions, and side effects.
- When behavior changes, update nearby comments in the same commit so docs and code stay aligned.
- If you intentionally remove a comment block, replace it with an updated equivalent when the context is still non-obvious.
- **Documentation is evergreen, NEVER a changelog.** Docs (CLAUDE.md files, `docs/`, rustdoc, docstrings) describe the current state of the code; they never narrate the edit that produced it. "X was removed", "this used to Y", "now does Z", "behaviour is unchanged" are all changelog sentences -- git history is the changelog, and readers dig there when they want it. When you delete or move something, rewrite the surrounding docs as if the code had always been this way. If the old design carried a lesson worth keeping, state it as a standing constraint ("never replace this alias with a second implementation: a hand-maintained copy drifts exactly where the real one is non-trivial"), not as a story about what happened. Citing a GH issue for a load-bearing decision is fine -- an issue number is a pointer, not a narrative.
- NEVER add a "Last updated" (or "Last verified") line to a `CLAUDE.md`: it is a perpetual rebase/merge-conflict magnet and goes stale immediately. Describe current state in prose; rely on `git log` / `git blame` for history.

## Development Standards
Expand Down
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions docs/design/ltm--loops-that-matter.md
Original file line number Diff line number Diff line change
Expand Up @@ -788,8 +788,8 @@ surfaces handle it differently:
from the engine primitive (bound as `Sim.get_loops_runtime` ->
`reclassify_loops_from_results`, GH #679/#685, the all-slots Rust source of
truth) and attaches the per-step relative-score series on top. There is no
separate Python slot-0 reclassification path. (`LoopPolarity.from_runtime_scores`
survives only as a standalone scalar-array convenience utility.)
Python-side reclassification: the classification rules live in exactly one
place, the Rust engine (`ltm/types.rs`).
- **libsimlin / WASM / TS `simlin_analyze_get_loops`**: **intentionally
structural-only**. The FFI takes only a `SimlinModel` (no simulation
`Results` in hand), folds `MostlyReinforcing`/`MostlyBalancing` to
Expand Down
155 changes: 139 additions & 16 deletions docs/sdai-model.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@
"items": {
"$ref": "#/$defs/View"
}
},
"loop_metadata": {
"type": "array",
"items": {
"$ref": "#/$defs/LoopMetadata"
}
}
},
"required": [
Expand Down Expand Up @@ -167,6 +173,14 @@
"type": "null"
}
]
},
"uid": {
"description": "Stable numeric identifier for this variable, used to track references\nfrom loop_metadata across file saves and reloads.",
"type": [
"integer",
"null"
],
"format": "int32"
}
},
"required": [
Expand Down Expand Up @@ -206,6 +220,14 @@
"type": "null"
}
]
},
"uid": {
"description": "Stable numeric identifier for this variable, used to track references\nfrom loop_metadata across file saves and reloads.",
"type": [
"integer",
"null"
],
"format": "int32"
}
},
"required": [
Expand Down Expand Up @@ -245,6 +267,14 @@
"type": "null"
}
]
},
"uid": {
"description": "Stable numeric identifier for this variable, used to track references\nfrom loop_metadata across file saves and reloads.",
"type": [
"integer",
"null"
],
"format": "int32"
}
},
"required": [
Expand Down Expand Up @@ -351,13 +381,19 @@
"kind": {
"type": "string"
},
"name": {
"type": [
"string",
"null"
]
},
"elements": {
"type": "array",
"items": {
"$ref": "#/$defs/ViewElement"
}
},
"view_box": {
"viewBox": {
"anyOf": [
{
"$ref": "#/$defs/Rect"
Expand All @@ -370,6 +406,9 @@
"zoom": {
"type": "number",
"format": "double"
},
"useLetteredPolarity": {
"type": "boolean"
}
},
"required": [
Expand Down Expand Up @@ -468,6 +507,19 @@
"required": [
"type"
]
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "group"
}
},
"$ref": "#/$defs/GroupViewElement",
"required": [
"type"
]
}
]
},
Expand All @@ -489,7 +541,7 @@
"type": "number",
"format": "double"
},
"label_side": {
"labelSide": {
"type": "string"
}
},
Expand All @@ -511,7 +563,7 @@
"type": "number",
"format": "double"
},
"attached_to_uid": {
"attachedToUid": {
"type": "integer",
"format": "int32"
}
Expand Down Expand Up @@ -539,7 +591,7 @@
"type": "number",
"format": "double"
},
"label_side": {
"labelSide": {
"type": "string"
},
"points": {
Expand Down Expand Up @@ -575,7 +627,7 @@
"type": "number",
"format": "double"
},
"label_side": {
"labelSide": {
"type": "string"
}
},
Expand All @@ -593,7 +645,7 @@
"type": "integer",
"format": "int32"
},
"flow_uid": {
"flowUid": {
"type": "integer",
"format": "int32"
},
Expand All @@ -608,7 +660,7 @@
},
"required": [
"uid",
"flow_uid",
"flowUid",
"x",
"y"
]
Expand Down Expand Up @@ -637,11 +689,11 @@
"type": "integer",
"format": "int32"
},
"from_uid": {
"fromUid": {
"type": "integer",
"format": "int32"
},
"to_uid": {
"toUid": {
"type": "integer",
"format": "int32"
},
Expand All @@ -652,17 +704,23 @@
],
"format": "double"
},
"multi_points": {
"multiPoints": {
"type": "array",
"items": {
"$ref": "#/$defs/LinkPoint"
}
},
"polarity": {
"type": [
"string",
"null"
]
}
},
"required": [
"uid",
"from_uid",
"to_uid"
"fromUid",
"toUid"
]
},
"ModuleViewElement": {
Expand All @@ -683,7 +741,7 @@
"type": "number",
"format": "double"
},
"label_side": {
"labelSide": {
"type": "string"
}
},
Expand All @@ -701,7 +759,7 @@
"type": "integer",
"format": "int32"
},
"alias_of_uid": {
"aliasOfUid": {
"type": "integer",
"format": "int32"
},
Expand All @@ -713,17 +771,57 @@
"type": "number",
"format": "double"
},
"label_side": {
"labelSide": {
"type": "string"
}
},
"required": [
"uid",
"alias_of_uid",
"aliasOfUid",
"x",
"y"
]
},
"GroupViewElement": {
"description": "Visual container for grouping related model elements.\nIn JSON (matching XMILE spec), x/y are top-left coordinates.",
"type": "object",
"properties": {
"uid": {
"type": "integer",
"format": "int32"
},
"name": {
"type": "string"
},
"x": {
"type": "number",
"format": "double"
},
"y": {
"type": "number",
"format": "double"
},
"width": {
"type": "number",
"format": "double"
},
"height": {
"type": "number",
"format": "double"
},
"isMdlViewMarker": {
"type": "boolean"
}
},
"required": [
"uid",
"name",
"x",
"y",
"width",
"height"
]
},
"Rect": {
"type": "object",
"properties": {
Expand All @@ -750,6 +848,31 @@
"width",
"height"
]
},
"LoopMetadata": {
"type": "object",
"properties": {
"uids": {
"type": "array",
"items": {
"type": "integer",
"format": "int32"
}
},
"deleted": {
"type": "boolean"
},
"name": {
"type": "string"
},
"description": {
"type": "string"
}
},
"required": [
"uids",
"name"
]
}
}
}
12 changes: 6 additions & 6 deletions docs/tech-debt.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,11 @@ Known debt items consolidated from CLAUDE.md files and codebase analysis. Each e

- **Component**: simlin-engine
- **Severity**: low
- **Description**: 49 `#[allow(dead_code)]` attributes across 24 files. Heaviest in bytecode.rs (8), expr3.rs (5), dimensions.rs (4), compiler/context.rs (3), test_common.rs (3). Remaining suppressions fall into three categories: (1) ByteCodeContext builder methods unused in production because ByteCodeCompiler builds tables directly, (2) expr3 variants and methods reserved for pass 2, (3) scaffolding types (DimensionRange, DimensionVec, StridedDimension) for future strided array views. The stale Opcode-level suppression and reachable dimensions.rs code were cleaned up in the close-array-gaps work.
- **Description**: `#[allow(dead_code)]` attributes scattered through simlin-engine. The count is dominated by the sixteen `SymbolicOpcode` variants codegen never constructs (superseded incremental view-stack/broadcast opcodes whose retirement -- together with their `Opcode` twins, VM arms, and wasm arms -- is sequenced as its own change; see symbolic.rs), plus expr3 variants and methods reserved for pass 2.
- **Measure**: `rg '#\[allow\(dead_code\)\]' --type rust src/simlin-engine/src/ -c`
- **Count**: 49 occurrences across 24 files (as of 2026-03-12)
- **Count**: 69 occurrences across 28 files (as of 2026-08-08)
- **Owner**: unassigned
- **Last reviewed**: 2026-03-12
- **Last reviewed**: 2026-08-08

### 13. Ignored Rust Tests

Expand Down Expand Up @@ -137,11 +137,11 @@ Known debt items consolidated from CLAUDE.md files and codebase analysis. Each e

- **Component**: simlin-engine, libsimlin
- **Severity**: low
- **Description**: 44 `eprintln!` calls in simlin-engine and 6 in libsimlin. In simlin-engine, 26 are in debug-gated functions (`debug_print_runlists` in interpreter.rs, `debug_print_bytecode` in vm.rs). The remaining 18 are runtime warnings in results.rs (unsupported sim methods), model.rs (compilation errors), and variable.rs. These should use proper error types or conditional logging rather than printing to stderr.
- **Description**: `eprintln!` calls in simlin-engine library code -- runtime warnings in results.rs (unsupported sim methods), model.rs (compilation errors), and variable.rs. These should use proper error types or conditional logging rather than printing to stderr. libsimlin has none.
- **Measure**: `rg 'eprintln!' --type rust src/simlin-engine/src/ src/libsimlin/src/ -c`
- **Count**: 44 in simlin-engine, 6 in libsimlin (as of 2026-02-15)
- **Count**: 18 in simlin-engine, 0 in libsimlin (as of 2026-08-08)
- **Owner**: unassigned
- **Last reviewed**: 2026-02-15
- **Last reviewed**: 2026-08-08

### 17. Embedded Error Fields on Variable/ModelStage Types

Expand Down
Loading
Loading