KB-7E85

O8E pre-production hardening (Contabo) — 05-f3-legb-verify-generalization-design

8 min read Revision 1
dieu44iu-cutterv0.6o8epre-production-hardening

O8E Report 05 — F3 LegB/Verify generalization design package (G5)

  • macro: v0.6-o8e-pre-production-hardening-bundle
  • date_utc: 2026-05-21 · host: Contabo vmi3080463
  • gate covered: G5 — F3 LegB/Verify generalization design
  • result: G5 PASS — implementation-ready design package (no code patched; Mac source work)

1. Current recorder assumptions — the N=60 / M1 pins

Inspected cutter_agent/ledger_v2_canonical_cut.py (LegBRecorder) and cutter_agent/ledger_v2_canonical_verify.py (VerifyRecorder). Both are single-use, frozen to the M1 Constitution cut. Pins found:

Pin Location Nature
PIN_CANDIDATE_COUNT = 60 ledger_v2_canonical_cut.py:65 (← prod_iu_adapter.PIN_CANDIDATE_COUNT) row-count, module-level
_require_list(live_state, k, 60) ×11 keys LegBRecorder.plan hard-asserts EVERY list is length 60
body_hash_match_60 literal key name in VerifyRecorder.REQUIRED_KEYS + both recorders' live_state dicts hardcoded 60 in an identifier
EXPECTED_SECTION_TYPE = {"principle":15,"section":3,"article":42} VerifyRecorder:185 (sums to 60) per-document histogram baked as a class constant
PIN_M1_CHANGE_SET_ID, PIN_M1_REVIEW_DECISION_ID, PIN_M1_MANIFEST_ENVELOPE_ID, PIN_M1_EXECUTOR_SIGNATURE_ID, PIN_M1_PAYLOAD_HASH ledger_v2_canonical_verify.py:101-105 hardcoded UUIDs of the one M1 cut
PIN_CUT_COMMITTED_AT, PIN_LEGB_COMMITTED_AT :76-77 hardcoded wall-clock timestamps
VerifyRecorder.plan_require_uuid(live_state,"change_set_id",PIN_M1_CHANGE_SET_ID) :204 hardest pin — refuses any change_set that is not M1

Consequence: VerifyRecorder will accept only the exact M1 Constitution cut. A cut of any other document — any change_set_id, any row count ≠ 60, any other section-type histogram — is rejected at plan(). LegBRecorder is length-pinned to 60. Neither can serve a second cut. This is why O8D correctly triaged F3 as not localised (it touches v0.5-ratified files).

Frozen regression anchor: the M1 Constitution cut's writer_digest is d99a31d4a4be907c510ae15965e9f7bb3387e9e28676e9f32adf463828b1aa28 (re-observed in the O8E test run) — it MUST stay byte-identical after generalization.

2. Implementation plan

2.1 Generic count — N becomes a per-run RunContext value

  • Delete PIN_CANDIDATE_COUNT as the source of truth for new runs. Add RunContext.candidate_count: int (set by the cutplan phase = len(cutplan_rows)).
  • LegBRecorder.plan / VerifyRecorder.plan take n from live_state["candidate_count"] instead of the module pin; _require_list(live_state, k, n) uses it.
  • Keep PIN_CANDIDATE_COUNT importable only as the frozen M1 regression constant used by test_ledger_v2_canonical_* — not by production paths.

2.2 Rename body_hash_match_60body_hash_match_count

  • Mechanical rename of the literal key in REQUIRED_KEYS, the live_state builders, and _require_int(live_state,"body_hash_match_count",n).
  • Update the v0.5 equivalence tests to the new key while keeping their expected value = 60 for the M1 fixture.

2.3 EXPECTED_SECTION_TYPE → per-document expectation

  • Remove the class constant. Add RunContext.expected_section_type: dict[str,int], derived by the cutplan phase from the actual cutplan rows (Counter(row.section_type for row in cutplan_rows)).
  • VerifyRecorder.plan validates section_type_cardinality against live_state["expected_section_type"] (must sum to candidate_count).

2.4 M1 identity pins → caller-supplied, not hardcoded

  • PIN_M1_* UUID/timestamp constants move into tests/fixtures/ as the M1 regression fixture. Production plan() reads change_set_id / review_decision_id / manifest_envelope_id / executor_signature_id from live_state and validates shape (_require_uuid = "is a UUID"), not equality to M1.
  • payload_hash becomes a computed value (already hashed from canonical JSON) — drop the equality-to-PIN_M1_PAYLOAD_HASH assertion for new runs.

2.5 Manifest linkage & verification-result linkage

  • manifest_envelope_id linkage: the leg-B writer emits the manifest; the verify writer must read it back from live_state, not assume M1's id.
  • verify_result rows link to change_set_id + review_decision_id of the current run (already parameter-shaped once 2.4 lands).
  • Generic idempotency keys: RunContext.idempotency_keys already exists per phase — leg-B / verify idempotency keys derive from sha256(change_set_id + phase_name), not from a 60-pinned digest.

2.6 Production governance_writer + verify_writer

Author the two injected collaborators the adapter expects (default = refuse):

def governance_writer(conn, ctx):   # → {manifest_envelope_id, executor_signature_id, governance_row_count}
    return LegBRecorder().record(conn, _live_state_from_ctx(ctx))
def verify_writer(conn, ctx):       # → {verify_result_id, verifier_signature_id}
    return VerifyRecorder().record(conn, _live_state_from_ctx(ctx))

_live_state_from_ctx builds live_state from RunContext.context_pins (counts, ids, section-type histogram) — fully per-run, no module pin.

3. Test matrix (for the implementing macro)

T1  M1 regression:    Constitution fixture (N=60) → writer_digest == d99a31d4… (frozen)
T2  generic N:        synthetic N=3 cut → plan() accepts, lists length-checked to 3
T3  section histogram: N=3 {article:2,section:1} → verify accepts; wrong histogram rejects
T4  non-M1 change_set: a fresh UUID change_set → plan() accepts (no M1 equality)
T5  idempotency:      re-run same change_set → LegBAlreadyRecorded / VerifyAlreadyRecorded
T6  fail-closed:      missing live_state key → LegB/VerifyLiveStateMismatch
T7  real-DB rollback: governance_writer + verify_writer driven rollback-only vs live DB

4. Constraints & honest scope note

  • These edits touch v0.5-ratified files (ledger_v2_canonical_*). Per the O8E G5 rule, no code was patched in this macro — this is a design package. It needs sovereign design ratification before implementation (the v0.5 ratification is being widened, not bypassed).
  • The M1 Constitution-cut equivalence (writer_digest d99a31d4…) is a frozen regression pin — generalization must not change M1's output.
  • Implementation is Mac source work (SSOT repo), bundled into the F3 implementation macro — see Report 09 §F3.

5. Verdict

recorder_pins_identified:  N=60 ×11 lists, body_hash_match_60, section histogram,
                           5 PIN_M1_* UUIDs, 2 timestamps, M1 change_set equality
generalization_plan:       6-part (count, key rename, histogram, identity pins,
                           manifest/verify linkage, production writers)
test_matrix:               7 tests incl. frozen M1 regression
code_patched:              NONE — design package only (needs sovereign ratify)
g5:                        PASS
Back to Knowledge Hub knowledge/dev/laws/dieu44-trien-khai/v0.6-o8e-pre-production-hardening-bundle/05-f3-legb-verify-generalization-design.md