ORACLE / LII Governance — the enforced gates, with citations

Scope: Cells 33–36 (src/cells/cell33–cell36) and the shared package src/shared/mizoki_intent/. claim_label for the whole platform: built, pre-benchmark. Authority: CONSTITUTION.md (supreme), then TRUTH.md / AGENTS.md / OPERATING_SYSTEM.md / GOVERNANCE.md, then the plan of record docs/INTENT_API_PLATFORM_BLUEPRINT.md §8.

Every claim below names the file and line that enforces it. Where a gate is documented but not implemented in code, this document says so explicitly.


1. Absolute prohibition on audio-derived signals

Rule (blueprint §8.1): no microphone-, voice-, or speech-derived features in the taxonomy, ingestion, or models. Ever.

Enforced twice — and one of the two is a boot refusal.

Where the enforcement actually lives — and where it does NOT. The refusal is hand-rolled, not schematic. It is check_audio_prohibition / validate_signal_payload in src/shared/mizoki_intent/signal.py, plus the taxonomy loader's boot-time refusal, plus the ingest orchestrator's call ordering. Pydantic does not enforce it. CanonicalEventEnvelope.payload is declared payload: Dict[str, Any] = Field(default_factory=dict) (contracts/mizoki_contracts/envelope.py:78) — an unconstrained dict with no validator on it. The envelope's only @field_validator / @model_validator cover timestamp tz-awareness and bitemporal ordering (envelope.py:80-94); none of them look at signal_type. A future code path that constructs a CanonicalEventEnvelope directly, rather than going through build_intent_signal (signal.py:222-280) or the Cell 33 ingest route, would bypass the audio gate entirely. Today no such path exists in Cells 33–36; the constraint is that none may be added. Describing this rule as "rejected at Pydantic validation" is wrong and should not be repeated.

How much defense in depth there actually is — stated neither high nor low. On the write path there are two independent layers, not more:

  1. the explicit check_audio_prohibition calls (§(a)); and
  2. the taxonomy signal-type registry, made audio-free by the loader's boot refusal (§(b)).

These are genuinely independent, and that is worth recording precisely: with the explicit audio check disabled, an audio signal_type is still refused — it fails taxonomy.is_valid_signal_type and comes back as invalid_signal_type (signal.py:170-174), because no audio-family entry can be in the registry of a taxonomy that loaded at all. The second layer is real, not decorative.

What is not a third write-path layer: the three check_audio_prohibition call sites listed in §(a) are the same layer invoked on three construction paths. §(c) below is a genuine additional check but sits on the read path — it scrubs what is returned, and cannot stop anything being written.

(a) At request validation

check_audio_prohibition — src/shared/mizoki_intent/signal.py:83-100. Raises SignalValidationError("audio_signal_prohibited", …).

It runs first, before anything else, at the Cell 33 ingest boundary: src/cells/cell33/ingest_cell/orchestrator.py:218-219 — # 1. AUDIO GATE — absolute prohibition, before anything else. It therefore fires even for a signal that would have been dropped for lack of consent (proven by test_audio_rejected_even_without_consent, src/cells/cell33/tests/test_ingest_api.py:205).

It is called again inside the payload validator (signal.py:169) and once more in build_intent_signal (signal.py:261) — defense in depth on the three construction paths.

Coverage is the whole term family, not a prefix. The blueprint's stated minimum is ^audio; the implementation keeps that (AUDIO_SIGNAL_PATTERN, src/shared/mizoki_intent/taxonomy.py:41) and adds AUDIO_DENY_TERMS (taxonomy.py:42-45): audio, voice, speech, spoken, mic, microphone, utterance, asr, stt, wake word, sound recording, call recording. Matching is case-insensitive, word-boundary, after normalizing _ - / , . to spaces (taxonomy.py:83-89) — so voice_note_upload, ambient_audio_capture and speech_to_text all refuse. Terms of ≥ 4 characters are suffix-tolerant; shorter terms match exactly so mic cannot match michigan (taxonomy.py:94, 97-120).

(b) At taxonomy load — the service refuses to BOOT

load_taxonomy lints every entry of the signal_types registry and raises TaxonomyError("audio_signal_type_prohibited", …) on any audio-family hit — src/shared/mizoki_intent/taxonomy.py:299-307.

Serving cells construct the taxonomy at boot, so a taxonomy containing an audio signal type means the service does not start. This is deliberate and fail-closed (taxonomy.py:6-8, taxonomy.py:275-278).

(c) On the way out, too

Subject access re-checks: scrub_deny_listed calls audio_match on every stored record before returning it (src/shared/mizoki_intent/subject.py:267-270) — "a corrupt row naming an audio-derived signal type must not leave through subject access any more than it could enter."

Negative tests: test_audio_signal_rejected and test_audio_signal_rejected_case_insensitive (src/cells/cell33/tests/test_ingest_api.py:193, 199), test_voice_family_signal_rejected (:357), test_audio_signal_type_refuses_to_load and test_audio_family_signal_type_refuses_to_load (src/cells/cell33/tests/test_taxonomy.py:136, 148).


Rule: CONSTITUTION.md Art. II.6 — "Consent checks precede persistence for all behavioral micro-signals… Without intent_modeling consent, the signal is never persisted." Blueprint §8.2 adds: region defaults deny for EU/EEA/UK; denials are counted and payload-free.

Enforced: evaluate_consent — src/shared/mizoki_intent/signal.py:103-129.

Ordering at ingest (src/cells/cell33/ingest_cell/orchestrator.py:218-234): audio gate → consent gate → envelope → validate → persist. A consent denial is a processed outcome, not a 422: it is recorded in the denial counter and returns {"status": "denied", "reason", "region", "claim_label"} — the signal is never persisted.

Denials are payload-free. The counter records only {region, reason, source_system} (orchestrator.py:222-228), asserted by test_denial_record_values_sanitized (src/cells/cell33/tests/test_ingest_api.py:396).

The payload contract is closed. ALLOWED_PAYLOAD_KEYS / ALLOWED_CONSENT_KEYS (signal.py:42-46) reject unknown keys outright (signal.py:148-164), so nothing beyond the consent-gated §4.1 projection can ride into persistence, the outbox, or Pub/Sub — test_unexpected_payload_keys_rejected_and_never_published (test_ingest_api.py:326) and test_published_notification_is_projection_only (:343).

Negative tests: test_no_consent_dropped_and_counted (:117), test_consent_false_dropped (:136), test_eu_region_without_explicit_basis_dropped (:143), test_eu_region_with_explicit_consent_accepted (:163), test_unknown_region_treated_strictly (:172), test_noncanonical_eu_region_strings_stay_strict (:367), test_lenient_branch_only_for_wellformed_non_eu_codes (:384).


3. Sensitive-topic deny-list

Rule (blueprint §8.3): no intent categories over health/medical conditions, sexual orientation or life, religion, political affiliation or opinions, ethnicity, immigration status, financial distress/hardship, union membership, or anything concerning minors.

Built-in terms: BASE_DENY_TERMS — src/shared/mizoki_intent/taxonomy.py:49-71. The nine categories above are all represented in code.

YAML may EXTEND, never shrink. load_taxonomy composes the effective list as (*BASE_DENY_TERMS, *yaml deny_list) — taxonomy.py:286-290. The in-code list is always enforced; nothing in the YAML can remove a term. config/intent_taxonomy.yaml states the same rule in its header.

A topic must declare sensitive: false EXPLICITLY or the taxonomy refuses to load:

Because serving cells load the taxonomy at boot, either case means the service refuses to boot.

The deny-list is applied to more than the topic id. At load: topic_id, label, and description are all scanned (taxonomy.py:348-354), as is every signal_types entry (taxonomy.py:308-313). At write: Taxonomy.deny_match is checked on topic_id before the "is this topic known?" check, so a deny-listed topic is refused as deny-listed even though it could never be in a loadable taxonomy (src/shared/mizoki_intent/signal.py:180-186). At read: scrub_deny_listed (subject.py:244-282) drops any stored record whose topic_id, topic, signal_type, outcome_type or label matches, and reports a count only, never the matched term (subject.py:239-241, subject.py:556).

Deny lists over-block by design: ≥ 4-character terms are suffix-tolerant, so "teens", "childrens", "healthcare", "unionized" are caught by their stems (taxonomy.py:97-120). Normalization closes the health_insurance hole that a bare \bhealth\b would miss (taxonomy.py:16-19, 83-89).

Negative tests: test_sensitive_true_refuses_to_load (test_taxonomy.py:73), test_sensitive_missing_refuses_to_load (:82), test_deny_listed_topic_refuses_to_load (:95), test_deny_matches_through_underscores (:108), test_deny_listed_label_refuses_to_load (:123), test_deny_listed_signal_type_refuses_to_load (:165), test_plural_and_compound_deny_terms_refuse_to_load (:178), test_deny_listed_topic_rejected (test_ingest_api.py:215), test_access_can_never_return_a_deny_listed_topic (src/cells/cell34/tests/test_subject_rights.py:235).


4. Probabilistic identities are excluded from causal math

Rule (blueprint §8.4): Cell 36 admits deterministic identities only into treatment/control and outcome joins. There is no operator override (blueprint Appendix A.6).

Enforced at three points in Cell 36:

  1. Holdout assignment — src/cells/cell36/causal_cell/holdouts.py:255-268. An identity unit whose identity_kind != "deterministic" raises HoldoutError("non_deterministic_identity", …) and increments intent_holdout_rejections_total. Refused, not silently skipped.
  2. The causal join — src/cells/cell36/causal_cell/orchestrator.py:227-238. Score rows with a non-deterministic identity_kind are excluded and counted into excluded["probabilistic_identity"], which is reported in the incrementality report.
  3. Outcome ingestion — src/cells/cell36/causal_cell/storage.py:147-154. Only deterministic rows enter the estimator path; the rest increment intent_causal_outcomes_excluded_total{reason="probabilistic_identity"}.

Cohort activation refuses too: a probabilistic identity in the cohort is rejected (src/cells/cell36/causal_cell/activation.py:14, 75).

Probabilistic identities may still be scored. The gate governs what enters the incrementality denominator, not what may be scored or what a data subject may see about themselves — stated explicitly at src/cells/cell36/causal_cell/storage.py:184-190 and proven by test_probabilistic_identity_scores_allowed (src/cells/cell33/tests/test_ingest_api.py:87).

Negative tests: test_probabilistic_identity_refused (src/cells/cell36/tests/test_holdouts.py:89), test_probabilistic_scores_excluded_from_report and test_probabilistic_outcome_never_joins (src/cells/cell36/tests/test_causal_api.py:159, 179), test_probabilistic_identity_still_refused_after_erasure (src/cells/cell36/tests/test_subject_rights.py:288).


5. GDPR/CCPA subject access and erasure (CONSTITUTION Art. II.6)

Rule: CONSTITUTION.md:50 — "GDPR/CCPA subject access and erasure are honored immediately."

Status: implemented; BigQuery path live-verified 2026-08-10. As originally written this section said the streaming-buffer path was fault-injected in tests (src/cells/cell34/tests/test_subject_rights.py:83, 329, 469) and had never been observed against real BigQuery. That was true when written and is no longer: a full DSAR round-trip ran against production on 2026-08-10, observing a 409 pending_streaming_buffer and then a clean 200 with remaining_total: 0 after the buffer flushed (evidence: .claude/memory/inbox/2026-08.md; 39 rows in intent_erasure_audit). Claims in this section are otherwise still not live-verified.

Neo4j is a different case: retired, not merely unverified. The owner decided on 2026-08-09 that Neo4j is not being re-provisioned — the platform stays on Firestore as its knowledge-graph backend, and Cell 35 runs its in-memory graph permanently. No deployment sets NEO4J_URI, so _Neo4jBackend is never constructed and the live Cypher is unreachable dead code, not an untested risk awaiting a first run. See docs/lii/RUNBOOK.md §1 "Cell 35 graph backend".

No test executes either live backend path. Neither neo4j nor google-cloud-bigquery is installed in the environment these tests run in (both imports raise ModuleNotFoundError; verified 2026-08-09), and every live path is behind a lazy, function-local import taken only when a real client is present. Nothing under src/cells/cell33–cell36/tests/ references bq_select_subject_rows, bq_count_subject_rows, bq_delete_subject_rows, _count_subject_live, _causal_join_live or _Neo4jBackend (grep, zero hits). Concretely, these statements have never run, never been parsed at runtime, and never been type-checked against a live driver:

Live path Location Executed by a test?
BigQuery SELECT / COUNT / DELETE for a subject subject.py:469-537 No
Cell 36 holdout live subject count src/cells/cell36/causal_cell/holdouts.py:167-188 No
Cell 36 live causal join src/cells/cell36/causal_cell/storage.py:160-179 No
Neo4j DETACH DELETE of the subject subgraph — unreachable, see above src/cells/cell35/graph_cell/graph_store.py:500-507 No

Everything asserted about erasure below is verified against in-memory doubles only; the table records test coverage, not live status. Current status: BigQuery implemented, live-verified 2026-08-10; Neo4j retired — the branch cannot execute.

No vector index exists in this stack. External descriptions of the platform have said erasure "cascades BQ + Neo4j + vector index" (the skillpack line that carried this has since been corrected — skills/miz-oki-platform-expert/SKILL.md:1457-1458 now states the real legs). In Cells 33–36 and src/shared/mizoki_intent/ there is no vector index, vector store, or embedding of any kind — a case-insensitive grep for vector index|vector store|vector search|vector db|embedding|faiss|pinecone|weaviate| qdrant|milvus|chroma|pgvector across those paths returns zero hits (verified 2026-08-09). That limb of the cascade requirement is therefore not-applicable, NOT satisfied: the cascade covers the two stores that exist. Adding a vector index later REQUIRES extending the cascade — a new store needs its own erase_with_receipt call and its own receipt line, or erasure silently stops being complete.

The contract

Identical in all four cells (src/shared/mizoki_intent/subject.py:9-13):

GET    /v1/intent/subject/{identity_id}         -> everything THIS cell stores
DELETE /v1/intent/subject/{identity_id}         -> erase from THIS cell's stores
POST   /v1/intent/subject/{identity_id}:erase   -> CASCADE (Cell 34 only)

Access is deliberately not a fan-out — each store answers for itself so no cell can claim to speak for another's contents (src/cells/cell34/scoring_cell/orchestrator.py:581-586).

Erasure honesty is structural: count → delete → RE-COUNT

erase_with_receipt — src/shared/mizoki_intent/subject.py:133-201. The order is not negotiable and there is no path around it:

  1. count — a count that fails is failed (subject.py:157-161).
  2. delete — UNCONDITIONALLY. There is no before == 0 short-circuit: a zero pre-count does not skip the DML (subject.py:157-164). The code gives the reason (subject.py:148-155) — the count predicate and the store's real contents can diverge (a coerced tenant_id, a NULL key, a legacy row the WHERE clause misses), and short-circuiting would then report erased while the subject's row is still in the table. A BigQuery streaming-buffer refusal becomes pending_streaming_buffer with the surviving row count (subject.py:165-175); any other exception is failed (subject.py:176-180).
  3. RE-COUNT — UNCONDITIONALLY, including after a zero-row pre-count (subject.py:182-192): "the recount is what makes 'erased' a measurement rather than an assumption." If the recount itself fails, the receipt is failed with detail "delete issued but could not be verified". An erasure that cannot be verified is never claimed (subject.py:145-146).
  4. remaining > 0 → pending_streaming_buffer, never erased (subject.py:194-200).
  5. remaining == 0 → erased (subject.py:201). Every erased receipt — including the zero-count idempotent one — is therefore backed by a post-delete observation that returned 0. Erasing an unknown or already-erased identity is still a zero-count success and never a 404, because a 404 would leak whether an identity exists to anyone who can guess an id (subject.py:29-32); the difference is that the success is now measured rather than assumed. Cost: one extra idempotent DML per store per DSAR.

This is the guarantee subject.py:25-27 states, and it now holds without exception. An earlier revision of this document and of docs/lii/ADR-LII-001.md described a before == 0 branch that returned erased without issuing the delete and without recounting; that branch has been removed from the code and the description corrected.

Three statuses, never collapsed (subject.py:53-58); the overall status is the worst across stores (subject.py:204-221); only a fully verified erasure is 2xx — 200 / 409 / 502 (subject.py:64-71). A partial cascade is deliberately non-2xx so no caller can mistake an incomplete erasure for a completed one.

No receipts is a FAILURE, not a success. overall_status([]) returns failed (subject.py:204-221) — the fold's identity element would otherwise be erased, so an empty receipt list would have rendered as 200 erased: an erasure asserted across zero stores checked. erasure_response adds the detail "no store receipts — nothing was verified, so this erasure is unproven; no store was counted, deleted, or recounted" (subject.py:590-597). No current route can produce an empty list anyway — all four cells build fixed, non-empty receipt lists, and the cascade's _erase_peer returns a failed receipt on every non-answer rather than an empty list (src/cells/cell34/scoring_cell/orchestrator.py:701-760) — so this closed a latent contract defect, not a live one.

Erasure is a DELETE, not an UPDATE: bitemporal event columns are append-only facts and are never rewritten in place (AGENTS.md 6.2), so erasure removes the rows themselves (subject.py:511-522). SQL is parameterized and the one interpolated identifier — the subject key column — is constrained to a frozen allowlist ({identity_id, unit_id}, subject.py:449-457), because BigQuery cannot parameterize identifiers.

The audit cannot re-identify the subject

ErasureAuditLog (subject.py:332-442) writes a salted sha256 subject_ref, never the identity — "an erasure audit that stored the erased identifier would defeat the erasure it records" (subject.py:34-36, subject.py:312-323). The row schema is a hard allowlist re-applied in code (subject.py:342-345, 396) so nothing beyond it can ever be written. The BigQuery DDL says the same at src/cells/cell33/schema/intent_bigquery_ddl.sql:192-199.

Auditing never blocks the request path (subject.py:397-408): an insert failure is logged and swallowed; the receipt returned to the caller is the primary record.

Trust boundary on peer receipts

The cascade coordinator coerces any peer status outside the three known outcomes to failed — an unrecognized status is never counted as a completed erasure (src/cells/cell34/scoring_cell/orchestrator.py:664-687). An unconfigured or unreachable peer produces a failed receipt, never a skipped store (orchestrator.py:693-711).

Operator dependencies that are still OPEN

See docs/lii/RUNBOOK.md §0. Until INTENT_INGEST_URL and INTENT_CAUSAL_URL are set on Cell 34, a DSAR would not fully erase — the cascade honestly returns 502 with failed receipts for cells 33 and 36, and GET /health reports cascade_peers_configured so the condition is visible before a request arrives (orchestrator.py:818-825).


6. OBSERVE-ONLY posture and the promotion criteria

Rule: CONSTITUTION.md:74 (Art. III.6) — "LII/ORACLE outputs recommend by default. Promotion beyond observe-only requires Brier ≤ 0.20, AUC ≥ 0.72, and stable lift across ≥ 2 purchase cycles — and only via human approval. If Brier exceeds 0.20 after promotion, the output is demoted to observe-only and an incident is opened."

These are documented gates, NOT defaults. Verified by search (re-run 2026-08-09): across src/cells/cell33–cell36, src/shared/mizoki_intent/ and src/shared/miz_oki_source_of_truth.py, the literal 0.72 does not occur at all, and every occurrence of 0.20 is the top_k_pct cohort-size default — not a Brier threshold (src/cells/cell36/causal_cell/activation.py:42, causal_cell/orchestrator.py:336, causal_cell/main.py:187). Neither promotion criterion exists as a threshold constant anywhere in the intent code. Promotion is a human decision recorded against a signed phase exit (blueprint §9 / A.8), not a code path that flips when a metric crosses a line. Nothing in the repository can promote LII out of observe-only automatically.

What the code does enforce, structurally:

A promotion decision today would fail on its own evidence — see §7. The AUC gate (≥ 0.72) has one measurement on the only real corpus available, and that measurement is 0.5749 (verified result). It does not meet the criterion, and the criterion is not the failed gate — see §7 for the gate that actually failed.


7. The Phase A ranking gate: FAILED, and OPEN

Source of record: docs/reports/INTENT_PHASE_A_GATE_REPORT_2026-08-01.md. Elevated to binding case law by TRUTH.md Article 4.1.

The intent model FAILED its ranking gate on the real mycocoons corpus.

On the only real corpus available, a boosted-tree intent model does not beat a naive recency sort at predicting 30-day repeat purchase:

Figure Value Label
Eval AUC 0.5749 verified result
Model cumulative-gain area 0.5703 verified result
Naive-recency baseline gain area 0.7492 verified result

The baseline is a plain sort by days_since_last_signal ascending. The model loses to it. Gate state: FAILED.

Three attempts, constant protocol, then STOPPED (all verified results):

Attempt Config Eval AUC Model gain area Recency gain area
1 fv1 (5 features), unweighted 0.5749 0.5789 † 0.7414 †
2 fv1, auto_class_weights 0.5749 0.5454 † 0.7329 †
3 fv2 (9 RFM features), weighted 0.5749 0.5771 † 0.7436 †
3 (clean) fv2, weighted, deduplicated eval 0.5749 0.5703 0.7492

† Attempts 1–3 as first computed were contaminated by the calibration range-join row multiplication (defect 7 in the gate report) — eval rows were inflated roughly threefold. The clean deduplicated re-measurement (104,782 rows / 61 positives) reaches the same conclusion under the same protocol.

Protocol held constant throughout: identical corpus (383,582 examples, 655 positives — 0.17%), identical time split (most recent 20% of weekly cutoffs, 2022-01 → 2025-09), identical baseline.

Calibration — and the caveat that must travel with it. ECE 0.0006 / Brier 0.0006 (verified result, fv2, calibrated, deduplicated eval). TRUTH.md Article 4.4 binds the caveat to the number: at a ~0.06% eval base rate these are near-trivially small — the calibration is honest but weakly informative. The numbers are never to be quoted without that sentence. In particular, a Brier of 0.0006 is not evidence against the Art. III.6 promotion bar; a near-constant predictor at that base rate gets a small Brier for free.

Binding rule — TRUTH.md Article 4.1: no metric-chasing, no synthetic positives, no baseline weakening, no protocol change mid-eval; a failed gate is recorded as failed, and frozen-corpus evals are not re-run expecting different results.

The gate stays OPEN until live pre-purchase signals flow. The report's own interpretation (labeled there as assessment, not measurement) is that the corpus is order-anchored — the only behavioral signals are prior purchases and their acquisition context — so "bought recently" is close to the whole signal, and no GA4 raw export exists in the project. That is an explanation of the measurement, not a prediction that a rerun would pass. Nothing in this document should be read as implying the gate will pass later.

Phase A exit status: 5 of 7 gates closed, 1 failed (AUUC vs naive-recency baseline), 1 pending (cost actuals — needs a billing window). Phase A remains open in Shadow. Named-human sign-off on the report is still blank.


8. Language discipline (TRUTH.md Article 6) — binding on all LII copy

Say Never say
"anticipatory intent with proof of causal lift" "mind-reading" (6.1)
calibrated probabilities, with confidence and an explanation path "will buy" (6.2)
iROAS — the incrementality language of DECIDE platform ROAS standing in for an incremental figure (6.7)
labeled design targets targets presented as achieved, promised, or guaranteed (6.3)
"Preview · in development" for in-development capability described as deployed (6.4)
— any guaranteed outcome, in any copy, on any surface (6.5)

Every figure carries exactly one of the five labels — verified result | benchmark result | pilot result | design target | illustrative scenario — within two lines (TRUTH.md Article 2; enforced by tools/claims_lint.py).

The ceiling rule: the platform ceiling is "built, pre-benchmark". Status words are distinct and never upgraded: designed / implemented / configured / deployed-unverified / partially operational / live-verified / blocked.


9. What this document verified, and what it did not

Verified by reading the cited files: every line reference above; the constitutional text at CONSTITUTION.md:50, 74; TRUTH.md Articles 4.1, 4.4, 6; the gate report's figures; the absence of any Brier/AUC promotion threshold in intent code.

Re-verified 2026-08-09, after src/shared/mizoki_intent/subject.py changed. The before == 0 short-circuit in erase_with_receipt was removed and overall_status([]) was changed from erased to failed while this document was being reviewed. §5 was rewritten against the new file and every subject.py line citation in this document was recomputed — the change shifted them by roughly sixteen lines. Two claims that this document and docs/lii/ADR-LII-001.md previously made — that the pre-count-zero branch returned erased without a delete or recount, and that an empty receipt list rendered as 200 erased — describe code that no longer exists and have been corrected rather than carried forward.

Not verified when this record was written: any live runtime behavior. No service was called, no BigQuery query was run, no deployment state was inspected — gcloud was not available in that environment. Amended 2026-08-10: the subject-rights implementation against real BigQuery, streaming buffer included, has since been exercised end to end and is live-verified (see the status note in the subject-rights section). Cell 35's graph leg was exercised against its in-memory store; there is no Neo4j to verify against and, per the 2026-08-09 owner decision, there will not be.

SUPERSEDED 2026-08-10 — the streaming-buffer path is now live-verified. The paragraph above was accurate when written on 2026-08-09 and is kept rather than rewritten, because a dated verification record is evidence and editing it in place would destroy the audit trail. A full DSAR round-trip has since run against production: the cascade returned 8 receipts across all four cells covering all six identity-linked tables plus the graph, and answered HTTP 409 pending_streaming_buffer, remaining=1, retry_after_seconds=5400 for a row still held in the BigQuery streaming buffer — it did not claim erased. 13 audit rows landed under a salted subject_ref. Live governance probes returned 422 for audio (3 variants), 422 for a deny-listed topic, and consent fail-closed.

This is the single most load-bearing result in this document: the count → delete → recount contract was designed for exactly that condition, and it held on first contact with a real streaming buffer rather than reporting a false success.

Still NOT live-verified: the Neo4j Cypher erasure path (the platform stays on Firestore by owner decision, so it is inert rather than pending), and the correctness of the DSAR readiness probe's verdict.

Correction, 2026-08-10: an earlier revision of this line said the probe "has never been called". It has — three times on 2026-08-10, and those calls exposed a false blocked on the first (cold-start) call that no test would have caught. What remains unverified is narrower: no green run's legs have been checked one by one against the deployment's actual configuration. Detail and the operator consequence are in docs/lii/RUNBOOK.md, "Start here".

Verified absent, by grep, on 2026-08-09 (recorded because an absence is a claim too): no vector index / vector store / embedding anywhere in Cells 33–36 or src/shared/mizoki_intent/; no test anywhere under src/cells/cell33–cell36/tests/ that references the live BigQuery or Neo4j erasure helpers; neither neo4j nor google-cloud-bigquery importable in this environment.

← All docsView source on GitHub →