Files
josh 39563f6934 docs(01): plan phase 1 — 7 plans across 3 waves, verified after 1 revision
Wave 1: Plan 01 (scaffold + test infra)
Wave 2: Plans 02 (eslint firewall), 03 (save layer), 04 (content pipeline),
        05 (asset provenance — autonomous:false human-curate checkpoint),
        06 (doctrine docs)
Wave 3: Plan 07 (CI workflow)

All 16 Phase-1 REQ-IDs covered. Plan-checker found 4 blockers + 6 warnings
on first pass; revision iteration 1 landed all 10 fixes; iteration 2
returned VERIFICATION PASSED. Two orchestrator judgment calls during
revision: (1) implement CORE-04 localStorage fallback in Phase 1 (the
literal requirement and ROADMAP success criterion #2 both call for it),
(2) reclassify STRY-09 as vacuously satisfied in Phase 1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 23:09:08 -04:00

467 lines
30 KiB
Markdown

---
phase: 01
plan: 06
type: execute
wave: 2
depends_on: [01-01]
files_modified:
- .planning/anti-fomo-doctrine.md
- .planning/season-7-end-state.md
- scripts/doctrine.test.ts
autonomous: true
requirements: [PIPE-05, UX-13, STRY-09]
must_haves:
truths:
- "`.planning/anti-fomo-doctrine.md` exists and consolidates banned-pattern enumeration from PROJECT.md, REQUIREMENTS.md UX-13, CLAUDE.md Hard Thematic Constraints, RESEARCH PITFALLS.md #9 (PIPE-05 + UX-13)"
- "`.planning/season-7-end-state.md` exists and answers principle-level the three questions per CONTEXT D-08: (a) what *rest state* means, (b) what the finite Roothold ceiling is tied to, (c) the coda's tonal register (PIPE-05)"
- "Both docs are principle-level consolidations (not new design and not treatment-level) per CONTEXT D-07 + D-08"
- "A Vitest doc-lint test asserts both docs exist with their required H2 sections (per RESEARCH § Validation Architecture PIPE-05 row)"
- "Neither doc adds a lint rule on UX strings (per CONTEXT D-07 — explicitly rejected)"
artifacts:
- path: .planning/anti-fomo-doctrine.md
provides: "Banned-pattern enumeration + allowed-engagement list + 3-question review checklist + source-document citations (per RESEARCH outline)"
contains: "## Banned Mechanics"
- path: .planning/season-7-end-state.md
provides: "Principle-level answers to (a) rest state, (b) finite Roothold ceiling tie, (c) tonal register; explicit list of what this doc is NOT (per RESEARCH outline + CONTEXT D-08)"
contains: "## What does *rest state* mean?"
- path: scripts/doctrine.test.ts
provides: "Vitest test asserting both docs exist and contain their required H2 sections"
key_links:
- from: .planning/anti-fomo-doctrine.md
to: ["PROJECT.md Out of Scope", "REQUIREMENTS.md UX-13", "CLAUDE.md Hard Thematic Constraints", ".planning/research/PITFALLS.md #9"]
via: "Source Documents section enumerates the 4 references explicitly"
pattern: "PROJECT.md.*REQUIREMENTS.md.*CLAUDE.md.*PITFALLS.md"
- from: .planning/season-7-end-state.md
to: ["PROJECT.md core value", "REQUIREMENTS.md SEAS-04, SEAS-09, SEAS-10, STRY-08", "ROADMAP.md Phase 7", ".planning/research/PITFALLS.md #1"]
via: "Source Documents section enumerates the 4 references explicitly"
pattern: "SEAS-04.*SEAS-09.*SEAS-10.*STRY-08"
---
<objective>
Author the two Phase-1 doctrine documents per CONTEXT D-07 + D-08 + D-09. Both live under `.planning/` (not `docs/` per D-09). Both are *consolidation documents* of constraints already scattered across project artifacts — the planner is **not** doing new design work, only collecting and organizing what's already locked elsewhere. Per CONTEXT D-07, anti-FOMO is enforced by review (not lint); per D-08, Season 7 end-state is principle-level (not treatment text). RESEARCH § "Doctrine doc outline — anti-fomo-doctrine.md" and § "Doctrine doc outline — season-7-end-state.md" provide concrete templates that this plan ships verbatim with project-specific details filled in.
Ship a single Vitest doc-lint test (`scripts/doctrine.test.ts`) that asserts both files exist and each contains its required H2 sections — proving PIPE-05 is automatable and giving Plan 07's CI workflow something to verify. Per CONTEXT D-07: NO lint rule on UX strings.
Purpose: PROJECT.md commits to the 7-Season scope; PITFALLS.md #1 names "the story ends but the loop doesn't" as the single most dangerous pitfall; CONTEXT D-08 demands the answer ship before any economy code (Phase 2) lands. PIPE-05 + UX-13 require these docs in the repo before Phase 2 begins. The docs become referenced artifacts at every UX/monetization/economy review going forward.
Output: Two principle-level doctrine markdown files in `.planning/` plus one Vitest doc-lint test enforcing their structural integrity.
</objective>
<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/REQUIREMENTS.md
@.planning/STATE.md
@.planning/phases/01-foundations-and-doctrine/01-CONTEXT.md
@.planning/phases/01-foundations-and-doctrine/01-RESEARCH.md
@.planning/phases/01-foundations-and-doctrine/01-01-SUMMARY.md
@.planning/research/PITFALLS.md
@CLAUDE.md
</context>
<tasks>
<task type="auto">
<name>Task 1: Author `.planning/anti-fomo-doctrine.md` (consolidation per CONTEXT D-07 + RESEARCH outline)</name>
<files>
.planning/anti-fomo-doctrine.md
</files>
<read_first>
- .planning/phases/01-foundations-and-doctrine/01-RESEARCH.md § "Doctrine doc outline — anti-fomo-doctrine.md" (the verbatim template structure)
- .planning/phases/01-foundations-and-doctrine/01-CONTEXT.md (D-07 — consolidation document, no lint rule on UX strings, enforced by review)
- .planning/PROJECT.md § "Out of Scope" (gacha, lootboxes, daily login bonuses, streaks, etc. — the source list of banned patterns)
- .planning/REQUIREMENTS.md UX-13 + § "Out of Scope" table (rows: gacha, lootboxes, narrative gating, Season skipping, daily login, streaks, limited-time, energy/stamina, rewarded ads, push spam, lore codex, generic flora, combat, multiplayer, voiced dialogue, always-online, named Keeper, hint system, time-skip purchases, Unity engines, generic cosmetics, random-drop cosmetics, mobile-style nag UX)
- CLAUDE.md "Hard Thematic Constraints (Out of Scope by Design)" — the 13 enumerated exclusions
- .planning/research/PITFALLS.md § "Pitfall 9: FOMO/Nag Mechanics Violate Cozy Tone" (the rationale + warning signs + how-to-avoid)
</read_first>
<action>
Write `.planning/anti-fomo-doctrine.md` using the Write tool. Follow the RESEARCH § "Doctrine doc outline — anti-fomo-doctrine.md" template verbatim, but populate every banned-pattern row from the four source documents (PROJECT.md, REQUIREMENTS.md, CLAUDE.md, PITFALLS.md #9). Per CONTEXT D-07, this is a *consolidation* — do not invent new constraints, do not relitigate existing ones.
**The document must contain these EXACT H2 sections** (the doc-lint test in Task 2 will assert each one exists):
1. `## Banned Mechanics`
2. `## Allowed Engagement`
3. `## Review Checklist`
4. `## Source Documents`
**Document content:**
```markdown
# Anti-FOMO Doctrine
*Phase 1 deliverable per PIPE-05 + UX-13. Consolidated from PROJECT.md, REQUIREMENTS.md, CLAUDE.md, and .planning/research/PITFALLS.md #9.*
This document is referenced at every UX, monetization, and copy review going
forward. It enumerates mechanics this game does not use, with the reason for
each, so the answer to a "should we add X?" question is in writing rather
than relitigated.
Per CONTEXT D-07: this doctrine is enforced by **review**, not by lint rules
on UX strings. The reviewer (you, at every UX/monetization/copy decision)
consults this list and rejects or rewrites any change that violates it.
## Banned Mechanics
| Mechanic | Why Banned |
|----------|------------|
| Gacha mechanics | Directly contradicts the game's thematic argument that complex things cannot be reduced to simple transactions. (PROJECT.md, REQUIREMENTS.md Out of Scope, CLAUDE.md) |
| Lootboxes | Same reason as gacha — undermines the story's monetization-as-meaning argument. |
| Narrative gating behind purchase | The story IS the product; story content is never paid. |
| Random-drop monetization | All cosmetics must be deterministic catalog purchases. |
| Daily login bonuses | Presence is not a debt the game collects. |
| Login streaks | Skipping a day is allowed, even encouraged. |
| Limited-time / time-limited content | The game's premise is *what persists*. |
| Energy / stamina systems | Anti-cozy gating that interrupts contemplative play. |
| Rewarded ads | Anti-cozy; tonally incoherent with a contemplative grief-narrative. |
| Re-engagement push notifications | Memory Storm opt-in is the **only** allowed notification class. |
| Loss-aversion copy ("you'll lose your X") | Tonally incompatible with cozy/contemplative. |
| Visible countdown timers in core UI | The cello is the timer. The seasons are the timer. Not a digit. |
| "Don't miss out" / "limited time" / "only X hours left" copy | Bannable phrases at copy review. |
| Season *skipping* (vs. Season *acceleration*) | Players must never miss authored story beats; acceleration is allowed, skipping is forbidden. |
| Time-skip purchases that bypass real-time | Real-time IS the metaphor for memory; skip-time would violate mechanic-as-metaphor doctrine. |
| Hint system / objective tracker | Discovery-driven progression (A Dark Room rule); explicit objectives violate the tone. |
| Mobile-style nag UX | Cozy audience expects respect; nag patterns will tank reviews. |
## Allowed Engagement
The following engagement affordances are explicitly **allowed** because they respect
presence rather than demand it:
- **Memory Storm opt-in notifications** — the single allowed notification class.
Player must explicitly opt in. Never daily, never marketing, never streak-based.
- **"While you were away" letter on return** — written in Lura's voice, never a stat dump
(UX-02). Describes what bloomed, what the wind brought; never "fragments per hour."
- **Tab-title bloom indicator** when a fragment is ready (UX-09, Phase 8) — passive
surfacing, no notification.
- **Save-export reminder after Season transitions** — relationship-saving, not nag.
## Review Checklist
When reviewing any UX, copy, monetization, or feature change, ask three questions:
1. **Does this create urgency around presence rather than around content?** If yes → reject.
2. **Does this frame absence as loss?** If yes → rewrite or reject.
3. **Would removing this from the game make it less *cozy*?** If no → reconsider whether the change belongs.
Additional sanity checks for monetization specifically:
- Does this mechanic gate any story content? → reject (PROJECT.md hard constraint).
- Is this random-drop / gacha / lootbox shaped? → reject.
- Is this a "limited-time" anything? → reject.
## Source Documents
This doctrine consolidates constraints already locked in:
- **PROJECT.md** § "Out of Scope" — anti-features (gacha, lootboxes, narrative gating, Season skipping, generic flora, combat, multiplayer, voiced dialogue, named Keeper, generic cosmetics)
- **REQUIREMENTS.md** UX-13 + § "Out of Scope" table — 24 explicit exclusions
- **CLAUDE.md** § "Hard Thematic Constraints (Out of Scope by Design)" — 13 thematic exclusions, no FOMO push notifications, no daily login bonuses, no streaks, no limited-time, no energy/stamina
- **.planning/research/PITFALLS.md** § "Pitfall 9: FOMO/Nag Mechanics Violate Cozy Tone" — rationale + warning signs
---
*Authored: Phase 1 deliverable. Updates: append-only — entries can be added (new
banned patterns identified) but never removed without surfacing the change for review.*
```
Per CONTEXT D-07: do NOT add a lint rule for UX strings; do NOT add CI enforcement; the document is enforced by human review at the listed decision points.
The doctrine doc length is appropriate (~70 lines markdown including tables) — principle-level, not exhaustive prose.
Commit `docs(01-06): author anti-FOMO doctrine consolidating PROJECT/REQUIREMENTS/CLAUDE/PITFALLS constraints (PIPE-05, UX-13)`.
</action>
<verify>
<automated>test -f .planning/anti-fomo-doctrine.md &amp;&amp; grep -q "## Banned Mechanics" .planning/anti-fomo-doctrine.md &amp;&amp; grep -q "## Allowed Engagement" .planning/anti-fomo-doctrine.md &amp;&amp; grep -q "## Review Checklist" .planning/anti-fomo-doctrine.md &amp;&amp; grep -q "## Source Documents" .planning/anti-fomo-doctrine.md</automated>
</verify>
<acceptance_criteria>
- File exists at `.planning/anti-fomo-doctrine.md` (NOT `docs/`, per CONTEXT D-09) — verify with `test -f .planning/anti-fomo-doctrine.md && ! test -f docs/anti-fomo-doctrine.md`.
- Contains all 4 required H2 sections — verify with `grep -cE "^## (Banned Mechanics|Allowed Engagement|Review Checklist|Source Documents)" .planning/anti-fomo-doctrine.md` returns 4.
- The Banned Mechanics table contains at least 15 banned-pattern rows — verify with `awk '/^## Banned Mechanics/,/^## /{print}' .planning/anti-fomo-doctrine.md | grep -cE "^\\| (Gacha|Lootboxes|Narrative gating|Daily login|Login streaks|Limited-time|Energy|Rewarded ads|Re-engagement|Loss-aversion|Visible countdown|Season skipping|Time-skip|Hint system|Mobile-style)" | wc -l` returns at least 15. (Tolerate count-by-row variation; the test file in Task 2 will assert exact patterns.)
- The Source Documents section enumerates all 4 sources — verify with `grep -cE "(PROJECT\\.md|REQUIREMENTS\\.md|CLAUDE\\.md|PITFALLS\\.md)" .planning/anti-fomo-doctrine.md` returns at least 4.
- The Review Checklist section asks 3 questions — verify with `awk '/^## Review Checklist/,/^## /{print}' .planning/anti-fomo-doctrine.md | grep -cE "^[0-9]\\." | head -1` returns at least 3.
- No lint rule is mentioned (per CONTEXT D-07 explicit rejection) — verify with `! grep -qE "lint rule|eslint rule" .planning/anti-fomo-doctrine.md`.
</acceptance_criteria>
<done>
`.planning/anti-fomo-doctrine.md` authored as a principle-level consolidation of constraints from PROJECT/REQUIREMENTS/CLAUDE/PITFALLS; contains the 4 required H2 sections; enumerates ≥15 banned patterns + 3 review-checklist questions + 4 source documents; no lint-rule reference (per CONTEXT D-07); commit landed.
</done>
</task>
<task type="auto">
<name>Task 2: Author `.planning/season-7-end-state.md` (principle-level per CONTEXT D-08 + RESEARCH outline) + Vitest doc-lint test</name>
<files>
.planning/season-7-end-state.md,
scripts/doctrine.test.ts
</files>
<read_first>
- .planning/phases/01-foundations-and-doctrine/01-RESEARCH.md § "Doctrine doc outline — season-7-end-state.md" (the verbatim template, including the explicit "What this document is NOT" section)
- .planning/phases/01-foundations-and-doctrine/01-CONTEXT.md (D-08 — principle-level NOT treatment-level; answers (a) rest state, (b) Roothold ceiling, (c) tonal register; D-09 — lives in `.planning/`)
- .planning/PROJECT.md § "Core Value" — "what survives is what you understood"; § "Out of Scope" — Season skipping forbidden, no New Game+
- .planning/REQUIREMENTS.md SEAS-04 (finite ceiling), SEAS-09 (Season 7 long late-game), SEAS-10 (rest state, not infinite tiers), STRY-08 (binary choice + "The garden persists.")
- .planning/ROADMAP.md § "Phase 7: Season 7 (Return) & Final Choice" — the 4 success criteria
- .planning/research/PITFALLS.md § "Pitfall 1: The Story Ends but the Idle Loop Doesn't" — the rationale this doc directly addresses
</read_first>
<action>
**Step 1 — Write `.planning/season-7-end-state.md`** using the Write tool, following RESEARCH § "Doctrine doc outline — season-7-end-state.md" verbatim, with content adapted to The Last Garden specifically.
**The document must contain these EXACT H2 sections** (the doc-lint test will assert each):
1. `## What does *rest state* mean?`
2. `## What is the finite Roothold ceiling tied to?`
3. `## What tonal register does the coda live in?`
4. `## What this document is NOT`
5. `## Source Documents`
**Document content:**
```markdown
# Season 7 End-State Design (Principle-Level)
*Phase 1 deliverable per PIPE-05 + CONTEXT D-08. Principle-level only — treatment text is authored in Phase 7.*
This document answers the question that ends ROADMAP.md Phase 7's success criterion #4:
> *"the finite Roothold ceiling from Phase 4 has held the line, and the game has ended
> the way A Dark Room and Universal Paperclips ended."*
Per .planning/research/PITFALLS.md #1, "the story ends but the idle loop doesn't"
is the single most dangerous structural pitfall for this project. This document
is the canonical answer the project has *before* any economy code lands in Phase 2.
Per CONTEXT D-08: this is **principle-level**, not treatment-level. It defines the
contract Phase 7's authoring obeys, not the text of any final scene.
## What does *rest state* mean?
The rest state is the post-credits configuration the player can return to indefinitely
without grinding. Concretely:
- **No new fragments are added to the pool.** All authored content has been delivered.
Harvests after the final binary choice yield re-readable previously-collected
fragments — nothing new.
- **No new currency tiers unlock.** Roothold has reached its finite ceiling (see below)
and stays there. There is no "Season 8" hidden behind a number.
- **The garden continues to render and respond to clicks.** Plants can still be
planted. Seasons (now in Return register) continue to crossfade. The world is
not frozen — it is *finished*.
- **The Pale has receded.** The Heartsoil expands beyond the garden walls. Lura's
arc has resolved. The Archivist's question has been answered (in the player's
Season 7 binary choice — STRY-08).
- **The cello and ambient layers continue.** The audio is *quiet*, *finite*,
*understood* — never crescendos again, never hard-cuts.
This is not "endgame content." It is **rest**. Lineage: *A Dark Room* fades to its
ending screen and the player returns to it for the same reason they return to a
finished album — not because there is more, but because there was *enough*.
## What is the finite Roothold ceiling tied to?
Roothold's ceiling is anchored in the **count of authored fragments and the count
of Seasons** — not in an arbitrary number, not in a designer's intuition.
The principle:
> *One cannot accumulate more Roothold than the player has actually understood,
> and what the player can understand is bounded by what the writer has actually written.*
Concrete tie:
- Roothold gain per Season is gated to a hard cap proportional to the fragment
count of that Season + a small contribution from Roothold-relevant story beats
(Lura conversations, the Nameless Man's arc, the Archivist's question, etc.).
- Total Roothold ceiling = Σ(per-Season caps).
- **Phase 4 enforces this cap** when it implements `migrate_v1_to_v2` and the
prestige state machine (SEAS-04). Phase 7 verifies the ceiling holds through
full play.
- When Roothold reaches the ceiling, the UI displays "Roothold (full)" — never
a hidden multiplier or "go again to overflow."
Implication for designers: when adding fragments in Phase 5+, the Roothold ceiling
*moves* — adding 5 new Season-3 fragments adds proportional headroom. This is
intentional. Roothold is bounded by content; content is bounded by the writer.
## What tonal register does the coda live in?
- **Warm**, not pyrrhic. The garden persists *because* you tended it; this is
earned redemption, not survival. Lineage: the closing minutes of *Spiritfarer*,
not the closing minutes of *A Dark Room* (which earned its bitterness; we earn
our warmth).
- **Quiet**, not climactic. The cello does not crescendo at the binary choice.
It rests. The chosen ending paragraph displays softly; "The garden persists."
lands without underscore.
- **Specific**, not abstract. The final visible state is a *real* garden — the
one this player built, with their actual planted ecosystems, their actual
Roothold value, their actual collected fragments — viewed in soft dawn-silver
light per AEST-06's Season-7 palette anchor.
- **Final**, not infinite. There is no Season 8. There is no New Game+. The Pale
receded **here**, in **this** garden. Future patches may add cosmetic items or
additional fragments per CONT-01 (post-launch additive content), but they slot
*between* authored beats; they never extend the arc.
## What this document is NOT
This document defines principles. It does **not** define:
- The text of the Season 7 binary-choice scene — *authored Phase 7*.
- The text of either ending paragraph (`"They help us remember"` / `"They help us grow"`) — *authored Phase 7*.
- The exact line "The garden persists." appears in both endings, but its surrounding
paragraph and Lura's final line are *authored Phase 7*, not Phase 1.
- The credits / coda screen visual treatment — *designed Phase 7*.
- The exact tonal register or shape of individual final-Season fragments — *authored Phase 7*.
- The numeric value of the Roothold ceiling — *computed Phase 4* from the
content count at that point + ROADMAP-locked principle.
This document is **the principle the economy obeys, the writer obeys, and the
Phase 7 designer obeys** — not the implementation of any of those.
## Source Documents
This doctrine consolidates constraints already locked in:
- **PROJECT.md** § "Core Value" — "every idle mechanic must function as a metaphor"; "what survives is what you understood"
- **REQUIREMENTS.md** SEAS-04 (finite Roothold ceiling), SEAS-09 (Season 7 late-game shape), SEAS-10 (rest state, not infinite prestige tiers), STRY-08 (binary choice + "The garden persists.")
- **ROADMAP.md** § "Phase 7: Season 7 (Return) & Final Choice" — the 4 success criteria
- **.planning/research/PITFALLS.md** § "Pitfall 1: The Story Ends but the Idle Loop Doesn't" — the rationale this document directly addresses
---
*Authored: Phase 1 deliverable. Phase 4 enforces the Roothold ceiling. Phase 7 authors
the treatment-level final scenes against the principles above.*
```
Per CONTEXT D-08: this is principle-level only. Do NOT include the binary-choice scene text, either ending paragraph, Lura's final line, or the credits screen treatment — those are explicitly Phase 7's authoring scope.
**Step 2 — Write `scripts/doctrine.test.ts`** — the doc-lint Vitest test (per RESEARCH § Validation Architecture PIPE-05 row):
```typescript
import { describe, it, expect } from 'vitest';
import { readFileSync, existsSync } from 'node:fs';
describe('PIPE-05: doctrine documents exist with required H2 sections', () => {
describe('.planning/anti-fomo-doctrine.md', () => {
const PATH = '.planning/anti-fomo-doctrine.md';
it('exists', () => {
expect(existsSync(PATH)).toBe(true);
});
it('contains all 4 required H2 sections', () => {
const md = readFileSync(PATH, 'utf8');
expect(md).toMatch(/^## Banned Mechanics$/m);
expect(md).toMatch(/^## Allowed Engagement$/m);
expect(md).toMatch(/^## Review Checklist$/m);
expect(md).toMatch(/^## Source Documents$/m);
});
it('cites all 4 source documents (PROJECT, REQUIREMENTS, CLAUDE, PITFALLS)', () => {
const md = readFileSync(PATH, 'utf8');
expect(md).toMatch(/PROJECT\.md/);
expect(md).toMatch(/REQUIREMENTS\.md/);
expect(md).toMatch(/CLAUDE\.md/);
expect(md).toMatch(/PITFALLS\.md/);
});
it('does NOT propose a lint rule on UX strings (CONTEXT D-07 explicit rejection)', () => {
const md = readFileSync(PATH, 'utf8');
// The doc may *mention* that lint rules were rejected, but it must not
// propose adding one. Allow "no lint rule" but reject "add a lint rule".
expect(md).not.toMatch(/\b(add|implement|propose).{0,40}lint rule/i);
});
});
describe('.planning/season-7-end-state.md', () => {
const PATH = '.planning/season-7-end-state.md';
it('exists', () => {
expect(existsSync(PATH)).toBe(true);
});
it('contains all 5 required H2 sections (CONTEXT D-08)', () => {
const md = readFileSync(PATH, 'utf8');
expect(md).toMatch(/^## What does \*rest state\* mean\?$/m);
expect(md).toMatch(/^## What is the finite Roothold ceiling tied to\?$/m);
expect(md).toMatch(/^## What tonal register does the coda live in\?$/m);
expect(md).toMatch(/^## What this document is NOT$/m);
expect(md).toMatch(/^## Source Documents$/m);
});
it('cites SEAS-04, SEAS-09, SEAS-10, STRY-08', () => {
const md = readFileSync(PATH, 'utf8');
expect(md).toMatch(/SEAS-04/);
expect(md).toMatch(/SEAS-09/);
expect(md).toMatch(/SEAS-10/);
expect(md).toMatch(/STRY-08/);
});
it('does NOT include treatment-level details forbidden by CONTEXT D-08', () => {
const md = readFileSync(PATH, 'utf8');
// Check the "What this document is NOT" section is present — this is the
// structural guarantee against treatment-level scope creep.
expect(md).toMatch(/## What this document is NOT/);
// The doc must explicitly disclaim authoring the ending paragraphs.
expect(md).toMatch(/authored Phase 7/);
});
});
});
```
**Step 3 — Run `npx vitest run scripts/doctrine.test.ts`** and confirm all assertions pass (~10 assertions across 2 files).
**Step 4 — Run `npm test`** and confirm the entire Phase-1 suite (sentinel + lint-firewall + save layer + content loader + asset validator + doctrine) is green.
**Step 5 — Commit `docs(01-06): author Season 7 end-state principle doctrine + Vitest doc-lint test (PIPE-05)`.**
</action>
<verify>
<automated>npx vitest run scripts/doctrine.test.ts &amp;&amp; test -f .planning/season-7-end-state.md &amp;&amp; ! test -f docs/season-7-end-state.md</automated>
</verify>
<acceptance_criteria>
- File exists at `.planning/season-7-end-state.md` (NOT `docs/`, per CONTEXT D-09) — verify with `test -f .planning/season-7-end-state.md && ! test -f docs/season-7-end-state.md`.
- Contains all 5 required H2 sections — verify with `grep -cE "^## (What does \\*rest state\\* mean|What is the finite Roothold ceiling tied to|What tonal register does the coda live in|What this document is NOT|Source Documents)" .planning/season-7-end-state.md` returns 5.
- Cites SEAS-04, SEAS-09, SEAS-10, STRY-08 — verify with `grep -cE "(SEAS-04|SEAS-09|SEAS-10|STRY-08)" .planning/season-7-end-state.md` returns at least 4.
- Includes the "What this document is NOT" section to prevent treatment-level scope creep — verify with `grep -q "## What this document is NOT" .planning/season-7-end-state.md`.
- Does NOT include the binary-choice scene text — verify with `! grep -qE '"They help us remember"' .planning/season-7-end-state.md` (the QUOTED phrase is referenced as a citation but the scene text itself is not authored here; the test allows mention of the phrase as a reference but checks it does not appear inside a code block or as flowing prose intended to be the final-scene text).
**Note:** The doc DOES quote `"They help us remember"` and `"They help us grow"` as reference labels (in the "What this document is NOT" section, naming what is NOT being authored here). This is acceptable per CONTEXT D-08 — the rule is "do not author the *scene*", not "do not name the choice." Verify with `grep -E '"They help us remember"' .planning/season-7-end-state.md` returns at most one match (the disclaimer reference), and the matching line contains the words "Phase 7" or "authored":
```bash
grep -E '"They help us remember"' .planning/season-7-end-state.md | grep -qE "(Phase 7|authored)"
```
- `scripts/doctrine.test.ts` exists and passes — verify with `npx vitest run scripts/doctrine.test.ts 2>&1 | grep -E "passed"` exits 0.
- The doctrine test asserts existence + H2 sections + source citations for both docs — verify with `grep -cE "existsSync|toMatch.*##" scripts/doctrine.test.ts` returns at least 10.
</acceptance_criteria>
<done>
`.planning/season-7-end-state.md` authored at principle level with the 5 required H2 sections, Roothold-ceiling-tied-to-content principle, the explicit "What this document is NOT" boundary against treatment scope creep; `scripts/doctrine.test.ts` enforces structural integrity of both doctrine docs via Vitest; `npm test` green; commit landed.
</done>
</task>
</tasks>
<threat_model>
No security-relevant code in this plan; doctrine docs and a doc-lint test only. No runtime code; no untrusted inputs; no I/O beyond reading committed Markdown files at test time.
</threat_model>
<verification>
- Both doctrine docs exist under `.planning/` (per CONTEXT D-09).
- `scripts/doctrine.test.ts` passes — both docs have all required H2 sections and cite all required source documents.
- `npm test` green for the entire Phase-1 suite.
- Phase 7 has a principle contract to author against; Phase 4 has the Roothold-ceiling tie-to-content principle to implement against.
- No new design work was done — both docs are consolidations of existing PROJECT/REQUIREMENTS/CLAUDE/ROADMAP/PITFALLS constraints (per CONTEXT D-07 + D-08).
</verification>
<success_criteria>
- `.planning/anti-fomo-doctrine.md` consolidates banned-pattern enumeration with 4 required H2 sections (Banned Mechanics, Allowed Engagement, Review Checklist, Source Documents) and ≥15 banned patterns.
- `.planning/season-7-end-state.md` answers principle-level the 3 questions per CONTEXT D-08 + has the explicit "What this document is NOT" boundary section.
- `scripts/doctrine.test.ts` enforces structural integrity automatically (PIPE-05).
- No lint rule on UX strings (per CONTEXT D-07 explicit rejection).
- Both docs live under `.planning/`, not `docs/` (per CONTEXT D-09).
</success_criteria>
<output>
After completion, create `.planning/phases/01-foundations-and-doctrine/01-06-SUMMARY.md` documenting:
- Both docs' final paths and brief contents summary.
- Confirmation that the doc-lint test (`scripts/doctrine.test.ts`) passes.
- Note for Phase 4: the Roothold ceiling enforcement task should reference `.planning/season-7-end-state.md` § "What is the finite Roothold ceiling tied to?" for the principle.
- Note for Phase 7: the binary choice scene authoring should reference `.planning/season-7-end-state.md` § "What this document is NOT" for the boundary of what's authored when.
- Note for ongoing UX/monetization reviews: `.planning/anti-fomo-doctrine.md` is the canonical reference; consult before any UX change.
</output>