168 records -> docs/decisions/records/<area>/<topic>.md (163 active, 23 dirs) and docs/decisions/archive/<area>/<topic>.md (5 archived). The filename IS the key, so one-active-record-per-key becomes a filesystem property rather than a validator check, and supersession becomes a `git mv`. WHY: the monolith was a concurrency problem before an aesthetic one. A 3,900-line append target made parallel sessions collide -- PR #605 and PR #614 both hit append-vs-append conflicts during routine rebases, and hand-resolving those inside the corpus is exactly the operation the rationale-rewrite guard exists to police. HOW IT IS VERIFIED: a ~170-file diff cannot be meaningfully read, so correctness does not rest on reading it. The parser was taught BOTH formats first, so the body-diff guard parses the old form at the merge-base and the new form at head -- the migration validates itself, no bypass. The proof is a field-level equivalence harness: 168 records before and after, zero lost, zero gained, zero field mismatches, zero rationale bodies differing. Reviewers should scrutinise the harness; it is the actual evidence. What measuring caught that reading would not have: - ~500 lines sit OUTSIDE any record -- decisions.md's lifecycle schema and each topic file's preamble, mostly the only copy. Source files are kept and stripped, never deleted. They also cannot be filed per-area: topic files hold several areas and 4 of 23 areas span several files. - Archive discovery was a non-recursive glob; after the split it found ZERO archived records, surfacing as four bogus "supersedes points to unknown key" errors rather than an obvious failure. - ~32 live docs point into the corpus BY DATE, which the split dangles. Each stripped file now ends with a generated "Records formerly in this file" index, which also rescues the identical breadcrumbs in old issue comments. - decisions.md's "In this file:" list was 97 same-file anchor bullets that the split makes WRONG, not merely stale. Dropped; the generated index replaces them with links that resolve. The equivalence harness now runs against a checked-in FIXTURE, not the live corpus. The earlier version migrated the real tree, which made it a one-shot: the moment the migration landed there was nothing left to move and the tests failed for reasons unrelated to the code. A fixture keeps them testing the SCRIPT rather than the repo's current state. Keys preserved verbatim, warts included: `sched` (12) and `scheduling` (1) remain two directories for one concept. Renaming a key is not a move -- it changes identity, breaks the equivalence proof, and invalidates MemPalace's per-key drawers. Taxonomy normalisation is separate work. refs #610
3.9 KiB
key, title, status, since, supersedes, superseded-by, rule, signals, mechanics
| key | title | status | since | supersedes | superseded-by | rule | signals | mechanics |
|---|---|---|---|---|---|---|---|---|
| iptv.logo-drives-bug-preset | 2026-07-20 — One logo drives the bug via a shared ChannelLogo preset, not new schema (#67) | active | 2026-07-20 | none | none | One uploaded channel logo drives both the listing logo and the on-screen bug via a shared, seeded `ChannelLogo`-sourced watermark preset (`Channel Bug`), not new per-channel schema. | channel logo, watermark bug preset, ChannelWatermark seeding, ChannelLogo imageSource, seed/adopt semantics, quick-add · paths: `ChannelWatermarkImageSource.ChannelLogo`, `DbInitializer.Initialize`, `watermark.channel_bug_seeded`, `WatermarkResponseModel` · issues: #67, #286, #502 | `DbInitializerChannelBugWatermarkTests`; `WatermarkResponseModel.imageSource`; `DbInitializer` seeded `Channel Bug` watermark + `watermark.channel_bug_seeded` ConfigElement marker |
#67 asked that one uploaded image drive both the listing logo and the on-screen bug, separably
overridable, with preview. Most of it already existed: ChannelWatermarkImageSource.ChannelLogo
resolves the channel's own logo artwork at render time at all three watermark precedence levels, and
Custom already provides the independent override. Production had already been running exactly this
pattern by hand — 43 channels pointing at one hand-made Channel Bug preset.
Decision: seed that preset rather than add per-channel bug columns. A watermark is a shared named
entity, so per-channel geometry would need either a dual-provider migration or one watermark row per
channel (under a unique-name index). Since ChannelLogo resolves per channel at render time, a single
shared row already delivers the user-visible behavior with no schema change.
- The seed adopts an existing
Channel Bugrow untouched, so an operator's tuned geometry is never overwritten, and aConfigElementmarker (watermark.channel_bug_seeded) makes it run once per database rather than once per name-absence —ChannelWatermarkhas noIsSystemflag andDbInitializer.Initializeruns at every startup, so a name-only guard would resurrect a deliberately deleted preset forever. Covered byDbInitializerChannelBugWatermarkTests. WatermarkResponseModelgainedimageSource(additive under the frozen/api/v1, #286) so clients identify logo-driven presets generically instead of matching a user-editable name. Note the limit: once a second logo-driven preset exists,imageSourceidentifies the class but not the default, sofindLogoBugWatermarkprefers the seeded name as a deterministic tiebreak.- The default is applied by the SPA's quick-add creation path, not by inferring "newness" in the
editor — quick-add creates through the API and then navigates to the editor, so the editor only ever
loads an existing row. The editor toggle reflects the referenced watermark's
imageSource; an earlier draft searched the list instead, which (becausegetWatermarks()sorts by name) would have silently repointed channels bound to a non-first logo-driven preset. Caught in independent review and pinned by a regression test. - The builder flow is covered on fresh installs only, by stamping the preset onto the system channel templates the seed itself creates; existing installs' templates are never mutated.
- Server-side create defaulting was rejected: making an omitted
watermarkIdmean "give me a watermark" would surprise machine clients of the frozen API.POST /api/v1/channels/auto-tuneis therefore unchanged. - Not fixed here: external-URL logos never render a bug (
WatermarkSelectorFile.Exists-checks a URL). Pre-existing, lands in the FFmpeg render path, tracked as #502. This change only stops the preview from promising it.
Accepted trade-off: every channel on the shared preset shares one geometry; per-channel tweaks mean creating a second preset on the Watermarks screen.