Skip to content

feat: phase AP-a foundations — db/42 + Abstractions 5.6.0 (plugin SPI + the ads seam) - #662

Merged
genwave-radio merged 5 commits into
mainfrom
feat/ap-a-foundations
Sep 3, 2026
Merged

genwave-radio merged 5 commits into
mainfrom
feat/ap-a-foundations

Conversation

@genwave-radio

@genwave-radio genwave-radio commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Phase AP-a of the Ads & the plugin seam epic (gh-#380, SPEC F156–F163) — the two foundation seams, plus the epic's seeded pending specs. One PR per phase, merged in order (AP-b the plugin door builds next, stacked on this).

🧱 What's in it

  • Spec seed (1246932): 15 pending spec files for STORY-384..394 across six test projects, including two new sln-wired projects (GenWave.Plugins.Tests, GenWave.Ads.Tests). All Skip/todo until their tasks land.
  • T389 — db/42 (5ca4faf): station.ad_spot (the F159 state machine, spot_seconds 15/30/60, voice_plan jsonb) + station.ad_brief (UNIQUE NULLS NOT DISTINCT (pack_slug, brand) — one shared upsert key for pack installs and owner briefs) + ad_state/ad_source enums + library.media.imaging_kind CHECK widened to 'ad', with fresh-init mirrors (db/06, 01-library.sh). Proven idempotent on scratch 16.4 from every lineage (incl. db/30's unnamed-constraint boxes); fresh-init == migrated byte-identically. No cross-schema FKs — the db/22 role boundary (booth_log.media_id precedent).
  • T389 fixup (8b2e426): Story346's marker-derivation suite tracks the repo's newest table-creating migration — bumped library.file_actionstation.ad_brief, scratch checkouts now delete db/42 like its siblings. 32/32.
  • T390 — Abstractions 5.6.0, additive (e63093f): IGenWavePlugin + IPluginHost (additive-only by construction: three members; growth = one Add* method = a minor bump) + IAdSpotSource (null = "no spot this break", always legal), BCL-only per L4; SegmentKind.Ad + ImagingKind.Ad appended last, prior values pinned repo-wide; PatterTemplateRenderer gains the Ad floor arm so the append leaves POST /api/personas/preview total instead of a reachable 500 (caught at review, proven on the running binary).

✅ Gates

  • Two opus review rounds on T390 (r1 FAIL → r2 PASS), one on T389 (PASS); every claim independently reproduced.
  • dotnet build 0/0 · full suites green (Host 2488+32, MediaLibrary 1156, Tts 815, Orchestration 430, Architecture 126 incl. Story384's 7 now-running facts, Core 181, Context 78).
  • Production-binary smoke: scratch Postgres 5499 + real Kestrel on 5236 → {"kind":"Ad"} preview answers 200 with the floor copy, no TTS/LLM present.

🖐️ For Dean alongside the merge

  • T393's manual half: create the genwave-plugin-example repo (the SPI's reference consumer — I author its content once it exists; it builds against a locally-packed 5.6.0-preview until release).
  • The one-owner-brief-per-brand cap (NULLS NOT DISTINCT) is an extension of F162.2 awaiting your ruling — recorded on T398.

15 spec files (14 xUnit pending-skip, 1 jest all-todo) across six test projects,
including two new sln-wired projects: GenWave.Plugins.Tests and GenWave.Ads.Tests
(production ProjectReferences arrive with the T391/T396 birth tasks). All specs
red-by-design behind Skip until /build-loop turns them green.

Claude-Session: https://claude.ai/code/session_019Pn3gCFBkB1ATXmFe1aLPk
…ng_kind widens to 'ad')

station.ad_spot carries the F159 state machine (draft|approved|rendering|ready|failed|retired,
spot_seconds in 15/30/60, voice_plan jsonb, generation); station.ad_brief is the brand universe,
UNIQUE NULLS NOT DISTINCT (pack_slug, brand) so the pack-install upsert and the owner lane share
one key. bed_media_id/media_id are plain bigint by the db/22 role boundary (no cross-schema FK —
the booth_log.media_id precedent); ids resolve through IMediaCatalog. library.media.imaging_kind
CHECK widens to five tokens, definition-guarded for idempotent re-runs from every lineage incl.
db/30's unnamed-constraint boxes. Fresh-init mirrors: db/06 (idempotent — it re-runs under the
migration glob) + 01-library.sh. Proven on scratch postgres:16.4: full set twice, byte-identical
dumps; fresh-init == migrated.

Claude-Session: https://claude.ai/code/session_019Pn3gCFBkB1ATXmFe1aLPk
…rief)

The WriteDockerStub migrationMarkerTable default deliberately tracks the repo's
newest table-creating migration's last CREATE TABLE; db/42 moves it from
library.file_action to station.ad_brief. Same bump shape as the db/41 one it documents.

Claude-Session: https://claude.ai/code/session_019Pn3gCFBkB1ATXmFe1aLPk
…s 5.6.0, additive)

IGenWavePlugin/IPluginHost (additive-only by construction: three members, growth = one
Add* method = a minor bump) and IAdSpotSource (null = no spot this break, always legal)
join the MIT contract surface, BCL-only per L4. SegmentKind and ImagingKind append Ad
last, prior values pinned repo-wide (Story329/Story005 pins extended, Story384's
exact-member-set + L4 facts now run). PatterTemplateRenderer gains the Ad floor arm so
the enum append leaves POST /api/personas/preview total instead of a reachable 500
(Story006's totality theory green with no test edits); the floor never airs — F158.3
vends ads pre-rendered. Name's published docs bind T392 to LogSanitize on the booth-log
narrative; ImagingKind's remarks name T395 as the fence's owner, future-tensed for the
5.6.0-preview pack.

Claude-Session: https://claude.ai/code/session_019Pn3gCFBkB1ATXmFe1aLPk
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant