Skip to content

Latest commit

 

History

History
174 lines (141 loc) · 46.2 KB

File metadata and controls

174 lines (141 loc) · 46.2 KB

Status (2026-06-22): Living backlog, headline refreshed. Kind: Descriptive (EV-ranked leak backlog vs LAWVM_PIPELINE_CONTRACT.md). Headline reclaimed: 10/10 waists now fully type-carried (StageResult endgame complete — superseded the earlier "~75% to contract / StageResult[T] realized nowhere (rank 12) / 10-of-10 waists mixed" framing; rank-12 RESOLVED, rank-11 RESOLVED-PARTIAL with §1.12 carve-out documented). Several older ranks (10, 17) already marked RESOLVED; re-score rank-11/12 deltas below before treating as open work queue.

Architecture Leak Ledger

EV-ranked backlog of representation/typing/authority leaks found by the e2e architecture-coherence audit (Pro-validated), measured against notes/LAWVM_PIPELINE_CONTRACT.md. This is the audit-and-enforce work queue Pro called for — not a rewrite plan. Each row resolves to a witnessed/typed object, never a silent path.

Headline. LawVM is 10/10 waists fully type-carried on the parts that matter most for trust (StageResult endgame complete; the earlier "~75% to contract / StageResult[T] realized nowhere (rank 12) / 10-of-10 waists mixed" framing is superseded). The authority firewall is structural (surface nodes default replay_authorized=False, assembler RAISES), manual claims cannot self-authorize, the evidence plane never promotes to replay authority (zero genuine silent authority-bleeds), conservation is honored across the core apply/elaborate path, guard-liveness is a first-class ratcheted harness, and the certificate writer emits the full checkable-leaf shape. Remaining gap is concentrated in three structural clusters, all audit-and-enforce, none requiring a rewrite:

  1. Certificate state-diff reach-back at the XML-flattened-None carve-out (rank 11, RESOLVED-PARTIAL) — typed-producer consumption shipped for receipts WITH source_anchor; the §1.12 carve-out (per notes/CERTIFICATE_SCHEMA_V0.md §10 step 4) remains for the common XML-flattened-None case where no source anchor is derivable.
  2. Live silent representation-regressions on the FI legal-state plane (ranks 1, 2, 3, 9, 15) — raw-text reach-back minting/dropping ops without a witness, the canonical Fable failure class.
  3. Coverage certificates exist but are detached from the live path (ranks 2, 8, 21) — materialize_pit discards the cert its _ex twin computes; LAWVM_PARSE_TOTALITY (the only silent-drop detector) is OFF by default; exports ship no coverage leaf.

Plus the one author-set authority leak at the fi_refs export (rank 4) — deterministic rows stamped replay_authorized=True/VERIFIED_MANUAL/SPAN_VERIFIED.

Boundary matrix: 10/10 waists now fully type-carried (StageResult endgame complete; this superseded the earlier mixed/none-type-carried state). Audit findings: representation_regression 4(0 high), untyped_boundary 5(1 high), filter_conservation 3(0 high), authority_bleed 7(0 high), guard_liveness 3(0 high).

witnessed_or_silentsilent_violation = no typed record (highest priority); needs_witness = firewalled-but-untyped; witnessed_ok = hardening target, recorded today.

# severity ev w/s leak class site fix
1 high high silent_violation representation_regression + silent_drop (legal-state plane) finland/kumotaan_replay.py:_inject_pure_kumotaan_repeal_ops + _inject_pure_kumotaan_subsection_repeal_ops (driver process_temporal_postprocessing.apply_kumotaan_replay_product_rewrites) Route both pure-injection and uncovered_kumotaan_recovery through ONE shared witnessed recovery helper: stamp every injected REPEAL op with a witness_rule_id (e.g. fi.recovery.pure_kumotaan_repeal) and emit a structured non-blocking Finding to findings_out (not the gated replay_print) recording that the repeal was reconstructed from raw johtolause because the typed pipeline produced no op. The witnessed sibling already proves the shape.
2 high high silent_violation representation_regression + silent_drop (legal-state plane) finland/replay_products.py:_drop_cited_version_item_ancestor_snapshots (~L1099-1149) + _cited_snapshot_materially_covers_current (80-char len delta) + materialize_pit call at L1770 Two coupled fixes: (a) replace the raw_text regex + irnode_to_text length-delta op-drop with a typed coverage comparison, and when an op IS dropped emit a TimelineIssue/Residual (no silent omission from filtered); (b) switch the dominant FI path from the raising materialize_pit to materialize_pit_ex and carry MaterializationResult.issues + MaterializationCertificate into ReplayProducts so the computed coverage account stops being thrown away.
3 high high needs_witness representation_regression (canonical_op / legal-state plane) finland/normalize.py:parse_ops_fallback_heuristic (+ extract*_fallback helpers, ~30 re.compile/search/findall over raw johto) Firewalled today only by strict_profile.allows_target_guessing (a profile flag, not a type) and stamped fallback_provenance. Convert the firewall to a type: gate this lane behind an explicit ExecutionAuthorization-shaped object and require it to emit a typed Finding per minted op; long-term migrate recognized shapes into the typed ResolvedSurfaceClause→ClauseAST owner so raw text stops being a semantic op producer.
4 high high silent_violation authority_bleed (projection plane) export_fi_refs.py:_DETERMINISTIC_ROW_EXTRAS / _augment_row Stop minting replay_authorized=True / review_status=VERIFIED_MANUAL / validator_status=SPAN_VERIFIED at projection time. Deterministic extraction is surface_only by construction (the graph plane already enforces this and RAISES). Either drop these fields from deterministic rows or rename them to surface-fact terms (e.g. deterministic_extraction=True) that carry no replay/review authority. Contradicts core/legal_surface_graph.py D7 and doctrine S8.
5 high high silent_violation silent_drop of accounting obligation (apply_receipt plane) apply_subsection_ops.py / apply_item_ops.py / apply_structure_ops.py (~76 tree_ops mutation sites vs 3 WriteReceipt sites) The mutation-boundary conservation account covers only a minority of writes (relabel/move/container). Make WriteReceipt+ObservedWriteAudit a structural product of the write primitive itself (wrap tops.replace_at/remove_at/insert_sorted so every landed write yields a receipt), and add a waist-level totality assertion that |receipts| == |landed writes|. This is the single weakest conservation point in the pipeline.
6 high high witnessed_ok silent_drop / passive-signal (apply_receipt plane) apply_resolved_op.py:531 observed_vs_declared_cross_check + mutation_accounting.py:535 + observed_write_audit status='violation' (all only logger.warning/serialize) Every accounting signal here is non-blocking: REPLAY_UNDECLARED_TREE_TOUCH, ObservedWriteAudit 'violation', WriteReceipt.divergence_explained=False all only warn or serialize. A receipt can truthfully record a bad/unexplained write and replay proceeds. Wire these into strict_profile so a 'violation'-status write trips a blocking Finding under strict mode (the guard-liveness fire-drills at rank 13 are the test counterpart).
7 high med silent_violation silent_drop (token_structure plane) xml_ingest.py:xml_to_ir_node child-loop else branch (~416-427) Unknown childless XML elements (or whose text collapses to '') are dropped with no residual, no ingest_observation, no coverage account; the structure-skeleton half has no totality/partition certificate. Emit a typed ingest_observation (family=source_pathology) for every dropped child and add a TokenPartitionCertificate over the structure side so a dropped source unit is visible.
8 high med silent_violation silent_drop / guard-not-live (token_structure + surface_syntax planes) finland/johtolause/api.py:parse_clause (LAWVM_PARSE_TOTALITY gate, ~586-604) + source_syntax_graph._emit_residual_nodes + token-tape side The ONLY detector of silent mid-stream token drops runs the totality predicate ONLY when LAWVM_PARSE_TOTALITY is set; OFF by default on the replay hot path because it doubles per-parse cost. The no-silent-drop guard is therefore not live in production. Either make it default-on (and pay/optimize the cost) or convert it from an ambient env flag to a typed policy argument folded into the cache key, and run it on a sampled production gate.
9 med high silent_violation representation_regression + silent_drop (canonical_op / legal-state) finland/normalize/effect_lowering.py:_extract_fi_date/_lower_voimaantulo/lower_johto_effects (temporal sub-lane) Re-greps raw MetaClause.raw_text/johto with date+sentence regexes to mint EffectIntents after the surface parse; lower_meta_clause returns None for unrecognized COMMENCEMENT shapes and unsupported_out capture is optional (caller must pass the sink) so the default path drops unmatched clauses silently. Make the unsupported sink non-optional and emit a typed residual for every unrecognized commencement/expiry shape.
10 RESOLVED high witnessed_ok untyped_boundary at authority boundary (legal-state plane) finland/apply_typed_dispatch.py:_new_pathologies_include_recovery_kind (recovery_kind/rebound_kind vocab in SourcePathology.detail) FIXED: recovery_kind/rebound_kind promoted to a closed RecoveryKind(StrEnum) (76 members) in core/recovery_kind.py; producer builder params and all producer sites typed/keyed on the enum; the apply-time allowance consumer keys on the enum and coerce_recovery_kind fails loud (UnregisteredRecoveryKind) on an unregistered string. Member values == prior strings (serialization-stable). Checkable producer-set==consumer-set test in tests/test_fi_recovery_kind_enum.py (no dead vocab, no bare-string producer). NB: the detail recovery_kind vocab is distinct from RECOVERY_AUTHORIZATION_RULES (which keys a separate projection-metadata vocabulary PARSE.*/APPLY.* consumed by recovery_temporal_proof_projector.py); the enum lives next to SourcePathology, not merged into that registry.
11 RESOLVED-PARTIAL med witnessed_ok representation_regression + untyped_boundary (certificate plane) — typed-producer consumption shipped for receipts WITH source_anchor; state-diff reach-back remains as the §1.12 carve-out for the common XML-flattened-None case tools/certificate_bundle.py:build_certificate_bundle (transition derivation loop) + orphaned core/certified_transition.py RESOLVED-PARTIAL: the certificate's central artifact now consumes the typed WriteReceipt→CertifiedTreeTransitionCore producer for receipts that carry a source_anchor (post-Wave-N3a+N3b); the diff-derivation reach-back is now scoped to the §1.12 carve-out for the common XML-flattened-None case (no source_anchor available — notes/CERTIFICATE_SCHEMA_V0.md §10 step 4 documents the residual). The producer is no longer "imported by nothing"; the historical orphan-tagging is reclaimed. Remaining work: tighten the carve-out where source anchors become derivable from later Wave replay state.
12 RESOLVED high witnessed_ok untyped_boundary / structural (all waists) — fully realized end-to-end StageResult[T] / PartitionResult realized as an actual return type across all 10 waists (core/stage_result.py + many consumers; the StageResult endgame reached 10/10 waists type-carried) RESOLVED. core/stage_result.py is the realized canonical carrier; the two seam conversions (apply-helper→WriteReceipt SEAM 1; FI frontend-parse→normalize_and_compile_ops SEAM 2) landed; rank-5 / rank-6 / rank-1/2/3/9 twin fixes inherited the typed carrier. StageResult adoption beyond the canonical seams remains incremental, NOT a mass migration, but the meta-leak (the value/evidence/residuals/findings/coverage/authority shape being convention-bridged at every boundary rather than type-carried) is closed: silent divergence is now a type error at every audit-coherence waist. The contract names the canonical types per waist; the migration target is fixed.
13 med high needs_witness guard-liveness debt (legal-state / apply) tests/test_fi_guard_liveness.py:NO_FIRE_DRILL_YET (REPLAY_SKIPPED_OP_MUTATED_TREE, REPLAY_FAILED_OP_MUTATED_TREE, REPLAY_MISSING_PRIMARY_TARGET_CONSUMPTION, REPLAY_APPLY_BOUNDARY_UNRESOLVED, REPLAY_APPLY_BOUNDARY_TOUCH_OUTSIDE_TARGET) Five hard_fail mutation-boundary codes have a fully-wired production emit (mutation_accounting.check_mutation_accounting → replay_findings._apply_mutation_boundary_violation_finding, blocking) but no fire-drill — the most safety-critical apply-boundary guards are unverified end-to-end. Add production fire-drills modeled on drill_replay_undeclared_tree_touch_apply_lane (run apply_ops_executor over a small renumber/replace op, patch the mutation-event stamping to leave a skipped/failed outcome with touched paths, assert the code reaches request.replay_findings as blocking) and move each from NO_FIRE_DRILL_YET to FIRE_DRILLS. Tracked debt, not silence.
14 med high silent_violation silent_drop / optional-sink (evidence/projection plane) finland/delegation.py:extract_delegations + extract_asetus_authority (diagnostics_out Optional=None, both production callers omit it) Filters return only list[kept]; rejected regex candidates + source pathologies route through Optional[diagnostics_out]=None which both production callers (tools/delegate.py, delegation_census.py) omit, so every false-positive rejection is computed and silently discarded. Change the return to PartitionResult/FilterResult[DelegationEdge] (accepted+rejected) so a caller cannot receive kept edges without the reject ledger; add a fire-drill driving a known false-positive through the production census path. Bounded to med because this extractor is demoted to cross-check (not the authoritative forward-grant source).
15 med med silent_violation representation_regression (legal-state plane) finland/process_temporal_postprocessing.py:apply_commencement_expiry_overrides (source_text_contains('voimaantulos')) + _content_is_editorial_repeal_notice ('kumottu' in irnode_to_text) Legal-state lifecycle decisions (expiry rewriting, repeal-placeholder restoration) gated on case-insensitive substring scans of plain/rendered text rather than typed temporal/commencement surface objects or the existing lawvm_repeal_placeholder attr. Replace with the typed markers; where a typed temporal surface does not yet exist, emit a witnessed Finding when the substring path fires.
16 med med witnessed_ok representation_regression + untyped_boundary (surface_families plane) finland/legal_surface/bundle.py:metadata['xml_bytes'] + lenses references.py/annotation_witness.py/definitions.py reaching back to re-parse raw AKN XML (the D4 Stage-1 bridge) The typed bundle already owns the body as raw_text/token_tape, yet these lenses reach back to an untyped metadata['xml_bytes'] dict to re-parse the lossier raw XML. Self-flagged temporary pending Phase-7 token_tape migration; fail-loud on miss (typed missing_xml_bytes residual) so contained. Complete the token_tape migration so the raw-XML view becomes a typed SourceSurfaceUnit field rather than a free-form dict channel. Not high because it is parser-input with a witnessed byte-origin span, not a semantic escape hatch.
17 med med witnessed_ok silent_drop (canonical_op plane) core/clause_ast.py:clause_ast_to_legal_ops (non-diagnostic variant at extract_legal_ops_from_parse_result) + lower_surface.py _lower_meta_clause/_lower_text_amend/_lower_valio_ref RESOLVED. extract_legal_ops_from_parse_result now routes through clause_ast_to_legal_ops_with_diagnostics and exposes a diagnostics_out accumulator; frontend_compile projects each ClauseAstLoweringDiagnostic into frontend_findings_out as a non-blocking LOWER.CLAUSE_AST_NODE_UNSUPPORTED_GENERIC_LOWERING observation. The lower_surface bridge gained a SurfaceLoweringResidual (kind LOWER.SURFACE_NODE_UNLOWERABLE_TO_PARSED_OP) emitted via residuals_out for SurfaceMetaClause/SurfaceTextAmend/SurfaceValiotsikkoRef/unresolved SurfaceBackRef. Ops are byte-identical to the silent variant (bench flat 97.74/99.67); only the already-dropped nodes gain a receipt.
18 med high silent_violation guard-liveness registry/producer mismatch (legal-state plane) core/observation_registry.py:FINDING_REGISTRY (TIME.SECTION_NO_TIMELINE / TIME.TIMELINE_NO_SECTION / TIME.CONTENT_DRIFT) vs tools/consistency.py:ConsistencyResult.to_phase_result Three codes registered hard_fail/violation (counted blocking) whose sole producer has zero callers in the compile/replay pipeline AND emits them role=observation/blocking=False. As blocking guards they are structurally unsatisfiable from production — a fire-drill could never satisfy them. Reconcile: either downgrade the registry entries to warn/info+observation (matching the only real producer) OR wire to_phase_result into a production verification lane emitting blocking findings + add a real fire-drill. Do not leave the contradiction.
19 med med silent_violation representation_regression + identity_positional (source_identity plane) finland/transparent_store.py:TransparentCorpusStore.read_source/read_oracle/read_amendment + source_model.py:AmendmentSourceModel.from_tree (source_ref=amendment id, source_bytes uncertified, no digest) Production source-identity entry returns bare bytes|None with no DigestWitness/SourceWitness/SourceLocator; AmendmentSourceModel (the carried source-identity object for the whole FI replay) has no intrinsic content digest, so downstream witnesses reconstruct identity from a name not a content hash. Compute artifact_digest sha256 at acquisition and bind it onto AmendmentSourceModel; re-bind a new digest after _apply_source_corrections (pre/post pair). The typed footing layer (core/source_witness.py, source_locator.py) already exists — it is just not produced here.
20 med med silent_violation identity_positional + silent_guess (token_structure plane) xml_ingest.py positional label assignment (~434-444) + _rehome_orphaned_letter_paragraphs / _absorb_orphaned_subsections / _merge_split_numbered_paragraph_continuations + core/ir_helpers.py:kind_for_tag (returns None on unknown tag) Unlabelled SUBSECTION/PARAGRAPH nodes get positional labels by enumeration order (the row-index anti-pattern, doctrine S8); structural-repair heuristics re-parent/merge tree shape on regex/letter-sequence guesses with no residual or finding; kind_for_tag returns None for unknown tags with no distinct diagnostic. Emit a typed Finding for every structural-repair mutation and a named diagnostic on unknown-tag; move toward intrinsic (non-positional) node identity.
21 med med silent_violation untyped_boundary + silent_drop (projection plane) export_fi_refs.py:_try_write_parquet (from_pylist schema inference on populated path) + export_parquet.py (dict rows, no coverage leaf, no .state.json at write) + union_ownership_census except Exception: continue Populated parquet path infers schema from dicts (only the empty path has the explicit 20-field schema) so a column drift produces a silently different schema not a type error; exports ship no coverage/verifier leaf; census driver swallows decode/classify failures with bare except:continue, understating the partition denominator with no skip count. Pin the explicit schema on the populated path, attach a projection_coverage leaf at write, and replace bare except with a counted residual.
22 med med silent_violation untyped_boundary at authority boundary (evidence→authority) core/adjudication_evidence.py:adjudication_record_diagnostic_detail / _adjudication_phase / _bool_detail (blocking default_blocking=True from untyped detail; phase by kind-substring match) The enforcement-significant blocking flag is read from untyped detail.get('blocking') defaulting True, and phase ownership is derived by substring/prefix matching on the kind string rather than typed provenance. Require a typed adjudication carrier with explicit blocking:bool (non-defaulting — fail loud if a blocking finding lacks disposition) and phase:Phase set by the emitter.
23 low med silent_violation silent_drop (source-acquisition / replay-plan) finland/amendment_selection.py:_read_amendment_candidates (corpus.read_source None → silent continue) When read_source returns None the candidate amendment is silently dropped via continue, unlike amendment_index.py which emits fi_amendment_index_source_vts_artifact_missing for the identical condition. A missing source becomes a silently shorter replay plan. Mirror the diagnostic: append a source_pathology record (add a residuals field to ApplicableAmendmentSelection) before continuing.
24 low med silent_violation representation_regression (evidence/diagnostic plane) finland/process_failed_op_governance.py:_governed (item_desc_re.match on FailedOp.description) + core/timeline_invariants.py:_typed_violation_from_address (str(address) then regex, when typed helper exists adjacent) Render-then-reparse roundtrips: FailedOp coordinates recovered by regexing the human-rendered description (no typed target_subsection/target_item fields); a typed LegalAddress stringified then regex-parsed when _section_label_from_address(address) is defined right below. Add typed target_subsection/item fields to FailedOp and call the typed address helper directly. Diagnostic-plane only, hence low.
25 low low witnessed_ok representation_regression (soft edge) + untyped_boundary (source_identity plane) finland/acquisition.py:should_use_sec1_fallback_post_routing / _extract_sec1_text / _extract_body_lead_text (OP_KEYWORDS raw-text op-verb scan to select operative lane) + SourceLaneSelectionEvidence flattened to dict In-plane today (source-plane lexical selection feeding the owning parser) but duplicates surface-grammar op-verb recognition in the source waist rather than delegating to a typed surface recognizer — the soft edge a forest/surface-flip must absorb; and the typed SourceLaneSelectionEvidence is built then flattened to dict[str,object] so consumers read an untyped boundary. Keep the dataclass as the emitted boundary; plan to delegate op-keyword recognition to the typed surface layer on the eventual flip.
26 low low witnessed_ok untyped_boundary + silent_drop (overlay plane) core/legal_surface_tokens.py:MorphOverlay/MorphAnnotation (absent==unknown contract by docstring only; no coverage account) + manual_claims/primitive.py target/value Tuple[Tuple[str,object]] + overlay waist no aggregate coverage cert The 'absent annotation == unknown, never no-lemma-exists' contract is convention-only with no coverage fingerprint, so a careless consumer can read absence as a negative fact; v2.2 claim payloads are untyped object tuples (mitigated by content-addressing + composer firewall). Add a typed coverage account to MorphOverlay (tokens-analyzed vs total + closed-vocab fingerprint). Honest-by-emptiness today, not honest-by-accounting. Best-disciplined waist overall — low priority.
27 low med witnessed_ok untyped_boundary adjacent to authority (multiple planes) core/execution_authorization.py:ExecutionAuthorization.detail (Mapping[str,Any]) + evidence_kernel.py Json=Any + finland/ops.py ScopeConfidence.is_explicit string-compares a Literal + compile_result._compiled_op_scope_witness string-branches an untyped row Hardening targets, not active leaks (witnessed/by-design): authority-surface detail is witness-only and drives no control flow; Json=Any disables checking on proof-verdict inputs (mitigated by closed-op-set fail-loud); ScopeConfidence Literal compared to bare strings (rename-unsafe); compile_result rebuilds a typed witness by untyped row-branching on a parity rail. Upgrade ScopeResolutionConfidence to StrEnum; constrain Json to a recursive JSON alias; document detail as read-as-witness-only. Keep the two-flag promotion + forbidden_shortcuts as the canonical authority waist.
28 RESOLVED high witnessed_ok silent_drop + untyped_boundary (§1.7 cross-act same-moment conflict resolution) — shared coverage present across EE/NO/EU/SE/NZ/US; UK preserved as effect-plane adapter core/cross_act_same_moment.py:detect_same_moment_conflict_groups_generic / detect_cross_act_same_moment_conflicts; op-ordering callers in EE/NO/EU/SE/NZ/US; UK delegates grouping through uk_legislation/ordering.py while preserving effect-id carriers (winner_effect_id, conflicting_effect_ids) RESOLVED: the iter2 H3 symptom "0 production callers of core/cross_act_same_moment.py" is closed across the same-moment frontends. EE retired its standalone detector; NO/EU/SE/NZ/US carry shared op-ordering coverage and production-path tests; UK uses the shared generic detector through an effect-plane adapter, preserving the effect-id vs op-id phase boundary pinned by tests/test_cross_jurisdiction_parity.py::test_same_moment_path_kinds_preserve_phase_boundary. Remaining work is stale-helper/prose cleanup and optional frontend-specific enrichment, not an active §1.7 last-wins silent risk.
29 high high silent_violation silent_drop (apply_receipt plane) + untyped_boundary (§1.6 unstated-migration, RENUMBER ops) — only SE + NO emit receipt-side migration_rule_ids EU/UK/US/NZ RENUMBER apply (no _eu_emit_one_op_receipt / _uk_emit_one_op_receipt / _us_emit_one_op_receipt / _nz_emit_one_op_receipt helpers; no eu_renumber_relabel / uk_renumber_relabel / us_renumber_relabel / nz_renumber_relabel registrations in tools/spec_ledger_*_catalog.py) versus the SE template at sweden/grafter.py:4157::_se_emit_one_op_receipt and NO template no_section_renumber_relabel Build per-op WriteReceipt helpers mirroring SE's _se_emit_one_op_receipt shape per-frontend and register the receipt-side migration_rule_ids stamp in the per-frontend spec-ledger catalog. B2-EU LANDED (9e50acc9: _eu_emit_one_op_receipt + eu_replay_write_receipts + emit_receipts param on apply_eu_ops_conserved + eu_renumber_relabel catalog registration); UK/US/NZ BLOCKED on D1's UKApplyResult/USApplyResult/NZApplyResult conserved wrapper system first (UK's procedural _apply_amendment_op does not yield per-op receipts). Without these, tools/certificate_bundle.py's §1.6 bound→landed divergence audit is structurally impossible for the 3 remaining RENUMBER-affected frontends (the audit fails open — no migration_rule_id to bind the receipt against the declared migration path).
30 med med silent_violation silent_drop (evidence-ledger reach gap) — production named_swallow primitive exists; per-op caller-context threading lags in EE + NZ EE + NZ conserved wrappers (estonia/grafter.py:apply_ee_ops, nz/...:apply_nz_ops) — emit log_emitter-only diagnostics at the swallow boundary because threading source-text + op_id context through the wrapping signatures has blast radius beyond iter4 W2's scope; the closed SE site threaded in W2 (sweden/grafter.py site now in tests/test_named_swallow_totality.py:_MIGRATED_FILES) iter4 W2 PARTIALLY CLOSED by threading the SE conserved wrapper's diagnostic-site through the named_swallow primitive (closes one of the two sweden/fetch.py:2729-kernel candidates per notes/DEFERRED_ROADMAP.md A3). REMAINING WORK: widen EE + NZ conserved wrappers to route through build_named_swallow_finding with op_id + truncated clause_text (~400 chars per §1.10) instead of log_emitter-only — blocked on signature blast radius across each apply-fold's call sites (D1/D2 dependency for UK/US/NZ wrappers). Pairs with notes/DEFERRED_ROADMAP.md A3.
31 RESOLVED med witnessed_ok silent_drop + weakest-contract drift (NO apply-raise, §1.10) — RESOLVED norway apply-raise site pre-iter4-W1 had a narrow except (covered only a pinned set of swallowing modes — TypeError, KeyError, AttributeError, etc.); the diagnostic was an unstructured string rather than a typed adjudication carrier, so coverage/accounting could not see it RESOLVED by iter4 W1 commit 3be460b9: the catch was widened to bare Exception (covers ALL §1.10 swallowing modes — the previous narrow set was a weakest-contract drift where a new swallowing mode silently fell through); AND the diagnostic was promoted to a typed no_replay_apply_raise adjudication registered in the spec-ledger catalog so it shows up in the producer-set==consumer-set coverage check. Live and blocking; tracked in tests/test_named_swallow_totality.py:_MIGRATED_FILES.
32 RESOLVED med witnessed_ok untyped_boundary (spec_ledger ratchet gap, §1.10) — RESOLVED tools/spec_ledger_catalog.py — the master catalog had gaps where some migration_rule_id values emitted by per-frontend conserved wrappers were NOT registered, so the typed producer-set==consumer-set check would have failed silent (a new migration_rule_id could land without a catalog row, no diagnostic) RESOLVED by iter4 W1 commit 6390038d: the missing catalog entries were added (one per migration_rule_id value minted by a frontend conserved wrapper). The ratchet is now closed: the producer-set==consumer-set check finds every emission site in the catalog, and a new migration_rule_id minted without a matching catalog row fails loud (AGENTS.md §1.10 fail-loud contract).

Enforcement: two CI gates (land first)

Pro Step-4: land these before chasing individual leaks, so the silent class cannot grow.

Gate 1

GATE 1 — Registered blocking finding requires a live production fire-drill (extends tests/test_fi_guard_liveness.py + core/observation_registry.py:FINDING_REGISTRY). Spec: a pytest gate that (a) computes BLOCKING = {code for code,spec in FINDING_REGISTRY.items() if spec.default_enforcement in BLOCKING_LEVELS}; (b) asserts BLOCKING == set(FIRE_DRILLS) | NO_FIRE_DRILL_YET (already the ratchet — keep it, it forces new blocking codes to land consciously); (c) NEW enforcement: convert the NO_FIRE_DRILL_YET allowlist from a frozenset into a registry of {code: (ticket_or_reason, last_reviewed_date)} and FAIL if any entry's last_reviewed is older than a window OR if the count exceeds a ratchet ceiling that only ever decreases (a monotone debt-burndown gate, so the allowlist cannot silently grow); (d) add a structural check that every FIRE_DRILL entry drives a PRODUCTION builder (assert the drill body imports/calls a finland.* or core.* production entrypoint, not only constructs a Finding and calls compute_verdict — distinguishing primary drills from the SECONDARY/verdict-mapping ones that must live in SECONDARY_FIRE_DRILLS); (e) add a registry/producer-consistency sub-check: for each blocking code, assert at least one production emit site exists (grep the code constant across src/lawvm/{core,finland} excluding tests) and FAIL on the TIME.SECTION_NO_TIMELINE-class mismatch where a blocking-registered code is emitted only role=observation/blocking=False or only off-pipeline. First conversions to land: the five REPLAY_*_MUTATED_TREE / APPLY_BOUNDARY codes (rank 13). This directly implements Pro Step-4 gate (a).

Gate 2

GATE 2 — No new post-parse raw-text semantic regex without a waiver/category (extends scripts/inventory_parser_smells.py + core/regex_recognition_coverage.py). Spec: turn the existing mechanical smell-inventory script into a CI ratchet. (a) Broaden DEFAULT_FILES from the current 8-file allowlist to ALL of src/lawvm/{core,finland} EXCEPT files explicitly classified as source-plane/lexer/owning-parser/diagnostic in a checked-in CATEGORY_MAP (so the legitimate lexical/owning-parser regexes from the representation_regression audit's NOT-findings list are pre-cleared by category, not by being outside the scan). (b) For every re.(search|finditer|findall|match) hit in a file categorized as a post-parse/semantic/replay/projection plane (canonical_op, legal-state, certificate, timeline), require either an inline category waiver comment (# lawvm-regex: <owning_parser|witness_only|diagnostic|prefilter|legacy_escape_hatch> + rationale) OR a registered RegexRecognitionCoverage row binding the recognizer to a typed coverage status. (c) Emit a per-file count and FAIL if the count of UN-waived semantic-plane regex hits increases over a committed baseline (.tmp or notes/ snapshot) — a monotone ratchet: the existing leaks (normalize.parse_ops_fallback_heuristic ~30 hits, kumotaan_replay, replay_products, effect_lowering) are baselined, but NO NEW ones may be added without a waiver category, and any reduction lowers the ratchet permanently. (d) Specifically flag any regex over raw_text/source_text/irnode_to_text/.description in a legal-state-plane file as category 'legacy_escape_hatch' (the highest-severity waiver, requiring a linked leak-ledger rank) so the rank-1/2/3/15 sites cannot be added to without explicit acknowledgement. This implements Pro Step-4 gate (b).

Seam conversions (highest risk deleted per unit work)

Seam 1

SEAM 1 (highest risk deleted) — apply-helper → WriteReceipt (apply_subsection_ops/apply_item_ops/apply_structure_ops, the ~76 tree_ops mutation sites). Convert the write primitive itself to return a StageResult-shaped WriteReceipt+ObservedWriteAudit so that mutating the legal-state tree without producing a conservation receipt becomes impossible by construction (you cannot call replace_at/remove_at/insert_sorted and get back a mutated tree without also getting the receipt). This deletes the single weakest conservation point in the pipeline (leak ranks 5+6): today 73 of 76 writes land un-audited and every audit signal is passive. It is also the prerequisite for fixing the certificate's central artifact (rank 11) — once apply emits real CertifiedTreeTransition-feeding receipts, the certificate stops re-deriving transitions by diffing materialized state. This is on the legal-state plane (plane C) where silent divergence is most consequential, so the type-enforcement yields the most risk reduction per unit of work. Wrap the three tree_ops primitives first, then make the receipts mandatory (non-Optional ApplyOpsSinks) so the opt-in-None path (rank 6 sub-case) is closed.

Seam 2

SEAM 2 (deletes a live legal-state representation-regression cluster) — FI frontend-parse → normalize_and_compile_ops (finland/normalize.py + the kumotaan/temporal post-processing seam). Convert the output of this seam to a PartitionResult/StageResult carrying {accepted ops, rejected-with-reason, residuals, findings, coverage} and route the raw-text fallback lanes (parse_ops_fallback_heuristic rank 3, _inject_pure_kumotaan_repeal_ops rank 1, the replay_products op-drops rank 2, effect_lowering rank 9) through it so that every op minted-from-raw-text or dropped-by-heuristic MUST carry a witness_rule_id + Finding to exist in the result. This is exactly Pro's named Fable failure class (raw text as semantic escape hatch on the replay plane) and the witnessed sibling uncovered_kumotaan_recovery already proves the target shape — so the conversion is low-design-risk and high-leverage: it turns four of the top-ranked silent legal-state leaks into first-class evidence objects in one structural move, and gives Gate 2 a concrete typed home (RegexRecognitionCoverage rows) for the baselined semantic regexes rather than leaving them as un-owned waivers forever.

Terminology note on "seam": the conversions catalogued above are waist conversions (upgrading a stage's typed input/output boundary to a StageResult-shaped carrier), not "seams" in the canonical consumer-contract sense (LAWVM_PIPELINE_CONTRACT.md: a seam is a stable downstream/interoperability contract over one or more waists). They are recorded here under the historical "seam" label; read them as waist-boundary conversions.

Deferred: terminology symbol renames & CI lints (open questions)

These are NOT to be done now — they are recorded as TODOs because each carries non-trivial churn or needs a migration plan, and the doc-only terminology reconciliation is deliberately landing first. Canonical vocabulary owner is notes/LAWVM_PIPELINE_CONTRACT.md; these renames would align code symbols to it.

Deferred symbol renames

  • core/authority.pycore/branch_authority.py — disambiguates branch/provenance authority from execution authority and the cross-plane firewall property. Deferred for the import-churn cost (every importer must update).
  • Leaf *Certificate*Coverage (e.g. TokenPartitionCertificate, MaterializationCertificate, CandidateSetCertificate) — reserve "certificate" for the top lawvm.certificate.v0 envelope + checker verdict; the per-waist leaves are coverage accounts. Needs a serialization-migration plan first: report-schema strings like lawvm.candidate_set_report.v1 and emitted root names are public/consumer-visible, so a rename must version-migrate them.
  • Reserve the word "certified" for cert-root-covered artifacts only; rename internal exporter success → exporter_invariants_passed (do not call exporter-invariant success "certified").
  • Namespace every bare status field (e.g. certificate_status, projection_status, resolution_status, authorization_status) so no public or cross-phase schema carries an unqualified status.
  • StageResult[T] adoption beyond the two seams above (rank-12, doc→code; now live in src/lawvm/core/stage_result.py with many consumers — the StageResult endgame reached 10/10 waists type-carried). Incremental, NOT a mass migration: adopt at the two seam conversions first, then extend stage-by-stage.
  • FilterResult/PartitionResult adoption at the remaining silent-drop sites, notably FI delegation (rank-14), so accepted/rejected-with-reason lanes are carried everywhere a filter today returns only the kept items.

Deferred CI-lint ideas (Pro §14)

  • Ban any NEW certified-family field unless it is certificate-root-related.
  • Ban a generic status field in a public schema without a namespace waiver.
  • Require every public schema to declare its plane and its seam/waist relation.
  • Require every projection to name its source dossier/root (or explicitly say "unchecked").

(The guard-liveness gate and the regex→recognizer ratchet already exist as Gate 1 / Gate 2 above; the lints here are the not-yet-built additions.)

§33 — core/ jurisdiction-neutrality audit (he_draft exemplar), 2026-07-10

Full audit of src/lawvm/core/ for jurisdiction-specific terms baked in as machine identifiers (enum/Literal values, source_role/status strings, rule-ids, error codes, field names, single-language structural-ontology regexes), per the §2.3 firewall. The user-flagged exemplar source_role="he_draft" (HE = Finnish hallituksen esitys) is neutralized end-to-end; the clear-cut small leaks are fixed; the larger relocations / persisted-contract renames are ledgered below.

Counts. REAL LEAK fixed: 3 core sites (2 = the he_draft exemplar, 1 = a stray fi_-prefixed rule-id). REAL LEAK ledgered (larger churn / persisted contract): 3 clusters. BENIGN (properly namespaced identifier, or an illustrative FI gloss in a comment/message framing a neutral concept — left as-is per policy): 7 categories.

The neutral role chosen for the exemplar: he_draftgovernment_proposal_draft (a Finnish HE luonnos, a draft SI, and a COM proposal all map onto it). Callers updated: 12 (core ×2, finland/source_document/lausuntopalvelu.py, tools/fi_he_branch.py, tools/fi_parse_compare.py, scripts/he_corpus_sweep.py, scripts/he_draft_materialize_report.py, and 6 test modules — all source_role value sites; the FI-frontend module finland/source_document/he_draft.py and its fetch_he_draft/extract_he_draft_proposal/HeDraftProposal names stay, being legitimately jurisdiction-specific and outside core/). No persisted parquet / baseline carried the he_draft value (the three ratchet baselines reference only the FI module path .../he_draft.py, which is unchanged). Regression guard added: tests/test_core_firewall_no_he_draft_source_role.py (AST zero-floor + liveness fire-drill), mirroring test_core_firewall_no_fi_definition_phrases.py.

# site (core) term class decision status
33.1 source_document/extraction.py:48 (SourceManifestation.source_role role docstring) he_draft REAL LEAK (source_role value in the neutral vocab) neutralize → government_proposal_draft FIXED
33.2 source_document/coverage.py:62 (ResidualFamily) HE_DRAFT_OP_SET_UNEXTRACTED = "he_draft.op_set_unextracted" REAL LEAK (enum member name + value; the "prefix names a format" docstring was untrue — HE is a role, not a format) rename member+value → GOVERNMENT_PROPOSAL_DRAFT_OP_SET_UNEXTRACTED = "government_proposal_draft.op_set_unextracted"; not referenced elsewhere FIXED
33.3 statute_validity.py:57 FIXED_TERM_WHOLE_STATUTE_RULE_ID = "fi_fixed_term_whole_statute_expiry" REAL LEAK (rule-id value with fi_ prefix on a jurisdiction-neutral concept — sunset/fixed-term whole-statute expiry exists in every jurisdiction) drop prefix → "fixed_term_whole_statute_expiry"; constant is unused (never imported; FI producers use their own finland/-local rule-ids), one test literal updated FIXED
33.4 ctsf.py:85 classifier_id="ctsf.momentti_ordinal_prefix" + _MOMENTTI_ORDINAL_PREFIX_RE; ctsf_rules.py:279 rule_id="ctsf.text.momentti_ordinal_elision" (+ momentti/kohta witness data); ctsf_gate.py:229 sid="ctsf_gate/momentti_ordinal" momentti/kohta structural-ontology regex + classifier/rule/gate ids REAL LEAK (FI single-language structural-ontology logic in core: a label-redundant-ordinal text rule keyed to the Finnish momentti unit) LEDGERED — relocate. The momentti-ordinal elision is FI-specific text logic misplaced in core. Plan: move the _MOMENTTI_ORDINAL_PREFIX_RE recognizer + the ctsf.text.momentti_ordinal_elision rule body into lawvm/finland/ (a finland/ctsf_fi_rules.py), and have core/ctsf_rules.py expose a neutral registration hook (a frontend supplies label-redundant-ordinal recognizers; core stays ontology-blind, mirroring the definition_introducer_predicate precedent). Blast radius: core/ctsf.py, core/ctsf_rules.py, core/ctsf_gate.py, semantic/diff.py, tools/spec_ledger_glue.py (the rule-id is a spec-ledger catalog row → needs a conscious catalog + baseline update), tests/test_ctsf*.py. Deferred as a giant risky refactor; at minimum the ids should be re-namespaced fi:ctsf.momentti_* when relocated. LEDGERED
33.5 manual_claims/primitive.py:49-50 (SourceWitnessType) FINLEX_AKN = "finlex_akn", FINLEX_CORRIGENDUM = "finlex_corrigendum" REAL LEAK (enum member+value; Finlex = the Finnish national legal database) LEDGERED — persisted contract. The value is a public parquet column (tools/export_fi_refs.py:249 writes source_witness_type=finlex_akn) and drives cross-witness precedence ordering (manual_claims/precedence.py, composer.py, source_provider.py). Neutralize to a role like NATIONAL_AUTHENTICATED_SOURCE / NATIONAL_CORRIGENDUM (a national gazette / authenticated-source witness), OR jurisdiction-namespace as fi:finlex-akn. Requires a serialization migration of the source_witness_type column + precedence table + the export_fi_refs schema. Deferred pending a migration plan (mirrors the deferred *Certificate*Coverage serialization-migration rule above). LEDGERED
33.6 compile_result.py:246 if code in {"EMPTY_OPERATIVE_BODY", "fi_amendment_selection_source_artifact_missing"} REAL LEAK (the neutral kernel branches on a FI-specific frontend code literal to pick the neutral-target construction path) LEDGERED — architectural. The fi_-prefixed code is itself the accepted jurisdiction-namespaced form (produced by finland/amendment_selection.py); the leak is core enumerating a frontend code. Plan: replace the hardcoded set with a typed signal on SourcePathology (e.g. a structural_target_optional: bool the emitter sets) so core routes on a neutral flag, not a frontend-code allowlist. Blast radius: core/compile_result.py, finland/amendment_selection.py, 3 tests. Deferred (design change to SourcePathology.from_internal_detail); bounded, low-severity (already namespaced). LEDGERED
33.7 claim_assumption_binding.py:865, claim_surface_manifest.py:625 ee_consolidation_candidate_is_flag_not_confirmed_error (+ siblings) BENIGN Properly ee_-namespaced binding-ids for a genuinely EE-unique v0 claim (Estonia consolidation-error candidates) — the accepted per-jurisdiction claim-register namespacing (like fi.frontend.<concept>). No change. NOTED
33.8 totalization.py:118,125 eu_replay_unknown_action, eu_replay_parent_not_found BENIGN Docstring illustration of the neutral totalization/θ-table model; the codes are emitted by the EU frontend, not core, and the passage frames SE/NO/EE/UK/EU together. No change. NOTED
33.9 cross_act_same_moment.py:105,1006 ee_replay_payload_after_eid BENIGN Comment/docstring illustration of "EE Pattern A" over the neutral generic same-moment detector. No change. NOTED
33.10 observation_registry.py (~15 finding messages) (fi: johtolause), voimaantulosäännös, (fi: säädöskokoelma) BENIGN The FI terms appear only in finding message strings as explicit fi:-prefixed glosses framing a neutral concept; every finding code key was verified neutral (no momentti/johtolause/etc. in any code). The correct neutral pattern. No change. NOTED
33.11 preparatory_reference.py:48,54,65-72 "Hallituksen esitys"/"lausunto" docstrings; EU_REGULATION/EU_DIRECTIVE/EU_DECISION values BENIGN Docstring glosses; the EU instrument-type enum values are genuine EU-legal-order concepts and appropriately EU_-namespaced. No change. NOTED
33.12 reference_mention.py, semantic_types.py (docstrings) momentti/kohta/alakohta/luku/pykälä BENIGN Docstring glosses explaining the neutral provision-path serialization; the serialized path tokens (ch/k/s) are neutral. No change. NOTED
33.13 claim_assumption_binding.py:221,643,649 momentti/kohta/alakohta/pykälä in scope/public_message prose BORDERLINE→BENIGN Illustrative FI-granularity examples in claim-register human text (not identifiers). Left per policy (prefer adding other-jurisdiction examples over renaming code for prose); a follow-up could add EE/UK granularity examples. No code change. NOTED

Cross-ref: the lawvm.finland.<module> owner=/checker_ref= literals in core/invariant_spec.py are already governed by the M13 §2.3 ratchet (tests/test_core_firewall_no_finland_module_paths.py) and are out of scope here.