This log reconstructs the dated choices that shaped the codebase and confirms their results against current code, newest first.

πŸ”Ή 🧭 Scope of this page

This log records when and why something was decided. For the architectural rules those decisions produced, and their present-day consequences, read βš–οΈ Key Decisions β€” that page is written from the code, this one from the history.

Where the chronicle records an outcome but not a date, the entry is grouped under undated foundations rather than given a fabricated date. Where it records a triumph without a verifiable technical change, it is not recorded here at all.

πŸ”Ή πŸ”Š 2026-02-12 β€” SFX provider chain becomes an orchestrator

Decision. Replace selector-style SFX provider wiring with an orchestrator, and fix provider ordering per strategy.

Context. The provider cascade collapsed entirely when one provider β€” the mock β€” failed to satisfy the provider contract. A selector picking a single provider could not express the intended fallback chain.

Consequence. SFX resolution now walks an ordered provider list with local sources first. The behaviour is documented on πŸ”Œ Integrations. The incident that forced it is on πŸ”₯ Incident Log.

πŸ”Ή πŸ“š 2026-02-03 β€” truth-first documentation policy

Decision. Treat the code as the single source of truth and re-derive project documentation from it rather than from accumulated prose.

Context. Documentation had drifted far enough that aspirational claims and implemented behaviour were indistinguishable.

Consequence. The direct ancestor of this wiki. It is also why the 🧾 Claim Registry exists: claims now carry a lifecycle state and a probe rather than being asserted in prose. The drift itself has not gone away β€” see the contradictions table on the 🎬 SSOT home page.

πŸ”Ή 🧯 2025-11-07 β€” exception context over bare failures

Decision. Patch service exceptions to carry the failing service’s name.

Context. CrewAI and story-mechanics failures surfaced without identifying which external service produced them.

Consequence. The ExternalServiceError family carries a service name and optional detail, described on 🧩 Domain Model.

πŸ”Ή πŸ“ˆ 2025-10-03 β€” instrument everything

Decision. Adopt OpenTelemetry tracing across the pipeline and Prometheus metrics across the helper stages.

Context. A production outage could not be diagnosed because nothing recorded per-stage timing or failure attribution.

Consequence. Twenty metric families and a stage-tracing decorator, documented on πŸ“ˆ Observability. Instrumentation reached seven of nine major stages β€” the gap is itself a documented fact rather than a claim of completeness.

πŸ”Ή ⏱️ 2025-09-30 β€” prove liveness, bound everything

Decision. Adopt heartbeat logging on a fixed interval and a layered timeout strategy for long-running work.

Context. A crashed run appeared to hang for over fifty minutes because a dead child process left a visible parent. Silence was indistinguishable from progress.

Consequence. Long operations emit periodic liveness output and stages carry timeouts. The reasoning is preserved as a maxim in the chronicle: a silent process must never be trusted, because heartbeats prove life and timeouts guarantee death.

πŸ”Ή πŸ€– 2025-09-23 β€” extract the pipeline coordinator, add the creative agents

Decision. Pull pipeline coordination out into its own service, delete orphaned crew modules, and extend the story crew with dedicated authorial-voice and visual-direction agents.

Context. Stage orchestration had accumulated inside the use case, and the crew had no agent responsible for stylistic or cross-modal consistency.

Consequence. The current six-agent story crew and its style-consistency task, documented on πŸ€– CrewAI Agents. Stage orchestration is described on 🎞️ Production Pipeline.

πŸ”Ή 🎬 2025-09-13 β€” asset-first sequential montage

Decision. Resolve every asset before montage assembly rather than fetching during assembly, and standardize the crew’s LLM access through a single provider path.

Context. Interleaving asset resolution with assembly made failures partial and hard to resume.

Consequence. The audio chain on πŸ”Š Audio Chain assembles from already-resolved assets.

πŸ”Ή πŸ“ 2025-09-12 β€” hierarchical, semantically named artifacts

Decision. Give every run a timestamped, title-named directory, split artifacts by kind, and name files from the story title instead of raw identifiers.

Context. Outputs were scattered with cryptic identifier filenames, making runs hard to inspect and compare.

Consequence. The output layout documented on πŸƒ Runbook β€” audio subdivided by kind, images and text separated, one directory per run.

πŸ”Ή πŸ“ 2025-09-04 β€” one source of truth for guidance

Decision. Consolidate scattered agent guidance into a single condensed reference, with local-first operation as an explicit guardrail.

Consequence. The lineage that ends at this wiki. The local-first guardrail is still the default posture and is enforced in code by the APP__DEV_LOCAL_ONLY gate.

πŸ”Ή β›” 2025-08-27 β€” bound and cancel async work explicitly

Decision. Add explicit cancellation handling and timeouts to SFX orchestration.

Context. The SFX pipeline raised cancellation errors under load and could hang unbounded.

Consequence. Adapter calls are async throughout with explicit timeouts, a convention recorded on πŸ“ Code Conventions.

πŸ”Ή πŸ’Έ 2025-08-18 β€” local-first, and cost control by default

Decision. Make Piper the default TTS provider and prefer local SFX and music libraries; mark the web UI experimental.

Context. Paid cloud providers were reachable by default, so ordinary development could incur real cost.

Consequence. The most load-bearing decision in the project. It produces the mock-and-local adapter set, the APP__DEV_LOCAL_ONLY gate, and the network-egress block in the test isolation layer. Provider defaults are on πŸ”Œ Integrations; the cost checklist is on πŸƒ Runbook.

πŸ”Ή 🧾 2025-07-29 and earlier β€” serialization correctness

Decision. Serialize enums and models explicitly at every boundary that produces JSON.

Context. Incorrectly serialized enums silently produced stories with no sound effects and no music.

Consequence. JSON-mode serialization at montage boundaries. The same class of bug recurred and was fixed again later, which is why it appears twice in πŸ”₯ Incident Log.

πŸ”Ή 🧱 Undated foundations

The chronicle’s earliest entries record these without dates. Each is verifiable in current source, so they are listed by what they produced rather than when.

DecisionConsequence in current code
Purge the legacy settings object and unify configurationThe layered Pydantic settings tree on βš™οΈ Configuration
Adopt dependency injection wholesaleThe container described on βš™οΈ System Design, with its lazy-inner-import rule
Migrate settings to Pydantic v2Settings classes built on the dedicated settings package rather than the base model
Make adapters async and CPU-onlyAsync ports throughout, with no GPU dependency in the required install
Derive identities deterministicallyUUID5 identity with fixed namespaces, on 🧩 Domain Model