chore: untrack docs/ and add to .gitignore

This commit is contained in:
Ma 2026-03-30 02:16:04 +08:00
parent b23f5bf46c
commit 44b5e52e50
6 changed files with 1 additions and 1224 deletions

1
.gitignore vendored
View file

@ -17,3 +17,4 @@ docs/
novel-to-comic-research.docx
.pnpm-store/
tmp/
docs/

View file

@ -1,171 +0,0 @@
# v0.6.3 Hardening Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** Close the remaining 0.6.3 safety gaps around agent tool misuse, final-content paragraph checks, duplicate chapter titles, migration hints, and rewrite regression coverage.
**Architecture:** Keep the current v2 pipeline, but tighten the remaining soft spots at the edges. Add deterministic guards in the agent dispatch layer, run final-content validation at the last safe point before persist, surface migration status in user-facing CLI flows, and add targeted regressions for the exact user-visible failures.
**Tech Stack:** TypeScript, Vitest, Commander CLI
---
### Task 1: Guard the remaining agent path
**Files:**
- Modify: `packages/core/src/__tests__/pipeline-agent.test.ts`
- Modify: `packages/core/src/pipeline/agent.ts`
**Step 1: Write the failing tests**
Add tests that prove:
- `write_full_pipeline` is rejected when the chapter sequence is inconsistent
- `write_truth_file` cannot use `current_state.md` to mutate progress
**Step 2: Run test to verify it fails**
Run:
```bash
pnpm vitest run src/__tests__/pipeline-agent.test.ts
```
**Step 3: Write minimal implementation**
Reuse the same guard logic currently applied to `write_draft` and block `write_full_pipeline` before it calls `writeNextChapter()`.
**Step 4: Run test to verify it passes**
Run:
```bash
pnpm vitest run src/__tests__/pipeline-agent.test.ts
```
**Step 5: Commit**
```bash
git add packages/core/src/pipeline/agent.ts packages/core/src/__tests__/pipeline-agent.test.ts
git commit -m "fix: guard write_full_pipeline in agent dispatch"
```
### Task 2: Validate final persisted chapter shape
**Files:**
- Modify: `packages/core/src/__tests__/post-write-validator.test.ts`
- Modify: `packages/core/src/__tests__/pipeline-runner.test.ts`
- Modify: `packages/core/src/agents/post-write-validator.ts`
- Modify: `packages/core/src/pipeline/runner.ts`
**Step 1: Write the failing tests**
Add tests that prove:
- final persisted content can trigger `段落过碎` / `连续短段`
- duplicate titles are handled as a real final-stage action, not a passive warning
**Step 2: Run tests to verify they fail**
Run:
```bash
pnpm vitest run src/__tests__/post-write-validator.test.ts src/__tests__/pipeline-runner.test.ts
```
**Step 3: Write minimal implementation**
Export a reusable final paragraph-shape detector and run it on `finalContent` before persist. Upgrade duplicate-title handling from a passive warning to an explicit final-stage resolution path.
**Step 4: Run tests to verify they pass**
Run:
```bash
pnpm vitest run src/__tests__/post-write-validator.test.ts src/__tests__/pipeline-runner.test.ts
```
**Step 5: Commit**
```bash
git add packages/core/src/agents/post-write-validator.ts packages/core/src/pipeline/runner.ts packages/core/src/__tests__/post-write-validator.test.ts packages/core/src/__tests__/pipeline-runner.test.ts
git commit -m "fix: harden final content validation and title handling"
```
### Task 3: Surface migration status in user-facing CLI flows
**Files:**
- Modify: `packages/cli/src/__tests__/cli-integration.test.ts`
- Modify: `packages/cli/src/commands/status.ts`
- Modify: `packages/cli/src/commands/write.ts`
- Modify: `packages/cli/src/utils.ts`
**Step 1: Write the failing tests**
Add tests that prove:
- `inkos status` shows a migration hint for legacy books
- `inkos write next` warns before auto-migrating a legacy book
**Step 2: Run tests to verify they fail**
Run:
```bash
pnpm vitest run src/__tests__/cli-integration.test.ts
```
**Step 3: Write minimal implementation**
Add a shared CLI helper that detects legacy pre-v0.6 books and emits a clear hint in `status` and `write next`.
**Step 4: Run tests to verify they pass**
Run:
```bash
pnpm vitest run src/__tests__/cli-integration.test.ts
```
**Step 5: Commit**
```bash
git add packages/cli/src/utils.ts packages/cli/src/commands/status.ts packages/cli/src/commands/write.ts packages/cli/src/__tests__/cli-integration.test.ts
git commit -m "feat: show migration hints in status and write flows"
```
### Task 4: Verify rewrite from user path
**Files:**
- Modify: `packages/cli/src/__tests__/cli-integration.test.ts`
**Step 1: Write the failing test**
Add a CLI-level regression covering:
- create 3 chapters
- rewrite chapter 2
- assert next chapter number is 2 again
**Step 2: Run test to verify it fails**
Run:
```bash
pnpm vitest run src/__tests__/cli-integration.test.ts
```
**Step 3: Write minimal implementation**
Prefer no production change unless the new CLI regression exposes a real gap.
**Step 4: Run tests to verify it passes**
Run:
```bash
pnpm vitest run src/__tests__/cli-integration.test.ts
```
**Step 5: Commit**
```bash
git add packages/cli/src/__tests__/cli-integration.test.ts
git commit -m "test: cover rewrite flow from CLI path"
```

View file

@ -1,76 +0,0 @@
# Book Create Atomic Init Design
**Goal:** Eliminate half-initialized books by making `inkos book create` fail-closed: foundation generation must either produce a complete book or leave no book directory behind.
## Problem
Current `book create` is not atomic:
- `PipelineRunner.initBook()` writes `book.json` before foundation generation.
- `ArchitectAgent.parseSections()` silently substitutes placeholder text when a required section is missing.
- CLI treats an existing but incomplete directory as resumable state.
This creates dirty `books/<bookId>/` directories with partial files. Re-running create on the same title can then behave unpredictably.
## Design
### 1. Stage to a temporary book directory
`initBook()` should build the full book in a temporary directory under `books/`:
- write `book.json`
- generate foundation
- write foundation files
- initialize control docs
- create chapter index
- snapshot chapter 0
Only after all of that succeeds should the temp directory be renamed to the final `books/<bookId>/`.
If any step fails, the temp directory is deleted.
### 2. Treat missing Architect sections as hard failure
`ArchitectAgent.parseSections()` should no longer emit placeholder text like:
- `[book_rules 生成失败,需要重新生成]`
Missing required sections should throw an error immediately. This prevents malformed foundations from being persisted as if they were valid content.
### 3. Remove resumable incomplete-init semantics
CLI should no longer “resume incomplete book creation”.
If `books/<bookId>/` exists:
- if it looks complete, `book create` should fail with “already exists”
- if it looks incomplete, it should be treated as stale partial state and removed before a fresh atomic create starts
This keeps the behavior simple:
- success => complete book exists
- failure => no book directory remains
## Scope
In scope:
- `book create`
- `PipelineRunner.initBook()`
- Architect foundation parsing
- stale incomplete directory cleanup
- regression tests
Out of scope:
- `initFanficBook()` atomic staging
- state-validator robustness
- interactive-fiction work
## Validation
Add regressions for:
1. `ArchitectAgent` throws when a required section is missing.
2. `PipelineRunner.initBook()` leaves no final book directory when foundation generation fails.
3. CLI `book create` removes stale incomplete directories and does not keep a dirty directory when create fails downstream.

View file

@ -1,116 +0,0 @@
# Book Create Atomic Init Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** Make `book create` atomic so malformed Architect output or failed initialization never leaves a half-built book directory behind.
**Architecture:** Stage new books in a temporary directory, require Architect to return all mandatory sections, and delete stale incomplete directories instead of resuming them. Promote the staged directory into place only after all initialization steps succeed.
**Tech Stack:** TypeScript, Vitest, Commander CLI, Node `fs/promises`
---
### Task 1: Lock down Architect missing-section failure
**Files:**
- Modify: `packages/core/src/__tests__/architect.test.ts`
- Modify: `packages/core/src/agents/architect.ts`
**Step 1: Write the failing test**
Add a test showing `generateFoundation()` rejects when `book_rules` is missing from the LLM response.
**Step 2: Run test to verify it fails**
Run: `pnpm vitest run src/__tests__/architect.test.ts -t "throws when a required foundation section is missing"`
**Step 3: Write minimal implementation**
Change `parseSections()` to throw on missing required sections instead of returning placeholder content.
**Step 4: Run test to verify it passes**
Run the same Vitest command and confirm it passes.
### Task 2: Lock down atomic init rollback
**Files:**
- Modify: `packages/core/src/__tests__/pipeline-runner.test.ts`
- Modify: `packages/core/src/state/manager.ts`
- Modify: `packages/core/src/pipeline/runner.ts`
**Step 1: Write the failing test**
Add a regression showing `initBook()` leaves no final `books/<bookId>/` when foundation generation fails.
**Step 2: Run test to verify it fails**
Run: `pnpm vitest run src/__tests__/pipeline-runner.test.ts -t "cleans staged files when initBook fails before foundation is complete"`
**Step 3: Write minimal implementation**
Implement staged initialization in a temporary directory, then rename into place only after success. Add helper methods in `StateManager` as needed for path-based control-doc/index/snapshot writes.
**Step 4: Run test to verify it passes**
Run the same Vitest command and confirm it passes.
### Task 3: Lock down stale incomplete-directory cleanup at CLI level
**Files:**
- Modify: `packages/cli/src/__tests__/cli-integration.test.ts`
- Modify: `packages/cli/src/commands/book.ts`
**Step 1: Write the failing test**
Add a CLI regression where a stale incomplete `books/<bookId>/` exists before `book create`, and verify the command does not preserve that stale directory when create later fails.
**Step 2: Run test to verify it fails**
Run: `pnpm vitest run src/__tests__/cli-integration.test.ts -t "removes stale incomplete book directories before retrying create"`
**Step 3: Write minimal implementation**
Replace “resume incomplete book creation” behavior with stale-directory cleanup plus fresh atomic create.
**Step 4: Run test to verify it passes**
Run the same Vitest command and confirm it passes.
### Task 4: Run focused verification
**Files:**
- No production changes expected
**Step 1: Run targeted suite**
Run:
```bash
pnpm vitest run src/__tests__/architect.test.ts src/__tests__/pipeline-runner.test.ts
```
in `packages/core`, and:
```bash
pnpm vitest run src/__tests__/cli-integration.test.ts
```
in `packages/cli`.
**Step 2: Run typecheck**
Run:
```bash
pnpm typecheck
```
in `packages/core` and `packages/cli`.
**Step 3: Commit**
```bash
git add docs/plans/2026-03-29-book-create-atomic-init-design.md docs/plans/2026-03-29-book-create-atomic-init-implementation-plan.md packages/core/src/agents/architect.ts packages/core/src/pipeline/runner.ts packages/core/src/state/manager.ts packages/core/src/__tests__/architect.test.ts packages/core/src/__tests__/pipeline-runner.test.ts packages/cli/src/commands/book.ts packages/cli/src/__tests__/cli-integration.test.ts
git commit -m "fix: make book creation fail closed"
```

View file

@ -1,356 +0,0 @@
# Interactive Fiction V1 Design
**Goal:** Add a first-class interactive-fiction mode to InkOS by introducing chapter-end branching while preserving the existing chapter-based writing, audit, revise, truth-file, and runtime-state pipeline.
## Summary
Interactive fiction v1 should not replace InkOS's chapter-writing core. It should add a branch system around that core.
The recommended v1 shape is:
- chapters remain the unit of generation
- each completed chapter can produce 2-4 grounded reader choices
- each choice creates a persistent branch node
- only the selected branch continues generating new chapters
- unselected branches remain dormant but recoverable later
This gives InkOS real branching narrative structure without forcing a rewrite into a node-by-node text-adventure engine.
## Why This Shape
### Do not rewrite the chapter engine first
InkOS already has valuable infrastructure:
- chapter writing
- revise / audit
- truth-file rebuild
- runtime state
- snapshots / rewrite / rollback
- export / review / eval
If v1 changes the smallest unit from "chapter" to "scene node", all of those systems become unstable at once.
So the right heavy refactor is:
- rebuild branching
- rebuild branch state management
- keep the chapter-writing engine intact
### Why not free-form player input first
Free-form actions look attractive, but they explode ambiguity:
- action parsing
- branch normalization
- invalid-action handling
- state mutation safety
- prompt drift
Reader-choice branching gives InkOS a constrained interaction surface first. Later, free-form player input can be added as a higher-risk edge type on top of the same branch tree.
## Narrative Mode
Add a new book-level mode in `book.json`:
- `narrativeMode: "linear" | "interactive-tree"`
Default remains `linear`.
Interactive branching behavior only activates when `narrativeMode === "interactive-tree"`.
## Core Model
### 1. Branch Tree
Create a new persistent artifact:
- `story/interactive/branch-tree.json`
This is the source of truth for interactive structure.
It contains:
- book-level metadata
- active branch pointer
- branch nodes
- branch edges / choices
### 2. Branch Nodes
A branch node represents a recoverable narrative state, not necessarily a fully written branch.
Recommended fields:
- `nodeId`
- `parentNodeId`
- `sourceChapterId`
- `sourceChapterNumber`
- `branchDepth`
- `branchLabel`
- `status: active | awaiting-choice | dormant | completed`
- `snapshotRef`
- `selectedChoiceId`
- `chapterIds: string[]`
- `displayPath`
Important meaning:
- a node is the point from which writing can continue
- multiple child nodes may initially share the same chapter-end snapshot
- only the active node is projected into live truth files
### 3. Branch Choices
Choices are explicit edges between nodes.
Recommended fields:
- `choiceId`
- `fromNodeId`
- `toNodeId`
- `label`
- `intent`
- `immediateGoal`
- `expectedCost`
- `expectedRisk`
- `hookPressure`
- `characterPressure`
- `tone`
- `selected: boolean`
Choices are not cosmetic strings. They are structured next-chapter directions.
## Chapter Identity
### Internal IDs
Use globally unique internal chapter IDs for storage.
Do not try to make each branch own an independent global chapter-number namespace.
Recommended split:
- internal: globally unique chapter id / monotonic storage number
- display: branch-local sequence index for UX
Why:
- preserves existing storage, export, review, and audit assumptions
- avoids collisions across branches
- lets linear tools keep working with minimal change
## Snapshot Strategy
Reuse the existing snapshot system.
After chapter `N` finishes:
- current state is snapshotted exactly once
- all generated child branch nodes reference that same snapshot
- no child branch pre-generates chapter `N+1`
So for a chapter with choices A/B/C:
- chapter 12 ends
- snapshot 12 exists
- child nodes A/B/C all point to snapshot 12
- user selects B
- only then does branch B generate its next chapter
This keeps branching persistent without duplicating a full book state tree at choice generation time.
## Choice Generation
Choice generation should be its own step, not something the writer casually appends.
### ChoiceGenerator
Inputs:
- current chapter content
- active branch runtime state
- current focus
- planner/composer intent
- active hooks / dormant pressure
- character pressure
Outputs:
- 2-4 structured choices
### ChoiceAuditor
Audits choice quality:
- choices must be meaningfully different
- no obviously fake branch set
- no nonsense or "bad joke" option
- choices must be grounded in chapter-end state
### Recommended choice policy
Prefer:
- 1 lower-risk / stabilizing option
- 1 higher-risk / high-payoff option
- 1 relationship / emotional option
- optional 4th only if naturally justified
This avoids both "three paraphrases of the same branch" and gimmicky fake interactivity.
## Truth Files And Runtime State
The live truth files for an interactive book represent the active branch only.
That means files like:
- `current_state.md`
- `pending_hooks.md`
- `chapter_summaries.md`
are branch-local projections, not universal whole-book truth.
Persistent cross-branch truth is stored in:
- `branch-tree.json`
- snapshots
- chapter lineage attached to branch nodes
### Branch switch behavior
Switching branch should perform:
1. restore the referenced snapshot
2. restore branch-local projected state
3. update active branch pointer
4. continue writing from that branch
The branch tree is canonical. The live markdown truth files are the active projection.
## CLI Flow
Keep `write next`, but add branch control commands.
Recommended commands:
- `inkos branch choices`
- `inkos branch choose <choice-id>`
- `inkos branch tree`
- `inkos branch switch <node-id>`
### Main loop
1. `write next`
2. chapter completes
3. choice generation runs
4. current node becomes `awaiting-choice`
5. user inspects choices
6. user chooses one
7. selected child node becomes active
8. next `write next` continues that branch
### Important gating rule
If the active node is `awaiting-choice`, `write next` must refuse to continue until a branch is selected.
This prevents accidental silent continuation down an undefined path.
## Compatibility Rules
### Linear books
Linear books should behave exactly as today.
### Interactive books
Interactive books reuse:
- writer
- reviser
- continuity auditor
- state validator
- snapshots
- rewrite
But commands operate on the active branch by default.
Later versions can add `--branch`, but v1 should keep default behavior simple.
## Export And Review
Do not solve full branch-aware export in v1.
V1 export and review policy should be:
- default export = active branch only
- default review = active branch only
- tree visualization = separate command / future enhancement
This keeps v1 bounded.
## Error Handling
### Branch tree missing or corrupt
- interactive commands fail closed
- linear commands remain unaffected
### Snapshot missing for target node
- branch switch fails
- active branch remains unchanged
### Choice generation fails
Recommended v1 behavior:
- chapter is still saved
- node is marked `awaiting-choice-generation`
- user can retry choice generation explicitly
Do not lose the chapter because choice generation failed.
### Invalid choose
- reject with a clear error
- do not mutate branch state
## Non-Goals For V1
Out of scope:
- free-form player action parsing
- scene/node-level engine
- branch-aware EPUB for all paths
- auto-generating all child branches in parallel
- full interactive UI
- branch-local manga export
These belong to v2+.
## Testing Strategy
Minimum required regressions:
1. interactive book writes one chapter and persists choice nodes
2. unselected choices persist as dormant branch nodes with shared snapshot refs
3. `write next` refuses when active node awaits choice
4. `branch choose` activates the selected child branch
5. `branch switch` restores the correct snapshot
6. linear books remain unaffected
## Recommendation
Build interactive fiction v1 as a chapter-tree system:
- branch-heavy
- stateful
- recoverable
- chapter-based
Do not build a free-form adventure engine first.
Do not rebuild InkOS around scene nodes in v1.
The right first step is a formal branch tree wrapped around the existing chapter pipeline.

View file

@ -1,505 +0,0 @@
# Interactive Fiction V1 Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** Add an `interactive-tree` narrative mode where chapter-end reader choices create persistent branch nodes, while keeping InkOS's chapter-writing pipeline intact.
**Architecture:** Reuse the existing chapter generation pipeline and snapshots. Add a branch-tree persistence layer, branch-aware state activation, chapter-end choice generation, and CLI branch commands. Keep live truth files as the active-branch projection only.
**Tech Stack:** TypeScript, Commander CLI, Vitest, existing InkOS pipeline/state/snapshot system
---
### Task 1: Add the narrative mode model
**Files:**
- Modify: `packages/core/src/models/book.ts`
- Test: `packages/core/src/__tests__/fanfic-models.test.ts` or a new book-model test
**Step 1: Write the failing test**
Add a test that parses:
- `narrativeMode: "linear"`
- `narrativeMode: "interactive-tree"`
and rejects unknown values.
**Step 2: Run test to verify it fails**
Run: `pnpm vitest run src/__tests__/...`
Expected: FAIL because `interactive-tree` is not yet allowed.
**Step 3: Write minimal implementation**
Add:
- `NarrativeModeSchema`
- `narrativeMode` on `BookConfigSchema`
- default to `linear`
**Step 4: Run test to verify it passes**
Run the targeted Vitest file again.
**Step 5: Commit**
```bash
git add packages/core/src/models/book.ts packages/core/src/__tests__/...
git commit -m "feat: add interactive narrative mode"
```
### Task 2: Define branch-tree persistence schema
**Files:**
- Create: `packages/core/src/models/interactive-fiction.ts`
- Test: `packages/core/src/__tests__/interactive-fiction-models.test.ts`
**Step 1: Write the failing test**
Add schema tests for:
- branch tree metadata
- branch nodes
- branch choices
- `activeNodeId`
- shared `snapshotRef`
**Step 2: Run test to verify it fails**
Run the new test file.
Expected: FAIL because schema file does not exist.
**Step 3: Write minimal implementation**
Create schema/types for:
- tree metadata
- node status
- choice record
- branch node
- branch tree
**Step 4: Run test to verify it passes**
Run the targeted schema test.
**Step 5: Commit**
```bash
git add packages/core/src/models/interactive-fiction.ts packages/core/src/__tests__/interactive-fiction-models.test.ts
git commit -m "feat: define branch tree schemas"
```
### Task 3: Add state-manager helpers for interactive storage
**Files:**
- Modify: `packages/core/src/state/manager.ts`
- Test: `packages/core/src/__tests__/state-manager.test.ts`
**Step 1: Write the failing test**
Add tests for helpers that:
- load/save `story/interactive/branch-tree.json`
- initialize an empty root branch
- return the active node
**Step 2: Run test to verify it fails**
Run the targeted tests.
Expected: FAIL because helper methods do not exist.
**Step 3: Write minimal implementation**
Add helpers such as:
- `interactiveDir(bookId)`
- `loadBranchTree(bookId)`
- `saveBranchTree(bookId, tree)`
- `ensureInteractiveTree(bookId)`
**Step 4: Run test to verify it passes**
Run the targeted state-manager tests.
**Step 5: Commit**
```bash
git add packages/core/src/state/manager.ts packages/core/src/__tests__/state-manager.test.ts
git commit -m "feat: add interactive branch tree persistence helpers"
```
### Task 4: Initialize interactive books correctly at create time
**Files:**
- Modify: `packages/core/src/pipeline/runner.ts`
- Modify: `packages/cli/src/commands/book.ts`
- Test: `packages/core/src/__tests__/pipeline-runner.test.ts`
- Test: `packages/cli/src/__tests__/cli-integration.test.ts`
**Step 1: Write the failing test**
Add tests that:
- create an interactive book
- verify `branch-tree.json` exists
- verify the tree contains a root node and active pointer
**Step 2: Run test to verify it fails**
Run the targeted test files.
Expected: FAIL because create flow does not initialize interactive metadata.
**Step 3: Write minimal implementation**
When `narrativeMode === "interactive-tree"`:
- create interactive storage during book initialization
- seed a root branch node
**Step 4: Run test to verify it passes**
Run the targeted tests again.
**Step 5: Commit**
```bash
git add packages/core/src/pipeline/runner.ts packages/cli/src/commands/book.ts packages/core/src/__tests__/pipeline-runner.test.ts packages/cli/src/__tests__/cli-integration.test.ts
git commit -m "feat: initialize interactive books with root branch tree"
```
### Task 5: Add chapter-end choice generation models and parser
**Files:**
- Create: `packages/core/src/agents/choice-generator.ts`
- Create: `packages/core/src/agents/choice-auditor.ts`
- Test: `packages/core/src/__tests__/choice-generator.test.ts`
- Test: `packages/core/src/__tests__/choice-auditor.test.ts`
**Step 1: Write the failing test**
Add tests that require generated choices to include:
- `label`
- `intent`
- `immediateGoal`
- `expectedCost`
- `expectedRisk`
- `hookPressure`
- `characterPressure`
- `tone`
Also add a failure case for near-duplicate choices.
**Step 2: Run test to verify it fails**
Run both targeted test files.
Expected: FAIL because these agents do not exist.
**Step 3: Write minimal implementation**
Implement:
- choice generation prompt/output parsing
- choice auditing for duplicate/fake branches
**Step 4: Run test to verify it passes**
Run targeted tests again.
**Step 5: Commit**
```bash
git add packages/core/src/agents/choice-generator.ts packages/core/src/agents/choice-auditor.ts packages/core/src/__tests__/choice-generator.test.ts packages/core/src/__tests__/choice-auditor.test.ts
git commit -m "feat: add interactive choice generation agents"
```
### Task 6: Persist branch children after chapter completion
**Files:**
- Modify: `packages/core/src/pipeline/runner.ts`
- Modify: `packages/core/src/state/manager.ts`
- Test: `packages/core/src/__tests__/pipeline-runner.test.ts`
**Step 1: Write the failing test**
Add a test for interactive mode where:
- `writeNextChapter()` saves chapter 1
- generates 2-4 choices
- creates child nodes
- all child nodes reference the same `snapshotRef`
- active node becomes `awaiting-choice`
**Step 2: Run test to verify it fails**
Run the targeted runner test.
Expected: FAIL because chapters do not yet emit branch nodes.
**Step 3: Write minimal implementation**
In interactive mode, after successful chapter persistence:
- run choice generation
- run choice audit
- create child nodes and choices
- store them in the branch tree
- leave only one active pointer
**Step 4: Run test to verify it passes**
Run the targeted runner test.
**Step 5: Commit**
```bash
git add packages/core/src/pipeline/runner.ts packages/core/src/state/manager.ts packages/core/src/__tests__/pipeline-runner.test.ts
git commit -m "feat: persist branch choices after interactive chapters"
```
### Task 7: Block write-next when a choice is pending
**Files:**
- Modify: `packages/core/src/pipeline/runner.ts`
- Modify: `packages/core/src/pipeline/agent.ts`
- Test: `packages/core/src/__tests__/pipeline-runner.test.ts`
- Test: `packages/core/src/__tests__/pipeline-agent.test.ts`
**Step 1: Write the failing test**
Add tests that:
- refuse `writeNextChapter()` on interactive books when active node is `awaiting-choice`
- refuse agent `write_draft` / `write_full_pipeline` in the same state
**Step 2: Run test to verify it fails**
Run the targeted tests.
Expected: FAIL because write flow still continues linearly.
**Step 3: Write minimal implementation**
Add fail-closed guards before chapter generation starts.
**Step 4: Run test to verify it passes**
Run targeted tests again.
**Step 5: Commit**
```bash
git add packages/core/src/pipeline/runner.ts packages/core/src/pipeline/agent.ts packages/core/src/__tests__/pipeline-runner.test.ts packages/core/src/__tests__/pipeline-agent.test.ts
git commit -m "fix: require branch choice before continuing interactive writing"
```
### Task 8: Add CLI branch commands
**Files:**
- Create: `packages/cli/src/commands/branch.ts`
- Modify: `packages/cli/src/index.ts`
- Test: `packages/cli/src/__tests__/cli-integration.test.ts`
**Step 1: Write the failing test**
Add CLI integration tests for:
- `inkos branch tree`
- `inkos branch choices`
- `inkos branch choose <choice-id>`
- `inkos branch switch <node-id>`
**Step 2: Run test to verify it fails**
Run the targeted CLI test(s).
Expected: FAIL because `branch` command does not exist.
**Step 3: Write minimal implementation**
Add a new CLI command group that:
- lists current branch tree
- shows pending choices
- selects a choice
- switches active node
**Step 4: Run test to verify it passes**
Run targeted CLI tests again.
**Step 5: Commit**
```bash
git add packages/cli/src/commands/branch.ts packages/cli/src/index.ts packages/cli/src/__tests__/cli-integration.test.ts
git commit -m "feat: add interactive branch CLI commands"
```
### Task 9: Restore the correct snapshot on branch switch
**Files:**
- Modify: `packages/core/src/state/manager.ts`
- Modify: `packages/core/src/pipeline/runner.ts`
- Test: `packages/core/src/__tests__/state-manager.test.ts`
- Test: `packages/core/src/__tests__/pipeline-runner.test.ts`
**Step 1: Write the failing test**
Add tests that switching to another branch:
- restores the referenced snapshot
- reprojects active branch truth files
- leaves other branch nodes unchanged
**Step 2: Run test to verify it fails**
Run the targeted tests.
Expected: FAIL because switch only updates metadata or is not implemented.
**Step 3: Write minimal implementation**
Implement branch activation as:
- restore snapshot
- mark branch active
- persist active branch pointer
**Step 4: Run test to verify it passes**
Run targeted tests again.
**Step 5: Commit**
```bash
git add packages/core/src/state/manager.ts packages/core/src/pipeline/runner.ts packages/core/src/__tests__/state-manager.test.ts packages/core/src/__tests__/pipeline-runner.test.ts
git commit -m "feat: restore snapshots when switching interactive branches"
```
### Task 10: Keep linear-mode behavior unchanged
**Files:**
- Modify: `packages/core/src/__tests__/pipeline-runner.test.ts`
- Modify: `packages/cli/src/__tests__/cli-integration.test.ts`
**Step 1: Write the failing test**
Add regressions proving:
- linear books still write chapters exactly as before
- no branch metadata is required for linear books
- branch commands reject linear books cleanly
**Step 2: Run test to verify it fails**
Run the targeted tests.
Expected: FAIL because interactive checks leak into linear mode or commands are too permissive.
**Step 3: Write minimal implementation**
Tighten mode checks so interactive behavior is gated strictly by `narrativeMode`.
**Step 4: Run test to verify it passes**
Run targeted tests again.
**Step 5: Commit**
```bash
git add packages/core/src/__tests__/pipeline-runner.test.ts packages/cli/src/__tests__/cli-integration.test.ts
git commit -m "test: lock linear compatibility for interactive mode"
```
### Task 11: Add minimal docs for user flow
**Files:**
- Modify: `README.md`
- Modify: `README.en.md`
- Modify: `skills/SKILL.md`
**Step 1: Write the failing test**
No automated doc test required. Instead, write a short checklist of required user-facing docs:
- create interactive book
- write chapter
- inspect choices
- choose branch
- switch branch
**Step 2: Run manual verification**
Check README/skill docs are missing or outdated.
Expected: missing interactive instructions.
**Step 3: Write minimal implementation**
Document:
- what interactive-tree mode is
- the branch CLI flow
- what remains out of scope in v1
**Step 4: Run manual verification**
Read both READMEs and `skills/SKILL.md` to verify the flow is discoverable.
**Step 5: Commit**
```bash
git add README.md README.en.md skills/SKILL.md
git commit -m "docs: add interactive fiction branch workflow"
```
### Task 12: End-to-end acceptance and release note prep
**Files:**
- Modify: `packages/core/src/__tests__/pipeline-runner.test.ts`
- Modify: `packages/cli/src/__tests__/cli-integration.test.ts`
- Optional: `docs/plans/...` if acceptance notes are appended
**Step 1: Write the failing test**
Add one narrow end-to-end acceptance test that:
- creates an interactive book
- writes chapter 1
- persists branch choices
- chooses a branch
- writes chapter 2 on that branch
**Step 2: Run test to verify it fails**
Run the targeted acceptance tests.
Expected: FAIL until all pieces are wired together.
**Step 3: Write minimal implementation**
Fill any missing wiring only if acceptance still fails.
**Step 4: Run test to verify it passes**
Run:
- targeted acceptance tests
- focused branch CLI tests
- focused runner tests
- `pnpm typecheck` in `packages/core`
- `pnpm typecheck` in `packages/cli`
**Step 5: Commit**
```bash
git add packages/core/src/__tests__/pipeline-runner.test.ts packages/cli/src/__tests__/cli-integration.test.ts
git commit -m "test: cover interactive fiction v1 end-to-end flow"
```