Skip to content

Benchtop Tool — capture and submit a lab witness against an energy summit

GFTCL-LION-ENERGY-LEDGER-001 / benchtop tool. The operator-facing or lab-facing workflow that lets an experimenter run an energy-summit protocol locally, lock the pre-registration at the moment the run starts, and submit a witness package to the cell. Two surfaces, one substrate: a headless CLI (M8BenchtopWitness) for lab-side / scripted use, and a co-resident SwiftUI sheet (BenchtopSessionSheet) attached to the summit cards in the workbench.

The integrity property the tool exists to enforce

A lab cannot retro-fit its pre-registration to its result. The substrate trigger trig_benchtop_preregistration_immutable refuses any UPDATE that touches preregistration_sha256, preregistration_at_iso, started_at_iso, or session_hash after a session is started. The pre-registration is locked at the call instant of startSession(…), and from there it is the ground truth the operator's verdict is graded against.

This is the same discipline the rest of the cell runs under (immutable witness columns on alert_queue / energy_ledger_receipts / summit_states), now applied to the lab-side capture surface. The benchtop tool structurally cannot let a lab cheat the pre-registration; the SQL layer refuses.

Two surfaces, one substrate

Surface When to use How
M8BenchtopWitness CLI Lab-side; headless; scriptable; CI/CD integration swift run M8BenchtopWitness <cmd> ...
BenchtopSessionSheet SwiftUI Operator-driven; co-resident on the energy summit cards Tap a NAMED OPEN summit card in EnergyDomainPanel

Both read and write the same benchtop_sessions table via BenchtopSessionStore. There is no second source of truth.

CLI workflow

# 1) List open summits
swift run M8BenchtopWitness list

# 2) Inspect a summit's pre-registered fields
swift run M8BenchtopWitness show --summit benchtop_divergence

# 3) Start a session (PRE-REGISTRATION LOCKED AT THIS INSTANT)
swift run M8BenchtopWitness start \
  --summit benchtop_divergence \
  --lab-identity "MIT-Plasma-Lab-2026" \
  --apparatus-id "rev-A-serial-0042" \
  --notes "blinded by independent witness Dr. X"
# → prints session_id (e.g., bts-B1E4AE91-...)

# 4) Record measured values (JSON file matching the predicted-values names)
swift run M8BenchtopWitness measure \
  --session-id bts-... \
  --measured ./measured.json

# 5) Mark ready to submit
swift run M8BenchtopWitness ready --session-id bts-...

# 6a) EITHER export the witness JSON for offline submission
swift run M8BenchtopWitness export --session-id bts-... > witness.json

# 6b) OR submit directly to the local endpoint
swift run M8BenchtopWitness submit \
  --session-id bts-... \
  --endpoint http://127.0.0.1:8423 \
  --membrane-token "$ENERGY_LAB_TOKEN"

# 7) Inspect a session at any time
swift run M8BenchtopWitness show --session-id bts-...

A measured.json file looks like:

[
  {"name": "thermal_suppression_pct",     "measured": 12.4, "instrument": "FLIR-T1020"},
  {"name": "clock_offset_slope",           "measured": 0.47, "instrument": "Microsemi-5071A"},
  {"name": "controls_match_classical",     "measured": true, "instrument": "calorimetry-baseline"}
]

The name field must match an entry in the summit's predicted_values_json (visible via show --summit <slug>). Free-form fields beyond the predicted set are allowed and preserved in the submission.

SwiftUI sheet workflow

In the workbench, EnergyDomainPanel shows the three energy summit cards. Tap any NAMED OPEN card → BenchtopSessionSheet opens with:

  • Read-only pre-registered prediction with the registration timestamp (immutable by trigger)
  • Success criterion and null-result clause displayed verbatim
  • Lab identity / apparatus ID / notes form fields (lockable on Save)
  • Measured values JSON editor
  • Action buttons:
  • Lock & Save Session → calls startSession(…) and captures the pre-registration anchor
  • Save Measured → calls updateMeasured(…) to persist the JSON in-progress
  • Export JSON → calls readyToSubmit(…) then renderSubmissionJSON(…); displays the witness package below
  • Submit Now → POSTs to /energy/summits/{slug}/witness with the operator-supplied membrane token; on 202 acceptance, the session flips to submitted (frozen by trigger)

Sheet is attached to EnergyDomainPanel via SwiftUI .sheet(item:), so it's modal but does not navigate away from the workbench — true to the co-resident HOME pattern.

Session lifecycle

   startSession()              updateMeasured()
        │                              │
        ▼                              ▼
┌───────────────┐  ────────►  ┌────────────────┐
│  in_progress  │  ──────────►│ ready_to_submit │
└───────┬───────┘             └────────┬────────┘
        │                              │
        │   POST /energy/...witness    │
        │   202 accepted               │
        ▼                              ▼
┌───────────────┐             ┌────────────────┐
│   abandoned   │             │    submitted   │  ← terminal, FROZEN by trigger
└───────────────┘             └────────────────┘
                                       │ on operator seal (sealed_confirm | sealed_refute)
                              ┌────────────────┐
                              │  summit status │
                              │  transitions   │
                              └────────────────┘

A submitted session row is frozen by trig_benchtop_terminal_frozen — no further UPDATEs accepted. The corresponding lab_submissions.submission_id links the two records; the operator's subsequent seal of the submission drives the summit_states.status transition (inReplicationclosedConfirmed | closedRefuted).

Substrate schema (V120)

CREATE TABLE benchtop_sessions (
  session_id                TEXT PRIMARY KEY,
  summit_id                 TEXT NOT NULL REFERENCES summit_states(summit_id),
  lab_identity              TEXT NOT NULL,
  apparatus_id              TEXT NOT NULL DEFAULT '',
  apparatus_calibration_json TEXT NOT NULL DEFAULT '{}',
  measured_values_json      TEXT NOT NULL DEFAULT '[]',
  preregistration_sha256    TEXT NOT NULL,              -- IMMUTABLE
  preregistration_at_iso    TEXT NOT NULL,              -- IMMUTABLE
  status                    TEXT NOT NULL DEFAULT 'in_progress',
  started_at_iso            TEXT NOT NULL,              -- IMMUTABLE
  last_updated_at_iso       TEXT NOT NULL,
  submitted_submission_id   TEXT,
  session_hash              TEXT NOT NULL,              -- IMMUTABLE
  notes                     TEXT NOT NULL DEFAULT '',
  timestamp_iso             TEXT NOT NULL,
  CHECK (status IN ('in_progress','ready_to_submit','submitted','abandoned'))
);

Two triggers enforce the discipline:

-- Pre-registration anchor + start time + session hash are immutable
CREATE TRIGGER trig_benchtop_preregistration_immutable BEFORE UPDATE ON benchtop_sessions
  ... RAISE(ABORT, 'benchtop_sessions pre-registration anchor is immutable');

-- A submitted session is fully frozen
CREATE TRIGGER trig_benchtop_terminal_frozen BEFORE UPDATE ON benchtop_sessions
  WHEN OLD.status = 'submitted' BEGIN
    RAISE(ABORT, 'benchtop_sessions terminal state submitted — row is frozen');
  END;

Verification (this commit)

The CLI has been exercised end-to-end against the live substrate:

  1. list enumerates the three energy summits.
  2. show --summit benchtop_divergence prints the pre-registered predicted-values schema.
  3. start locks the pre-registration anchor and prints the session_id + sha + timestamp.
  4. measure persists measured values from a JSON file.
  5. ready transitions the session to ready_to_submit.
  6. export prints the witness submission JSON to stdout (verified to include lab_identity, apparatus_id, measured_values, preregistration_sha256, preregistration_at_iso, session_hash, blinding_attestation).
  7. Retro-fit attempt REFUSED: UPDATE benchtop_sessions SET preregistration_sha256='tampered' produces Error: benchtop_sessions pre-registration anchor is immutable (19) — the trigger fires.

The SwiftUI sheet compiles clean and is wired to EnergyDomainPanel's summit cards via .sheet(item: $benchtopSummit).

Constitutional posture

  • One substrate, two surfaces — CLI and SwiftUI both read/write benchtop_sessions through BenchtopSessionStore. They cannot disagree because there is no second source of truth.
  • Pre-registration immutable by SQL trigger — the lab cannot retro-fit the prediction to the result. Refused at the database layer, not at the application layer.
  • No external dependency — the CLI uses URLSession to POST locally; the sheet uses the same. No HTTP framework, no auth service.
  • Membrane-token-gated submission — direct POST requires the lab's ENERGY_LAB_TOKEN value supplied via X-Gaia-Membrane header. Without it, the substrate rejects the submission with 401.
  • A null result is the protocol working — the sheet displays the null-result clause in the same visual weight as the success criterion. The lab_submissions.seal_state distinguishes sealed_confirm from sealed_refute; the summit transitions to closedConfirmed or closedRefuted accordingly, with equal weight on both publish paths.

What this tool is NOT

  • Not a calibration utility. Apparatus calibration is the lab's responsibility; the tool records the calibration manifest the lab supplies but does not certify it.
  • Not a grader. The operator (or a future automated grader) compares measured values against the success criterion + null-result clause to decide sealed_confirm or sealed_refute. The CLI / sheet records the witness; the seal is a separate operator action on lab_submissions.
  • Not an automation harness. The tool captures what the lab measured; running the apparatus, recording instrumentation, and aggregating raw data are out of scope — that's the lab's instrumentation stack.

Next moves (named)

  • Schema validation against predicted_values_json — currently the measured JSON is checked only for parseability. A v2 pass would enforce that every entry's name matches a predicted-values entry and that the measured value's type matches the predicted unit / shape.
  • Per-lab membrane token registry with revocation + audit — the v1 model uses a single ENERGY_LAB_TOKEN env var. v2 lands lab_credentials table with per-lab tokens, expiry, and revocation.
  • Operator seal workflow — a LabSubmissionSealSheet co-resident on the summit drill-in that lets the operator step through pending submissions and seal confirm or refute against the criterion. The substrate path is already in place via EnergySummitReader.transitionSummit(_:to:causedByRef:).

© 2026 Richard Gillespie. All rights reserved. USPTO patent applications 19/460,960 and 19/096,071.


Federation-cosigned

This page's source is sealed in the GaiaFTCL federation manifest — page SHA-256 97a595f9c179e770…, manifest witness a090592e0609adc8…, signed 2026-06-02T18:58:22Z by cell gaiaftcl-mac-cell. Verify with gaiaftcl wiki sign --all and compare wiki-all-signatures.json.