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.
| Decision | Consequence in current code |
|---|---|
| Purge the legacy settings object and unify configuration | The layered Pydantic settings tree on βοΈ Configuration |
| Adopt dependency injection wholesale | The container described on βοΈ System Design, with its lazy-inner-import rule |
| Migrate settings to Pydantic v2 | Settings classes built on the dedicated settings package rather than the base model |
| Make adapters async and CPU-only | Async ports throughout, with no GPU dependency in the required install |
| Derive identities deterministically | UUID5 identity with fixed namespaces, on π§© Domain Model |
πΉ π Related
- βοΈ Key Decisions β the same choices as architectural rules, written from code
- π₯ Incident Log β the failures that forced several of these decisions
- π History β what happened to the documents these decisions were originally recorded in