Skip to content

Lattice: read-only device map + producers + authority-ranked merge & resolve (conformance-pinned)#4147

Draft
mgazza wants to merge 14 commits into
mainfrom
lattice-pr5-merge
Draft

Lattice: read-only device map + producers + authority-ranked merge & resolve (conformance-pinned)#4147
mgazza wants to merge 14 commits into
mainfrom
lattice-pr5-merge

Conversation

@mgazza

@mgazza mgazza commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

Single consolidated draft for the Lattice work (supersedes the stacked drafts #4081 / #4082 / #4084 — closing those in favour of this one).

All read-only and flag-gated (lattice_projection_enable, default off) — no control, no behavioural change when disabled.

What's here

  • Device-mapping core (apps/predbat/lattice.py) — pure model + merge_fragments (union device map) + resolve_sensor. No PredBat/HA deps; unit-tested standalone.
  • Read-only producers — gateway, GE-Cloud, Fox, Solax, Solis each emit a Lattice fragment (device map + sensor inventory referencing existing entities) via device_fragment.
  • Projection (lattice_projection.py + lattice_component.py) — merges producer fragments into one site device map; flag-gated component + enable switch.
  • Authority-ranked merge (merge) — a pure mirror of the lattice-spec TypeScript reference (editor/src/merge-engine.ts): identity-keyed, authority/recency precedence, per-field/bag/wholesale/collection-union override, removal tombstones, synthetic provenance.
  • Cross-language conformance — the vendored conformance/merge/ corpus (apps/predbat/tests/lattice_merge_corpus/) + runner pins merge to the identical 13-case golden the lattice-spec TS reference passes. This makes batpred the first provably-identical second-language implementation of the merge contract.

Tests

apps/predbat/test_lattice.py + test_lattice_merge.py (18) + test_lattice_merge_corpus.py (13 subtests) — all green; pre-commit (interrogate/black/ruff/cspell) passing.

Spec & guide: Predictive-Cloud-Ltd/lattice-spec (schema, conformance/, IMPLEMENTING.md).

Draft — read-slice + merge layer; control is a separate, deferred model.


Update: resolve corpus adopted

Adds a pure resolve(doc, capability, side, intent, offline, altitude) to lattice.py, mirroring the lattice-spec reference (editor/src/resolve-engine.ts): read vs control routing, ranked access-path fallback, aggregate delegation/expansion, ownership, derived reads, and intent clamping. Vendors conformance/resolve/{cases,expected}.json (byte-identical) with a runner that asserts batpred == the reference on all 6 cases — making batpred a provably-identical second-language adopter of both merge and resolve.

mgazza and others added 11 commits June 19, 2026 08:10
…resolve)

Pure, dependency-free model: Fragment/Node/Sensor/AccessPath, merge_fragments (one node per
device by serial, ranked access paths, combined sensors), resolve_sensor (preferred entity), and
the device_fragment builder. READ-ONLY by design — control is a separate, deferred model.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
LatticeProjection discovers any component publishing a fragment, merges them into the site map,
and resolves a device's sensor to its preferred entity. LatticeComponent (registered, phase 2)
rebuilds + logs the merged map when lattice_projection_enable is on; no-op when off (default).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
GatewayMQTT.lattice_fragment maps each battery inverter it sees (identity + type) on a local-Modbus
access path and references the gateway sensor entities (soc/power/temperature) that already exist.
Read-only — no control.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tory)

GECloudDirect.lattice_fragment publishes its cloud-reachable devices (topology + soc/power sensor
inventory) on a low-preference cloud access path, so a device also seen by the gateway resolves to
the gateway entity. Read-only — no control.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
FoxAPI.lattice_fragment publishes its cloud devices (real deviceSN identity + soc/power sensor
inventory) on a cloud access path. Read-only — no control.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
SolaxAPI.lattice_fragment publishes its cloud plants (topology + soc sensor inventory) on a cloud
access path. Read-only — no control.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
SolisAPI.lattice_fragment publishes its cloud inverters (topology + soc/power sensor inventory) on
a cloud access path. Read-only — no control.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rence

Pure Python port of editor/src/merge-engine.ts: merge(docs) -> {"site", "warnings"}.
Operates on raw dicts (corpus wire shape); independent of existing dataclasses and
does not replace merge_fragments. 16 unit tests cover precedence, tombstones,
bag/wholesale/collection-union overrides, refs, docVersion digest, and errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tionship tombstone

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ases)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…iebreak)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a pure resolve(doc, capability, side, intent, offline, altitude) to lattice.py,
mirroring the lattice-spec reference (editor/src/resolve-engine.ts): read vs control
routing, ranked access-path fallback, aggregate delegation/expansion, ownership,
derived reads, and intent clamping. Returns the observable result dict.

Vendor conformance/resolve/{cases,expected}.json (byte-identical) + a runner that
projects the observable FIELD set and asserts batpred == the reference on all 6 cases.
This makes batpred a provably-identical second-language resolve adopter, alongside the
existing merge corpus.

Reviewed (sonnet) vs the TS line-by-line incl. branches the corpus doesn't cover; folded
in: JS-style number stringification in display labels (integer floats lose the trailing
.0, e.g. cap/2 label), nullish reducer default, and a NaN-intent guard.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mgazza mgazza changed the title Lattice: read-only device map + producers + authority-ranked merge (conformance-pinned) Lattice: read-only device map + producers + authority-ranked merge & resolve (conformance-pinned) Jun 29, 2026
mgazza and others added 2 commits June 30, 2026 08:21
Align the merge() site topologyVersion default with the frozen spec and the canonical TS
reference (merge-engine.ts) and the gateway merge_eval port. Only reached when an input doc
omits topologyVersion (the corpus always sets it, so all conformance cases are unaffected) —
this keeps the Python and C++ merge ports consistent on that fallback branch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mirror lattice-spec merge fix (PR #28): a tombstone is a barrier — when a node is re-added
above a removal, only contributors ranked strictly above the highest tombstone participate
in _merge_node, so sub-barrier (lower-authority) discovery data is not resurrected. Re-vendor
the 14-case conformance/merge corpus (adds the 'tombstone-barrier' golden) which verifies it.
13->14 corpus cases pass; all lattice tests green (32).

Co-Authored-By: Claude Opus 4.8 (1M context) <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.

1 participant