Skip to content

feat(cache): composite topology cache key (Band 2) - #74

Open
tinix84 wants to merge 4 commits into
masterfrom
feat/band2-topology-cache-key
Open

feat(cache): composite topology cache key (Band 2)#74
tinix84 wants to merge 4 commits into
masterfrom
feat/band2-topology-cache-key

Conversation

@tinix84

@tinix84 tinix84 commented Aug 28, 2026

Copy link
Copy Markdown
Owner

Band 2 — the answer is cheap

Delivers the destination of the wayfinder map #30: a Cache Record is addressed by a Cache Key of four independent ids — topology_id, params_id, solver_id, environment_id — and a hit requires all four. Spec: #71 (tickets #72, #73). Decision: ADR-0010. Also closes the lifecycle track #45 by verification and carries the offline converter/MCP catalogue work that was staged on the Band 1 branch but not part of #70.

What changes for an engineer

  • A dragged component, a re-saved model, a reordered or re-routed wire, a renamed Goto/From tag, a CRLF/LF change or an annotation still hits.
  • A rewired terminal, a retyped or renamed component, a rebound parameter, a changed solver field, an edited initial state, or a different PLECS version misses — and SimulationCache.explain_miss() names which id differed.
  • The canonical Topology Document is persisted once per topology (<cache>/v2/topologies/<id>.json) and can be diffed; one rewiring diffs in a dozen pin-named lines.
  • The key never claims equality it cannot prove: unrecognised constructs degrade to normalized bytes per construct and are listed in the document's coverage; unparseable files degrade whole; an unknown PLECS environment disables caching with one warning instead of equating two unknowns.

Commits

  1. feat: add offline PLECS converter and typed MCP tool catalogue — the work that was staged on feat/band1-tas-studies when this session started (parser, mapper, SPICE/LTspice emitters, CLI, REST endpoint, typed MCP catalogue).
  2. fix(converter): keep brace-list values intact across wrapped lines — 4 of the 25 local corpus models did not parse.
  3. feat(cache): key Cache Records by topology, params, solver and PLECS version — canonicalizer, identity, v2 layout, plecs.version config, ADR-0010, CONTEXT.md terms.
  4. fix(cache): close review gaps in the canonicalizer's degrade path — findings from the two-axis /code-review.

Evidence

  • Invariance and sensitivity property tests over all 5 tracked models; Merkle/Goto paths on a synthetic fixture (tests/fixtures/subsystem_goto.plecs) because no tracked model has a subsystem.
  • 0 degraded regions on the tracked corpus; 1–18 ms per model (unreproducible local 25 included).
  • Gate: ruff, vulture, structure check, 188 passed / 1 skipped (tests/test_basic.py, tests/test_webgui.py fail to collect on the dev machine for pre-existing missing optional modules).

Still owed

🤖 Generated with Claude Code

Closes #20 — the converter spec is met by commits 1–2 above (Day-1 models, NIBB .cir, CLI, REST route, platform-independent tests).

tinix84 and others added 4 commits August 28, 2026 18:54
The converter parses .plecs schematic text into the Circuit Model and emits
SPICE .cir and LTspice .asc through one mapper, exposed as a CLI
(pyplecs-convert) and a REST endpoint. The MCP server replaces the
introspection-driven tool registry with a typed catalogue so tool schemas
are declared rather than guessed. CONTEXT.md gains the two MCP surface
terms the catalogue distinguishes.

Refs: #20, #49

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Scope Axis blocks write `Signals {"a", "b"}` and wrap long entries by
closing and reopening the quote on the next line, exactly like plain
strings. The parser tried to JSON-decode that continuation and failed on
the trailing brace, so 4 of the 25 local corpus models could not be parsed
at all. Brace lists now stay raw text and their quoted chunks are joined.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…version

The cache addressed a record by one digest of the model path, its bytes and
the runtime parameters, so a dragged component or a no-op re-save busted
every record while a PLECS upgrade silently served stale waveforms (library
Reference blocks never enter the file bytes).

A Cache Record is now addressed by four independent ids. The topology id
digests a persisted canonical document: nodes with parameter symbols, one
net set tagged electrical/signal, Goto/From collapsed into the wires they
stand for, subsystems as their own documents with the interface order in
the id. Cosmetics, declaration order, line endings and annotations cannot
reach it. The params id holds init-script bindings overridden by ModelVars,
the solver id every run-shaping top-level field, the environment id the
PLECS version resolved without starting PLECS. Anything the canonicalizer
does not recognise degrades to normalized bytes at the granularity of that
construct and is recorded in the document's coverage; an unknown PLECS
environment disables caching instead of equating two unknowns.

Records live under a v2 layout keyed by topology id first, with the
canonical document stored once per topology; explain_miss names the id
that differed. ADR-0010 records the decision and the two charting premises
the implementation overturned. The .gitignore rule for the runtime cache
directory is anchored to the repo root so pyplecs/cache/ modules are
tracked.

Refs: #30, #31, #32, #36, #37, #38, #39, #40, #41

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review of the composite key found four ways the canonicalizer could stay
silent where the governing invariant demands a miss: an unwired Goto was
collapsed with its Froms (inventing connectivity), a component without a
Name vanished without a trace, a non-local Goto was kept without a coverage
note, and a second degrade on one node overwrote the first and was never
counted. Each now degrades, is counted once, and is listed in coverage.

Also: the canonicalizer shares the parser's block accessor instead of
re-implementing it, the manifest carries the record id under one name
(no `simulation_hash` synonym, which CONTEXT.md lists under Avoid),
topology_document no longer fabricates an environment, explain_miss keeps
one shape, the cost test uses the ticket's 50 ms bound, and CONTEXT.md
keeps its alphabetical order.

Refs: #72, #73

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

feat: PLECS-to-netlist converter (.cir + .asc)

1 participant