49 decisions · closed to new entries

Vespera — Decision ledger#

Project
Document Curation Pipeline → Knowledge Base
Status
closed to new entries. Decisions from ADR-050 onward are written as files in docs/adr/, each carrying its own full text.
Companion
architecture.md describes the system these decisions produced, and says more about most of them than the rows below do.

Superseded as a record, retained as a witness. Every decision below now has its own file in docs/adr/, and that folder is what to cite. This table stays because those files were rebuilt from it on 2026-08-22 — mechanically, field by field — after the original ADR text was lost, and each one claims a verbatim transcription that only this table can verify.

Do not edit it, and do not add to it: new decisions start at ADR-050 and are written as files with their own full text. Where a row here says less than §1 or §2 does about the same decision, §1 and §2 are the fuller record.

All decisions are append-only: a decision is reopened only by a later ADR that explicitly references and amends it (noted below where that happened). Full text lives in docs/adr/ in the repo; this is the condensed record.

IDDateTitleSummary
ADR-0012026-08-20Tech stack is a fixed constraintJava + Spring Boot + Spring AI + a vector database, given as input, not derived.
ADR-0022026-08-20Confluence is the publication targetCurated output published as surviving originals + synthesised docs. Confluence is the sink, not the working store. (Softened by ADR-024, refined by ADR-025.)
ADR-0032026-08-20Domain-agnostic and reusableCorpus content unknown and unassumed; domain judgement externalised to a per-corpus input.
ADR-0042026-08-20Relevance defined by an exemplar seed set"Trash" includes topical irrelevance. Relevance supplied per corpus as a folder of known-relevant documents; one-class (positives only).
ADR-0052026-08-20Prototype firstCorners may be cut on anything reversible — never on destructive deletion, lost provenance, or un-cached expensive extraction.
ADR-0062026-08-20Census: measure before judgingA verdict-free measurement pass runs first; expensive walk produces an immutable artifact, analysis is cheap and re-runnable. Thresholds ship null.
ADR-0072026-08-20No supplied negative example setTrash is the unbounded complement of relevance. Hand-picked negatives are uninformative; hard negatives must be mined post-scoring.
ADR-0082026-08-20SQLite is the census artifact storeAmends ADR-006's file formats. Aggregates/collisions/run identity become queries. Phase-A immutability becomes a convention, not a filesystem guarantee.
ADR-0092026-08-20One storage technology; single databaseSQLite replaces flat-file artifacts, scoped to census. Clarified same day: not a ban on a separate vector store — relational and vector stores serve different purposes.
ADR-0102026-08-20Extraction via Docling; scanned PDFs in scopeExtraction is out-of-process, returns a structured document (not plain text), is cached under full extractor identity, and can fail silently.
ADR-0112026-08-20Managed containers; the tool owns its sidecarsThe app starts/stops its own dependencies for a single-command UX.
ADR-0122026-08-20Extraction engine is configurableServing runtime is config, not code. Cache key must carry full extractor identity; calibration must not cross engines.
ADR-0132026-08-20(config) Ollama is the default engineChosen on friction; changeable without a new ADR.
ADR-0142026-08-20Verdict-ledger modelDocuments never move; stages append verdict rows. "Survivors" is a query. Enables cheap retuning and full-audit "why not published" queries.
ADR-0152026-08-20Identity is a surrogate key per file occurrenceKeyed on file occurrence (path/size/mtime, hash nullable) — not path, not content hash. Content identity is a discovered relation, not a collapse.
ADR-0162026-08-20The corpus is treated as staticOne archive, walked once; re-walks happen because code changed, not content. Explicit assumption, not a discovered property.
ADR-0172026-08-20The cascadeDefines the 8-stage pipeline (0–7) and the verdicts each stage writes. Cheapest filter runs first.
ADR-0182026-08-20Stage 4 uses MinHash with LSH bandingNot SimHash — MinHash catches containment (not just similarity) and supports analytically-derivable LSH parameters.
ADR-0192026-08-20Content census is derived columns plus a reportNot a second traversal — extraction writes per-occurrence metrics as columns while the document is open.
ADR-0202026-08-20Relevance scoring functionscore = max over seeds of (mean top-3 chunk similarity); winning seed stored. Not a centroid, not top-k. Needs no vector DB at scoring time.
ADR-0212026-08-20Synthesis exists to make the survivor set coherentClarifies ADR-002: stage 5 leaves a heap; synthesis is connective material about the collection, not per-document summarisation.
ADR-0222026-08-20Stage 6 splits into arrangement (6a) then generation (6b)6a builds a page tree (seed-named top level + unattributed, clusters within); 6b generates cited overviews, gated on human review of 6a.
ADR-0232026-08-20Surviving originals stored in Confluence as attachmentsNot an object store with links — self-contained, indexed by Confluence search. Storage limits and per-attachment cap noted as residue.
ADR-0242026-08-20Publication is terminal and one-shotOne run per corpus; no re-publication, no idempotency-by-hash, no unpublish problem. Softens ADR-002 (Confluence's scope not fully settled).
ADR-0252026-08-20Stage 7 is an adapter, not a stagePipeline terminates at a self-contained publication-ready artifact; rendering it (to Confluence or elsewhere) is a separate adapter concern.
ADR-0262026-08-20Generated content verified mechanically and by human reviewMechanical citation-existence check + human review at the consolidation gate. Model-checking model output explicitly rejected.
ADR-0272026-08-20Clustering moves to stage 5Amends ADR-017/ADR-022 ordering — stage 5 already embeds everything, so clustering there is nearly free and precedes threshold-setting. (Scope clarified by ADR-045.)
ADR-0282026-08-20Relevance threshold: human labelling, gated by score distributionGo/no-go on distribution shape, then calibrate via sampled human labelling at the candidate cut. Cluster-level adjudication and leave-one-out seed scoring rejected as the calibration mechanism.
ADR-0292026-08-20Chunking: structure-first, with a measured LLM fallbackDefault Docling HybridChunker, tokenizer-aligned; LLM fallback only for measured structureless (scanned) cases, currently off. Boundaries cached, keyed by content hash + chunker identity.
ADR-0302026-08-20(parked) Late chunking not adoptedModest retrieval gain, but requires token-level embeddings Spring AI's EmbeddingModel doesn't expose. Revisit if boundary sensitivity dominates.
ADR-0312026-08-20Human gates are optionalA gate is a required input, not a pause. Profile carries every gate input with per-value provenance (human/carried-over/auto-derived).
ADR-0322026-08-20Embeddings are durable; the index is disposableVectors cached (chunk hash + model identity); ANN index is rebuildable. Partially retired by ADR-047 (index no longer needs to survive human-paced gates, since the pipeline terminates instead of pausing).
ADR-0332026-08-20Embedding model: criteria recorded, model unsetRequirements: separable tokenizer, pinned weights, Italian+English, judged on Clustering/STS not Retrieval, OCR tolerance. Several candidates evaluated and rejected on criteria; model ships unset.
ADR-0342026-08-20Embedding model chosen by bake-off, not argumentSame sample/seeds, ADR-028's gate run under each candidate. Abort verdicts must be confirmed against a larger model. Clarified by ADR-044: "same chunking" means method, not byte-identical output.
ADR-0352026-08-20Pipeline never publishes; adapter invoked separately, never unattendedPipeline runs unattended through 6b; publication is a distinct, always human-initiated invocation.
ADR-0362026-08-20Spring Batch with ResourcelessJobRepository; Camel droppedBatch used for retry/skip/parallelism on long extraction runs, not restartability (ledger owns that). No integration topology needed, so Camel dropped.
ADR-0372026-08-20Spring Modulith event publication registry droppedNo application events exist in this design; registry also lacked a SQLite schema and threw a hard startup failure. starter-core retained for boundary checks.
ADR-0382026-08-20Shingling moves to stage 3; boilerplate detected before it distorts anythingShingles computed as a derived column during extraction; corpus-wide document frequency identifies boilerplate before it corrupts stage-4 dedup or stage-5 relevance (false smear/abort risk).
ADR-0392026-08-21Chroma is derived; SQLite is authoritative for vectorsVectors written to SQLite when computed; Chroma populated from that cache, droppable/rebuildable at any time. Reconciles ADR-020 with ADR-032. (Open condition resolved by ADR-045.)
ADR-0402026-08-21Modules are capability-shaped, not stage-shapedDefines the 9 modules (ledger, corpus, extraction, similarity, embedding, synthesis, publication, profile, pipeline) and the rule: a capability module depends only on ledger.
ADR-0412026-08-21ledger owns identity and verdicts; capabilities own their own tablesSide tables per capability, keyed by occurrence_id, driven by cache-key semantics (chunk/vector caches aren't keyed by occurrence). Records a known ArchUnit enforcement gap for raw SQL.
ADR-0422026-08-21ledger owns the verdict vocabulary, not the cascadeFixed, closed verdict vocabulary with blocking-ness, exposed via survivors(runId). Runtime/opaque verdict registries rejected — the failure mode of drift is asymmetric (over-publishing).
ADR-0432026-08-21The profile is authored as a file and recorded in the ledgerFile is input (mutable, per-corpus); ledger snapshot is history (immutable, per-run). Drift rule: file never overridden by history. Anti-regeneration rule protects human edits.
ADR-0442026-08-21The bake-off re-chunks per candidate modelEach embedding candidate is compared with its own tokenizer-aligned chunking, to avoid incumbent-tokenizer bias. Cache key must carry tokenizer identity.
ADR-0452026-08-21Clustering runs within each seed partitionNever corpus-wide. Bounds compute (N²/2 distances per partition, not corpus-wide), keeps the "seed owns 60%" alarm aligned with a real cost, enables Batch-native parallelism, resolves ADR-039's open sizing condition.
ADR-0462026-08-21The pom carries what a recorded decision requiresNot "what current code uses." Lists specific removals (Camel, vector-store advisor, batch-jdbc, document readers, contract-verifier, Modulith observability/actuator) and additions (Ollama starter alongside OpenAI), each tied to an ADR.
ADR-0472026-08-21The pipeline never blocksTerminates at a missing gate input, resumes on re-invocation; iteration happens between runs. Sizes the CLI to two commands. Auto-derivation of thresholds is an explicit, off-by-default profile input. Partially retires ADR-032.
ADR-0482026-08-21Walk and run identityTwo distinct identities: walk (owns occurrences, filesystem-scoped) and run (owns verdicts, one stage/one config, chained to upstream run ids and implementation version). Continuation vs. minting rule defined.
ADR-0492026-08-21Verdict rows, and schema versioning without a migration toolEvery stage writes a row per occurrence including non-blocking passed; verdicts use a surrogate key (multiple rows allowed). Schema via schema.sql + version check; migration tool deferred until real data exists.

Vocabulary reference#

Project-specific terms (file occurrence, content identity, ledger, verdict, survivor, seed set, hard negative, winning seed, seed partition, census, observe-before-enforce, profile, gate, walk, walk anomaly, stage, run, invocation, arrangement, synthesis doc, publication-ready artifact, extraction cache, chunk cache) are defined in CONTEXT.md in the repo and are binding usage across the codebase and its documentation.

Open questions#

Tracked on the wayfinder map, Census slice: the way to a hand-off spec. Its open child issues are the live list; the two items parked on measurement data — shingle granularity and target hardware — sit in its Out of scope section with the trigger that revives each one.