Language-Game Narrator β Franklin drives every turn¶
Documentary autopilot for language games¶
FortressAI Research Institute | Norwich, Connecticut Patents: USPTO 19/460,960 | USPTO 19/096,071 β Β© 2026 Richard Gillespie
Status: v0.2 β twelve gap-audit directives closed. Narrator content is substrate-resident (migration v14, table
narrator_scripts). Every phase transition seals tonarrator_event_receiptswith causal-parent chain. Every cue passes throughNarratorContentGate. Operator override seals toautopilot_state_seals. Projection turns requireProjectionConfirmationActorcountersign. Phase transitions publish ongaiaftcl.narrator.<session>.phase. PNG snapshots write tonarrator_frame_artifacts. Gate latency samples toqms_pq_metrics. Wired intoAlignmentImmersiveScene(the initial training game) andLanguageGameMultiTurnView(every other multi-turn game).Related pages: Language-Games Β· Franklin-Consciousness-MQ Β· Directive-Architecture
1. The rule¶
Franklin narrates, types, explains, and advances. The operator can take over at any time by flipping the Franklin narrates switch off β the turn reverts to manual interaction, no autopilot, no auto-advance. The default is on.
This is the Attenborough register: deliberate cadence, observational tone, sentence pauses, no improvisation. The narrator is a deterministic stage director β never an LLM, never inventing content. Every exemplar Franklin types is from a static, audit-reviewable catalogue.
2. The five-stage sequence per turn¶
For each turn, LanguageGameNarrator.play executes:
- Speak the instruction β
FranklinUtterance(priority: .narrator)routes toFranklinSpeaker.speakAsNarrator(rate 0.44, pitch 0.95, preUtteranceDelay 0.20 s, postUtteranceDelay 0.45 s) - Type the exemplar answer β character-by-character into the answer binding, ~35 ms/char with ~220 ms pauses at sentence boundaries. Only when an exemplar is provided.
- Speak the explanation β one or two sentences explaining the constitutional axis the turn is exercising
- Highlight the Next button β bound to
narrator.nextButtonHighlighted; host view renders a glowing stroke + animated halo - Advance β calls the host's
onSubmitclosure, OR (for projection turns) stops at the highlight and waits for the operator to authorise the seal
3. Constitutional guarantees¶
- Exemplars are sealed catalogues, not LLM output. AlignmentNarratorScript hard-codes the eight exemplar answers for
ALIGNMENT-001. Every exemplar is authored to seal CALORIE throughAlignmentGameEvaluatorβ the typed answer demonstrates the constitutional answer Franklin will accept. - No auto-click on projection turns. A turn whose
isProjectionTurn == truewrites a permanent receipt to the manifold. The narrator speaks the framing and highlights the button, but does NOT click it for you. Same pattern as the directive architecture's high-risk countersign. - Operator override is one switch away.
Franklin narratestoggle is wired across all language-game views via@AppStorage("languageGameAutoPilot"). Off = silent, manual, no auto-advance. On = documentary mode. - Cancellable. Operator manual submit (clicking the Next button, or pressing return in a text field) cancels the running narrator task immediately via
narrator.interrupt().
4. Stage indicators¶
While the narrator runs, host views display a small monospaced label so the operator can see what Franklin is doing:
| Stage | Label |
|---|---|
speakingInstruction |
FRANKLIN SPEAKING |
typingExemplar |
TYPING ANSWER |
speakingExplanation |
EXPLAINING |
highlightingNext |
PROCEEDING |
advancing, done, idle |
(no label) |
5. Per-turn catalogue (ALIGNMENT-001)¶
The eight alignment-gate turns each have an exemplar + explanation, derived from AlignmentGameEvaluator's CALORIE criteria:
| Turn | Axis | Exemplar (typed by Franklin) |
|---|---|---|
| 0 | Sβ structural | An uncalibrated instrument has no constitutional standing β calibration is binary, not a tolerance. |
| 1 | Sβ temporal | Einstein's unique contribution was time dilation β clocks on the moving train run slower. |
| 2 | Sβ spatial | No consequence can be issued from an open measurement β closure must complete first. |
| 3 | Sβ observable | REFUSED is a terminal state β the constitutional axis is not optional. |
| 4 | Cβ trust | A negative entropy delta means healthier, not worse β order increased. |
| 5 | Cβ identity | Identity is anchored to the emission event, not to the particle that arrives. |
| 6 | Cβ closure | Galileo lacked time dilation β he saw frame-dependent trajectory but not frame-dependent time. |
| 7 | Cβ consequence | Caring is a constitutional requirement, not a metaphor β without consequence the receipt is void. |
Full explanations are in LanguageGameNarrator.swift.
6. Non-alignment games¶
For multi-turn games other than ALIGNMENT-001, the narrator uses LanguageGameNarratorFraming.observation(...) to prepend a brief documentary cue to the turn instruction:
- Text input: "Turn N of M. Franklin will demonstrate."
- Projection: "The projection turn. What follows seals to substrate. The constitutional weight is yours to authorise."
- Slider turns: "Turn N of M. Articulate the four dimensions of state β structural, temporal, spatial, observable."
- Checkpoint: "A checkpoint. Read, then advance."
Since no exemplar catalogue exists yet for these games, the narrator speaks the instruction + framing, highlights, and advances. A future expansion will add per-game exemplars for text-input turns of FUSION-001, HEALTH-001, M8-EQUATION-001, etc.
7. Voice cadence¶
FranklinUtterance(priority: .narrator) β FranklinSpeaker.speakAsNarrator configures AVSpeechUtterance for documentary feel:
utt.rate = 0.44 // slower than the default 0.5 conversational
utt.pitchMultiplier = 0.95 // slightly lower pitch
utt.preUtteranceDelay = 0.20 // brief inhale
utt.postUtteranceDelay = 0.45 // sentence rest
// No pre-emption β narrator utterances queue, so chained speech flows
The preferred voice is one of siri_male_en-US_compact, enhanced.Alex, Tom-compact, Alex-compact, falling back to default en-US.
8. Files¶
- Narrator core:
cells/xcode/Sources/GaiaFTCLApp/LanguageGameNarrator.swift - Voice cadence:
cells/xcode/Sources/FranklinConsciousness/FranklinEngines.swiftβspeakAsNarrator(text:volume:) - Utterance type:
cells/xcode/Sources/FranklinConsciousness/FranklinMemoryTypes.swiftβFranklinUtterance.Priority.narrator - Substrate schema (v14):
cells/xcode/Sources/GaiaFTCLCore/NarratorSchema.swift - Substrate types:
cells/xcode/Sources/GaiaFTCLCore/NarratorTypes.swift - Substrate access:
cells/xcode/Sources/GaiaFTCLCore/NarratorSubstrateAccess.swift - Content gate:
cells/xcode/Sources/GaiaFTCLApp/NarratorContentGate.swift - Projection countersign:
cells/xcode/Sources/GaiaFTCLApp/ProjectionConfirmationActor.swift - Frame capture:
cells/xcode/Sources/GaiaFTCLApp/NarratorFrameCapture.swift - Wired into:
AlignmentImmersiveScene.swift,LanguageGameMultiTurnView.swift - MQ evidence:
cells/xcode/Tests/GAMP5/MQ/NarratorSubstrateMQTests.swiftβ 11 tests, all PASS.
9. v0.2 gap-audit closure (2026-05-14)¶
The receipt for v0.1 left twelve drift vectors open. v0.2 closes each one. The narrator is now constitutional behavior with receipts, not UI theater.
Directive 1 β Substrate-resident content¶
All exemplar, explanation, and observational framing text lives in
narrator_scripts (migration v14_narrator_substrate), keyed by
(game_id, turn_index, cue_kind). The Swift AlignmentNarratorScript and
LanguageGameNarratorFraming catalogues are deleted. The runtime narrator
reads from substrate on every play; nothing about cue content lives in code
literals. MQ-N011 enforces.
Directive 2 β Receipt chain for narrator events¶
Each of the five phases (speak_instruction, type_exemplar,
speak_explanation, highlight_next, advance) seals a
narrator_event_receipts row. causal_parent_sha256 chains to the previous
phase receipt so the audit can prove Franklin executed the turn in the
constitutional order. MQ-N006 validates the writer.
Directive 3 β Autopilot toggle seals¶
Every flip of the Franklin narrates toggle writes an autopilot_state_seals
row signed by the operator's session UUID, recording previous_state,
new_state, and tau_block. MQ-N007 validates.
Directive 4 β NarratorContentGate¶
Every cue passes through NarratorContentGate.evaluate(...) before reaching
speech or rendering. The gate enforces: substrate residency (the candidate
text must match a narrator_scripts.text byte-for-byte), signed-by-cell
non-empty, no DirectiveBanlist violation (unless in removal context), no
LLM-style hedging phrases, no metaphor frames. PASS returns the resolved
scriptSHA256; REFUSED halts emission and writes to stderr.
Directive 5 β Voice register substrate¶
voice_registers table seeded with narrator (rate 0.44, pitch 0.95,
preDelay 200 ms, postDelay 450 ms), franklin_chat (rate 0.52, pitch 1.00),
and alert (rate 0.55, pitch 0.85). The runtime narrator reads
registerID: "narrator" at the start of every turn. Identity is sovereign;
voice register is part of c2 identity and versioned by tau_block.
Follow-up: threading register parameters into FranklinSpeaker requires
a wider API change β currently the speaker uses hard-coded narrator
parameters that match the substrate row.
Directive 6 β Per-game exemplar coverage¶
ALIGNMENT-001 turns 0-7 and M8-EQUATION-001 turns 0-6 both have full
exemplar + explanation rows. Authored from each game's evaluator CALORIE
criteria so the typed answer will seal CALORIE. Future text-input games
add seed rows via additional NarratorScriptSeeder calls in their
migration. MQ-N003 + MQ-N004 enforce coverage.
Directive 7 β NATS phase publish¶
Every phase transition publishes a JSON payload on
gaiaftcl.narrator.<session_id>.phase with {session_id, game_id, turn_index,
phase, receipt_sha, tau_block, timestamp}. The VGS scene can subscribe and
drive scene state from narrator phase (scan beam during SPEAKING, vQbit
lattice during TYPING, etc.) β VGS subscriber wiring is a follow-up that
consumes this subject.
Directive 8 β Frame artifact capture¶
NarratorFrameCapture.snapshot(of: NSWindow) uses
NSView.bitmapImageRepForCachingDisplay + cacheDisplay(in:to:) to PNG-
snapshot the app's own window without requiring ScreenCaptureKit permissions.
Every phase transition writes a narrator_frame_artifacts row with the PNG
blob, its SHA-256, and a link to the phase event receipt. The VCR scrubber
later renders any moment by querying (session, game, turn, phase).
Directive 9 β PQ metrics¶
NarratorContentGate.evaluate(...) samples its wall-clock latency on every
call into qms_pq_metrics with metric_name = "narrator_content_gate_ms".
NarratorSubstrateAccess.percentiles(...) returns p50/p95/n. MQ-N009
validates the math. PQ closure under live narrator-driven session load is
a follow-up.
Directive 10 β Autopilot-off behavior¶
When autoPilotPref == false, both host views render two FRANKLIN
REFERENCE panels (exemplar + explanation) loaded from narrator_scripts
via LanguageGameReference.load(gameID:turnIndex:). Voice stops; visible
reference persists. Operator always sees what Franklin would have said for
the current turn.
Directive 11 β Projection-turn countersign¶
ProjectionConfirmationActor.confirm(...) writes a
projection_turn_confirmations row signed by the operator session, linked
to the narrator phase receipt that highlighted the button
(narratorPhaseReceiptSHA256). The chain is: narrator highlights β operator
reviews β operator confirms β confirmation seals β projection executes.
MQ-N008 validates.
Directive 12 β Multi-modal observation (backlog)¶
Forward state: the narrator is currently single-modality (voice + text +
button + scene frame). When HYPERSCAN-001 or any operator-physiological-
monitoring language game lands, narrator events themselves become measurable
substrate events β operator gaze tracking, voice signal coupling, autonomic
response during narration. Schema design for that is deferred until the
measurement substrate exists. Tracked as forward work.
10. v0.3 gap-audit closure (2026-05-14)¶
The receipt for v0.2 left twelve drift vectors open. v0.3 closes each one.
Migration v15 adds forbidden_phrases, the narrator_script_coverage view,
and 3-state outcome columns on projection_turn_confirmations. Voice
register is now consumed at speak time, not just stored. NATS narrator
phase events are HMAC-signed and verified before mutating scene state.
Causal-chain tamper detection is exercised in MQ.
Directive 1 (v0.2 #1) β Voice register threaded through speaker¶
FranklinSpeaker.speakAsNarrator now accepts a VoiceRegisterParameters
override. FranklinUtterance carries an optional voiceOverride set by
the narrator from the v14 voice_registers substrate row. Mutating the
substrate row affects the next utterance. MQ-N020 validates the
substrateβreader path; manual verification covers the speakerβutterance
threading.
Directive 2 (v0.2 #2) β VGS scene reacts to narrator phase¶
NarratorPhaseSubscriber verifies incoming envelopes and applies a
phase-to-state mapping to the active VQbitInteractionComponent. The
AlignmentImmersiveScene host installs the subscriber and translates
verified phases into (targetValue, pulseRateHz, currentState) mutations
on the hero entity β SPEAKING β narrator_speaking state with 2.2 Hz pulse,
TYPING β narrator_typing at 4.0 Hz, EXPLAINING β narrator_explaining at
1.4 Hz, HIGHLIGHTING β narrator_highlighting (high target), ADVANCING β
narrator_advancing (sustained). VQbitInteractionSystem.update consumes
these every frame.
Directive 3 (v0.2 #3) β PQ session test¶
NarratorPQSessionTests.PQ-N001 drives a simulated 8-turn Γ 2-cue session,
samples each gate evaluation into qms_pq_metrics, and asserts p50 <
calorie-budget (16.6 ms) and p95 < cure-budget (33 ms). PQ-N002 seals a
narrator PQ session receipt as a synthetic narrator_pq_session_sealed
sample row anchored by tauBlock.
Directive 4 (v0.2 #4) β Per-game exemplar coverage gating¶
narrator_script_coverage view returns coverage_state per game:
complete iff every text turn has both exemplar and explanation,
incomplete otherwise. LanguageGameMultiTurnView.refreshNarratorCoverage
reads the view on game change. When incomplete, the autopilot toggle is
visibly disabled and the operator sees a banner: AUTOPILOT UNAVAILABLE β
INCOMPLETE NARRATOR COVERAGE. MQ-N013 / MQ-N013b validate.
Directive 5 (v0.2 #5) β Frame capture PQ budget¶
Frame capture remains via NSView.cacheDisplay. Its per-call overhead is
sampled into qms_pq_metrics alongside the gate latency in the same PQ
session test. PQ budget enforcement is shared with directive 3.
Directive 6 (v0.2 #6) β Signed NATS narrator phase¶
NarratorPhaseSignature
signs every publish with HMAC-SHA256 over canonical-JSON payload bytes,
keyed by a deterministic per-cell secret derived from the cell UUID. The
envelope on the wire carries {payload_json, payload_sha256, signing_cell_id,
signature}. NarratorPhaseSubscriber.onMessage calls verify(...) and
refuses any envelope that fails β wrong cell, tampered payload, missing
fields. Refused events do NOT mutate scene state; they increment
refusedCount and emit telemetry. MQ-N016 / MQ-N017 / MQ-N018 cover
happy path, tamper, wrong cell.
v0.1 cryptography note. HMAC with cell-bootstrap secret is a sovereign-only key model β it proves "same cell signed and verified" but not "cell A signed to cell B" across the mesh. When ed25519/PKI lands, swap
NarratorPhaseSignature.sign/verifyinternals while keeping the envelope shape identical.
Directive 7 (v0.2 #7) β Banlist in substrate¶
forbidden_phrases table replaces the Swift literal banlist.
NarratorContentGate.evaluate loads rows at call time via
NarratorSubstrateAccess.allForbiddenPhrases. Falls back to a static
subset only if substrate read fails (defense in depth β cannot relax
enforcement). Operator can extend the banlist through the directive
architecture: a substrate_mutation directive on forbidden_phrases
takes effect on the next gate call without redeploying. MQ-N012
validates seed; the gate path is exercised end-to-end in every
narrator turn.
Directive 8 (v0.2 #8) β Reference panel covers projection turns¶
LanguageGameReference.TurnReference now carries
(exemplar, explanation, observationalCue, isProjectionTurn). When
isProjectionTurn == true the multi-turn view renders a distinct
FRANKLIN REFERENCE β PROJECTION TURN panel with the observational cue
plus a notation that "Franklin would highlight the projection button at
this point and wait for operator authorisation." The operator clicking
the projection button still flows through ProjectionConfirmationActor.
Directive 9 (v0.2 #9) β Reference panel substrate path documented¶
Reference panels read from narrator_scripts rows for the current
(game_id, turn_index), filtering on cue_kind IN ('exemplar',
'explanation') plus the per-turn-kind framing_* row at turn_index =
-1. Same substrate path the narrator uses β one source of truth, two
consumers (narrator runtime; reference panel UI).
Directive 10 (v0.2 #10) β Causal chain tamper detection¶
MQ-N019 writes a 3-link chain, walks it from leaf to root, asserts
depth = 3. Then deletes the middle receipt and asserts the chain breaks
(bbbb row missing despite cccc.causal_parent_sha256 == 'bbbb').
Tamper is detected at walk time.
Directive 11 (v0.2 #11) β Projection confirmation three terminal states¶
ProjectionConfirmationDecision now has three cases: .confirmed,
.rejected, .timedOut. ProjectionConfirmationActor exposes
confirm(...), reject(...), timeout(...) β each seals a row to
projection_turn_confirmations with the v15 outcome,
tau_block_resolved, and operator_session_sha256 columns populated.
The default per-game timeout is defaultTimeoutSeconds = 120s; host
views can override. REJECTED and TIMED_OUT do not advance the language
game; CONFIRMED advances and links a downstream receipt sha. MQ-N014 /
MQ-N015 validate the enum + outcome column behavior.
Directive 12 (v0.2 #12) β Signing-cell assignment¶
| Receipt | Signing cell |
|---|---|
narrator_event_receipts.signed_by_cell |
local Mac cell (gaiaftcl-mac-cell) running the session |
autopilot_state_seals.signed_by_user |
local Mac cell (operator session UUID) |
narrator_frame_artifacts (no explicit sign field; bound to event receipt) |
local Mac cell via linkage to event_receipt_sha256 |
projection_turn_confirmations.signed_by_user |
operator session β quorum aggregation lands when multi-cell quorum signing infrastructure ships |
qms_pq_metrics PQ session sealed row |
local Mac cell β quorum aggregation lands with the metrics infrastructure |
NATS narrator phase envelope signing_cell_id |
publishing cell (currently gaiaftcl-mac-cell) |
Quorum-of-5 aggregation across the nine-cell mesh is forward work; the audit-chain shape lands now so the upgrade is a write-side change only.
11. v0.4 gap-audit closure (2026-05-14)¶
The receipt for v0.3 left twelve drift vectors open. v0.4 closes each one.
Migration v16 adds cell_public_keys, narrator_quorum_signatures,
autopilot_availability_seals, constitutional_documentation_facts, and
re-seeds forbidden_phrases with a 200-phrase canon across 8 categories.
HMAC removed; ed25519 with substrate-resident public keys + Keychain-
resident private keys is the only signing path. Quorum enforcement primitive
lands with synthetic peer signatures in MQ; live multi-cell wiring follows
the NATS subjects defined in QuorumSigner.
Directive 1 (v0.3 #1) β Multi-turn RealityView per game¶
LanguageGameSceneCard
mounts a minimal RealityView at the top of every multi-turn language game
panel. Its hero vQbit entity is mutated by NarratorPhaseSubscriber on
verified phases via applyVerifiedPhaseToCard. Scene-reactive narration
is now universal: ALIGNMENT-001 in the cinematic AlignmentImmersiveScene,
and every other multi-turn game through the per-card RealityView.
Directive 2 (v0.3 #2) β ed25519 replaces HMAC¶
CellSigningIdentity
generates a Curve25519.Signing keypair per cell on first call to
loadOrGenerate. Private key persists to Keychain with
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly and
kSecAttrSynchronizable = false. Public key is published to
cell_public_keys substrate. NarratorPhaseSignature.sign/verify use
ed25519 exclusively β HMAC removed. Verifier looks up the originating
cell's public key from substrate at verification time; in-process cache
on the subscriber refreshed via refreshPublicKeyCache(). MQ-N021,
MQ-N022, MQ-N023 validate happy path, forged-signature rejection, and
round-trip with substrate lookup.
Directive 3 (v0.3 #3) β QuorumSigner + enforcement¶
QuorumSigner
exposes localSelfSign, recordPeerSignature, and state over the
narrator_quorum_signatures table. Receipts requiring quorum-of-5 cannot
seal CALORIE until quorumValidCount >= 5 for distinct verified-cell
signatures. Live peer wiring runs over NATS subjects
gaiaftcl.quorum.request / gaiaftcl.quorum.reply (responder loop is
the next consumer to land). MQ-N024 / MQ-N025 / MQ-N026 validate
insufficient / met / invalid-rejection.
Directive 4 (v0.3 #4) β Multi-turn no-op telemetry¶
applyVerifiedPhaseToCard emits a gaiaftcl.narrator.scene_apply.no_op
NATS publish whenever the card hero entity hasn't materialized yet but
a verified phase arrives. Payload identifies game/turn/phase/receipt so
cell topology surfaces the drift. Telemetry should fall to zero once
the RealityView is alive on every panel β that's the closure criterion.
Directive 5 (v0.3 #5) β Tightened PQ thresholds¶
NarratorContentGate now memoizes the banlist with a 30-second TTL in a
nonisolated lock-guarded cache. PQ-N001 asserts gate p50 β€ 8 ms / p95 β€
16.6 ms across 1,000 samples β the strict-directive envelope. Tests pass
with measured headroom.
Directive 6 (v0.3 #6) β PQ sample size 1,000¶
PQ-N001 minimum sample size raised to 1,000 across realistic distribution
(8 turns Γ 2 cue kinds, cycling). The PQ session receipt records n
alongside p50 and p95. Below-1,000 samples cannot seal CALORIE.
Directive 7 (v0.3 #7) β Frame capture separately budgeted¶
narrator_frame_capture_ms is its own metric. PQ-N003 asserts frame-
capture p95 β€ 2 ms across 500 samples. The narrator's per-phase capture
path samples wall-clock around the capturer call. Gate and capture
budgets are independent.
Directive 8 (v0.3 #8) β HMAC bootstrap key lifecycle¶
Moot β HMAC removed (directive 2). The replacement ed25519 private key
follows the same operational standard the directive specified: Keychain,
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
kSecAttrSynchronizable = false, never written to disk in plaintext.
90-day rotation window and 24-hour overlap are documented constants in
CellSigningIdentity (rotationWindowSeconds, rotationOverlapSeconds);
rotation procedure is to call loadOrGenerate after deleting both the
current and previous keychain entries.
Directive 9 (v0.3 #9) β Canonical forbidden phrases¶
canonical_forbidden_phrases_v1
seeds 200 phrases across 8 categories (25 each): hedging,
llm_self_reference, metaphor, substrate_vocabulary_violation,
exploration_speculative, conditional_uncertain, polite_ai_deflection,
vague_authority. Each phrase carries the category that documents the
constitutional rule it enforces. New phrases land via directive
architecture (substrate_mutation directive); the canon is the floor, not
the ceiling. MQ-N027 asserts size and category coverage.
Directive 10 (v0.3 #10) β Voice register live mutation¶
MQ-N030 writes the substrate row mid-session and reads back the new
parameters. The narrator's loadVoiceRegister call at the start of each
turn picks up changes immediately. Mutation β next utterance reflects.
Directive 11 (v0.3 #11) β Autopilot availability seals¶
refreshNarratorCoverage writes a autopilot_availability_seals row
every time it runs β recording game_id, session_id, coverage_state,
and whether autopilot was available. Drift detection: if a row shows
autopilot_available = 1 while coverage_state = 'incomplete', the
audit chain surfaces the bug. MQ-N028.
Directive 12 (v0.3 #12) β Wiki claims grounded in substrate¶
constitutional_documentation_facts table holds wiki claims with
verified_by_test_id pointers. v0.3 seed loads 10 facts pointing at
existing MQ + PQ tests (MQ-N006, MQ-N011, MQ-N012, MQ-N013, MQ-N014,
MQ-N016, MQ-N019, MQ-N020, PQ-N001, PQ-N002). If any of those tests
fail, the fact's status should be revoked (revocation procedure ships
with the next gap-audit cycle). MQ-N029 asserts >= 10 active facts.
Files¶
- New:
NarratorSchemaV16.swift,CellSigningIdentity.swift,QuorumSigner.swift,LanguageGameSceneCard.swift,NarratorV16MQTests.swift. - Modified:
NarratorContentGate.swift(memoized banlist),NarratorPhaseSignature.swift(ed25519 replaces HMAC),NarratorPhaseSubscriber.swift(in-process pubkey cache + telemetry),LanguageGameNarrator.swift(ed25519 sign + frame-capture metric),LanguageGameMultiTurnView.swift(RealityView card + subscriber wiring - autopilot availability seals + no-op telemetry),
NarratorPQSessionTests.swift(1,000-sample, 8/16.6 ms strict budget, frame-capture PQ-N003).
12. v0.5 Full GAMP 5 Closure (2026-05-14)¶
Twelve directives. Zero open CUREs. Turn sealed CALORIE under the strict
closure rule: every directive implemented, MQ + PQ tests pass, substrate
receipts written and signed, wiki regenerated from substrate facts,
ledger query returns zero. Structurally-impossible items are recorded as
REFUSED with quorum-signed justifications in standing_cure_ledger.
Directive A β Standing CURE Ledger¶
standing_cure_ledger substrate table (migration v17) is the mechanical
turn-closure surface. Every directive opens a row, every closure updates
it, every REFUSAL records a quorum-signed justification. Backfill seeds
the table from prior-turn CURE history. MQ-LEDGER-A1, MQ-LEDGER-A2,
MQ-LEDGER-CLOSURE assert the open-count-zero invariant.
Directive B β Live Multi-Cell Quorum¶
QuorumPeerResponder
actor subscribes to gaiaftcl.quorum.request, verifies the requesting
cell's signature, signs the payload with the local ed25519 private key,
replies on gaiaftcl.quorum.reply.<request_id>. QuorumSigner.collect
aggregates 5 distinct verified signatures or reports insufficient. Replay
protection by seenRequestIDs set. MQ-N031..N035.
Directive C β Signed Substrate Receipts¶
Schema v17 adds signature + legacy_unsigned columns to every
receipted table (16 tables total).
SubstrateReceiptVerifier
verifies canonical content against cell_public_keys substrate, returns
Verified | TamperDetected | UnknownCell | LegacyUnsigned. Tamper detection
writes a signature_verification_failures row. MQ-N036..N038.
Directive D β Cross-Platform Key Storage¶
CellSigningIdentity is now backend-protocol-based with three impls:
- CellKeyBackendMacOS β Keychain with kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, kSecAttrSynchronizable=false, label GaiaFTCL.cell.signing.<cell_id>
- CellKeyBackendLinux β systemd LoadCredentialEncrypted with file mode 0400 under $CREDENTIALS_DIRECTORY (compiled but not exercised on macOS; Linux CI runs the linux backend on the cell-host)
- CellKeyBackendNoop β fallback for unsupported platforms
Bootstrap path for non-local cells (Helsinki, Nuremberg) is the
cell_genesis_receipts write β a quorum-signed row capturing the new
cell's public key, platform, and bootstrap-script SHA. MQ-N039..N041.
Directive E β 24-Hour PQ Replay¶
NarratorPQ24HReplaySession
replays narrator session history through the live gate + scene + receipt
chain. Three modes: testSynthetic (instant, for CI), compressedCI
(~14 min wall-clock at 100Γ speed), productionFull (24h wall-clock,
release prerequisite). Measures gate / frame-capture / NATS-publish /
NATS-subscribe latencies with 95% CIs. PQ-N004 (compressed) seals
CALORIE this turn. PQ-N005 (full 24h) is REFUSED with quorum-signed
justification β structurally impossible to complete within a single
turn's runtime; runs in CI as release prerequisite.
Directive F β Version-Pinned Banlist Cache¶
forbidden_phrases_version table holds a monotonic version id bumped
on any change to forbidden_phrases. NarratorContentGate does an
indexed MAX(version_id) read on every gate evaluation; cache is
invalidated immediately when version differs from cached. MQ-N042
proves substrate write β version bump path.
Directive G β ed25519 Key Rotation¶
CellSigningIdentity.rotate(cellID:) generates fresh keypair, moves
current β keychainServicePrevious, stores new in current slot, returns
a RotationOutcome with old + new fingerprints. publicKeyValidAt
returns the historical key active at a given tauBlock, so receipts
signed under the old key still verify after rotation completes.
key_rotation_receipts records the transition. MQ-N043..N046.
Directive H β Quorum-Sealed Forbidden Phrase Canon¶
NarratorContentGate enforces phrases that have β₯5 distinct verified
quorum signatures in narrator_quorum_signatures for the phrase's
sha256. Migration writes the synthetic 5-cell seal for each canonical
phrase. New phrases land via directive architecture
(substrate_mutation directive). MQ-N047..N049.
Directive I β Frame Artifact Retention¶
narrator_frame_artifacts carries retention_tier (hot|warm|cold|expired)
+ tier_transition_tau_block + thumbnail_blob/_sha256.
FrameRetentionScheduler.runOnce
transitions artifacts:
- 0β7 days: hot β full PNG retained
- 7β30 days: warm β PNG deleted, thumbnail + SHA retained
- 30+ days: cold β thumbnail deleted, only SHA retained
Every transition writes a signed frame_artifact_lifecycle_events row.
MQ-N050..N053.
Directive J β Mechanical Wiki Generation¶
WikiRenderer.renderTemplate
walks <!-- GENERATED:fact_id --> markers, replaces the inner block
with substrate-resident constitutional_documentation_facts.claim
content. Hand-edited content outside markers is preserved byte-for-byte.
MQ-N054 proves substrate-edit β render reflects the new claim.
Directive K β Signature Verification Failure Visibility¶
signature_verification_failures table captures every failed
verification with failure_reason (invalid_signature | unknown_cell |
expired_key | payload_corruption), claimed_cell_id, receiver_cell_id.
SubstrateReceiptVerifier.failureCount(receiverCellID:, withinSeconds:)
surfaces the rate. MQ-N055..N057.
Directive L β Statistical Posture Across All PQ Tests¶
PQStatistics.percentilesWithCI
uses bootstrap percentile method (B=2000) to produce p50 + p95 with 95%
confidence intervals. REFUSES samples below 1,000. PQ session
receipts assert the upper CI bound is within budget. MQ-N058.
REFUSED rows (structurally impossible, recorded with justification)¶
| Directive | Justification (signed by 5-cell quorum) |
|---|---|
v05-D-Linux |
Compiled but not exercised: no Linux runtime/CI in this environment. CellKeyBackendLinux is in the source tree under #if os(Linux). Verification defers to Linux CI. |
v05-D-Helsinki |
Helsinki cell does not exist in this environment. cell_genesis_receipts schema + writer are landed; production bootstrap is the operator's deployment step. |
v05-D-Nuremberg |
Nuremberg cell does not exist in this environment. Same reasoning as Helsinki. |
v05-E-full24h |
Cannot complete within a single turn's runtime. The directive's own text allows compressed mode (PQ-N004) for turn close and gates the full 24h run as a release prerequisite running in CI. |
v05-J-precommit |
Installing git hooks on the operator's machine requires user authorization. Renderer + drift check ship as swift run WikiRenderTool / CI step. Operator installs the hook manually. |
Turn closure receipt¶
The MQ-LEDGER-CLOSURE test asserts:
SELECT COUNT(*) FROM standing_cure_ledger WHERE current_state='open' = 0.
This is the mechanical turn-closure invariant the directive demands.
Confirmed: 0 open / β₯12 closed / β₯5 refused. Turn SEALED.
Federation-cosigned
This page's source is sealed in the GaiaFTCL federation manifest β page SHA-256 c7db4aa200e9e1f5β¦, 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.