first pass at the newspaper builder
Test / test (push) Has been cancelled

This commit is contained in:
2026-09-14 11:57:22 +10:00
commit bec1eaac87
497 changed files with 178953 additions and 0 deletions
@@ -0,0 +1,41 @@
# NFR Design — Logical Components (unit: ai-draft)
> Logical infrastructure component inventory for the ai-draft library unit. Per
> Q2=A: ai-draft is one isolated library boundary; its blast radius is bounded
> and its failure degrades gracefully.
## Component inventory
| Logical component | Kind | Failure domain | Blast radius |
|---|---|---|---|
| ai-draft (library) | library boundary | Isolated to the ai-draft process | Low — its only external effect is producing (or empty-returning) a DraftBundle; it cannot corrupt the generator or the emitted page |
## Boundaries & isolation
- **ai-draft** is a single isolated library unit (confirmed at domain-design and
units-generation). It has no shared mutable state with the generator or funnies;
it communicates only via the in-process DraftBrief → DraftBundle contract.
- **Blast radius**: A failure in ai-draft (model unavailable, error, timeout) does
not propagate to the generator's render, the funnies output, or the emitted
page. Per the fail-soft design (Q3=A), a failure yields an empty DraftBundle +
status message, and the generator builds the paper without AI.
## Component isolation strategy
- ai-draft depends on neither the funnies logic nor on shared infrastructure
with the generator beyond the in-process call boundary.
- Its only external dependency is the granted cloud model endpoint (sanctioned,
human-approved), which is not shared with any other unit.
## Shared resource identification
- None beyond the local runtime itself. ai-draft introduces no database, cache,
or shared queue. (See functional-design — the DraftBundle is a file handoff to
the review page, read via the native file picker, not a shared live resource.)
## Bridge to Infrastructure Design
- The ai-draft library boundary maps to the `u2-ai-draft` build unit. No
distributed infrastructure is required; the single model endpoint is its only
external dependency. Failure domains are intentionally as-isolated-as-possible
given the one-shot local-tool posture.
@@ -0,0 +1,15 @@
<!-- INVARIANT: examples are single-line HTML comments so a fresh template parses to total=0 (MEMORY_EMPTY). Do NOT un-comment or split across lines. t100 guards this. -->
> This file is kept up to date automatically while the stage runs. Add observations at the review step, not by editing here directly.
## Interpretations
<!-- example: 2026-05-29T10:14:32Z — chose REST over GraphQL; the consuming team only needs CRUD, revisit if subscriptions land -->
## Deviations
<!-- example: 2026-05-29T10:14:32Z — skipped the optional caching layer the stage prose suggested; the dataset is small enough that it adds risk -->
## Tradeoffs
<!-- example: 2026-05-29T10:14:32Z — picked TDD over BDD this run; the team is unit-first and the domain is well-understood -->
## Open questions
<!-- example: 2026-05-29T10:14:32Z — confirm the retention window with compliance before the next stage hardens the schema -->
2026-09-14T00:25:00Z — Interpretation — ai-draft NFR Design (all A): minimal-surface security, single isolated library boundary, fail-soft graceful degradation, injected structured logger. Produces security-design + logical-components + traceability (perf/scalability/reliability/observability N/A for library kind).
@@ -0,0 +1,67 @@
# NFR Design — Questions (unit: ai-draft)
> Fill in each `[Answer]:` tag. Options A-E plus X (Other). ai-draft is a
> `library` unit: NFR Design produces security-design + logical-components +
> traceability (perf/scalability/reliability/observability designs are
> service-only, N/A). The confirmed ai-draft NFR targets: moderate latency,
> strict draft-isolation, graceful fallback, light logging, Python+uv.
## Q1: Security pattern approach
The ai-draft NFR requires strict isolation (only the draft brief/text to the cloud model; nothing else leaves the machine). What security design pattern applies?
A) Minimal-surface — a single narrow caller to the granted model; brief built locally, minimal prompt, no secrets/credentials embedded or logged; response parsed locally (recommended)
B) Defense-in-depth — add an explicit allow-list of the endpoint + input sanitization before the call
C) Zero-trust style — every local→model interaction authenticated/verified
X) Other (please specify)
[Answer]: A
## Q2: Logical component boundary
As a library unit, what should `logical-components.md` capture for blast radius?
A) ai-draft as a single isolated library boundary — it cannot corrupt the generator/emitted page; its only external effect is producing (or empty-returning) a DraftBundle, and a failure degrades gracefully (recommended)
B) Split ai-draft into sub-components (brief-builder, model-client, bundle-assembler) with separate failure domains
X) Other (please specify)
[Answer]: A
## Q3: Reliability/graceful-degradation pattern
The NFR says best-effort with graceful fallback (paper builds without AI). What pattern should the design specify?
A) A fail-soft wrapper — on model error/timeout, ai-draft returns an empty DraftBundle + status message; no retry storm; the generator proceeds without AI (recommended)
B) Circuit-breaker style with bounded retries then fallback
C) Retry-with-backoff a bounded number of times, then fallback
X) Other (please specify)
[Answer]: A
## Q4: Observability design (logical)
The NFR is light logging. What logging design fits a library unit?
A) A small structured logger the generator passes in — one concise line per draft run (requested types, success/empty status); no metrics/tracing (recommended)
B) Built-in logging writes to stderr directly
X) Other (please specify)
[Answer]: A
## Consolidated Summary Confirmation
> Summary of the four ai-draft NFR Design answers before the unit design artifacts are generated:
>
> - Security pattern: **minimal-surface** — single narrow caller to the cloud model, brief built locally, no secrets (Q1=A)
> - Logical boundary: **single isolated library** — cannot corrupt generator/page; failure degrades gracefully (Q2=A)
> - Reliability: **fail-soft wrapper** — empty DraftBundle + status on model error, no retry storm (Q3=A)
> - Observability: **injected structured logger** — one line per draft run (Q4=A)
>
> Human auto-approved summary; other units' nfr-design answers to mirror as applicable.
Does this all look correct before I generate the unit design artifacts?
- Looks correct
- Request changes
[Answer]: Looks correct
@@ -0,0 +1,39 @@
# NFR Design — Security Design (unit: ai-draft)
> Minimal-surface security design for the ai-draft library unit, per Q1=A. Strict
> isolation: only the draft brief/text to the granted cloud model; nothing else
> leaves the machine.
## Approach: minimal-surface
- **Single narrow caller**: one thin model client in ai-draft talks only to the
granted `deepseek-v4-flash:cloud` endpoint. No other outbound call.
- **Brief built locally**: the DraftBrief (couple names, occasion/date, key
themes) is assembled in-process from the content-derived context; only this
brief + a keepsake-tone instruction travel to the model.
- **No secrets/credentials**: no API keys, tokens, or private data are embedded,
logged, or transmitted. Authentication (if the model endpoint needs any) comes
from a locally-managed config the user supplies, never hard-coded.
- **Response parsed locally**: the model's draft text is parsed into
DraftArticle entities in-process; nothing from the response is ever executed.
## Design decisions
| Decision | Design |
|---|---|
| Endpoint | A single configurable model endpoint (the granted cloud model), allow-listed in ai-draft only |
| Input to model | Minimal prompt: brief + tone instruction; nothing else |
| Output handling | Parsed locally into structured DraftArticle(s); never evaluated/executed |
| Logging | Light, one line per run (Q4=A); never logs brief content or secrets |
| Secrets | None bundled; local config if endpoint auth is required |
## Security controls map (from ai-draft security-requirements)
- **NFR9.1 (strict isolation)** — satisfied by minimal-surface single-caller design.
- **NFR9.2 (no secrets/credentials)** — satisfied by no-embedded-secrets + light logging.
- **NFR9.3 (local-only elsewhere)** — satisfied by the single narrow external call.
## Verification
- Only one outbound call path exists in ai-draft (to the model endpoint).
- The emitted page and DraftBundle make no network requests (NFR4).
@@ -0,0 +1,13 @@
{
"stage": "nfr-design",
"unit": "ai-draft",
"upstream_ids": ["NFR9.1", "NFR9.2", "NFR9.3"],
"coverage": [
{ "id": "NFR9.1", "status": "OK", "target": "security-design.md (minimal-surface single-caller to model)" },
{ "id": "NFR9.2", "status": "OK", "target": "security-design.md (no secrets/credentials embedded or logged)" },
{ "id": "NFR9.3", "status": "OK", "target": "security-design.md / logical-components.md (local-only; single narrow external call)" }
],
"reverse": [
{ "id": "NFR1.1", "status": "N/A", "target": "performance design is service/ui-only (library unit)" }
]
}