- Every publish is a permanent immutable revision (manifestpublishedversions),
kept indefinitely; optional retention policy (keep last M / prune older than N)
deferred, default keep-everything.
- Draft edits are not versioned (working copy overwrites), so field-level "who
changed what between publishes" rides the existing core audit system - no new
table, shows in the Audit Logs UI IT already uses.
- Runbook: History tab for published versions + roll back; Audit Logs for draft
edit provenance.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add an execution plan and simplify the design for average-site-IT operability
(the governing constraint from the review):
Model simplifications:
- One wide manifestentries table with an entrytype discriminator, not SQLAlchemy
STI subclasses and not a JSON blob. ~64 total entries fleet-wide make sparse
columns free and keep rows readable in plain SQL.
- Published snapshots freeze the rendered JSON document in a single manifestjson
column; drop the row-mirrored manifestpublishedentries family. Immutability is
structural, rollback is a one-flag flip, diff is a text diff.
- New manifestpayloads table for inline bytes with a ~1 MB app cap.
- regvalue stores the raw JSON literal (DWord typing); applymode/updatewindow
flagged inert-in-engine so the UI labels them.
Execution plan (section 13):
- Phases P0-P6 with gates; parity harness spec (two checks, IT-readable output,
~16-18 machine-profile fixtures); first vertical slice through
gea-shopfloor-cmm; ranked fail-fast risks.
- Milestone 1 = author + publish in shopdb, export to the share by a button,
engine/dispatcher/PCs unchanged. Real pain relief at zero client risk, with a
rollback IT already knows (restore the _meta/history backup).
- Export-to-share promoted to a first-class feature and permanent break-glass.
- Split permission geenforce.manage (edit) vs geenforce.publish (ship).
- Move Up/Down instead of drag-and-drop; a "what would this PC get" simulator
endpoint + UI; three-increment editor build.
- Two-source pctypemap transition window; scope-inventory reconciliation
(gea-shopfloor-display has no share dir).
- Plain-English IT day-to-day runbook proving the design is manageable.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fold six review findings into docs/proposals/ge-enforce-plugin.md:
- Parity gate is behavioral equivalence, not byte-identity. Re-serialized JSON
differs in key order/whitespace/_comment formatting, so a raw diff never
converges; the test is same ordered entry set with identical detection/
targeting/action per entry.
- Dedicated payloadsha256 column, independent of detectionmethod. DetectionValue
is a SHA256 only for detectionmethod=Hash; MSIs with Registry/FileVersion
detection carry no payload hash, so an HTTP/inline fetch would otherwise run
unverified bytes. Client verifies fetched bytes against payloadsha256.
- Immutable published snapshots (manifestpublishedversions). Editing touches a
draft only; publish freezes a snapshot; the client is always served the latest
published snapshot, never the live draft; rollback republishes a prior
snapshot (the post-cutover safety net once the on-share JSON is retired).
- Scope uniqueness is (scopename, phase), not scopename alone; preinstall is one
flat scope gated internally by PCTypes, not per-pctype scopes.
- Alias graph: engine lib stays the single source of truth, shopdb only mirrors
it for validation; do not invert to engine-fetches-from-shopdb.
- Desired-vs-observed needs a new collector field (the installedVersions status
map), not existing data; flagged as a dependency.
Plus TLS trust for the SYSTEM-context client and importer skips .bak variants.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Metrology PCs (CMM, Keyence, Genspect, wax-and-trace imaging pc-types) drive
an attached measuring instrument. The PC itself stays a shopfloor PC, but the
collector now models the instrument:
- New METROLOGY_TOOL_MAP (pctypemap.py) maps those pc-types to a
MeasuringToolType (CMM, Vision System, Genspect, Form Tracer).
- ComputersPlugin._sync_measuringtool_link creates the MeasuringTool asset
once and a directional PC->tool "controls" relationship, tagged
collector:measuringtool. Idempotent (re-push reuses, no duplicate asset) and
self-archiving (a PC re-imaged to a non-metrology type deactivates the link
but keeps the asset and any calibration history). Mirrors the printer-link
pattern. The MeasuringToolType is created on demand if not seeded.
- 4 tests: create+link, idempotent re-push, non-metrology skip, repurpose
archives. Non-metrology PCs never warn about a missing controls type.
Settings rail cleanup:
- Collapsible groups so the 13-group rail fits without scrolling (1511px ->
488px). The group containing the current page expands; the rest collapse.
CSS-drawn caret (ASCII source, no Unicode). Empty groups never render, in
both the rail and the landing page.
- Measuring Tools group placed with the other asset groups (right after
Machines) instead of appended last; empty placeholder positions the
plugin-contributed cards.
- Operating Systems moved from PCs to General Reference: OS is cross-asset
(PCs, machines, measuring tools, network devices all run one).
Plus docs/proposals/ge-enforce-plugin.md: a planning doc for refactoring
GE-Enforce/DSC into a shopdb plugin (manifest as shopdb data, payloads on
SMB/HTTP/inline), grounded in the real manifest schema.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>