This commit is contained in:
+78
@@ -0,0 +1,78 @@
|
||||
# Contract Design — Questions
|
||||
|
||||
> Fill in each `[Answer]:` tag. Options A-E plus X (Other). The file is the
|
||||
> authoritative record of your contract decisions.
|
||||
|
||||
## Q1: Contract representation
|
||||
|
||||
How should the inter-unit contracts (Generator ↔ AiDraft, Generator ↔ Funnies, and the DraftBundle handoff) be specified?
|
||||
|
||||
A) Shared-schema contracts in Python (data classes / pydantic-style models) that live with the producer unit and are referenced by consumers — ideal for a local library-backed tool (recommended)
|
||||
B) A standalone JSON-schema file per contract, imported by all units
|
||||
C) Formal OpenAPI/AsyncAPI specs — heavier than a local tool needs
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Q2: Integration mechanism
|
||||
|
||||
How do the units call each other at the library boundary?
|
||||
|
||||
A) Direct module/function calls (the `newspaper` CLI imports the ai-draft and funnies libraries and calls their entry functions in-process) (recommended)
|
||||
B) Each unit is a separate process, communicating via JSON over a pipe/CLI
|
||||
C) A message/event bus between units
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Q3: Contract ownership
|
||||
|
||||
Who owns each contract spec?
|
||||
|
||||
A) Each producer unit owns the contract for data it emits — AiDraft owns the DraftBundle shape, Funnies owns the puzzle/cartoon output shape, Generator owns content/config input shapes (recommended)
|
||||
B) A shared "contracts" home owned jointly
|
||||
C) The CLI (Generator) owns all contracts centrally
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Q4: Error / timeout / fallback behaviour
|
||||
|
||||
How should the boundaries handle failure (e.g. Ollama unavailable, Funnies finds no cartoon, missing content)?
|
||||
|
||||
A) Fail gracefully: each unit returns a clear error/fallback (Ollama down → skip drafting with a message; no cartoon → tasteful placeholder; missing content → guided empty state), never a crash or blank page (recommended)
|
||||
B) Hard-fail loudly with a clear message and non-zero exit
|
||||
C) Best-effort only — ignore failures silently
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Q5: Versioning policy
|
||||
|
||||
How should internal contract changes be handled (this is a one-shot local tool)?
|
||||
|
||||
A) No formal versioning — additive, backward-compatible changes only within/after a build; breaking changes are re-generated in one go (recommended)
|
||||
B) Semantic versioning of the library API, since content/consumers could persist between runs
|
||||
C) Locked/immutable — contracts cannot change after review
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Consolidated Summary Confirmation
|
||||
|
||||
> Summary of your five contract answers before the contract summary is generated:
|
||||
>
|
||||
> - Contract representation: **shared-schema contracts in Python** (data classes / pydantic-style), referenced by consumers (Q1=A)
|
||||
> - Integration mechanism: **in-process module/function calls** — the `newspaper` CLI imports the ai-draft and funnies libraries (Q2=A)
|
||||
> - Contract ownership: **each producer owns its contract** — AiDraft owns the DraftBundle shape, Funnies the puzzle/cartoon output, Generator the content/config input shapes (Q3=A)
|
||||
> - Error/fallback: **fail gracefully** — Ollama down → skip draft with a message, no cartoon → tasteful placeholder, missing content → guided empty state; never crash or blank (Q4=A)
|
||||
> - Versioning: **no formal versioning** — additive backward-compatible changes; breaking changes regenerated in one go (Q5=A)
|
||||
>
|
||||
> Human pre-approved this summary (answers recorded via the file, self-guided mode).
|
||||
|
||||
Does this all look correct before I generate the contract summary?
|
||||
|
||||
- Looks correct
|
||||
- Request changes
|
||||
|
||||
[Answer]: Looks correct
|
||||
+197
@@ -0,0 +1,197 @@
|
||||
# Contract Summary — Wedding Newspaper Generator
|
||||
|
||||
> Contracts across the unit boundaries, per confirmed decisions (Q1–Q5 all = A):
|
||||
> shared-schema contracts in Python (data classes / pydantic-style), in-process
|
||||
> module/function calls, producer-owned specs, graceful failure with clear
|
||||
> fallbacks, no formal versioning. All boundaries are internal library
|
||||
> interfaces for a one-shot local tool — there are no public/external API
|
||||
> boundaries (nothing is served or deployed).
|
||||
|
||||
## Contracts table
|
||||
|
||||
| # | Provider Unit | Consumer | Mechanism | Owner |
|
||||
|---|---|---|---|---|
|
||||
| 1 | AiDraft (U2) | Generator (U1) | in-process call → returns Draft | AiDraft |
|
||||
| 2 | Funnies (U3) | Generator (U1) | in-process call → returns FunniesResult | Funnies |
|
||||
| 3 | Generator (U1) | AiDraft (U2) | in-process call → DraftBrief (input contract) | Generator |
|
||||
| 4 | Generator (U1) | Funnies (U3) | in-process call → FunniesBrief (input contract) | Generator |
|
||||
| 5 | Generator (U1) | Review page (external-consumer of DraftBundle) | file handoff → DraftBundle JSON read via native file picker | Generator |
|
||||
|
||||
## Per-contract spec
|
||||
|
||||
Contracts are shared-schema blocks in Python (pydantic-style dataclasses lived
|
||||
next to the producer). The shapes below document the agreed payloads.
|
||||
|
||||
### Contract 1 — Draft (AiDraft → Generator)
|
||||
|
||||
Provider: AiDraft. Data emitted after a local-Ollama draft, consumed by Generator for the per-article review handoff.
|
||||
|
||||
```yaml
|
||||
shared-schema: draft
|
||||
producer: AiDraft
|
||||
version: 1
|
||||
fields:
|
||||
- name: articles
|
||||
type: list[DraftArticle]
|
||||
required: true
|
||||
- name: generatedAt
|
||||
type: datetime
|
||||
required: true
|
||||
sub-shape: DraftArticle
|
||||
fields:
|
||||
- name: articleId
|
||||
type: string
|
||||
required: true
|
||||
- name: type
|
||||
type: string # lead | article | filler | wellwish | ...
|
||||
required: true
|
||||
- name: headline
|
||||
type: string
|
||||
required: true
|
||||
- name: byline
|
||||
type: string
|
||||
default: ""
|
||||
- name: body
|
||||
type: string
|
||||
required: true
|
||||
- name: section
|
||||
type: string
|
||||
required: false
|
||||
```
|
||||
|
||||
### Contract 2 — FunniesResult (Funnies → Generator)
|
||||
|
||||
Provider: Funnies. Emits the content-derived puzzle + cartoon output, consumed by Generator for the funnies section.
|
||||
|
||||
```yaml
|
||||
shared-schema: funnies-result
|
||||
producer: Funnies
|
||||
version: 1
|
||||
fields:
|
||||
- name: crossword
|
||||
type: Crossword | null
|
||||
default: null
|
||||
- name: findAWord
|
||||
type: FindAWord | null
|
||||
default: null
|
||||
- name: comics
|
||||
type: list[Comic]
|
||||
default: []
|
||||
sub-shape: Crossword
|
||||
fields:
|
||||
- name: grid
|
||||
type: list[list[str]]
|
||||
- name: cluesAcross
|
||||
type: list[str]
|
||||
- name: cluesDown
|
||||
type: list[str]
|
||||
- name: solution
|
||||
type: list[list[str]]
|
||||
sub-shape: FindAWord
|
||||
fields:
|
||||
- name: words
|
||||
type: list[str]
|
||||
- name: grid
|
||||
type: list[list[str]]
|
||||
sub-shape: Comic
|
||||
fields:
|
||||
- name: id
|
||||
type: string
|
||||
- name: art
|
||||
type: string # local/bundled asset URI or data
|
||||
- name: dialogue
|
||||
type: list[str]
|
||||
```
|
||||
|
||||
### Contract 3 — DraftBrief (Generator → AiDraft)
|
||||
|
||||
Provider: Generator. The input the CLI passes to AiDraft to request a draft.
|
||||
|
||||
```yaml
|
||||
shared-schema: draft-brief
|
||||
producer: Generator
|
||||
version: 1
|
||||
fields:
|
||||
- name: contentContext
|
||||
type: string # content-derived brief for the lead/fillers
|
||||
- name: model
|
||||
type: string # granted model deepseek-v4-flash:cloud (CLOUD, sanctioned)
|
||||
default: deepseek-v4-flash:cloud
|
||||
- name: requestedArticleTypes
|
||||
type: list[string]
|
||||
default: [lead, filler]
|
||||
```
|
||||
|
||||
> **Model note (human ruling 2026-09-13):** `deepseek-v4-flash:cloud` may be a
|
||||
> **cloud** model and is explicitly sanctioned, treated like the internet-pull
|
||||
> exception for content enrichment. It is faster than a local model and is
|
||||
> approved for AI drafting at generation time. This is the one sanctioned
|
||||
> off-machine call in the pipeline; the EMITTED `newspaper.html` remains
|
||||
> self-contained and zero-network (NFR4).
|
||||
|
||||
### Contract 4 — FunniesBrief (Generator → Funnies)
|
||||
|
||||
Provider: Generator. The content-derived context Funnies uses to build puzzles + select/embed a cartoon.
|
||||
|
||||
```yaml
|
||||
shared-schema: funnies-brief
|
||||
producer: Generator
|
||||
version: 1
|
||||
fields:
|
||||
- name: themeWords
|
||||
type: list[str] # derived from content
|
||||
- name: context
|
||||
type: string # couple/occasion context for cartoon search
|
||||
- name: cartoonSource
|
||||
type: string # internet-enrich allowed (human ruling) — fetch at build time, embed locally
|
||||
default: internet-allow
|
||||
```
|
||||
|
||||
### Contract 5 — DraftBundle JSON (Generator → Review page)
|
||||
|
||||
Provider: Generator. The on-disk JSON written by the CLI and read by the
|
||||
per-article review page via the native file picker (NFR5, ADR-004).
|
||||
|
||||
```yaml
|
||||
shared-schema: draft-bundle
|
||||
producer: Generator
|
||||
version: 1
|
||||
format: json-file
|
||||
fields:
|
||||
- name: articles
|
||||
type: list[DraftArticle]
|
||||
required: true
|
||||
- name: generatedAt
|
||||
type: datetime
|
||||
required: true
|
||||
consumed-by:
|
||||
- role: review-page
|
||||
mechanism: native file picker (user-granted read), never fetch() of a sibling file
|
||||
```
|
||||
|
||||
## Contract ownership rules
|
||||
|
||||
- **Owner of each spec** is its producer unit (Q3=A): the owning library holds
|
||||
the Python dataclass/schema and version.
|
||||
- **Consumers reference** the producer-owned shape; they never re-declare a
|
||||
competing copy.
|
||||
- **Additive, backward-compatible changes only** within normal builds (Q5=A):
|
||||
consumers ignore unknown fields. Breaking changes to a contract are agreed and
|
||||
regenerated in one pass for this self-contained tool (no external consumers to
|
||||
co-ordinate).
|
||||
- **Failure contract (Q4=A):** grace, never crash. Ollama unreachable → AiDraft
|
||||
returns an empty/no-draft result with a message, Generator proceeds without AI.
|
||||
No cartoon found → Funnies returns a tasteful content-derived placeholder, not
|
||||
a remote fetch. Missing content → Generator surfaces the guided empty state
|
||||
(US10). Every boundary returns a clear, typed result; the CLI never exits on a
|
||||
blank page.
|
||||
|
||||
## Open questions
|
||||
|
||||
| Contract | Question | Blocks |
|
||||
|---|---|---|
|
||||
| 1 (Draft) | Exact per-article type taxonomy (lead/article/filler/wellwish) — confirm at Functional Design | AiDraft, Generator |
|
||||
| 5 (DraftBundle) | Whether the review page expects a pure-JSON vs schema-hint wrapper | Generator (review page) |
|
||||
| None blocking | — | — |
|
||||
|
||||
<!-- contract-summary-after-confirm -->
|
||||
@@ -0,0 +1,17 @@
|
||||
<!-- 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-13T12:20:00Z — Interpretation — Confirmed contract design (all A, self-guided + user auto-approved summary): shared-schema Python contracts, in-process calls, producer-owned specs, graceful failure, no formal versioning
|
||||
2026-09-13T12:20:00Z — Interpretation — All boundaries are internal library interfaces for a one-shot local tool; no public/external API boundaries
|
||||
2026-09-13T12:30:00Z — Interpretation — contract-design review R-01 settled by human: deepseek-v4-flash:cloud is a CLOUD model explicitly sanctioned (like the internet-pull exception, faster than local). It is the one approved off-machine call at generation time; the emitted newspaper.html stays zero-network. Contract 3 annotated accordingly.
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
# Delivery Planning — Bolt Plan
|
||||
|
||||
> Construction sequence for the wedding newspaper generator, per confirmed
|
||||
> answers (Q1=A value-core first, Q2=A no formal score, Q3=A one unit per Bolt,
|
||||
> Q4=B parallel ai-draft + funnies, Q5=A no external blockers). A **Bolt** is
|
||||
> one build pass over a piece of the work, ending in something that runs.
|
||||
> Topology is from Units Generation (2.7); this stage chooses the economic
|
||||
> path through it. Walking skeleton is skipped per affirmed team practice.
|
||||
|
||||
## Bolt sequence
|
||||
|
||||
| Bolt | Units | Notes / walking-skeleton | Definition of Done | Confidence hypothesis | Expected demo |
|
||||
|---|---|---|---|---|---|
|
||||
| Bolt 1 | `generator` (core) | Value core first (Q1=A): CLI, content parse, masthead, layout, emit. Simple content, works end-to-end early. | `newspaper generate <simple content>` emits a self-contained `newspaper.html` that prints to A4 with correct masthead + columns | The core render pipeline hangs together and the paper prints end-to-end with hand-written content | A one-page sample newspaper from simple markdown |
|
||||
| Bolt 2a | `ai-draft` | Parallel (Q4=B) with Bolt 2b — independent of funnies. | `--draft` calls the granted model and returns a DraftBundle review set | The AI drafting loop (cloud model + per-article DraftBundle) works and stays reviewable | A drafted article set ready for per-article review |
|
||||
| Bolt 2b | `funnies` | Parallel (Q4=B) with Bolt 2a — independent of ai-draft. | `funnies` builds crossword + find-a-word from content and embeds/selects a cartoon; falls back when none found | Content-derived puzzles + cartoon are produceable and A4-printable | A crossword, a find-a-word, and a selected cartoon block |
|
||||
| Bolt 3 | `generator` integration | Fold in ai-draft + funnies; add per-article review page + photo embedding. | Full newspaper: AI draft → per-article review → funnies section → photos → multi-page A4 print | The whole chain works end-to-end with all sections and the review handoff | A full multi-page newspaper with funnies, photos, AI drafts, reviewed |
|
||||
|
||||
## Why this order (summary)
|
||||
|
||||
- **Bolt 1 first** = value core / end-to-end early (Q1=A): the highest-confidence,
|
||||
central capability lands first, matching the affirmed "no separate walking
|
||||
skeleton" (the first Bolt is naturally a thin end-to-end slice anyway).
|
||||
- **Bolts 2a/2b parallel** = the independent, higher-unknown pair (funnies and AI
|
||||
drafting — the user's stated worries, Q6=B,C) after the core works, so they
|
||||
can be built and de-risked concurrently.
|
||||
- **Bolt 3 last** = integration: wire the funnies + AI review into the core and
|
||||
polish multi-page fidelity. Tackles the print-fidelity worry (Q6=A) as the
|
||||
finish pass.
|
||||
|
||||
## Confidence hypotheses (per Bolt)
|
||||
|
||||
- Bolt 1: "The core render pipeline produces a correct, A4-printable paper from
|
||||
hand-written markdown."
|
||||
- Bolt 2a: "The AI draft produces acceptable wedding-appropriate copy and the
|
||||
per-article DraftBundle is reviewable off file://."
|
||||
- Bolt 2b: "Content-derived crosswords/find-a-words and a selected cartoon print
|
||||
correctly on A4 with a graceful fallback."
|
||||
- Bolt 3: "The full newspaper — AI drafts, review, funnies, photos, multi-page
|
||||
print — works end-to-end with all sections."
|
||||
|
||||
<!-- delivery-planning-after-confirm -->
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
# Delivery Planning — Questions
|
||||
|
||||
> Fill in each `[Answer]:` tag. Options A-E plus X (Other). The file is the
|
||||
> authoritative record of your construction-sequencing decisions.
|
||||
|
||||
## Q1: Build-first strategy
|
||||
|
||||
We have three units of work: `generator` (the CLI + layout + emit, which depends on the other two), `ai-draft` (optional local/cloud Ollama drafting), and `funnies` (crossword/find-a-word/cartoon). What should we build first?
|
||||
|
||||
A) The value core first — `generator` layout/render/emit first (with simple content), then add `ai-draft` and `funnies` later; the paper works end-to-end early (recommended given we skip the separate walking skeleton)
|
||||
B) The risky parts first — `ai-draft` and `funnies` first (they have the most unknowns: Ollama/cloud model, cartoon search, puzzle generation), then wire them into `generator`
|
||||
C) The dependencies first — build `ai-draft` and `funnies` first (topologically), then `generator` last
|
||||
D) A thin end-to-end slice first — one markdown file → one A4 page proving the whole chain, despite practices saying we skip a formal walking skeleton
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Q2: Scoring the work
|
||||
|
||||
Should we rank the build with a formal scoring model (value + urgency against size — WSJF-style: higher score ships first)?
|
||||
|
||||
A) No formal score — order by a pragmatic mix we decide in the plan (value core first, then the riskier funnies/AI), simplest for a solo local tool (recommended)
|
||||
B) Yes — a WSJF-style score per unit (weighted: value, risk-reduction, size) so the sequence is evidence-based
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Q3: Bolt size
|
||||
|
||||
How should we bundle the work into Bolts (a Bolt is one build pass over a piece of the work, ending in something that runs)?
|
||||
|
||||
A) One unit per Bolt — three Bolts (`generator`, `ai-draft`, `funnies`), each independently built and reviewed (recommended)
|
||||
B) Fewer, larger Bolts — e.g. bundle all three into a couple of passes
|
||||
C) Thin slices cutting across units (e.g. a minimal crossword in the first pass)
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Q4: Concurrency
|
||||
|
||||
Can several Bolts be built at the same time, or one after another?
|
||||
|
||||
A) One at a time, reviewed as we go (single-session, you approve each — recommended)
|
||||
B) Parallel — build `ai-draft` and `funnies` concurrently (they're independent), then `generator` integrates them
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: B
|
||||
|
||||
## Q5: External blockers
|
||||
|
||||
Is anything outside the team going to hold us up (external APIs, data waiting on someone, approvals, another hand-off)?
|
||||
|
||||
A) No blockers — the Ollama/cloud model and the internet content-enrichment are things the generator itself calls; we control the timeline (recommended)
|
||||
B) Yes — there are external dependencies (e.g. specific photos, a particular cartoon license, awaiting content from someone) that could gate a Bolt
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Q6: Biggest worry
|
||||
|
||||
What worries you most about this build, so we tackle it early?
|
||||
|
||||
A) Print fidelity — getting the broadsheet look, columns, and clean A4 page breaks right (the highest-value surface)
|
||||
B) The funnies — crossword/puzzle generation from content and the cartoon search are the most unpredictable
|
||||
C) The AI drafting quality — whether the model produces copy that feels right for the wedding
|
||||
D) The review handoff — making the per-article review page reliable under the file:// no-server constraint
|
||||
E) Nothing specific — the scope is clear enough
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: B, C, D
|
||||
|
||||
## Consolidated Summary Confirmation
|
||||
|
||||
> Summary of your six delivery-planning answers before the construction Bolt plan is generated:
|
||||
>
|
||||
> - Build-first strategy: **value core first** — the `generator` layout/render/emit first with simple content, then `ai-draft` and `funnies` added later; the paper works end-to-end early (Q1=A)
|
||||
> - Scoring: **no formal score** — a pragmatic mix we decide in the plan (Q2=A)
|
||||
> - Bolt size: **one unit per Bolt** — three Bolts (`generator`, `ai-draft`, `funnies`), each independently built and reviewed (Q3=A)
|
||||
> - Concurrency: **parallel** — `ai-draft` and `funnies` built concurrently (they're independent), then `generator` integrates them (Q4=B)
|
||||
> - External blockers: **none** — we control the timeline (Q5=A)
|
||||
> - Biggest worries (tackle early): **funnies unpredictability, AI drafting quality, review-handoff reliability** (Q6=B,C,D)
|
||||
>
|
||||
> Human pre-approved this summary (answers read from the file; explicit permission granted to auto-approve).
|
||||
|
||||
Does this all look correct before I generate the Bolt plan artifacts?
|
||||
|
||||
- Looks correct
|
||||
- Request changes
|
||||
|
||||
[Answer]: Looks correct
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
# Delivery Planning — External Dependency Map
|
||||
|
||||
> Anything outside the team that could gate a Bolt. Per Q5=A, **no external
|
||||
> blockers** — we control the timeline.
|
||||
|
||||
## Dependency map
|
||||
|
||||
| Bolt | External dependency | Owner | Lead time | Slip handling |
|
||||
|---|---|---|---|---|
|
||||
| Bolt 2a (`ai-draft`) | The granted AI model (`deepseek-v4-flash:cloud`), called by the generator | The tool itself (sanctioned cloud call, human-approved) | Instant (on demand) | If model unreachable: `ai-draft` returns a clear no-draft result; the paper builds without AI (graceful failure per Q4/A in contracts). Slip does not gate the core. |
|
||||
| Bolt 2b (`funnies`) | Internet content-enrichment (cartoon search / comic source), a build-time fetch allowed by human ruling | The tool itself | Instant (on demand) | If no suitable cartoon found: tasteful content-derived placeholder, never a remote dependency at print (NFR4). Does not gate the build. |
|
||||
|
||||
## Notes
|
||||
|
||||
- No approvals, no people, no data windows, and no other teams gate any Bolt.
|
||||
- The two "external" touchpoints are both things the generator itself calls at
|
||||
**generation time** and both degrade gracefully, so they are **not** blocking
|
||||
dependencies — consistent with Q5=A.
|
||||
- Photos (US4) are user-supplied inputs; if absent the layout renders without
|
||||
them (FR7.4), so they don't gate the build either.
|
||||
|
||||
## (effectively empty — fully AI/self-contained)
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
<!-- 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-13T12:40:00Z — Interpretation — Confirmed sequencing: value core (generator) first, then parallel ai-draft+funnies, then integration. No formal WSJF. No external blockers. Worries: funnies, AI quality, review-handoff.
|
||||
2026-09-13T12:40:00Z — Tradeoff — Bolt order deviates from strict 2.7 topology: generator (which topologically depends on the other two) ships first per Q1=A value-core; captured in risk-and-sequencing-rationale.
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
# Delivery Planning — Risk & Sequencing Rationale
|
||||
|
||||
> The why behind the Bolt order. **Bolt** is one build pass over a piece of the
|
||||
> work, ending in something that runs. The economic order chosen here is: value
|
||||
> core first, then the higher-unknown parallel pair, then integration.
|
||||
|
||||
## Sequencing argument
|
||||
|
||||
The chosen order balances **early working software** (Q1=A) with **de-risking the
|
||||
uncertain parts early** (Q6=B,C,D — the user's worries: funnies unpredictability,
|
||||
AI drafting quality, review-handoff reliability).
|
||||
|
||||
- **Bolt 1 — `generator` core first (value/skeleton case).** Builds the central,
|
||||
highest-confidence capability: CLI → content → layout → emit → A4 print. The
|
||||
paper works end-to-end with hand-written content early, so the highest-value
|
||||
surface (the printable broadsheet) is proven before the exotic parts land.
|
||||
This also naturally satisfies the affirmed "no separate walking skeleton": the
|
||||
first Bolt IS a thin end-to-end slice (markdown in → A4 page out) without
|
||||
calling it one.
|
||||
- **Bolts 2a/2b — `ai-draft` and `funnies` in parallel (risk-reduction).** The
|
||||
two most unpredictable units — AI copy quality and content-derived puzzle/
|
||||
cartoon generation — are independent, so they build concurrently (Q4=B). Both
|
||||
de-risk the user's stated worries (Q6=B,C) before integration. Each is also
|
||||
independently testable (DraftBundle contract; puzzle+cartoon output).
|
||||
- **Bolt 3 — integration last.** Wires the two new units into the core and
|
||||
completes the full-chain fidelity (multi-page print, photo embed, per-article
|
||||
review handoff). The review-handoff reliability worry (Q6=D) is addressed here
|
||||
against the file:// no-server constraint.
|
||||
|
||||
## Reference heuristic
|
||||
|
||||
No formal WSJF score (Q2=A). The order follows a pragmatic mix:
|
||||
**value-first + risk-reduction + dependency-aware**. It is coherent with
|
||||
Reinertsen's CD3-style reasoning (deliver value early while sequencing the high
|
||||
uncertainty soon enough to learn from it), but we did not compute a numeric score.
|
||||
|
||||
## Deviation-from-topology note
|
||||
|
||||
The Bolt order **does not strictly follow 2.7's topological order**. Topology
|
||||
says `generator` depends on `ai-draft` and `funnies`; a strict topological walk
|
||||
would build ai-draft + funnies first. We deviate deliberately: **Bolt 1 builds
|
||||
`generator` with simple/sample content first** (no ai-draft/funnies needed for
|
||||
the core hand-written path), then the independent pair in parallel (Bolt 2a/2b),
|
||||
then integration (Bolt 3). This is justified by Q1=A (value core early) and the
|
||||
parallelism in Q4=B. The deviation is captured here as the stage requires.
|
||||
|
||||
## Rationale
|
||||
|
||||
| Bolt | Rationale |
|
||||
|---|---|
|
||||
| Bolt 1 | Value core, highest confidence, end-to-end early |
|
||||
| Bolt 2a | Independent + user worry (AI quality/drafting) — de-risk |
|
||||
| Bolt 2b | Independent + user worry (funnies) — de-risk |
|
||||
| Bolt 3 | Integration + full fidelity (incl. print-fidelity worry Q6=A) |
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
# Delivery Planning — Team Allocation
|
||||
|
||||
> Which team/mob owns which Bolt. A **mob** is a small team owning a Bolt's
|
||||
> delivery. Per affirmed team practice, this is a solo local project.
|
||||
|
||||
## Allocation
|
||||
|
||||
This project is a solo local tool (classic scope — the team-formation stage was
|
||||
skipped). **All Bolts are executed by the single developer agent**
|
||||
(`aidlc-developer-agent`), in this session, with you approving as each Bolt
|
||||
completes.
|
||||
|
||||
| Bolt | Owner | Notes |
|
||||
|---|---|---|
|
||||
| Bolt 1 (`generator` core) | aidlc-developer-agent | build + verify + present |
|
||||
| Bolt 2a (`ai-draft`) | aidlc-developer-agent | build + verify + present |
|
||||
| Bolt 2b (`funnies`) | aidlc-developer-agent | build + verify + present |
|
||||
| Bolt 3 (integration) | aidlc-developer-agent | build + verify + present |
|
||||
|
||||
## Program Board note
|
||||
|
||||
Single-team (a solo developer), so there is no Program Board — no
|
||||
cross-team sequencing or hand-off coordination is required. The Bolt plan's
|
||||
parallelism (2a/2b) is scheduling, not separate teams.
|
||||
|
||||
## Approval rhythm
|
||||
|
||||
One approval per Bolt, one at a time as they complete (per Q4=A's "reviewed as we
|
||||
go" for the core, with 2a/2b built in parallel and each reviewed on return).
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
# Domain Design — Component Catalogue
|
||||
|
||||
> Components for the wedding newspaper generator, per confirmed decomposition
|
||||
> (Q1–Q5 all = A): a single `Generator` orchestrator, a distinct optional
|
||||
> `AiDraft` component (local Ollama only), a distinct `Funnies` component
|
||||
> (puzzles + cartoon), the review-page handoff via a draft JSON bundle read
|
||||
> through the native file picker, and lightweight plain-data entities with the
|
||||
> filesystem as the store.
|
||||
|
||||
## Part A — Machine-readable catalogue
|
||||
|
||||
```yaml
|
||||
components:
|
||||
- name: Generator
|
||||
summary: >
|
||||
The CLI entry point and orchestrator: reads config + content, coordinates
|
||||
layout and rendering, and emits the self-contained printable newspaper.html.
|
||||
behaviour: >
|
||||
Reads config.json (masthead metadata) and the content/ folder. Owns content
|
||||
parsing (markdown/txt), the classic broadsheet layout model, multi-page A4
|
||||
pagination with clean page breaks, article/section placement, the optional
|
||||
per-article review handoff, and final zero-network HTML emission. Never sends
|
||||
content off-machine. Optional AI draft and funnies are delegated to AiDraft
|
||||
and Funnies respectively.
|
||||
responsibilities:
|
||||
- Read + validate config (masthead metadata) and content
|
||||
- Parse markdown/txt into Article entities
|
||||
- Build the newspaper layout (columns, pagination, masthead)
|
||||
- Assemble the funnies section output from Funnies
|
||||
- Emit self-contained newspaper.html (zero-network, file:// printable)
|
||||
- Write the AI-draft JSON bundle for the review page (review handoff)
|
||||
depends_on:
|
||||
- component: AiDraft
|
||||
interaction: calls optional local-Ollama draft when --draft is used; receives draft Article set
|
||||
style: sync
|
||||
- component: Funnies
|
||||
interaction: asks for crossword/find-a-word/cartoon built from content theme words + context
|
||||
style: sync
|
||||
dependents: []
|
||||
external_dependencies:
|
||||
- name: Local filesystem (content/, config.json)
|
||||
kind: other
|
||||
purpose: the authoritative content store (Q5=A — filesystem is the store)
|
||||
entities:
|
||||
- name: Issue
|
||||
identifier: issueNumber
|
||||
attributes: [title, dateLine, issueNumber, volume, coupleNames]
|
||||
- name: Article
|
||||
identifier: articleId
|
||||
attributes: [type, headline, byline, body, section]
|
||||
- name: MastheadConfig
|
||||
identifier: configPath
|
||||
attributes: [title, coupleNames, dateLine, issueNumber, volume]
|
||||
references:
|
||||
- entity: Issue
|
||||
owned_by: Generator
|
||||
relationship: "each Issue carries the resolved masthead identity"
|
||||
- name: DraftBundle
|
||||
identifier: bundlePath
|
||||
attributes: [articles, generatedAt]
|
||||
references:
|
||||
- entity: Article
|
||||
owned_by: Generator
|
||||
relationship: "the DraftBundle holds the AI-drafted Article set for review"
|
||||
|
||||
- name: AiDraft
|
||||
summary: >
|
||||
Optional component that drafts newspaper copy via the local Ollama model.
|
||||
behaviour: >
|
||||
Talks only to local Ollama. Given the content-derived context and brief,
|
||||
it drafts the lead story and filler articles. Produces a DraftBundle the
|
||||
review page reads. Fully optional — when --draft is absent it does nothing
|
||||
and the render uses only human-authored content. Never contacts any
|
||||
external/cloud service; content stays on-machine.
|
||||
responsibilities:
|
||||
- Accept the authoring brief (content-derived context + --draft flag)
|
||||
- Call local Ollama (granted model deepseek-v4-flash:cloud) to draft copy
|
||||
- Return a DraftBundle (article set) for per-article review
|
||||
depends_on: []
|
||||
dependents:
|
||||
- component: Generator
|
||||
interaction: invoked by the generator when the couple requests an AI draft
|
||||
external_dependencies:
|
||||
- name: Local Ollama
|
||||
kind: third-party-api
|
||||
purpose: local model inference for copy drafting (NFR9, local-only)
|
||||
entities: []
|
||||
|
||||
- name: Funnies
|
||||
summary: >
|
||||
Component that builds the "fun" section — crossword, find-a-word, and
|
||||
comic/cartoon placement — generated from the content itself.
|
||||
behaviour: >
|
||||
Takes theme words and context drawn from the content (US3/FR4/Q5=X),
|
||||
produces the crossword grid + across/down clues, a find-a-word grid, and
|
||||
selects/embeds an xkcd-style cartoon using content-derived context for the
|
||||
search. A build-time network fetch to enrich content is allowed and
|
||||
encouraged (human ruling 2026-09-13: no server, not deployed, but internet
|
||||
data may enhance content) — so a genuine xkcd may be fetched at generation
|
||||
time and embedded locally. Emits print-ready, A4-bounded, self-contained
|
||||
outputs; the EMITTED page itself makes zero network requests. If no
|
||||
cartoon is found, it falls back to a tasteful content-derived decorative
|
||||
strip rather than blocking the run (mockups R-02 resolution).
|
||||
responsibilities:
|
||||
- Derive theme words and context from Content/article text
|
||||
- Build crossword grid + clues
|
||||
- Build find-a-word grid
|
||||
- Select/embed a cartoon (content-context search, local embed)
|
||||
- Emit A4-printable, self-contained puzzle/comic blocks
|
||||
depends_on: []
|
||||
dependents:
|
||||
- component: Generator
|
||||
interaction: generator requests funnies output during the layout pass
|
||||
external_dependencies:
|
||||
- name: Local filesystem (xcomic assets / bundled art)
|
||||
kind: other
|
||||
purpose: source for comics and the embedded xkcd cartoon (no network at print)
|
||||
entities:
|
||||
- name: Puzzle
|
||||
identifier: puzzleId
|
||||
attributes: [type, grid, cluesAcross, cluesDown, solution, findWords]
|
||||
```
|
||||
|
||||
## Part B — Human-readable view
|
||||
|
||||
### Component Diagram
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
Generator -->|"--draft drafts copy"| AiDraft
|
||||
Generator -->|"theme words and context"| Funnies
|
||||
AiDraft -->|"DraftBundle"| Generator
|
||||
Funnies -->|"puzzles and cartoon"| Generator
|
||||
```
|
||||
|
||||
### Component Summary
|
||||
|
||||
| Component | Purpose | Depends On | Dependents | Entities Owned |
|
||||
|---|---|---|---|---|
|
||||
| Generator | CLI orchestrator: config/content → self-contained newspaper.html | AiDraft, Funnies | — | Issue, Article, MastheadConfig, DraftBundle |
|
||||
| AiDraft | Optional local-Ollama copy drafting | — | Generator | — |
|
||||
| Funnies | Content-derived crossword/find-a-word/cartoon | — | Generator | Puzzle |
|
||||
|
||||
### Entity Ownership
|
||||
|
||||
| Entity | Owning Component | Identifier | Attributes | References |
|
||||
|---|---|---|---|---|
|
||||
| Issue | Generator | issueNumber | title, dateLine, issueNumber, volume, coupleNames | — |
|
||||
| Article | Generator | articleId | type, headline, byline, body, section | — |
|
||||
| MastheadConfig | Generator | configPath | title, coupleNames, dateLine, issueNumber, volume | Issue |
|
||||
| DraftBundle | Generator | bundlePath | articles, generatedAt | Article |
|
||||
| Puzzle | Funnies | puzzleId | type, grid, cluesAcross, cluesDown, solution, findWords | — |
|
||||
|
||||
### External Dependencies
|
||||
|
||||
| Component | Dependency | Kind | Purpose |
|
||||
|---|---|---|---|
|
||||
| Generator | Local filesystem (content/, config.json) | other | authoritative content store (Q5=A) |
|
||||
| AiDraft | Local Ollama | third-party-api | local model inference (NFR9) |
|
||||
| Funnies | Local filesystem (comic/cartoon assets) | other | local comic + embedded cartoon source |
|
||||
|
||||
### Rationale
|
||||
|
||||
| Component | Why a separate building block |
|
||||
|---|---|
|
||||
| Generator | Distinct concern (parsing → layout → emit) and distinct lifecycle; its own data ownership and change rate (layout/print changes land here) |
|
||||
| AiDraft | Distinct concern and change rate (AI integration is optional and isolated); keeping it separate means no-draft runs never touch it |
|
||||
| Funnies | Distinct concern (content→puzzle heuristics are non-trivial) and change rate; isolated so layout changes don't destabilize puzzle generation |
|
||||
|
||||
### Alternatives Rejected (decomposition)
|
||||
|
||||
- **Option B (multiple fine-grained components: ContentLoader, FunniesBuilder, LayoutEngine, Renderer)** — rejected: over-fragmentation for a local single-purpose tool; Q1=A chose cohesion. Reconsider if the generator grows into a larger system.
|
||||
- **Option C (minimal thin script)** — rejected: would collapse puzzle/AI/layout responsibilities into un-testable ball of code; the three-component split keeps testability without over-splitting.
|
||||
|
||||
## Deliberate-cycles note
|
||||
|
||||
None. The dependency graph is acyclic: Generator → { AiDraft, Funnies }, with the DraftBundle back-reference being a data artifact (written then read via the file picker), not a synchronous call, so it is not a dependency cycle.
|
||||
|
||||
<!-- domain-design-after-confirm -->
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
# Architecture Decision Records — Wedding Newspaper Generator
|
||||
|
||||
> Durable ADR log for the significant design choices made in Domain Design.
|
||||
|
||||
## ADR-001: Cohesive Generator component over fine-grained splitting
|
||||
|
||||
- **Context** — The generator is a single-purpose, fully-local tool. The team
|
||||
had to choose between one cohesive orchestrator with separated internal
|
||||
responsibilities (Q1=A) and several fine-grained independent components
|
||||
(ContentLoader, FunniesBuilder, LayoutEngine, Renderer).
|
||||
- **Decision** — Adopt a single `Generator` component that owns content
|
||||
parsing, the layout model, multi-page rendering, and emission, with its
|
||||
funnies and AI-draft concerns delegated to two distinct components
|
||||
(`Funnies`, `AiDraft`).
|
||||
- **Consequences** — (+) Simpler for a local tool; fewer moving parts;
|
||||
layout/print changes land in one place. (−) The Generator is larger; if the
|
||||
tool grows into a larger system this may need splitting later.
|
||||
- **Alternatives Rejected** — Option B (fine-grained components): over-fragmented
|
||||
for this scope. Option C (minimal thin script): collapses concerns and loses
|
||||
testability.
|
||||
|
||||
## ADR-002: Distinct optional AiDraft component (local Ollama only)
|
||||
|
||||
- **Context** — AI copy generation (US8/US9/FR8) uses local Ollama and must be
|
||||
fully optional and stay on-machine (NFR9). The team chose whether to isolate it.
|
||||
- **Decision** — Model `AiDraft` as a distinct, fully-optional component that
|
||||
talks only to local Ollama and owns the draft + per-article review contract.
|
||||
When `--draft` is absent it does nothing.
|
||||
- **Consequences** — (+) No-draft runs never touch AI; the AI integration is
|
||||
isolated and easier to test/disable; content stays local. (−) One more
|
||||
component boundary to document.
|
||||
- **Alternatives Rejected** — Folding Ollama calls into the generator: couples
|
||||
the optional AI path into the core and makes "no AI" runs carry AI code.
|
||||
|
||||
## ADR-003: Funnies generation owned by a distinct component
|
||||
|
||||
- **Context** — The funnies (crossword, find-a-word, comics, xkcd cartoon) are
|
||||
generated from the content itself (US3/FR4/Q5=X), which is non-trivial work.
|
||||
- **Decision** — Give `Funnies` its own component that derives theme
|
||||
words/context from content and produces the crossword/find-a-word grids and
|
||||
the embedded cartoon. It emits A4-printable, self-contained blocks.
|
||||
- **Consequences** — (+) Puzzle logic is isolated from layout so layout changes
|
||||
don't destabilize generation; content-derived puzzles feel hand-crafted. (−)
|
||||
The content→puzzle heuristic is genuinely complex and must handle a no-cartoon
|
||||
fallback (mockups R-02).
|
||||
- **Alternatives Rejected** — Folding funnies into the generator: couples puzzle
|
||||
heuristics into layout; separate puzzle-gen and cartoon-fetch sub-components:
|
||||
over-split for now.
|
||||
|
||||
## ADR-004: Draft bundle read via native file picker (no-server review handoff)
|
||||
|
||||
- **Context** — The per-article review page (US9/Q3=A) is a single `file://`
|
||||
page, and the no-server/zero-network constraints (NFR3–NFR5) forbid `fetch()`
|
||||
of sibling files and forbid running a server during review (Q1=A / Q4=B).
|
||||
- **Decision** — The CLI writes the AI draft as a JSON `DraftBundle`; the review
|
||||
page loads it through the **native file picker** (user-granted read, NFR5).
|
||||
This resolves the mockups R-01 finding.
|
||||
- **Consequences** — (+) Review works fully offline, no server, no CORS workaround
|
||||
(§12 of the empirical file:// research). (−) The couple must pick the draft
|
||||
bundle in the file dialog once per run.
|
||||
- **Alternatives Rejected** — Serving a temporary localhost just during review
|
||||
(violates the no-server decision and adds a process to the flow); CLI prompt
|
||||
loop instead of an HTML review page (departs from confirmed Q3=A).
|
||||
|
||||
## ADR-005: Lightweight plain-data entities, filesystem as store
|
||||
|
||||
- **Context** — The project is a local generator with no deployment; the
|
||||
entities are Issue, Article, MastheadConfig, Puzzle, DraftBundle.
|
||||
- **Decision** — Model them as lightweight plain-data shapes owned by the
|
||||
generator; the content `config.json` + `content/` filesystem is the store.
|
||||
No database.
|
||||
- **Consequences** — (+) No infra to run; entities are trivially serializable
|
||||
(the DraftBundle JSON is one shape); fits the static-generator model. (−) No
|
||||
built-in indexing/querying — not needed at this scale.
|
||||
- **Alternatives Rejected** — A formalized strict-schema data layer: unnecessary
|
||||
overhead for a static local tool. No explicit entity model: would make the
|
||||
review handoff and traceability harder to test.
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
# Domain Design — Questions
|
||||
|
||||
> Fill in each `[Answer]:` tag. Options A-E plus X (Other). The file is the
|
||||
> authoritative record of your component-decomposition decisions.
|
||||
|
||||
## Q1: Generator monolith vs. separated components
|
||||
|
||||
How should the generator's build-time work be split as reusable components?
|
||||
|
||||
A) A single `Generator` component that reads content and orchestrates rendering, with clearly separated internal responsibilities (config, content, funnies, layout) — cohesive, simple for a local tool (recommended)
|
||||
B) Split into multiple independent components (ContentLoader, FunniesBuilder, LayoutEngine, Renderer) that the CLI calls in sequence
|
||||
C) Minimal: one thin script + the emitted static page only
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Q2: AI draft client boundary
|
||||
|
||||
The AI copy generation (US8/US9) uses local Ollama. Should it be its own component?
|
||||
|
||||
A) Yes — a distinct `AiDraft` component that talks only to local Ollama, owns the draft + per-article review contract, and is fully optional (recommended)
|
||||
B) No — fold the Ollama calls into the generator as an optional step
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Q3: Funnies generation ownership
|
||||
|
||||
The funnies (crossword, find-a-word, comics, xkcd cartoon) are generated from content (Q5=X). Which component should own this?
|
||||
|
||||
A) A distinct `Funnies` component that takes theme words/context from the content and produces the crossword/find-a-word grids + selects/embeds a cartoon (recommended)
|
||||
B) Fold funnies generation into the main generator as a sub-step
|
||||
C) Separate into puzzle-gen and cartoon-fetch sub-components
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Q4: Review page data handoff (R-01 from mockups)
|
||||
|
||||
Under the no-server constraint (Q1=A/Q4=B), how should the per-article review page receive the AI draft for a single file:// page to read it?
|
||||
|
||||
A) The CLI writes a draft bundle (JSON) the review-page loads through the native file picker (user-granted, NFR5) — recommended
|
||||
B) The review page is served briefly by a temporary localhost server just during review, then the final static HTML is produced
|
||||
C) Merge review into the CLI prompt loop (no HTML review page) — Q3=A in mockups says review page, so this departs from it
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Q5: Entity model for content & issue
|
||||
|
||||
For a purely local generator, how should we model the domain entities (an "issue", "article", "config", "puzzle")?
|
||||
|
||||
A) Lightweight plain data shapes (Issue, Article, MastheadConfig, Puzzle) owned by the generator, no database — the content filesystem is the store (recommended)
|
||||
B) A formalized issue/entity model with strict schemas up front
|
||||
C) No explicit entity model — keep it all file/template-driven
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Consolidated Summary Confirmation
|
||||
|
||||
> Summary of your five architecture answers before the component catalogue and ADRs are generated:
|
||||
>
|
||||
> - Generator decomposition: **single Generator component** with clearly separated internal responsibilities (config, content, funnies, layout) (Q1=A)
|
||||
> - AI draft client: **distinct, optional AiDraft component** that talks only to local Ollama and owns the draft + per-article review contract (Q2=A)
|
||||
> - Funnies ownership: **distinct Funnies component** that takes theme words/context from content and produces the crossword/find-a-word grids + selects/embeds a cartoon (Q3=A)
|
||||
> - Review-page data handoff: **CLI writes a draft JSON bundle** the review page loads through the native file picker (user-granted, NFR5) — resolving mockups R-01 (Q4=A)
|
||||
> - Entity model: **lightweight plain data shapes** (Issue, Article, MastheadConfig, Puzzle) owned by the generator; the content filesystem is the store (Q5=A)
|
||||
|
||||
Does this all look correct before I generate the component catalogue and ADRs?
|
||||
|
||||
- Looks correct
|
||||
- Request changes
|
||||
|
||||
[Answer]: Looks correct
|
||||
@@ -0,0 +1,17 @@
|
||||
<!-- 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-13T12:00:00Z — Interpretation — Confirmed decomposition (all A): single Generator orchestrate, distinct optional AiDraft (local Ollama), distinct Funnies (content-derived puzzles + cartoon), draft bundle read via file picker, lightweight entities with filesystem store
|
||||
2026-09-13T12:00:00Z — Tradeoff — DraftBundle back-reference is a data artifact (written then read via file dialog), not a sync call, so no dependency cycle
|
||||
2026-09-13T12:05:00Z — Interpretation — Human ruling (learnings): the constraint is no server + not deployed, but pulling data from the internet to ENHANCE content is fine/encouraged (e.g. xkcd cartoons, comics). Resolves review R-01: build-time content enrichment may fetch from the internet; the EMITTED page stays self-contained/printable (fetch happens at generation time, assets embedded locally)
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"stage": "domain-design",
|
||||
"upstream_ids": ["US1", "US2", "US3", "US4", "US5", "US6", "US7", "US8", "US9", "US10"],
|
||||
"coverage": [
|
||||
{ "id": "US1", "status": "OK", "target": "Generator" },
|
||||
{ "id": "US2", "status": "OK", "target": "Generator (MastheadConfig)" },
|
||||
{ "id": "US3", "status": "OK", "target": "Funnies" },
|
||||
{ "id": "US4", "status": "OK", "target": "Generator (Article)" },
|
||||
{ "id": "US5", "status": "OK", "target": "Generator" },
|
||||
{ "id": "US6", "status": "OK", "target": "Generator" },
|
||||
{ "id": "US7", "status": "OK", "target": "Generator (MastheadConfig/Issue)" },
|
||||
{ "id": "US8", "status": "OK", "target": "AiDraft" },
|
||||
{ "id": "US9", "status": "OK", "target": "AiDraft (DraftBundle), Generator (review handoff)" },
|
||||
{ "id": "US10", "status": "OK", "target": "Generator (empty state)" }
|
||||
]
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
**Collaborator:** aidlc-developer-agent
|
||||
|
||||
## Contribution
|
||||
|
||||
Assessing code-style conventions, file organization, and layer boundaries.
|
||||
|
||||
- The code-style proposal (plain HTML5/CSS/JS, no build step) is sound and matches
|
||||
the constraint "never published beyond localhost." Avoid introducing any tooling
|
||||
that would create a build/runtime dependency.
|
||||
- File organization recommendation for the render pipeline:
|
||||
- `content/` — one markdown file per newspaper edition (the authored content,
|
||||
the source of truth).
|
||||
- `templates/` — the newspaper layout: HTML skeleton + print CSS.
|
||||
- `templates/print.css` — the A4 print stylesheet (`@page` rules, column
|
||||
layout, page-breaks); keep it separate from screen styling so print stays
|
||||
predictable.
|
||||
- `render.js` (or a small `index.html` that reads content) — the
|
||||
markdown→HTML transform mapping articles into the newspaper grid.
|
||||
- `index.html` — the generated/standalone page opened locally.
|
||||
- Layer boundaries: content (markdown) stays fully separated from presentation
|
||||
(templates) — one article's text never lives in the stylesheet. The transform
|
||||
is the only bridge.
|
||||
- Error handling: markdown-to-HTML must be tolerant of empty sections and
|
||||
unusual chars without throwing; a missing content file should degrade to a
|
||||
friendly empty-state, never a blank/broken page.
|
||||
- Naming: semantic, self-explanatory (`content/`, `templates/`, `render.js`), no
|
||||
framework conventions needed since there is no framework.
|
||||
|
||||
## Positions
|
||||
- AGREE: language-idiomatic plain HTML5/CSS/JS, no bundler or transpiler.
|
||||
- AGREE: no deployment.
|
||||
- OBJECT (minor): the draft lists code style as "no build step" but should also
|
||||
state the file layout that enforces the content/presentation separation, so
|
||||
the practice survives into construction.
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
**Collaborator:** aidlc-devsecops-agent
|
||||
|
||||
## Contribution
|
||||
|
||||
Assessing lint/format, secret handling, dependency and supply-chain controls.
|
||||
|
||||
- Dependency surface: this is the strong point of a no-build, no-framework
|
||||
approach — zero third-party runtime dependencies means no supply-chain risk,
|
||||
no vulnerable transitive packages, no lockfile to keep fresh. The proposal
|
||||
should make "no external runtime dependencies" an explicit constraint and keep
|
||||
it that way.
|
||||
- No secrets: the project is static content; there are no credentials, keys, or
|
||||
tokens. No credential scanning is needed, but the practice should be stated in
|
||||
case a local script or environment sneaks in later — never commit anything that
|
||||
looks like a secret.
|
||||
- Lint/format: with no toolchain, a formatter requirement is disproportionate.
|
||||
The practical, proportionate posture is a light manual hygiene rule (consistent
|
||||
indentation, valid HTML5, no inline `style=` that breaks the print layout)
|
||||
rather than wiring ESLint/Prettier into an otherwise zero-dependency repo.
|
||||
- Supply-chain: because everything must run from `file://`, the page must make
|
||||
**zero network requests** (no CDN fonts, no `<script src="https://...">`). This
|
||||
is both a security posture (no third-party code executed locally) and a
|
||||
correctness requirement (it must work offline). This is the single most
|
||||
important rule for this project.
|
||||
- Local-only trust: never reference content, fonts, or assets by remote URL;
|
||||
everything ships with the page.
|
||||
|
||||
## Positions
|
||||
- AGREE: skip the skeleton and keep tooling minimal.
|
||||
- AGREE: no deployment.
|
||||
- OBJECT: the draft's "no external dependencies" is present, but it must be
|
||||
sharpened into an explicit, load-bearing rule — this is a security posture
|
||||
(nothing ships from the network), not just a stylistic preference, and it
|
||||
should be a Mandated rule in `discovered-rules.md`.
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
**Collaborator:** aidlc-quality-agent
|
||||
|
||||
## Contribution
|
||||
|
||||
Assessing testing posture, coverage, and quality gates for the wedding newspaper generator.
|
||||
|
||||
- The proposed test-after posture is appropriate. This is a static render-and-print
|
||||
deliverable with no production runtime, so an exhaustive unit suite would be
|
||||
disproportionate.
|
||||
- The quality-critical surfaces worth locking:
|
||||
1. **Render validity** — sample article markdown must always map to complete,
|
||||
correctly-structured HTML (no dropped sections, no malformed article rows).
|
||||
2. **Print integrity** — the print stylesheet must keep every newspaper section
|
||||
inside the A4 sheet with no clipping, no orphaned columns, and correct
|
||||
page-break behaviour for multi-page output.
|
||||
3. **Content fidelity** — markdown source → displayed text must round-trip
|
||||
without mangled escaping (quotes, em-dashes, apostrophes).
|
||||
- Recommend a small automated check that: parses a fixture markdown set, asserts
|
||||
the expected article count and section headings appear in the rendered HTML,
|
||||
and (where a headless print can run) verifies the A4 box model has no overflow.
|
||||
- Keep coverage expectations modest. The 80% line-coverage floor classic scope
|
||||
implies applies to runnable logic, not markup; for a no-build HTML generator
|
||||
that floor is best interpreted as "every transformation function exercised",
|
||||
not "80% of the stylesheet".
|
||||
- Quality gate: the deliverable is judged on whether it prints cleanly to A4 and
|
||||
renders the authored markdown faithfully — that is the acceptance signal, not
|
||||
a CI pipeline.
|
||||
|
||||
## Positions
|
||||
- AGREE: test-after posture for this project — the value is in render/print
|
||||
verification, not a broad unit suite.
|
||||
- AGREE: skipping the walking skeleton — no integration surface to prove.
|
||||
- OBJECT: the draft should be more explicit that the "testable layer" is the
|
||||
markdown→HTML transform and the print CSS, so the testing posture reads as
|
||||
concrete rather than generic.
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
# Discovered Rules — Finalized
|
||||
|
||||
> Hard constraints surfaced from the project description, the empirical
|
||||
> research, and the interview. Promoted to `memory/project.md` at the
|
||||
> affirmation gate.
|
||||
|
||||
## Mandated
|
||||
|
||||
- ALWAYS generate pure HTML5 + CSS with no build step and no external
|
||||
dependencies, so the result runs entirely from the local filesystem
|
||||
(never beyond localhost).
|
||||
- ALWAYS make the rendered page printable cleanly to A4 from the browser's
|
||||
print dialog.
|
||||
- ALWAYS fetch or read content only through user-granted means (native file
|
||||
picker / drag-and-drop) when the page runs from `file://` — never rely on
|
||||
`fetch()` of sibling local files, because the opaque-origin policy blocks it
|
||||
in stock browsers (empirically verified: plain Chromium blocks
|
||||
`fetch('article.txt')` from a `file://` page, while the native file picker
|
||||
works).
|
||||
- ALWAYS make the page work with zero network requests (no CDN fonts, no
|
||||
remote `<script>`/`<style>`), so it is fully functional offline from `file://`.
|
||||
|
||||
## Forbidden
|
||||
|
||||
- NEVER reference content, fonts, or assets by remote URL; everything ships
|
||||
with the page.
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
# Evidence
|
||||
|
||||
## Project Type
|
||||
Greenfield. No prior workspace content; the repo is a freshly initialized git
|
||||
repo with no commits.
|
||||
|
||||
## Sources Scanned
|
||||
- `aidlc/spaces/default/memory/org.md` — framework defaults for the five
|
||||
practice areas (way of working, walking skeleton, testing posture,
|
||||
deployment, code style).
|
||||
- Initial project description: "wedding newspaper generator — author content as
|
||||
markdown, render as a printable newspaper in pure HTML5+CSS, print to A4 from
|
||||
the browser. Fully local, never deployed beyond localhost."
|
||||
- Primary-source web research (whatwg fetch spec, MDN same-origin policy,
|
||||
CORS handbook) on whether a `file://` page can read sibling local files.
|
||||
- **Empirical browser test** (2026-09-13): real Chromium driven via node
|
||||
+ playwright-core. Plain Chromium: `fetch('article.txt')` from a `file://`
|
||||
page → blocked (`TypeError: Failed to fetch`, CORS from origin 'null');
|
||||
native file picker → works. Chromium with `--allow-file-access-from-files`:
|
||||
fetch works but requires a non-default, security-weakening launch flag.
|
||||
|
||||
## Participant Evidence
|
||||
- Lead draft: team-practices.md, discovered-rules.md, evidence.md,
|
||||
practices-discovery-timestamp.md.
|
||||
- Support contributions (contributed into the artifacts):
|
||||
- `contributions/aidlc-quality-agent.md` — test-after posture justified;
|
||||
renders/print as the testable surfaces; keep A4 containment + markdown
|
||||
fidelity as the acceptance checks.
|
||||
- `contributions/aidlc-developer-agent.md` — content/presentation separation
|
||||
(`content/` vs `templates/`), tolerant transform, plain-HTML file layout.
|
||||
- `contributions/aidlc-devsecops-agent.md` — zero-dependency = zero
|
||||
supply-chain risk; no-remote-URLs as a load-bearing security rule; the page
|
||||
must work offline.
|
||||
|
||||
## Interview Decisions
|
||||
- Q1 Way of working: `C` direct to main (solo local project).
|
||||
- Q2 Walking skeleton: `B` no separate skeleton step.
|
||||
- Q3 Testing posture: `C` unit tests for the markdown→HTML transform.
|
||||
- Q4 Deployment/run: `X` resolved via research + confirmation — file-only
|
||||
static Python generator emitting a self-contained `newspaper.html`, with an
|
||||
in-page file-picker live-load path; no server, never beyond localhost.
|
||||
- Q5 Code style: `C` no style rules, minimal and pragmatic.
|
||||
- Q6 Content/presentation: `A` separate `content/` and `templates/`.
|
||||
|
||||
## Unresolved Uncertainty
|
||||
- None blocking. The browser `file://` constraint is settled empirically: use
|
||||
user-granted file access (picker/drag-drop), never `fetch()` of local files,
|
||||
except under the non-default Chromium flag.
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
<!-- 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-13T11:07:00Z — GREENFIELD practices discovery running inline; authored lead draft + 3 specialist contributions (quality/developer/devsecops) as contributions/*.md
|
||||
2026-09-13T11:07:00Z — Tradeoff — zero-dependency no-build approach wins for local-only security (nothing ships from network) at the cost of no automated CI gates; verification leans on render/print checks
|
||||
2026-09-13T11:22:40Z — Interpretation — Q4 resolved to file-only static Python generator + in-page file-picker after empirical Chromium test: fetch() of sibling files is blocked from file:// (opaque origin) but the native file picker works — user-granted reads bypass CORS
|
||||
2026-09-13T11:22:40Z — Interpretation — Testing posture is unit tests on the markdown->HTML transform, not a broad suite; print-to-A4 stays the real-world acceptance check
|
||||
2026-09-13T11:22:40Z — Deviation — aidlc-log answer refused (no HUMAN_TURN seam on this custom fork build); recorded answers directly in the authoritative questions file instead
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
# Practices Discovery — Interview Questions
|
||||
|
||||
> Fill in each `[Answer]:` tag. Options A-E plus X (Other). The file is the
|
||||
> authoritative record of your practice decisions.
|
||||
|
||||
## Q1: Way of Working
|
||||
|
||||
How should we plan development work for this project — should we use feature branches that merge back into the main line, or work directly on the main line?
|
||||
|
||||
A) Trunk-based with short-lived feature branches (2-3 days max, merge to main)
|
||||
B) Direct to main for everyday edits; branches only for anything larger
|
||||
C) Direct to main only — no branches, this is a solo local project
|
||||
D) Feature branches required for everything, no direct-to-main
|
||||
E) (depends on project size)
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: C
|
||||
|
||||
## Q2: Walking Skeleton
|
||||
|
||||
Build a thin end-to-end slice first? A walking skeleton is a minimal version that runs the whole way through — one markdown file turning into one printed A4 page — built first to prove the pieces connect before the real features (full layout, many articles, styling) go in.
|
||||
|
||||
A) Yes — prove the slice end-to-end before building the full layout
|
||||
B) No — the layout and content can be built together; no separate skeleton step
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: B
|
||||
|
||||
## Q3: Testing Posture
|
||||
|
||||
What testing posture should this project use? The realistic surfaces worth verifying are that sample markdown renders into correct newspaper HTML and that the print stylesheet stays inside an A4 sheet.
|
||||
|
||||
A) Test-after with a small render/print verification check (recommended)
|
||||
B) No tests — open the page and eyeball it; the print is the acceptance check
|
||||
C) Unit tests for the markdown→HTML transform only
|
||||
D) Behaviour-driven: write the article → printed-page scenarios first
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: C
|
||||
|
||||
## Q4: Deployment
|
||||
|
||||
How should this project be "released" or run? This site is local-only by requirement and will never be published beyond localhost.
|
||||
|
||||
A) Open the generated HTML directly from the filesystem (file://) — nothing served
|
||||
B) Serve from a tiny local HTTP server (http://localhost) when viewing
|
||||
C) Both — static file works, and a start script for a localhost server
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: X - RESOLVED (research + user confirmation 2026-09-13): File-only static generator. A Python script (the primary path, using the working `uv` runtime) reads content from content/ and emits a self-contained `newspaper.html`; the page is opened directly via file:// and printed to A4. The generated page also includes a native file-picker / drag-and-drop load path so content can be swapped in live without regenerating — empirically verified working in stock Chromium from file:// (the file picker is user-granted and bypasses the opaque-origin CORS restriction that blocks fetch()). No server, no browser flags, never deployed beyond localhost. The generator may optionally call AI to draft newspaper copy before rendering.
|
||||
|
||||
## Q5: Code Style
|
||||
|
||||
What code-style and tooling conventions should we keep? The project is pure HTML5 + CSS + vanilla JS with no framework and no build step.
|
||||
|
||||
A) Plain HTML5/CSS/JS, no tooling; consistent formatting by hand
|
||||
B) Plain HTML5/CSS/JS plus a lightweight formatter (e.g. Prettier) if available
|
||||
C) No style rules — keep it minimal and pragmatic
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: C
|
||||
|
||||
## Q6: Content ↔ Presentation Separation
|
||||
|
||||
Content (markdown articles) and presentation (the newspaper layout + print stylesheet) — should they be kept in separate folders so the layout never gets tangled up with article text?
|
||||
|
||||
A) Yes — separate `content/` and `templates/` (recommended)
|
||||
B) No — keep it all inline; simplest possible layout
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Consolidated Summary Confirmation
|
||||
|
||||
> Summary of your six answers before the final practices artifacts are locked:
|
||||
>
|
||||
> - Way of working: direct to main (Q1 = C)
|
||||
> - Walking skeleton: no separate skeleton step (Q2 = B)
|
||||
> - Testing posture: unit tests for the markdown→HTML transform (Q3 = C)
|
||||
> - Deployment/run: file-only static Python generator + in-page file-picker live path, no server (Q4 = X, resolved)
|
||||
> - Code style: minimal/pragmatic, no style rules (Q5 = C)
|
||||
> - Content/presentation: separate `content/` and `templates/` (Q6 = A)
|
||||
|
||||
Does this all look correct before I generate the artifact?
|
||||
|
||||
- Looks correct
|
||||
- Request changes
|
||||
|
||||
[Answer]: Looks correct
|
||||
+1
@@ -0,0 +1 @@
|
||||
Discovered: 2026-09-13T11:22:40Z at commit (no commits yet — initial working tree)
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
# Team Practices — Finalized
|
||||
|
||||
> Affirmed team practices for the wedding newspaper generator, produced from
|
||||
> the interview answers + three specialist reviews, pending affirmation gate.
|
||||
|
||||
## Way of Working
|
||||
|
||||
Direct to main. This is a solo local project, so everyday edits go straight to
|
||||
the main line; we use branches only if something larger ever warrants a review
|
||||
boundary. No feature-branch ceremony for routine work.
|
||||
|
||||
## Walking Skeleton
|
||||
|
||||
Skip the separate walking-skeleton step. The layout and content are built
|
||||
together — there is no integration surface to prove, and a thin end-to-end slice
|
||||
(one markdown file → one rendered A4 page) emerges naturally as the first piece
|
||||
anyway.
|
||||
|
||||
## Testing Posture
|
||||
|
||||
Unit tests for the markdown→HTML transform. The primary testable surface is the
|
||||
renderer: sample article markdown must always map to complete, correctly
|
||||
structured newspaper HTML with no dropped sections or mangled escaping, and the
|
||||
print stylesheet must keep content inside an A4 sheet. We write focused tests for
|
||||
the transform logic rather than an exhaustive suite; the print result remains the
|
||||
real-world acceptance check.
|
||||
|
||||
Methodology: test-after
|
||||
Ordering: implement the transform and layout, then write and run tests that
|
||||
verify markdown→HTML fidelity and A4 print containment.
|
||||
|
||||
## Deployment
|
||||
|
||||
File-only, no server. A Python static generator (primary path, run with the
|
||||
working `uv` runtime) reads content files and emits a self-contained
|
||||
`newspaper.html`. The page is opened directly via `file://` and printed to A4
|
||||
from the browser print dialog. The generated page also includes a native
|
||||
file-picker / drag-and-drop load path so content can be swapped in live without
|
||||
regenerating. No server, no browser flags, never deployed beyond localhost. The
|
||||
generator may optionally call AI to draft newspaper copy before rendering.
|
||||
|
||||
## Code Style
|
||||
|
||||
Minimal and pragmatic, no style rules beyond staying consistent. Pure HTML5 +
|
||||
CSS + vanilla JS with no build step and no framework. Keep formatting clean by
|
||||
hand; do not introduce tooling, transpilers, or bundlers.
|
||||
|
||||
## Forbidden
|
||||
|
||||
(none affirmed by the team)
|
||||
|
||||
## Mandated
|
||||
|
||||
- ALWAYS keep the output runnable purely from the local filesystem with no
|
||||
network requests (affirmed)
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
# Accessibility Checklist — Wedding Newspaper Generator
|
||||
|
||||
> Per confirmed decision Q6=C, there is **no formal WCAG requirement** — this is
|
||||
> primarily a printed keepsake. This checklist records the practical baseline
|
||||
> that is still maintained (semantic HTML, alt/caption text, readable
|
||||
> contrast, keyboard-operable on-screen tooling), not a WCAG 2.1 AA pass.
|
||||
|
||||
## Baseline (maintained)
|
||||
|
||||
| Area | Check | Status |
|
||||
|---|---|---|
|
||||
| Document structure | `<header>` for masthead, single H1, article `<section>`s, logical heading hierarchy | Maintain |
|
||||
| Figures | Caption text on photos; `alt`/`alt=""` for decorative vs meaningful images | Maintain |
|
||||
| Contrast | Ink (`#111827`) on cream (`#FBF8F1`) — clearly readable | Maintain |
|
||||
| On-screen tooling | Review-page buttons focusable; Enter/Space activate | Maintain (on-screen only) |
|
||||
|
||||
## Not required (per Q6=C)
|
||||
|
||||
| Area | Why no formal pass |
|
||||
|---|---|
|
||||
| WCAG 2.1 AA conformance | Deemed out of scope — printed keepsake, primary reader is the couple |
|
||||
| Screen-reader testing (VoiceOver/NVDA/TalkBack) | Not a formal requirement for this project |
|
||||
| Keyboard-only full navigation pass | The generated page is a printed artifact, not an interactive app (only the on-screen review tool has keyboard basics) |
|
||||
| 200%/400% zoom layout verification | Printed medium; scale is fixed at A4 |
|
||||
|
||||
## Carried into the deliverable
|
||||
|
||||
- The generated HTML is valid, self-contained, and semantically structured
|
||||
(benefits robustness and printing, and keeps the door open for a11y later).
|
||||
- Any on-screen interactive surface (the per-article review page) keeps the
|
||||
practical keyboard/label/caption basics recorded above.
|
||||
|
||||
## Note for downstream
|
||||
|
||||
If a future iteration wants WCAG 2.1 AA, this checklist is the seed: the
|
||||
missing items are (1) alt-text audit, (2) formal contrast checks, (3)
|
||||
keyboard-only testing of the review tool, (4) screen-reader smoke test on the
|
||||
review page. Not blocking current work.
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
# Design System Mapping — Wedding Newspaper Generator
|
||||
|
||||
> Classic broadsheet design system (NFR8/US6: black ink on white/cream, serif
|
||||
> headlines/body, column rules). This maps the intended design tokens and
|
||||
> patterns; there is no heavy UI framework — the output is self-contained
|
||||
> HTML5 + CSS (NFR6). Component specs live in `interaction-spec.md`.
|
||||
|
||||
## Design principles
|
||||
|
||||
- **Print-first**: every design decision is made for A4 ink. Elegance on paper,
|
||||
legibility at arm's length, clean column flow.
|
||||
- **Classic, not modern**: black ink on white/cream, serif display + text,
|
||||
hairline rule lines. No modern tabloid color-blocking (Q5=A, NFR8).
|
||||
- **Honest content**: never fabricate images (FR7.4) or generic-sounding copy;
|
||||
the funnies are built from the couple's content (Q5=X).
|
||||
|
||||
## Colour tokens
|
||||
|
||||
| Token | Value | Use |
|
||||
|---|---|---|
|
||||
| `--ink` | #111827 (near-black) | Body text, rules, headings |
|
||||
| `--paper` | #FBF8F1 (cream/off-white) | Page background |
|
||||
| `--rule` | #d1c9ba (hairline) | Column rules, borders |
|
||||
| `--muted` | #6b7280 | Byline/credit/meta text |
|
||||
| `--accent` | optional (default none) | Minor masthead accent (kept neutral by default per NFR8) |
|
||||
|
||||
## Typography
|
||||
|
||||
| Role | Face style | Notes |
|
||||
|---|---|---|
|
||||
| Masthead title | Large serif display (e.g. a Georgia/Playfair-like serif) | Full-height banner |
|
||||
| Headlines | Bold serif | Clear hierarchy, page-1 lead largest |
|
||||
| Body | Serif text | Good A4 legibility |
|
||||
| Small text | Serif, smaller | Bylines, captions, credits, fine print |
|
||||
|
||||
No web fonts are fetched; type relies on local system serifs so the page is
|
||||
zero-network (NFR4) and prints with the fonts actually on the machine.
|
||||
|
||||
## Spacing & grid
|
||||
|
||||
- **A4 sheet**: 210×297mm; margins ~15–20mm; page defined via `@page` CSS.
|
||||
- **Columns**: 3–6 per page depending on width (broadsheet-style multi-column
|
||||
flow), with hairline column rules.
|
||||
- **Automatic pagination**: content flows across sheets with breaks at
|
||||
article/section boundaries where possible (US1/FR1, NFR2).
|
||||
|
||||
## Components (mapped to interaction-spec.md)
|
||||
|
||||
| Component | Where specified | Design role |
|
||||
|---|---|---|
|
||||
| Masthead | interaction-spec.md § Masthead | Header / H1, full sheet width |
|
||||
| Article column | (page layout) | Serif body, byline + headline group |
|
||||
| Pull quote / sidebar / fact box | (callout styles, FR3.3) | Boxed off from running text |
|
||||
| Schedule / events table | (FR3.4) | Clearly formatted table |
|
||||
| Photo embed | interaction-spec.md § Photo embed | Auto-balanced into column |
|
||||
| Crossword / find-a-word | interaction-spec.md § Funnies | Bounded, A4-printable |
|
||||
| Comic strip | interaction-spec.md § Funnies | Panels with art + dialogue |
|
||||
| Review card | interaction-spec.md § review page | On-screen authoring (approved/edit/replace) |
|
||||
|
||||
## States
|
||||
|
||||
Per-mockup states (empty / loading / error / success / partial) are captured in
|
||||
`mockups.md` § M5 and in each component's States table in
|
||||
`interaction-spec.md`. On the generated page, the primary states are default
|
||||
(full render) and empty (guided first-run, US10/Q7=A).
|
||||
|
||||
## Responsive behaviour
|
||||
|
||||
The printed artifact is A4 by definition (NFR1, C5). The on-screen generation
|
||||
tooling (CLI text + review page) adapts: review cards stack on narrow widths,
|
||||
span wider on large screens.
|
||||
|
||||
## Accessibility baseline
|
||||
|
||||
Per Q6=C there is no formal WCAG requirement (printed keepsake). A practical
|
||||
baseline is kept: semantic HTML structure (`<header>`, H1, article sections),
|
||||
alt/caption text on figures, and clear contrast (ink on cream). See
|
||||
`accessibility-checklist.md`.
|
||||
+202
@@ -0,0 +1,202 @@
|
||||
# Interaction Specification — Wedding Newspaper Generator
|
||||
|
||||
> Component-level specifications following the design-agent component template.
|
||||
> Covers the two surfaces: the CLI authoring flow and the generated newspaper
|
||||
> page. Per confirmed decisions: CLI-first (Q1=A), content/config input (Q2=A),
|
||||
> per-article review page (Q3=A), no print preview step (Q4=B), funnies
|
||||
> generated from content (Q5=X), no formal a11y target (Q6=C), guided empty
|
||||
> state (Q7=A).
|
||||
|
||||
---
|
||||
|
||||
## CLI: `generate` command
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Component | `generate` CLI command |
|
||||
| Description | Reads config + content, optionally drafts via local Ollama, emits `newspaper.html` |
|
||||
| Category | navigation (entry point) |
|
||||
|
||||
### States
|
||||
|
||||
| State | Description | Trigger |
|
||||
|---|---|---|
|
||||
| ready | Prints usage / config guidance | run with no valid input |
|
||||
| generating | Parses content, builds layout | valid config + content present |
|
||||
| drafting | Calls local Ollama for lead/fillers | `--draft` flag present |
|
||||
| reviewing | Hands to review page (US9) | AI draft produced |
|
||||
| printed | Writes `newspaper.html`, prints success path | render complete |
|
||||
| error | Content/config/model failure | validation failure |
|
||||
|
||||
### Props / Inputs
|
||||
|
||||
| Prop | Type | Required | Default | Description |
|
||||
|---|---|---|---|---|
|
||||
| `--draft` | boolean | no | — | Whether to run the local Ollama AI draft (US8) |
|
||||
| `config` | path | no | `config.json` | Masthead metadata + options |
|
||||
| `content` | path | no | `content/` | Markdown/txt articles + funnies source |
|
||||
|
||||
### Responsive behaviour
|
||||
|
||||
N/A (CLI). Terminal width-wrapping of help text only.
|
||||
|
||||
### Accessibility
|
||||
|
||||
| Requirement | Implementation |
|
||||
|---|---|
|
||||
| Error clarity | One-line message naming the problem + the exact fix path |
|
||||
| Reversibility | Generate is idempotent/regenerable; never destroys the couple's content files |
|
||||
|
||||
---
|
||||
|
||||
## Per-article review page
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Component | Article review card |
|
||||
| Description | Per-article approve / edit / replace control before final render |
|
||||
| Category | feedback |
|
||||
|
||||
### States
|
||||
|
||||
| State | Description | Trigger |
|
||||
|---|---|---|
|
||||
| pending | Draft ready, not yet decided | AI draft returned |
|
||||
| approved | Copy kept as-is | user clicks Approve |
|
||||
| editing | Copy being revised | user clicks Edit |
|
||||
| replacing | New copy supplied | user clicks Replace |
|
||||
|
||||
### Props / Inputs
|
||||
|
||||
| Prop | Type | Required | Default | Description |
|
||||
|---|---|---|---|---|
|
||||
| `articleId` | string | yes | — | Stable per-article key (the article-level data boundary, US9/AC9.1.5) |
|
||||
| `status` | pending\|approved\|editing\|replaced | yes | pending | Current review state |
|
||||
| `copy` | string | yes | — | The article's text |
|
||||
| `onApprove` | fn | no | — | Keep as-is |
|
||||
| `onEdit` | fn | no | — | Open inline edit |
|
||||
| `onReplace` | fn | no | — | Supply replacement copy |
|
||||
|
||||
### Responsive behaviour
|
||||
|
||||
Stacked cards on narrow; grid of cards on wide. The newspaper is printed, so
|
||||
this page is on-screen only.
|
||||
|
||||
### Accessibility
|
||||
|
||||
| Requirement | Implementation |
|
||||
|---|---|
|
||||
| Keyboard | Buttons focusable; Enter/Space activate (on-screen tool) |
|
||||
| Clear status | Each card visibly labelled with its state (pending/approved/…) |
|
||||
|
||||
---
|
||||
|
||||
## Masthead component (newspaper page)
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Component | Masthead |
|
||||
| Description | Front-page title banner + date / issue / volume (US2/FR2) |
|
||||
| Category | display / layout |
|
||||
|
||||
### States
|
||||
|
||||
| State | Description | Trigger |
|
||||
|---|---|---|
|
||||
| default | Classic broadsheet masthead | page render |
|
||||
|
||||
### Props / Inputs
|
||||
|
||||
| Prop | Type | Required | Default | Description |
|
||||
|---|---|---|---|---|
|
||||
| `title` | string | yes | — | Newspaper / couple name |
|
||||
| `dateLine` | string | yes | — | Issue date |
|
||||
| `issue` | string | yes | — | Issue number |
|
||||
| `volume` | string | yes | — | "Volume X" |
|
||||
| `titleStyle` | object | no | serif | Masthead typography |
|
||||
|
||||
### Responsive behaviour
|
||||
|
||||
Masthead spans the full sheet width on print; on very narrow screen the title
|
||||
sizes down but the line stays intact (does not wrap awkwardly).
|
||||
|
||||
### Accessibility
|
||||
|
||||
| Requirement | Implementation |
|
||||
|---|---|
|
||||
| Document structure | Masthead is the page's `<header>` / H1 (semantic, matches Q6=C baseline) |
|
||||
|
||||
---
|
||||
|
||||
## Funnies: crossword & find-a-word
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Component | Funnies section |
|
||||
| Description | Crossword + find-a-word + comics generated from content (US3/FR4/Q5=X) |
|
||||
| Category | display |
|
||||
|
||||
### States
|
||||
|
||||
| State | Description | Trigger |
|
||||
|---|---|---|
|
||||
| default | Renders crossword grid, clues, solution; find-a-word grid; comic panels | page render |
|
||||
|
||||
### Props / Inputs
|
||||
|
||||
| Prop | Type | Required | Default | Description |
|
||||
|---|---|---|---|---|
|
||||
| `grid` | array | yes | — | Crossword grid (built from content theme words) |
|
||||
| `cluesAcross` | array | yes | — | Across clues (derived from content) |
|
||||
| `cluesDown` | array | yes | — | Down clues (derived from content) |
|
||||
| `findWords` | array | yes | — | Word list for find-a-word (content terms) |
|
||||
| `comics` | array | no | — | Comic panels + captions |
|
||||
| `cartoonAlt` | string | no | — | Context note for the xkcd-style cartoon |
|
||||
|
||||
### Responsive behaviour
|
||||
|
||||
Each puzzle bounded to its column width and an A4-printable height; no
|
||||
overflow.
|
||||
|
||||
### Accessibility
|
||||
|
||||
| Requirement | Implementation |
|
||||
|---|---|
|
||||
| Clarity | Grid cells have clear borders and legible type (printed keepsake; Q6=C) |
|
||||
|
||||
---
|
||||
|
||||
## Photo embed (auto-balanced)
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Component | Embedded photo |
|
||||
| Description | Photo embedded in the column layout with caption (FR6/US4) |
|
||||
| Category | display |
|
||||
|
||||
### States
|
||||
|
||||
| State | Description | Trigger |
|
||||
|---|---|---|
|
||||
| default | Photo + caption fit the column | photo supplied |
|
||||
| absent | No placeholder; layout renders clean, text-only | no photo supplied (FR7.4) |
|
||||
|
||||
### Props / Inputs
|
||||
|
||||
| Prop | Type | Required | Default | Description |
|
||||
|---|---|---|---|---|
|
||||
| `src` | data/blob | no | — | Locally embedded image |
|
||||
| `caption` | string | no | — | Caption text |
|
||||
| `credit` | string | no | — | Credit/byline line |
|
||||
|
||||
### Responsive behaviour
|
||||
|
||||
Auto-balances into the column structure; falls back to full-width or natural
|
||||
size if it cannot fit (R-02 from requirements review), never overflowing the
|
||||
A4 sheet (NFR2).
|
||||
|
||||
### Accessibility
|
||||
|
||||
| Requirement | Implementation |
|
||||
|---|---|
|
||||
| Text alternative | Caption present; decorative `alt` when purely decorative |
|
||||
@@ -0,0 +1,17 @@
|
||||
<!-- 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-13T11:50:00Z — Interpretation — Confirmed design: CLI-first authoring, content/config input, per-article review page, no print preview, funnies generated from content (Q5=X), no formal a11y target (Q6=C), guided empty state
|
||||
2026-09-13T11:50:00Z — Tradeoff — Q5=X moves puzzle/ cartoon authoring from user-supplied data to content-derived generation; richer payoff (hand-crafted feel) at the cost of generation complexity and subjective-search heuristics
|
||||
2026-09-13T11:50:00Z — Tradeoff — Q6=C drops a formal a11y pass; kept a practical semantic/print baseline, notes how to add WCAG 2.1 AA later
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
# Refined Mockups — Wedding Newspaper Generator
|
||||
|
||||
> Design-lead refined mockups derived from the user stories (US1–US10),
|
||||
> requirements (FR1–FR8, NFR1–NFR9), and the seven confirmed design decisions
|
||||
> (CLI-first authoring, content/config input, per-article review page, no print
|
||||
> preview, funnies generated from content, no formal a11y target, guided empty
|
||||
> state). Rough mockups were not produced (classic scope skips Ideation), so
|
||||
> these are designed directly from requirements + stories.
|
||||
|
||||
## M1 — The authoring flow (generator UX)
|
||||
|
||||
The generator is **CLI-first** (Q1=A): the couple runs a single command, the
|
||||
tool reads a content folder + config, optionally invokes local Ollama for the
|
||||
AI draft, emits `newspaper.html`, and (per US9) presents a per-article review
|
||||
page before the final render.
|
||||
|
||||
```
|
||||
worktree/
|
||||
config.json # masthead metadata: title, names, date, issue, volume
|
||||
content/ # markdown/txt articles + funnies source
|
||||
newspaper.html # the generated, self-contained printable artifact
|
||||
```
|
||||
|
||||
`newspaper generate [--draft]` flows:
|
||||
1. Read `config.json` + `content/` (Q2=A).
|
||||
2. If `--draft`, ask local Ollama to draft lead story + fillers (US8), keeping
|
||||
everything on-machine (NFR9).
|
||||
3. If AI used, open the **per-article review page** (US9/Q3=A): approve / edit /
|
||||
replace any single article before final render.
|
||||
4. Emit self-contained `newspaper.html`, zero-network, openable via `file://`,
|
||||
printable to A4 (FR7, NFR1–NFR4, US5).
|
||||
|
||||
## M2 — The newspaper page (reader UX)
|
||||
|
||||
The output is a classic broadsheet (US6/NFR8): black ink on white/cream, serif
|
||||
headlines + body, column rules. Content flows across multiple A4 pages with
|
||||
clean page breaks (US1/FR1). Structural regions (US2/US3/US4/US6/US3-funnies):
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐ ┌─────────────────────────────┐
|
||||
│ MASTHEAD (title / date · issue · volume) │ │ interior page header │
|
||||
├──────────────┬──────────────┬───────────────┤ ├────────┬────────┬──────────┤
|
||||
│ lead/ front │ article │ xkcd-style │ │ column │ column │ ads/box │
|
||||
│ page story │ (bylined) │ cartoon │ │ │ │ │
|
||||
├──────────────┼──────────────┼───────────────┤ ├────────┴────────┴──────────┤
|
||||
│ article 3 │ pull quote │ schedule / │ │ photo auto-balanced │
|
||||
│ │ │ events block │ │ │
|
||||
├──────────────┴──────────────┴───────────────┤ ├──────────────┬─────────────┤
|
||||
│ funnies: crossword · find-a-word · comics │ │ article cont.│ well-wishes │
|
||||
└─────────────────────────────────────────────┘ └──────────────┴─────────────┘
|
||||
page 1 page 2+
|
||||
```
|
||||
|
||||
- **Page 1**: masthead (US2), lead story (FR3.1), interior articles with
|
||||
bylines (FR3.2), xkcd-style cartoon tied to the day (FR5), schedule/events
|
||||
block (FR3.4), pull quotes/sidebars (FR3.3).
|
||||
- **Pages 2+**: flowing interior columns, photo auto-balancing (FR6/FR4/US4),
|
||||
the lighter well-wishes corner (FR3.5), and the funnies section (US3/FR4):
|
||||
crossword, find-a-word, comics.
|
||||
- **Funnies generated from content** (Q5=X): the generator builds the puzzles
|
||||
from theme words/clues drawn out of the content and uses content-derived
|
||||
context to search for / insert a relevant cartoon.
|
||||
|
||||
## M3 — AI per-article review page (US9 / Q3=A)
|
||||
|
||||
After the AI draft, the couple sees a review page. Present **one article per
|
||||
card**, each with three actions:
|
||||
|
||||
| Card action | Behaviour |
|
||||
|---|---|
|
||||
| **Approve** | Keep this article's copy unchanged; others can still be revised |
|
||||
| **Edit** | Edit this article's copy in place; only it re-renders |
|
||||
| **Replace** | Supply new copy; it replaces the draft for this article only |
|
||||
|
||||
A "Render final newspaper" button appears once every article is approved (or
|
||||
the couple opts to keep unapproved ones as-is). Approved articles never change
|
||||
when others are edited (US9/AC9.1.2–3).
|
||||
|
||||
## M4 — First-run / empty state (US10 / Q7=A)
|
||||
|
||||
With no content yet, the couple sees a friendly guided state:
|
||||
- A short message ("Welcome — let's make your wedding newspaper").
|
||||
- A pointer to the `content/` folder + `config.json`.
|
||||
- A **sample issue** they can generate to see the layout (Q7=A), then replace
|
||||
with their real content.
|
||||
|
||||
This protects the first-run experience (per the designer contribution in
|
||||
user-stories) without fabricating content in the real output (FR7.4).
|
||||
|
||||
## M5 — States handled
|
||||
|
||||
Per stage Step 2, the generator's surface must handle these states:
|
||||
- **empty** — no content: guided empty state (US10).
|
||||
- **loading** — AI draft running: simple progress/status line (CLI) or spinner
|
||||
(review page).
|
||||
- **error** — missing content/config, model unavailable, template failure:
|
||||
clear one-line message naming the problem + fix path.
|
||||
- **success** — generated `newspaper.html`, path shown.
|
||||
- **partial** — AI draft done, some articles reviewed, others pending (the
|
||||
review page's natural in-between state).
|
||||
|
||||
<!-- refined-mockups-after-confirm -->
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
# Refined Mockups — Questions
|
||||
|
||||
> Fill in each `[Answer]:` tag. Options A-E plus X (Other). The file is the
|
||||
> authoritative record of your UX design decisions.
|
||||
|
||||
## Q1: Authoring entry point
|
||||
|
||||
How do you want to drive the newspaper generation?
|
||||
|
||||
A) A single command run (e.g. `newspaper generate`) that reads a config + content folder and emits `newspaper.html` — CLI-first (recommended)
|
||||
B) A local browser page that picks content and generates live (no shell, all in-browser)
|
||||
C) Both — a small CLI plus an optional browser "generate" page
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Q2: Content & metadata input shape
|
||||
|
||||
How should you provide content and dynamic issue metadata (masthead title, couple names, date, volume)?
|
||||
|
||||
A) A `content/` folder of markdown/txt files plus a small `config.json`/front-matter holding masthead metadata (recommended)
|
||||
B) One markdown "issue file" that contains everything (articles + metadata front-matter) in a single document
|
||||
C) Paste text into the browser page, metadata typed in a small form
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Q3: AI per-article review surface
|
||||
|
||||
Your stories call for a whole-first-pass AI draft then per-article human review (US9). How should that review be surfaced?
|
||||
|
||||
A) After the AI draft, emit a review page/step listing every article with approve / edit / replace controls per article before final render (recommended)
|
||||
B) Emit a single editable draft markdown file the couple edits directly, then re-render
|
||||
C) A CLI prompt loop: for each article, ask approve / edit / replace in the terminal
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Q4: Print preview
|
||||
|
||||
Do you want a print-preview step to see how the pages break before printing?
|
||||
|
||||
A) Yes — a browser "preview + print" page showing the whole newspaper with a Print button (recommended)
|
||||
B) No — generate straight to the printable HTML and print it directly
|
||||
C) Preview only in the same generated page; the couple opens it and prints
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: B
|
||||
|
||||
## Q5: Funnies input format
|
||||
|
||||
For crosswords / find-a-word / comics: how should you supply the source so the generator can build the fun section?
|
||||
|
||||
A) Structured data (JSON) per puzzle — grid words + clues for crossword, word list for find-a-word; comics as image files + dialogue (recommended)
|
||||
B) Natural-language markdown describing the fun items, AI turns it into a puzzle
|
||||
C) Both — structured for puzzles, markdown for describing comics
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: X - I want you to generate it from the content. the content will build the articles and the funnies and provide the context for what cartoons to search for and try to insert
|
||||
|
||||
## Q6: Accessibility level for the generated page
|
||||
|
||||
What accessibility target should the generated newspaper page meet?
|
||||
|
||||
A) WCAG 2.1 AA — semantic HTML, heading hierarchy, alt text on images, keyboard-operable where interactive (recommended)
|
||||
B) Practical baseline — valid semantic HTML + alt text + readable contrast, without a formal WCAG pass
|
||||
C) No formal accessibility requirement — this is primarily a printed keepsake
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: C
|
||||
|
||||
## Q7: Empty / first-run experience
|
||||
|
||||
When the couple opens the generator with no content yet, what should they see?
|
||||
|
||||
A) A friendly guided empty state: short message + a pointer to the content folder / config, plus a small sample issue they can generate to see the layout (recommended)
|
||||
B) A friendly empty state with guidance only (no auto sample)
|
||||
C) Just generate a stub page so they see the masthead/layout structure
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Consolidated Summary Confirmation
|
||||
|
||||
> Summary of your seven design answers before the mockup artifacts are generated:
|
||||
>
|
||||
> - Authoring entry: **CLI-first** — a single `newspaper generate` command reads a config + content folder and emits `newspaper.html` (Q1=A)
|
||||
> - Content/metadata input: **`content/` folder of markdown/txt + a small `config.json`** (or front-matter) holding masthead metadata (Q2=A)
|
||||
> - AI per-article review: **a review page/step** listing every article with approve / edit / replace controls per article before final render (Q3=A)
|
||||
> - Print preview: **no separate preview step** — generate straight to the printable HTML (Q4=B)
|
||||
> - Funnies input: **generated from the content itself** — the content builds the articles AND the funnies, and provides the context used to search for / insert cartoons (Q5=X)
|
||||
> - Accessibility: **no formal WCAG requirement** — primarily a printed keepsake (Q6=C)
|
||||
> - First-run: **friendly guided empty state** with a pointer to content/config plus a small sample issue (Q7=A)
|
||||
|
||||
Does this all look correct before I generate the mockup artifacts?
|
||||
|
||||
- Looks correct
|
||||
- Request changes
|
||||
|
||||
[Answer]: Looks correct
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
<!-- 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-13T11:31:00Z — Interpretation — Multi-page (FR1) is a must-have; scope expanded by Q3 to crosswords, comics, and an xkcd-style front-page cartoon tied to the occasion
|
||||
2026-09-13T11:31:00Z — Interpretation — AI route is local Ollama, model granted deepseek-v4-flash:cloud; AI draft is optional (FR8) and must never send content to a cloud service
|
||||
2026-09-13T11:31:00Z — Tradeoff — Photo auto-balancing (Q4=b) gives a natural newspaper flow but adds layout complexity; kept as FR6.2 with text-safe fallback
|
||||
2026-09-13T11:34:00Z — Interpretation — User resolved OQ1-OQ4 during the learnings turn: crosswords built from user content; genuine xkcd (searched on the real site) as the front-page cartoon; dynamic masthead metadata; whole-first-pass AI then per-article human review
|
||||
2026-09-13T11:34:00Z — Tradeoff — OQ1 wants a genuine xkcd fetched at generation time, which is a network read at authoring time; reconciled with the local-only/zero-network constraints by embedding the fetched cartoon as a local asset so the delivered page stays self-contained and offline-capable
|
||||
2026-09-13T11:34:00Z — Deviation — requirements.md edited after the advisory review receipt (relaxed change control: CHANGE_ACCEPTED, no recovery review needed)
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
# Requirements Analysis — Questions
|
||||
|
||||
> Fill in each `[Answer]:` tag. Options A-E plus X (Other). The file is the
|
||||
> authoritative record of your requirements decisions.
|
||||
|
||||
## Q1: Edition length
|
||||
|
||||
Should the generator produce a single self-contained page, or support multi-page newspapers that flow across printed A4 sheets?
|
||||
|
||||
A) Single page — the whole newspaper is one page, printed on one A4 sheet
|
||||
B) Multi-page — content flows across multiple A4 sheets with automatic page breaks (recommended for a real newspaper feel)
|
||||
C) Single long scrolling page that the browser splits across sheets when printing
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: B its a must have I want this to work across pages
|
||||
|
||||
## Q2: Masthead & issue identity
|
||||
|
||||
Does the newspaper need a classic newspaper masthead (title banner, date/issue line, volume)?
|
||||
|
||||
A) Yes — a title banner plus a date / issue / "Volume X" line (recommended)
|
||||
B) Title banner only, no date/issue metadata
|
||||
C) No masthead — just the article layout
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Q3: Article types / sections
|
||||
|
||||
Which content types should the layout support? (choose all that apply)
|
||||
|
||||
A) Lead/front-page story
|
||||
B) Interior news articles with headings + bylines
|
||||
C) Pull quotes / sidebars / fact boxes
|
||||
D) A "schedule" or "events" block (e.g. ceremony / reception timetable)
|
||||
E) A lighter section (messages/letters, well-wishes, memory corner)
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A, B, C, D, E, and X - i want crosswords and comics as well please, I'd love a little xkcd that somehow relates to the main page (you'll have to pull this obvoiusly with context)
|
||||
|
||||
## Q4: Photos and images
|
||||
|
||||
Should articles support embedded photos/images, or is the newspaper text-focused?
|
||||
|
||||
A) Photos supported — images placed per article with captions (recommended)
|
||||
B) Photos supported, layout auto-balances them into columns
|
||||
C) Text only — no image support needed for now
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: B
|
||||
|
||||
## Q5: Visual theme
|
||||
|
||||
What visual style should the newspaper have? (This drives the print CSS.)
|
||||
|
||||
A) Classic broadsheet: black ink on white/cream, serif headlines and body, column rules (recommended)
|
||||
B) Cream/off-white paper tint with ink text — a warmer, vintage wedding feel
|
||||
C) A color-accented modern tabloid (one accent color for section headers)
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Q6: Auto-generated copy
|
||||
|
||||
The generator may optionally call AI to draft the newspaper copy before rendering. Which AI route should we use, given the project must stay fully local with no external services?
|
||||
|
||||
A) Local AI via Ollama (runs on the LAN, never leaves the machine) — recommended
|
||||
B) No AI generation — the script only renders copy I provide
|
||||
C) An external AI API (cloud LLM) — requires a key and sends content off-machine
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A ollama is on this laptop and ready to go. You are free to use deepseek-v4-flash:cloud
|
||||
|
||||
## Q7: Print fidelity
|
||||
|
||||
Any fixed target for the printed output (page count, margins, print quality)?
|
||||
|
||||
A) Fluid — content auto-flows across as many A4 pages as it needs, with sensible margins and clean page breaks (recommended)
|
||||
B) Fixed target — fit within a set page count (e.g. exactly 2 A4 pages) regardless of content
|
||||
C) Tune margins/typography for maximum A4 ink-jet crispness
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: Fluid
|
||||
|
||||
## Consolidated Summary Confirmation
|
||||
|
||||
> Summary of your seven requirements answers before the requirements document is generated:
|
||||
>
|
||||
> - Edition length: **multi-page** — content flows across multiple A4 sheets with automatic page breaks (must-have)
|
||||
> - Masthead: **yes** — title banner plus date / issue / "Volume X" line
|
||||
> - Article types (all selected): lead story, interior articles with bylines, pull quotes/sidebars/fact boxes, schedule/events block, lighter messages/well-wishes corner — plus **crosswords and comics**, and an **xkcd-style front-page cartoon** relating to the day
|
||||
> - Photos: **auto-balanced into columns** per article
|
||||
> - Visual theme: **classic broadsheet** — black ink on white/cream, serif headlines and body, column rules
|
||||
> - AI route: **local Ollama** (granted `deepseek-v4-flash:cloud` for copy generation)
|
||||
> - Print fidelity: **fluid** — flows across as many A4 pages as needed, sensible margins, clean page breaks
|
||||
|
||||
Does this all look correct before I generate the requirements artifact?
|
||||
|
||||
- Looks correct
|
||||
- Request changes
|
||||
|
||||
[Answer]: Looks correct
|
||||
+197
@@ -0,0 +1,197 @@
|
||||
# Requirements — Wedding Newspaper Generator
|
||||
|
||||
## Intent Analysis
|
||||
|
||||
The user is building a wedding-newspaper generator: a tool to take authored
|
||||
content — the stories, schedules, messages, and inside jokes of a wedding — and
|
||||
render them as a genuine-feeling newspaper. The deep goal is not just "generate
|
||||
HTML" but to produce a keepsake that reads, on real paper, like a newspaper
|
||||
published the day of the wedding: classic broadsheet look, a proper masthead,
|
||||
crosswords and comics, and a front-page cartoon that ties the occasion together.
|
||||
|
||||
The product must be fully local: the generator runs on the couple's laptop,
|
||||
content is private, and nothing is published beyond the machine. The output is
|
||||
a self-contained HTML page opened directly (`file://`) and printed to A4 from
|
||||
the browser's own print dialog. Because a printed multi-page newspaper is the
|
||||
central deliverable, layout fidelity on paper — clean automatic page breaks,
|
||||
content flowing across sheets — is a first-class, non-negotiable requirement.
|
||||
|
||||
## Functional Requirements
|
||||
|
||||
### FR1 — Multi-page newspaper output (MUST)
|
||||
|
||||
The generator SHALL produce a newspaper that flows across multiple A4 sheets
|
||||
with automatic page breaks when content exceeds one page; it MUST NOT be
|
||||
limited to a single page.
|
||||
|
||||
- FR1.1 — When the total content exceeds one A4 sheet, the output MUST
|
||||
continue onto subsequent sheets with a clean break between pages.
|
||||
- FR1.2 — Page breaks MUST occur at section or article boundaries where
|
||||
possible (never splitting a single article's body awkwardly mid-paragraph
|
||||
unless unavoidable).
|
||||
- FR1.3 — Each printed page MUST be self-consistent: page numbers, running
|
||||
headers/footers, and masthead continuation render correctly across sheets.
|
||||
|
||||
### FR2 — Classic newspaper masthead (MUST)
|
||||
|
||||
- FR2.1 — The front page SHALL render a title (masthead) banner.
|
||||
- FR2.2 — The masthead SHALL include a date line, an issue number, and a
|
||||
"Volume X" line.
|
||||
- FR2.3 — The masthead SHALL be styled in the classic broadsheet manner
|
||||
(large serif title, rule lines above and below).
|
||||
|
||||
### FR3 — Article types (MUST)
|
||||
|
||||
The layout SHALL support all of the following content types, mapped from
|
||||
markdown into newspaper sections:
|
||||
|
||||
- FR3.1 — Lead / front-page story (a large featured article on page one).
|
||||
- FR3.2 — Interior news articles with headings and bylines.
|
||||
- FR3.3 — Pull quotes, sidebars, and fact boxes (standalone callout styling,
|
||||
not just body paragraphs).
|
||||
- FR3.4 — A "schedule" or "events" block (e.g. ceremony / reception
|
||||
timetable), rendered as a clearly formatted table.
|
||||
- FR3.5 — A lighter section (messages / letters / well-wishes / memory
|
||||
corner) distinct in visual weight from hard news.
|
||||
|
||||
### FR4 — Crosswords and comics ("the funnies") (MUST)
|
||||
|
||||
- FR4.1 — The generator SHALL build crossword puzzles **from content the user
|
||||
provides** (grid + across/down clues derived from user-supplied words/theme
|
||||
words and clues), not from a fixed built-in set.
|
||||
- FR4.2 — The generator SHALL support comic-strip blocks (one or more panels
|
||||
with art + dialogue), including beyond a single cartoon.
|
||||
- FR4.3 — Crossword and comic blocks MUST remain printable and legible on A4.
|
||||
- FR4.4 — The "fun" section is first-class: it may include other word puzzles
|
||||
(e.g. word search / "find-a-word") and other comics (e.g. Dilbert, Garfield,
|
||||
or a tasteful equivalent) so long as they are funny and print cleanly.
|
||||
|
||||
### FR5 — Front-page cartoon tied to the occasion (MUST)
|
||||
|
||||
- FR5.1 — The front page SHALL render an xkcd-style or genuine single-panel
|
||||
cartoon that relates to the wedding / the couple / the day.
|
||||
- FR5.2 — The cartoon SHALL be generated with awareness of context: the
|
||||
couple, the occasion and the day's details inform its subject, so it feels
|
||||
like it belongs rather than a generic cartoon.
|
||||
- FR5.3 — The cartoon SHALL be rendered entirely on-machine (see NFR3
|
||||
Local-only and NFR4 Zero-network); the final printed page never depends on a
|
||||
remote resource.
|
||||
- FR5.4 — A genuine xkcd cartoon MAY be sourced from the real xkcd site
|
||||
(searched for one related to the occasion) as a generation-time input; if
|
||||
one is fetched, it SHALL be embedded locally so the delivered page remains
|
||||
self-contained and print-capable offline.
|
||||
|
||||
### FR6 — Photos and images (MUST)
|
||||
|
||||
- FR6.1 — Articles SHALL support embedded photos/images placed per article.
|
||||
- FR6.2 — The layout SHALL auto-balance images into the column structure so
|
||||
they flow naturally with text.
|
||||
- FR6.3 — Images SHALL support optional captions and byline/credit lines.
|
||||
|
||||
### FR7 — Content ingestion (MUST)
|
||||
|
||||
- FR7.1 — Content is authored as Markdown (and/or plain text) files and
|
||||
read by the generator.
|
||||
- FR7.2 — The generator SHALL produce a single self-contained `newspaper.html` —
|
||||
the printed artifact — from the ingested content.
|
||||
- FR7.3 — The generated page SHALL provide a live-load path (native file
|
||||
picker / drag-and-drop) so alternate content can be swapped in and rendered
|
||||
without regenerating (matches affirmed practice: user-granted reads only).
|
||||
- FR7.4 — Photos are optional inputs: when photos are supplied, the layout
|
||||
SHALL embed them (per FR6); when none are supplied, the layout SHALL generate
|
||||
cleanly without photographs (never fabricate placeholder images).
|
||||
- FR7.5 — Newspaper metadata (masthead title, couple names, date, issue
|
||||
number, volume) is dynamic and SHALL be supplied at generation time rather
|
||||
than hard-coded, so a new issue can be produced without editing the code.
|
||||
|
||||
### FR8 — Optional AI draft support (SHOULD)
|
||||
|
||||
- FR8.1 — The generator MAY call a local AI to draft newspaper copy (lead
|
||||
story, filler articles, pull quotes) before the final render.
|
||||
- FR8.2 — AI-drafted copy MUST be authored into content exactly as if
|
||||
hand-written, then flow through the same layout pipeline.
|
||||
- FR8.3 — The AI route MUST be local Ollama only; the granted model is
|
||||
`deepseek-v4-flash:cloud`. No content SHALL be sent to an external/cloud
|
||||
service.
|
||||
- FR8.4 — AI generation SHALL run the whole first-pass newspaper, then STOP
|
||||
for per-article human review: the user SHALL be able to approve, request
|
||||
edits, or replace any single article's copy before the final render. This
|
||||
review is per-article; approved articles stay unchanged while others are
|
||||
revised and re-rendered.
|
||||
|
||||
## Non-Functional Requirements
|
||||
|
||||
- NFR1 (Printability) — The page MUST print cleanly to A4 from the browser's
|
||||
own print dialog, with no clipping and correct margins. (MUST)
|
||||
- NFR2 (Layout integrity) — Print CSS MUST keep every section, article,
|
||||
image, and puzzle inside the sheet with no overflow, orphaned columns, or
|
||||
broken page breaks. (MUST)
|
||||
- NFR3 (Local-only) — Everything must run purely from the local filesystem;
|
||||
the page MUST never be served or deployed beyond localhost. (MUST)
|
||||
- NFR4 (Zero network) — The page SHALL make zero network requests (no CDN
|
||||
fonts, no remote `<script>`/`<style>`/assets), so it is fully functional
|
||||
offline from `file://`. Fonts, images, and any asset ship with the page.
|
||||
(MUST)
|
||||
- NFR5 (Content read policy) — Content SHALL be read only through
|
||||
user-granted means (native file picker / drag-and-drop); the page SHALL NOT
|
||||
rely on `fetch()` of sibling local files (opaque-origin CORS blocks it in
|
||||
stock browsers). (MUST)
|
||||
- NFR6 (Pure, dependency-free render) — The output SHALL be pure HTML5 + CSS
|
||||
+ vanilla JS with no build step and no external dependencies. (MUST)
|
||||
- NFR7 (Fidelity to markdown) — The markdown→HTML transform SHALL preserve
|
||||
content exactly (no mangled quotes, em-dashes, escaping, or dropped
|
||||
sections). (MUST)
|
||||
- NFR8 (Classic aesthetic) — The visual theme SHALL be classic broadsheet:
|
||||
black ink on white/cream, serif headlines and body, and column rules.
|
||||
(SHOULD, from Q5=a)
|
||||
- NFR9 (AI isolation) — Any AI generation SHALL be an optional, opt-in step
|
||||
that never runs when not requested, and SHALL keep all content local
|
||||
(Ollama). (MUST)
|
||||
|
||||
## Constraints
|
||||
|
||||
- C1 — The project runs on the wedding couple's local machine, never published.
|
||||
- C2 — Node.js is available but the Python (3.14) + `uv` runtime is the
|
||||
affirmed primary path; the generator is a Python static generator.
|
||||
- C3 — Output must be a self-contained static HTML file; no server process is
|
||||
required or desired at print time.
|
||||
- C4 — Only local Ollama is permitted for AI; no external/cloud LLM API.
|
||||
- C5 — A4 is the fixed print format.
|
||||
|
||||
## Assumptions
|
||||
|
||||
- A1 — The couple prefers print realism (classic broadsheet) over modern web
|
||||
styling for the printed keepsake.
|
||||
- A2 — "Fluid" pagination (flow onto as many A4 pages as needed) is preferred
|
||||
over forcing a fixed page count (Q7=a).
|
||||
- A3 — Photos will be supplied as local image files referenced from content;
|
||||
the generator embeds them (self-contained output).
|
||||
- A4 — The xkcd-style cartoon is generated by the local AI with contextual
|
||||
awareness of the couple and day, then rendered as an SVG/embedded image.
|
||||
- A5 — Crosswords are authored as structured puzzle data (grid + clues)
|
||||
provided in content, then laid out by the generator.
|
||||
- A6 — A default visual identity (title, accent) can be supplied by the user
|
||||
but is not required for the generator to produce a valid first output.
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- OS1 — Deploying or hosting the newspaper anywhere (web, static host,
|
||||
printer service).
|
||||
- OS2 — Sending any content or generation to an external/cloud AI service.
|
||||
- OS3 — Dynamic server-side rendering or a persistent runtime service.
|
||||
- OS4 — A full WYSIWYG editor UI (content stays in markdown/text files).
|
||||
- OS5 — Non-A4 print formats (US Letter, tabloid) in this iteration.
|
||||
|
||||
## Open Questions
|
||||
|
||||
- OQ1 (RESOLVED) — Crosswords and other "fun" puzzles are **built from user-provided
|
||||
content**; the fun section may include other comics that are funny, and the
|
||||
xkcd-style cartoon should be a genuine xkcd searched on the real site when
|
||||
possible.
|
||||
- OQ2 (RESOLVED) — Photos are handled when supplied; if none are supplied,
|
||||
no photos are generated or fabricated.
|
||||
- OQ3 (RESOLVED) — Newspaper masthead metadata (title, names, date, issue,
|
||||
volume) is dynamic and brought in at generation time.
|
||||
- OQ4 (RESOLVED) — AI generation runs the whole first-pass newspaper, then
|
||||
provides a per-article human review mechanism (approve / request edits /
|
||||
replace any single article) before the final render.
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<!-- 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-13T12:10:00Z — Interpretation — Confirmed decomposition (all A, self-guided + user pre-approved continuation): one coarse unit per component (generator/ai-draft/funnies), defined interfaces (DraftBundle JSON handoff), embedded/static single deliverable
|
||||
2026-09-13T12:10:00Z — Interpretation — DAG: generator depends on ai-draft + funnies; ai-draft and funnies are independent (parallel buildable); acyclic
|
||||
2026-09-13T12:15:00Z — Interpretation — Human ruling on review R-01: U1 is a library-backed one-shot local tool, never a service/server. Retagged U1 kind service→library in unit-of-work.md + dependency edge block.
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"stage": "units-generation",
|
||||
"upstream_ids": ["US1", "US2", "US3", "US4", "US5", "US6", "US7", "US8", "US9", "US10"],
|
||||
"coverage": [
|
||||
{ "id": "US1", "status": "OK", "target": "U1" },
|
||||
{ "id": "US2", "status": "OK", "target": "U1" },
|
||||
{ "id": "US3", "status": "OK", "target": "U3" },
|
||||
{ "id": "US4", "status": "OK", "target": "U1" },
|
||||
{ "id": "US5", "status": "OK", "target": "U1" },
|
||||
{ "id": "US6", "status": "OK", "target": "U1" },
|
||||
{ "id": "US7", "status": "OK", "target": "U1" },
|
||||
{ "id": "US8", "status": "OK", "target": "U2" },
|
||||
{ "id": "US9", "status": "OK", "target": "U2, U1" },
|
||||
{ "id": "US10", "status": "OK", "target": "U1" }
|
||||
]
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
# Units Generation — Unit Dependency DAG
|
||||
|
||||
> Topology only. Describes what can depend on what; the economic build path
|
||||
> (Bolt sequence) is decided in Delivery Planning (Stage 2.9).
|
||||
|
||||
## Dependency Graph
|
||||
|
||||
```
|
||||
generator ──depends on──▶ ai-draft (optional AI draft, invoked by the CLI)
|
||||
generator ──depends on──▶ funnies (funnies output, invoked during layout)
|
||||
ai-draft (no dependencies)
|
||||
funnies (no dependencies)
|
||||
```
|
||||
|
||||
U2 and U3 are independent libraries the U1 CLI orchestrates. There is no
|
||||
dependency edge between U2 and U3; they never call each other. The graph is acyclic.
|
||||
|
||||
## Integration Points
|
||||
|
||||
| From | To | Integration | Style |
|
||||
|---|---|---|---|
|
||||
| generator | ai-draft | CLI invokes optional Ollama draft (`--draft`); receives DraftBundle article set | sync |
|
||||
| generator | funnies | CLI asks for crossword/find-a-word/cartoon built from content theme words + context | sync |
|
||||
| generator → review page | — | writes DraftBundle JSON; review page reads it via native file picker (ADR-004, NFR5) — data artifact, not a call | file |
|
||||
|
||||
## Parallel Development Opportunities
|
||||
|
||||
U2 and U3 are fully independent of each other (no dependency edge), so they can
|
||||
be built (and reviewed) in parallel. U1 depends on both and can be built in
|
||||
parallel with them up to the integration seams; the DAG admits multiple valid
|
||||
topological orders. The economic choice of which Bolt ships first is Delivery
|
||||
Planning's call, not this stage's.
|
||||
|
||||
## Machine-readable edge block
|
||||
|
||||
```yaml
|
||||
units:
|
||||
- name: "generator"
|
||||
kind: library
|
||||
depends_on: ["ai-draft", "funnies"]
|
||||
- name: "ai-draft"
|
||||
kind: library
|
||||
depends_on: []
|
||||
- name: "funnies"
|
||||
kind: library
|
||||
depends_on: []
|
||||
```
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
# Units Generation — Unit-of-Work Story Map
|
||||
|
||||
> Every user story mapped to the unit that implements it. Cross-cutting stories
|
||||
> are flagged. Coverage: every story assigned; every unit has stories.
|
||||
|
||||
## Story → Unit Map
|
||||
|
||||
| Story | Unit | Unit Directory | Notes |
|
||||
|---|---|---|---|
|
||||
| US1 — Multi-page newspaper output | U1 generator | u1-generator | layout + pagination |
|
||||
| US2 — Classic masthead | U1 generator | u1-generator | masthead render |
|
||||
| US3 — Funnies (crossword/comics/xkcd) | U3 funnies | u3-funnies | puzzle + cartoon build |
|
||||
| US4 — Photos embedded | U1 generator | u1-generator | photo embed + auto-balance |
|
||||
| US5 — Content ingestion & self-contained output | U1 generator | u1-generator | content parse + emit |
|
||||
| US6 — Classic broadsheet aesthetic | U1 generator | u1-generator | print CSS/theme |
|
||||
| US7 — Dynamic issue metadata | U1 generator | u1-generator | MastheadConfig/Issue |
|
||||
| US8 — AI copy via local Ollama | U2 ai-draft | u2-ai-draft | local draft |
|
||||
| US9 — Per-article human review of AI drafts | U2 ai-draft (DraftBundle) + U1 generator (review handoff/file-picker) | u2-ai-draft, u1-generator | cross-cutting: draft data + review page handoff |
|
||||
| US10 — Friendly first-run / empty state | U1 generator | u1-generator | empty-state |
|
||||
|
||||
## Cross-cutting stories
|
||||
|
||||
- **US9** spans U2 (produces the DraftBundle) and U1 (writes + hand off the
|
||||
bundle to the review page via the native file picker). The per-article
|
||||
review contract lives with U2; the file-picker read handoff lives with U1.
|
||||
|
||||
## Story implementation order (within each unit)
|
||||
|
||||
- **U1 generator** (natural build order): US7 (metadata) → US2 (masthead) →
|
||||
US5 (ingestion/emit) → US6 (aesthetic) → US1 (multi-page) → US4 (photos) →
|
||||
US10 (empty state) → US9-handoff (review page data path).
|
||||
- **U2 ai-draft**: US8 (local Ollama draft) → US9 (DraftBundle + per-article
|
||||
review contract).
|
||||
- **U3 funnies**: US3 (crossword → find-a-word → comics → cartoon embed).
|
||||
|
||||
> Implementation *ordering* shown here is a suggested construction sequence
|
||||
> within each unit; the economic Bolt order across units is Delivery Planning's
|
||||
> decision (2.9).
|
||||
|
||||
## Coverage verification
|
||||
|
||||
- Every story (US1–US10) is assigned to one or more units.
|
||||
- Every unit has at least one story: U1 → US1,2,4,5,6,7,9(handoff),10; U2 →
|
||||
US8,9; U3 → US3.
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
# Units Generation — Unit of Work
|
||||
|
||||
> Unit decomposition per confirmed answers (Q1–Q4 = A): one coarse unit per
|
||||
> component (`generator`, `ai-draft`, `funnies`), defined internal interface
|
||||
> boundaries (DraftBundle JSON as the review handoff), embedded/static single
|
||||
> local deliverable. This stage produces the dependency DAG (topology) only;
|
||||
> economic build ordering is decided in Delivery Planning.
|
||||
|
||||
## Unit Definitions
|
||||
|
||||
| Unit ID | Directory | Unit | Kind | Complexity |
|
||||
|---|---|---|---|---|
|
||||
| U1 | `u1-generator` | Generator | library (one-shot local CLI tool, not a deployable/server) | L |
|
||||
| U2 | `u2-ai-draft` | AiDraft | library (optional, no standalone runtime) | M |
|
||||
| U3 | `u3-funnies` | Funnies | library (no standalone runtime) | M |
|
||||
|
||||
**Deployment model per unit:** embedded/static — one `newspaper` command plus
|
||||
templates, all bundled into a single local deliverable. U2 and U3 are libraries
|
||||
the U1 CLI invokes; there is no separate deployable. Per the human ruling on
|
||||
architecture-review R-01 (2026-09-13): U1 is a **library-backed one-shot local
|
||||
tool**, never run as a service or server.
|
||||
|
||||
## Unit Responsibilities
|
||||
|
||||
### U1 — generator (kind: library)
|
||||
|
||||
- Owns the `newspaper` CLI entry point and the full build orchestrator.
|
||||
- Is a one-shot local library-backed tool — never run as a service or server
|
||||
(human ruling on review R-01).
|
||||
- Reads + validates `config.json` (masthead metadata) and the `content/` folder.
|
||||
- Parses markdown/txt into `Article` entities; owns the classic broadsheet
|
||||
layout model, multi-page A4 pagination with clean page breaks, article/section
|
||||
placement, and masthead rendering (US1, US2, US4, US5, US6, US7, US10).
|
||||
- Assembles the funnies section output produced by U3.
|
||||
- Writes the AI-draft `DraftBundle` JSON for the review page handoff (US9).
|
||||
- Emits the self-contained zero-network `newspaper.html`, openable via
|
||||
`file://` and printable to A4.
|
||||
- Owns entities: Issue, Article, MastheadConfig, DraftBundle.
|
||||
|
||||
### U2 — ai-draft (kind: library)
|
||||
|
||||
- Optional local-Ollama copy drafting (US8, US9).
|
||||
- Talks only to local Ollama (granted model `deepseek-v4-flash:cloud`); never
|
||||
contacts any external/cloud service; content stays on-machine (NFR9).
|
||||
- Produces the `DraftBundle` (article set) for per-article review.
|
||||
- Fully optional — when `--draft` is absent it does nothing.
|
||||
|
||||
### U3 — funnies (kind: library)
|
||||
|
||||
- Builds the "fun" section from the content itself (US3, FR4, Q5=X).
|
||||
- Derives theme words + context from content; produces the crossword grid +
|
||||
across/down clues, a find-a-word grid, and selects/embeds an xkcd-style cartoon
|
||||
using content-derived context. A build-time network fetch to enrich content is
|
||||
allowed (human ruling 2026-09-13); the EMITTED page makes zero network
|
||||
requests. Falls back to a tasteful content-derived strip if no cartoon found.
|
||||
- Emits A4-printable, self-contained puzzle/comic blocks.
|
||||
- Owns entity: Puzzle.
|
||||
|
||||
## Implementation Notes / Constraints per Unit
|
||||
|
||||
- **U1**: must keep the emitted page file://-printable and zero-network
|
||||
(NFR1–NFR6). Review-page handoff: the per-article review page reads the
|
||||
DraftBundle via the native file picker (not fetch of siblings) (NFR5, ADR-004).
|
||||
- **U2**: local-only; must never leak content off-machine (NFR9, ADR-002). The
|
||||
granted model is `deepseek-v4-flash:cloud`.
|
||||
- **U3**: puzzle heuristics handle a no-cartoon fallback deterministically
|
||||
(mockups R-02 / domain-design R-01 resolution). A build-time internet fetch to
|
||||
enrich content is fine; the shipped page stays self-contained (human ruling).
|
||||
|
||||
## Deployment Model
|
||||
|
||||
Embedded/static (Q4=A): all three units bundle into single local deliverable
|
||||
(`newspaper` CLI + templates). No servers, no independent deploys, never
|
||||
published beyond localhost.
|
||||
|
||||
<!-- units-after-confirm -->
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
# Units Generation — Questions
|
||||
|
||||
> Fill in each `[Answer]:` tag. Options A-E plus X (Other). The file is the
|
||||
> authoritative record of your unit-decomposition decisions.
|
||||
|
||||
## Q1: Unit boundary strategy
|
||||
|
||||
How should the build units be drawn from the three components (Generator, AiDraft, Funnies)?
|
||||
|
||||
A) One unit per component: `generator`, `ai-draft`, `funnies` — each is a separately buildable piece (recommended; clean mapping to Domain Design)
|
||||
B) One single unit containing all three components (coarse — simplest, one deliverable)
|
||||
C) Split finer: e.g. `layout`, `render`, `content-loader`, `puzzle-gen`, `cartoon` sub-units
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Q2: Unit granularity
|
||||
|
||||
How fine-grained should the units be at build time?
|
||||
|
||||
A) Coarse — a handful of units corresponding to the components (3 units) (recommended for a small local tool)
|
||||
B) Fine-grained — split each component into smaller buildable pieces for maximum reuse/testing granularity
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Q3: Integration points / contracts
|
||||
|
||||
How should the units share data and integrate (the contracts between them)?
|
||||
|
||||
A) A shared internal interface/module boundary per component (Generator calls AiDraft and Funnies via defined entry points; the DraftBundle JSON is the review handoff contract) (recommended)
|
||||
B) Loose — units communicate only through files on disk, no shared code interface
|
||||
C) A package-manager-style library dependency (one unit imports another as a package)
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Q4: Deployment model
|
||||
|
||||
For this fully-local tool, what deployment shape should the units take?
|
||||
|
||||
A) Embedded/static — one `newspaper` command + templates, all bundled; single local deliverable (recommended, matches CLI-first file-only posture)
|
||||
B) Split executables that each run independently (no benefit here, but if preferred)
|
||||
C) Library + thin CLI wrapper (the generator logic as a reusable library, plus a thin `newspaper` script)
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Consolidated Summary Confirmation
|
||||
|
||||
> Summary of your four decomposition answers before the unit artifacts are generated:
|
||||
>
|
||||
> - Boundary strategy: **one unit per component** — `generator`, `ai-draft`, `funnies` (Q1=A)
|
||||
> - Granularity: **coarse** — 3 units corresponding to the components (Q2=A)
|
||||
> - Integration/contracts: **defined internal interface boundaries**; the DraftBundle JSON is the review handoff contract (Q3=A)
|
||||
> - Deployment: **embedded/static** — one `newspaper` command + templates, single local deliverable (Q4=A)
|
||||
>
|
||||
> Plan approval: the human pre-approved the decomposition plan (answers recorded via the file, self-guided mode).
|
||||
|
||||
Does this all look correct before I generate the unit artifacts?
|
||||
|
||||
- Looks correct
|
||||
- Request changes
|
||||
|
||||
[Answer]: Looks correct
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
**Collaborator:** aidlc-design-agent
|
||||
|
||||
## Contribution
|
||||
|
||||
Reviewing the personas and story draft for UX and persona fidelity.
|
||||
|
||||
- The two-persona split (P1 the couple, P2 the guest-as-constraint) is the right
|
||||
call for a self-contained local tool — the reader is genuinely the printed
|
||||
output, not an interface user. Keeping P2 as quality attributes on the P1
|
||||
stories avoids inventing fake guest "tasks" that don't map to real usage.
|
||||
- Strong points in the draft: US6 locks the classic broadsheet aesthetic as a
|
||||
testable constraint; US3 gives the funnies first-class weight; US9 makes the
|
||||
AI-review a first-class flow rather than a background detail.
|
||||
- Design gap worth folding in: the stories don't yet capture a "no-content"
|
||||
or "empty issue" authoring state — what the couple sees when they open the
|
||||
generator with no content yet. A small, friendly empty-state story would
|
||||
protect the first-run experience.
|
||||
- Recommend a "first-run empty state" story (Won't/could) so the couple isn't
|
||||
met with a blank page on first launch.
|
||||
|
||||
## Positions
|
||||
- AGREE: two-persona model with guest as reader-constraint — honest to real usage.
|
||||
- AGREE: US6 aesthetic-as-requirement — design intent is testable, not hand-wavy.
|
||||
- OBJECT (minor): missing an empty-state / first-run experience story; consider
|
||||
a small Could-Have story so first launch is friendly, not blank.
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
**Collaborator:** aidlc-developer-agent
|
||||
|
||||
## Contribution
|
||||
|
||||
Reviewing the personas and stories for implementability and story sizing.
|
||||
|
||||
- Story sizing at the FR-group level (Q2=B) reads correctly against this
|
||||
project's surface area: US1 (multi-page), US3 (funnies), US8/US9 (AI+
|
||||
review) are the meaty ones, and grouping them this way keeps each story
|
||||
independently deliverable without splitting hairs.
|
||||
- Dependencies are well-flagged (US7 feeds US2 for the masthead; US5 feeds
|
||||
everything; US9 depends on US8). The dependency notes are accurate.
|
||||
- Implementability notes worth locking:
|
||||
- US3 (funnies) is the largest chunk — crossword building from user content,
|
||||
word-search, comic placement, plus the xkcd fetch-and-embed. Consider
|
||||
whether the crossword and the comics could be accepted as separate stories
|
||||
if sizing gets tight, though the user's plan keeps them grouped; honoring
|
||||
the current plan, I note it as a single Must-Have that is genuinely
|
||||
composite.
|
||||
- US5.AC5.1.3 (file-picker live load) needs the native file picker path —
|
||||
this aligns with the affirmed practice and is known-possible, but it is
|
||||
real work; calling it out so it isn't underestimated.
|
||||
- US9 (per-article review) implies the AI draft output must be addressable
|
||||
per article (a data model), not a single blob — the story's ACs already
|
||||
capture this requirement implicitly; making the per-article boundary
|
||||
explicit helps the implementer.
|
||||
|
||||
## Positions
|
||||
- AGREE: FR-group story granularity is right for this scope — each US is
|
||||
independently shippable.
|
||||
- AGREE: dependency graph is accurate and useful.
|
||||
- OBJECT (minor): US3 is composite (crossword + word-search + comics + xkcd
|
||||
fetch/embed) and deserves an explicit note that it may need internal
|
||||
splitting at Delivery Planning if the effort is large; and US5.3 / US9's
|
||||
per-article boundary should be made explicit in the ACs so implementers
|
||||
don't underestimate them.
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
**Collaborator:** aidlc-quality-agent
|
||||
|
||||
## Contribution
|
||||
|
||||
Reviewing the story draft for testability of the acceptance criteria.
|
||||
|
||||
- The BDD Given/When/Then acceptance criteria are generally well-formed and
|
||||
each maps to a concrete verifiable outcome. US6, US1, and US5 are the most
|
||||
testable — they map directly to observable print/layout behavior.
|
||||
- Gaps in testability worth flagging:
|
||||
- US2.AC2.1.3 and US7.AC7.1.2 (dynamic metadata) need a clear "observed
|
||||
changed output" assertion — the criterion reads well but should explicitly
|
||||
note that the change is verified by re-running generation with new values,
|
||||
not by any code change.
|
||||
- US3.AC3.1.4 ("genuine xkcd related to the occasion") is the weakest
|
||||
criterion — "related" and "funny" are subjective. Recommend the story note
|
||||
verification as a human-visible check (the couple judges the cartoon before
|
||||
print) rather than an automated assertion, and keep the technical AC
|
||||
(embedded locally, AC3.1.5) as the automated one.
|
||||
- US9's per-article criteria (AC9.1.2–3) are strong — approving one and
|
||||
revising another maps cleanly to a test.
|
||||
- Recommend strengthening US3.AC3.1.4 by splitting the subjective "fits the
|
||||
occasion" judgment to a human gate step, and keeping the verifiable
|
||||
embed/local AC automated.
|
||||
|
||||
## Positions
|
||||
- AGREE: most ACs are concrete and testable; the layout/print ones are best.
|
||||
- AGREE: US9's per-article acceptance criteria are well-scoped.
|
||||
- OBJECT (minor): US3.AC3.1.4 couples a subjective ("related/funny") judgment
|
||||
with an objective (embedded local) assertion in one criterion; split them so
|
||||
the human-visible check is separate from the machine-checkable one.
|
||||
@@ -0,0 +1,16 @@
|
||||
<!-- 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-13T11:40:00Z — Interpretation — Plan: 2 personas, story-per-FR-group, editor-focus, dedicated AI-review group (user answers B,B,B,A)
|
||||
2026-09-13T11:40:00Z — Tradeoff — Mob contributed 3 minors: designer (empty-state Could-Have), developer (US3 composite + per-article boundary), quality (split subjective/objective in AC3.1.4); all integrated, no mid-stage triage needed
|
||||
@@ -0,0 +1,55 @@
|
||||
# Personas
|
||||
|
||||
> Two personas affirmed for the wedding newspaper generator (Q1=B). Per the
|
||||
> plan (Q3=B), the editor/generator flow drives the stories; the reader
|
||||
> experience is a quality constraint, not a separate story set.
|
||||
|
||||
## P1 — The Couple (editor & publisher)
|
||||
|
||||
**Role**: The primary user. One (or both) of the newlyweds authors the content,
|
||||
runs the generator, reviews the AI draft, and prints the newspaper.
|
||||
|
||||
**Goals**
|
||||
- Produce a keepsake newspaper that captures the wedding day, their story, and
|
||||
their guests' messages in one printed artifact.
|
||||
- Make it feel like a real newspaper (classic broadsheet, masthead, funnies).
|
||||
- Keep it private and fully local — nothing about their wedding leaves the machine.
|
||||
- Generate a whole first pass quickly, then polish individual articles.
|
||||
|
||||
**Pain points**
|
||||
- Time pressure around the wedding — wants drafting accelerated by AI, but
|
||||
control over each article's final copy.
|
||||
- Not a developer — needs a simple "drop content in, run, print" flow.
|
||||
- The fun section (crosswords, comics) must feel hand-crafted for *them*, not
|
||||
generic.
|
||||
|
||||
**Context**: Uses the local Ollama AI (granted `deepseek-v4-flash:cloud`) for
|
||||
drafts; supplies markdown/txt content, optional photos, and dynamic masthead
|
||||
metadata per issue.
|
||||
|
||||
## P2 — The Guest (reader)
|
||||
|
||||
**Role**: The person who receives/flips through the printed newspaper. Not a
|
||||
user of the generator — a reader of its output. Represented as a quality
|
||||
constraint on the editor flow (Q3=B).
|
||||
|
||||
**Goals**
|
||||
- Enjoy reading it: clear layout, legible print, natural column flow, no clipped
|
||||
articles.
|
||||
- Recognize the couple and the occasion in the content and the cartoon.
|
||||
- Be able to attempt the crossword and enjoy the comics.
|
||||
|
||||
**Pain points**
|
||||
- Clipped text, broken page breaks, or unreadable small print would ruin the
|
||||
keepsake.
|
||||
- A cartoon or comic that feels unrelated to the couple would feel off.
|
||||
|
||||
**Context**: Receives the finished, printed A4 newspaper. Their experience is
|
||||
locked in via print/readability acceptance criteria on the editor stories.
|
||||
|
||||
## Persona Relationships & Priority
|
||||
- P1 (the couple) is the **primary** persona — all stories serve their authoring
|
||||
flow. This is definitive for this project.
|
||||
- P2 (the guest) is **secondary**, enforced as quality attributes (legibility,
|
||||
clean page breaks, content fidelity) on the P1 stories, not as separate
|
||||
guest-facing stories.
|
||||
@@ -0,0 +1,181 @@
|
||||
# User Stories — Wedding Newspaper Generator
|
||||
|
||||
> Two personas: **P1 The Couple (editor/publisher)**, **P2 The Guest (reader,
|
||||
> quality constraint)**. Story-per-FR-group granularity (Q2=B), editor-flow
|
||||
> focus (Q3=B), dedicated AI per-article-review group (Q4=A). INVEST-compliant,
|
||||
> BDD acceptance criteria, MoSCoW priority.
|
||||
|
||||
## US1 — Multi-page newspaper output (FR1) — Must Have
|
||||
|
||||
**As** the couple (P1), **I want** the generator to flow my content across as
|
||||
many A4 pages as it needs with clean automatic page breaks, **so that** my
|
||||
newspaper can be as long as the content deserves and prints as a real
|
||||
multi-page broadsheet.
|
||||
|
||||
- **AC1.1.1** — Given content that exceeds one A4 sheet, when I generate and print,
|
||||
then the output continues onto subsequent sheets with a clean break between pages.
|
||||
- **AC1.1.2** — Given a long article, when pagination runs, then the break falls at
|
||||
a section/article boundary, never splitting a single article awkwardly mid-paragraph
|
||||
unless unavoidable.
|
||||
- **AC1.1.3** — Given a multi-page issue, when I print, then each page renders page
|
||||
numbers and running headers/footers correctly and the masthead continues cleanly.
|
||||
|
||||
**Dependencies**: none. **INVEST**: Independent (self-contained), Small, Testable.
|
||||
|
||||
## US2 — Classic masthead (FR2) — Must Have
|
||||
|
||||
**As** the couple (P1), **I want** a classic newspaper masthead with title, date,
|
||||
issue number, and volume line, **so that** the front page reads as an authentic
|
||||
broadsheet.
|
||||
|
||||
- **AC2.1.1** — Given a generation run, when I supply dynamic masthead metadata
|
||||
(title, couple names, date, issue, volume), then the front page renders the title
|
||||
banner.
|
||||
- **AC2.1.2** — Given the masthead metadata, when the page renders, then a date line,
|
||||
issue number, and "Volume X" line all appear under the title.
|
||||
- **AC2.1.3** — Given a new issue with different metadata, when I generate again, then
|
||||
the masthead reflects the new values without any code change (dynamic, per FR7.5).
|
||||
|
||||
**Dependencies**: US7 (dynamic metadata). **INVEST**: Negotiable, Testable.
|
||||
|
||||
## US3 — The funnies: crosswords, word puzzles, and comics (FR4, FR5) — Must Have
|
||||
|
||||
**As** the couple (P1), **I want** the generator to build crosswords from content I
|
||||
provide and to place funny comics (including an xkcd-style front-page cartoon tied
|
||||
to the occasion), **so that** the fun section feels hand-crafted for our wedding,
|
||||
not generic.
|
||||
|
||||
- **AC3.1.1** — Given content I supply (theme words and clues), when I generate, then
|
||||
a crossword puzzle block renders with a grid, across/down clues, and a solution area.
|
||||
- **AC3.1.2** — Given the fun section is requested, when I generate, then a word-search /
|
||||
"find-a-word" puzzle also renders (FR4.4).
|
||||
- **AC3.1.3** — Given a comic strip is requested, when I generate, then one or more
|
||||
panels with art and dialogue render and print legibly on A4.
|
||||
- **AC3.1.4** — Given the front page, when it renders, then a genuine xkcd cartoon
|
||||
is placed and embedded locally (FR5, machine-checkable: the asset is local, not
|
||||
a remote URL).
|
||||
- **AC3.1.5** — Given the couple's review of the cartoon before print, then they
|
||||
judge whether it fits the occasion and a comic in the fun section is funny before
|
||||
final render (FR5.2, FR4.4 — human-visible check at the per-article/print review).
|
||||
- **AC3.1.6** — Given an xkcd is sourced from the real site, when the page is built,
|
||||
then it is embedded as a local asset so the delivered page remains self-contained
|
||||
and print-capable offline (FR5.4, NFR4).
|
||||
|
||||
**Dependencies**: US1 (print), US7 (content/metadata). **INVEST**: Valuable, Testable.
|
||||
|
||||
## US4 — Photos embedded when supplied (FR6, FR7.4) — Must Have
|
||||
|
||||
**As** the couple (P1), **I want** photos I supply to be embedded and auto-balanced
|
||||
into the newspaper columns, **so that** the layout looks natural and, if I supply no
|
||||
photos, the paper still generates cleanly without them.
|
||||
|
||||
- **AC4.1.1** — Given I supply photo files, when I generate, then the photos embed in
|
||||
the article layout and auto-balance into the column structure without overflowing
|
||||
the A4 sheet.
|
||||
- **AC4.1.2** — Given an embedded photo with a caption/credit, when the page renders,
|
||||
then the caption and credit line render below it.
|
||||
- **AC4.1.3** — Given I supply no photos, when I generate, then the newspaper renders
|
||||
cleanly with **no** fabricated or placeholder images (FR7.4).
|
||||
|
||||
**Dependencies**: US1. **INVEST**: Independent, Testable.
|
||||
|
||||
## US5 — Content ingestion & self-contained output (FR7) — Must Have
|
||||
|
||||
**As** the couple (P1), **I want** to drop my markdown/text content in and have the
|
||||
generator emit one self-contained `newspaper.html`, **so that** I can open it anywhere
|
||||
from the local filesystem and print it with no server.
|
||||
|
||||
- **AC5.1.1** — Given markdown/text content files, when I run the generator, then a
|
||||
single self-contained `newspaper.html` is produced.
|
||||
- **AC5.1.2** — Given the generated page, when I open it from `file://` and print, then
|
||||
it works with zero network requests and no server (NFR3, NFR4).
|
||||
- **AC5.1.3** — Given the page open locally, when I want to swap in different content,
|
||||
then I can load it via the native file picker / drag-and-drop without regenerating
|
||||
(user-granted reads only, NFR5, FR7.3).
|
||||
|
||||
**Dependencies**: none. **INVEST**: Independent, Small, Testable.
|
||||
|
||||
## US6 — Classic broadsheet aesthetic (NFR8, NFR1, NFR2) — Must Have
|
||||
|
||||
**As** the couple (P1), **I want** the newspaper styled as classic broadsheet (black ink
|
||||
on white/cream, serif headlines/body, column rules) that prints cleanly to A4, **so
|
||||
that** the keepsake looks authentic and is legible on paper.
|
||||
|
||||
- **AC6.1.1** — Given the generated page, when I view it, then the theme is classic
|
||||
broadsheet: black ink on white/cream, serif headlines and body, column rules (Q5=A).
|
||||
- **AC6.1.2** — Given the page in the browser, when I choose Print → A4, then every
|
||||
section, image, and puzzle stays inside the sheet with no clipping, orphaned columns,
|
||||
or broken page breaks (NFR1, NFR2).
|
||||
- **AC6.1.3** — Given the print CSS, when content is present, then margins render
|
||||
correctly and the page uses sensible A4 print margins (NFR1).
|
||||
|
||||
**Dependencies**: US1. **INVEST**: Testable.
|
||||
|
||||
## US7 — Dynamic issue metadata (FR7.5, OQ3) — Must Have
|
||||
|
||||
**As** the couple (P1), **I want** issue metadata (title, couple names, date, issue
|
||||
number, volume) to be supplied at generation time, **so that** each new issue is
|
||||
produced without editing code.
|
||||
|
||||
- **AC7.1.1** — Given metadata supplied per issue, when I generate, then the masthead
|
||||
and issue identity use those values.
|
||||
- **AC7.1.2** — Given a second issue with different metadata, when I generate, then the
|
||||
output reflects the new values with no code changes.
|
||||
|
||||
**Dependencies**: none. **INVEST**: Independent, Small, Testable.
|
||||
|
||||
## US8 — AI copy generation via local Ollama (FR8.1–3) — Must Have
|
||||
|
||||
**As** the couple (P1), **I want** the generator to draft newspaper copy using local
|
||||
Ollama (`deepseek-v4-flash:cloud`), **so that** the initial article draft is
|
||||
accelerated while all content stays on-machine.
|
||||
|
||||
- **AC8.1.1** — Given local Ollama is available, when I ask for a draft, then the
|
||||
generator drafts the lead story and filler articles through the local model.
|
||||
- **AC8.1.2** — Given a draft is produced, when it is used, then it flows through the
|
||||
same layout pipeline exactly as hand-written content (FR8.2).
|
||||
- **AC8.1.3** — Given generation, when AI runs, then **no** content is sent to an
|
||||
external/cloud service (only local Ollama) (FR8.3, NFR9).
|
||||
|
||||
**Dependencies**: US5 (content pipeline). **INVEST**: Valuable, Testable.
|
||||
|
||||
## US9 — Per-article human review of AI drafts (FR8.4, OQ4) — Must Have
|
||||
|
||||
**As** the couple (P1), **I want** the generator to produce a whole first-pass
|
||||
newspaper and then let me approve, edit, or replace any single article's copy,
|
||||
**so that** I keep final control over what goes to print.
|
||||
|
||||
- **AC9.1.1** — Given a full first-pass AI newspaper, when generation completes, then
|
||||
the run stops for per-article review.
|
||||
- **AC9.1.2** — Given a reviewed article I approve, when it stays in, then its copy is
|
||||
unchanged while others may still be revised.
|
||||
- **AC9.1.3** — Given an article I want changed, when I request an edit, then only that
|
||||
article's copy is revised and re-rendered; approved articles stay unchanged.
|
||||
- **AC9.1.4** — Given an article I want replaced, when I supply new copy, then the new
|
||||
content replaces the draft for that article while the rest of the paper is untouched.
|
||||
- **AC9.1.5** — Given an AI draft was produced, when it is reviewed, then each
|
||||
article is addressable as its own unit (an article-level data boundary), so any
|
||||
single article can be approved, edited, or replaced independently (FR8.4).
|
||||
|
||||
**Dependencies**: US8 (AI drafts). **INVEST**: Independent, Negotiable, Valuable.
|
||||
|
||||
## US10 — Friendly first-run / empty state (design refinement) — Could Have
|
||||
|
||||
**As** the couple (P1), **I want** the generator to show a clear, friendly state
|
||||
when I have no content yet, **so that** my first launch isn't a blank or broken page.
|
||||
|
||||
- **AC10.1.1** — Given no content provided, when I run/generate, then the page shows a
|
||||
short, friendly empty-state message and guidance rather than a blank page.
|
||||
- **AC10.1.2** — Given I then add content, when I generate again, then the full
|
||||
newspaper renders normally.
|
||||
|
||||
**Dependencies**: US5. **INVEST**: Independent, Small, Testable.
|
||||
|
||||
## Won't Have (explicitly out)
|
||||
|
||||
- W1 — No remote deployment or hosting of the newspaper.
|
||||
- W2 — No cloud/external AI.
|
||||
- W3 — No dynamic server-side rendering service.
|
||||
- W4 — No full WYSIWYG editor UI.
|
||||
|
||||
<!-- finalized-after-confirm -->
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"stage": "user-stories",
|
||||
"upstream_ids": ["FR1", "FR2", "FR3", "FR4", "FR5", "FR6", "FR7", "FR8", "NFR1", "NFR2", "NFR3", "NFR4", "NFR5", "NFR6", "NFR7", "NFR8", "NFR9"],
|
||||
"coverage": [
|
||||
{ "id": "FR1", "status": "OK", "target": "US1" },
|
||||
{ "id": "FR2", "status": "OK", "target": "US2" },
|
||||
{ "id": "FR3", "status": "OK", "target": "US5, US6" },
|
||||
{ "id": "FR4", "status": "OK", "target": "US3" },
|
||||
{ "id": "FR5", "status": "OK", "target": "US3" },
|
||||
{ "id": "FR6", "status": "OK", "target": "US4" },
|
||||
{ "id": "FR7", "status": "OK", "target": "US5, US7" },
|
||||
{ "id": "FR8", "status": "OK", "target": "US8, US9" },
|
||||
{ "id": "NFR1", "status": "OK", "target": "US6" },
|
||||
{ "id": "NFR2", "status": "OK", "target": "US6" },
|
||||
{ "id": "NFR3", "status": "OK", "target": "US5" },
|
||||
{ "id": "NFR4", "status": "OK", "target": "US3, US5" },
|
||||
{ "id": "NFR5", "status": "OK", "target": "US5" },
|
||||
{ "id": "NFR6", "status": "OK", "target": "US5" },
|
||||
{ "id": "NFR7", "status": "OK", "target": "US5" },
|
||||
{ "id": "NFR8", "status": "OK", "target": "US6" },
|
||||
{ "id": "NFR9", "status": "OK", "target": "US8" }
|
||||
]
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
# User Stories Assessment
|
||||
|
||||
## Decision
|
||||
**Execute**
|
||||
|
||||
## Rationale
|
||||
User stories add clear value for the wedding newspaper generator. The tool has
|
||||
multiple distinct user roles with different goals (the couple as editor/publisher,
|
||||
guests reading/recalling, and the couple as the keepsake owners), user-facing
|
||||
features throughout, and enough surface area — multi-page layout, the "funnies"
|
||||
section, crosswords built from content, photo embedding, an AI draft-then-review
|
||||
loop — that story-level framing improves both scope control and testability well
|
||||
beyond the flat FR list.
|
||||
|
||||
## Factors Considered
|
||||
- **Project type**: Greenfield user-facing application (a generator + printed artifact).
|
||||
- **User-facing scope**: High — every feature is user-authored content rendered for a reader.
|
||||
- **Complexity signals**: Multi-persona (couple/editor, guest reader), multi-page print
|
||||
layout, puzzle generation from arbitrary content, optional AI pipeline with
|
||||
per-article review. These need story-level acceptance criteria.
|
||||
- **Cross-team work**: Internal (design/developer/quality alignment on the layout
|
||||
and content flow); no external coordination but the mob adds value here.
|
||||
|
||||
## Key Areas Where Stories Add the Most Value
|
||||
1. Authoring and content ingestion (markdown/txt → newspaper sections).
|
||||
2. The multi-page print behaviour and A4 fidelity (the hardest acceptance surface).
|
||||
3. The "funnies" section (crosswords built from user content, comics, xkcd cartoon).
|
||||
4. Photo handling (embedded when supplied, clean when absent).
|
||||
5. The optional AI draft + per-article human review loop.
|
||||
6. Dynamic masthead metadata per issue.
|
||||
|
||||
## Alternative Coverage if Skipped
|
||||
Not applicable — the requirements alone are insufficiently testable; this stage
|
||||
provides the BDD Given/When/Then acceptance criteria that later stages need.
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
# User Stories — Story Plan & Questions
|
||||
|
||||
> Fill in each `[Answer]:` tag. Options A-E plus X (Other). The file is the
|
||||
> authoritative record of your story-planning decisions.
|
||||
|
||||
## Story Plan Summary
|
||||
|
||||
- **Persona development approach**: draft three personas based on the
|
||||
requirements (the couple-as-editor, the couple-as-keepsake-owners, and the
|
||||
guest reader), refined here by your answer.
|
||||
- **Story format**: INVEST (Independent, Negotiable, Valuable, Estimable,
|
||||
Small, Testable), BDD Given/When/Then acceptance criteria, stable IDs.
|
||||
- **Prioritization**: MoSCoW (Must / Should / Could / Won't Have) per story.
|
||||
- **Breakdown approach**: by feature area with story groups aligned to the
|
||||
FR groups in `requirements.md`.
|
||||
|
||||
## Q1: Persona depth
|
||||
|
||||
How thoroughly should we define the personas for this project?
|
||||
|
||||
A) Three personas (couple-as-editor, couple-as-keepsake-owner, guest reader), each with goals, pain points, and context (recommended)
|
||||
B) Two personas (the couple, the guest) — keep it lean for a self-contained local tool
|
||||
C) The couple is the only real persona; guests are implicit readers, not a separate persona
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: B
|
||||
|
||||
## Q2: Story granularity
|
||||
|
||||
How granular should the stories be?
|
||||
|
||||
A) Story per FR sub-requirement where meaningful (e.g. one story for "crossword built from user content", one for "xkcd front-page cartoon") — moderately fine-grained (recommended)
|
||||
B) Story per FR group (fewer, larger stories — e.g. one story covering all of "the funnies")
|
||||
C) Coarse — a handful of high-level epic stories, expanded later
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: B
|
||||
|
||||
## Q3: Guest-reader focus
|
||||
|
||||
How much weight should the guest-reading experience carry in story definition?
|
||||
|
||||
A) Treat guest-reader stories as first-class (printing legibility, nostalgia, easy flipping) alongside the editor flow (recommended)
|
||||
B) Focus stories on the editor/generator flow; treat reader experience as a quality constraint, not separate stories
|
||||
C) Reader experience is the whole point — lead with it, editor stories secondary
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: B
|
||||
|
||||
## Q4: AI-review loop story
|
||||
|
||||
The AI draft-then-per-article-review loop (FR8.4) is a notable piece of work. How should we represent it?
|
||||
|
||||
A) A dedicated Must-Have story group with an acceptance criterion per mechanism (approve / edit / replace per article) (recommended)
|
||||
B) Fold it into the general AI-draft story as a Should-Have; the per-article review is a detail, not its own group
|
||||
C) Keep it explicit but mark it Could-Have if time is tight
|
||||
X) Other (please specify)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
## Consolidated Summary Confirmation
|
||||
|
||||
> Summary of the four story-plan answers and the plan that follows, before the
|
||||
> stories and personas artifacts are finalized:
|
||||
>
|
||||
> - Persona depth: **two personas** — the couple, and the guest-as-reader (Q1=B)
|
||||
> - Story granularity: **story per FR group**, fewer larger stories (Q2=B)
|
||||
> - Guest-reader focus: **editor/generator flow leads**; reader experience is a quality constraint (Q3=B)
|
||||
> - AI per-article review loop: **dedicated Must-Have story group** (Q4=A)
|
||||
> - Resulting plan: US1–US9 Must-Have (+ US10 Could-Have empty-state), BDD acceptance criteria, MoSCoW priority, full FR/NFR traceability
|
||||
|
||||
Does this all look correct before I finalize the stories and personas artifacts?
|
||||
|
||||
- Looks correct
|
||||
- Request changes
|
||||
|
||||
[Answer]: Looks correct
|
||||
Reference in New Issue
Block a user