document the writing pipeline and record Phase 2

CLAUDE.md gains the writing/ layout, the voice-sheet pipeline and its direction
of truth, the sync commands, and a pointer that Ground Truth must never be
copied into this repo. The writer-owned/code-owned table now covers writing/.

The restructure plan records Phase 2 as executed, and closes its first open
question: the writing handbook does exist, in the Obsidian vault, so STYLE.md
became a digest with pointers rather than the reconstruction the plan assumed.

Also noted there: the vault's opening-scene spec records SC-101's tone check as
BLOCKED on a one-page Voice Sheet that was never written. STYLE.md now holds
that sheet with four fields explicitly unset.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-08-25 20:23:42 +02:00
co-authored by Claude Opus 5
parent f1fadf7909
commit ed28763017
2 changed files with 103 additions and 24 deletions
+64 -7
View File
@@ -17,7 +17,9 @@ to fix — it is the checkout path). The Unity project is a **subdirectory**:
/Users/lennart/Dev/nightlcub-arcadia/ # git root
├── CLAUDE.md, AGENTS.md # this reference
├── docs/ # design + plan docs (markdown)
├── writing/ # writer-facing context — see §4
├── tools/YarnCheck/ # .NET 9 Yarn compiler/player, no Unity needed
├── tools/writing/ # voice-sheet sync (md <-> skill_bible.json)
├── .gitignore # macOS / IDE / toolchain rules
└── NightclubArcadia/ # ← the Unity project (-projectPath)
├── .gitignore # Unity rules (anchored, must stay here)
@@ -49,7 +51,7 @@ AI Navigation 2.0.14, ProBuilder 6.1.2, Test Framework 1.7.0. Yarn Spinner is an
mode while the Editor has it open — a single instance at a time. Always check before
any `-batchmode` invocation (§3.1).
4. **Prefer YarnCheck over Unity for dialogue validation.** It is seconds, not minutes,
and needs no Editor lock (§5.3).
and needs no Editor lock (§5.4).
5. **Do not commit on the user's behalf** unless asked. Unity writes to tracked files
(`ProjectSettings/*`, `.meta`, scenes) as a side effect of simply being open, so
`git status` noise is expected and is not always yours.
@@ -174,6 +176,25 @@ NightclubArcadia/Assets/Dialogue/
└── Objects/ Chair
```
The writer-facing context sits at the repo root, outside `Assets/` so it gets no `.meta` files:
```
writing/
├── README.md session entry point
├── STYLE.md register, tone moves, ban list, branching rules ← read first
├── YARN-PRIMER.md the one page of syntax a writer needs
├── GLOSSARY.md in-world and project vocabulary
├── voices/ the eleven skill voices, one sheet each (generated — see §4.7)
├── characters/ named NPCs, dialogue-facing
├── scenes/ per-scene briefs: intent, beats, checks, constraints
└── lore/ candidates.md — the three identity readings and their hard rules
```
Design material deeper than this lives in Obsidian, not the repo:
`~/Obsidian-Vaults/obsidian-vault/Projects/Active/NightclubArcadia/`. **`Ground Truth.md` there
is the solution document — never copy, quote, or summarise it into this repo**, including into
commit messages. The game's premise is that the protagonist's identity never resolves.
**Dialogue is already plain text in the repo.** It is authored in `.yarn` files, not inside
the Unity Editor, and any new `.yarn` file dropped anywhere under `Assets/Dialogue/` is picked
up automatically by the `**/*.yarn` glob in the `.yarnproject`. Adding a scene or a character
@@ -249,13 +270,41 @@ candidates.json → Tools ▸ Nightclub Arcadia ▸ (CandidateSystemSetup)
Those setup scripts also register a `[DidReloadScripts]` callback, so in practice the assets
regenerate on script reload too. The JSON is the source of truth either way.
### 4.6 Code-owned vs writer-owned
### 4.6 The voice-sheet pipeline
The Skill Bible prose used to live as a `\n`-escaped string inside `skill_bible.json`, which no
writer could comfortably read or revise. It now lives in `writing/voices/*.md`, and truth flows
in opposite directions for the two halves of each sheet:
```
PROSE writing/voices/<id>.md -> skill_bible.json -> Skills/Definitions/*.asset
MACHINE skill_bible.json -> the "Machine fields" table in the .md
```
```bash
python3 tools/writing/sync_voices.py --check # verify; exit 1 on drift
python3 tools/writing/sync_voices.py --to-json # fold edited prose into the bible
python3 tools/writing/sync_voices.py --to-md # refresh the machine table from the bible
```
`tools/writing/voicelib.py` does the parsing and guarantees `notes -> dict -> notes` is identity
for all eleven skills. `--to-json` on unchanged sheets is byte-identical, so it is safe to run
at any time.
`VoiceSheetSyncTests` (EditMode) enforces the same invariant, so drift fails the build instead
of silently shipping a voice that no longer matches the sheet the next scene is written against.
It deliberately does not reimplement the markdown parser in C# — it asserts the shipped prose
appears verbatim in the sheet, which catches drift in either direction with no second parser to
keep in step.
### 4.7 Code-owned vs writer-owned
| Writer-owned (edit freely, no Unity) | Code-owned (needs an engineer) |
|---|---|
| `Assets/Dialogue/**/*.yarn` | `Assets/Scripts/**/*.cs` |
| `<<declare>>` lines in `Common.yarn` | `Assets/Editor/**/*.cs` |
| `Assets/Skills/skill_bible.json` (prose fields) | Yarn command/function *implementations* |
| `writing/**` | `Assets/Scripts/**/*.cs` |
| `Assets/Dialogue/**/*.yarn` | `Assets/Editor/**/*.cs` |
| `<<declare>>` lines in `Common.yarn` | Yarn command/function *implementations* |
| `writing/voices/*.md` (prose → the bible, §4.6) | `Assets/Skills/skill_bible.json` (machine fields) |
| `Assets/Candidates/candidates.json` (`status`, `sceneId`, `notes`, `unlockFlag`) | `.asset`, `.prefab`, `.unity`, `.meta` |
| `docs/` writing docs | `ProjectSettings/**` |
@@ -278,11 +327,19 @@ or a branch.** If a writing task requires either, that is a pipeline bug — fil
`$self_lean_*` / `$found_*` in any `.yarn` file resolves to a real id in `CandidateDatabase`.
It is a tripwire, not a proof.
### 5.2 One-click in-Editor run
### 5.2 Voice-sheet sync
```bash
python3 tools/writing/sync_voices.py --check
```
Seconds, no Unity. Run it after touching `writing/voices/*.md` or `skill_bible.json` (§4.6).
### 5.3 One-click in-Editor run
`Tools ▸ Nightclub Arcadia ▸ Run Skill EditMode Tests` (`Assets/Editor/SkillSystemTestRunner.cs`).
### 5.3 YarnCheck — validate dialogue without Unity ⭐
### 5.4 YarnCheck — validate dialogue without Unity ⭐
`tools/YarnCheck` is a .NET 9 console app that compiles **and plays** the Yarn scripts using
the exact Yarn Spinner DLLs shipped in `Packages/dev.yarnspinner.unity/Runtime/DLLs`, so it
+39 -17
View File
@@ -10,7 +10,7 @@ Companion reading: `docs/skill-system-refactor-plan.md`, `docs/candidate-system-
---
## 0. Status — Phase 0 is complete
## 0. Status — Phases 0 and 2 are complete
Executed 2026-08-25. The working tree is clean and tagged `pre-restructure`.
@@ -19,7 +19,7 @@ the UI layer, player control setup, the dialogue-vs-menu interaction fix, and th
A full pre-flight backup was taken first (`.tar.gz` of the tree excluding `Library/`, `Temp/`,
`Logs/`, and build output) plus a separate copy of the scene file.
Everything below from §1 onward is unchanged proposal. Nothing in §2–§5 has been applied.
Phase 2 (the writing pipeline) is also done — see §4. Phases 1, 3, 4 and 5 remain proposal.
### 0.1 The binary scene — diagnosis corrected
@@ -405,20 +405,41 @@ Effort marks are rough: **S** ≲1h, **M** a half day, **L** a day or more.
`.gitattributes` before any restructuring is deliberate — the moment work happens on a branch,
scene merges without a merge driver will corrupt files.
### Phase 2 — writing pipeline (no Unity changes, fully parallel to Phase 3+)
### Phase 2 — writing pipeline ✅ DONE (2026-08-25)
| # | Step | Detail | Effort |
|---|---|---|---|
| 2.1 | Create `writing/` skeleton + templates | §2.2, §2.3 | S |
| 2.2 | **Write `writing/STYLE.md`** | The missing handbook. Recover the rules from `.yarn` header comments and the three `docs/` plans. Highest-value single item in this plan. | M |
| 2.3 | Extract `skill_bible.json` `notes` → `writing/voices/*.md` | one-shot script, 11 files | M |
| 2.4 | Write the sync script md → JSON + an EditMode drift test | §2.4 | M |
| 2.5 | Author the three character sheets | Bartender, Bradford Kane, Chevalier Cassian Thal | M |
| 2.6 | Write `writing/README.md` + `YARN-PRIMER.md` | The Cowork session entry point, incl. the YarnCheck caveat (§2.6) | S |
| 2.7 | Move `SC101.yarn`'s header rules into `writing/scenes/sc101-*.md` | leave a one-line pointer in the `.yarn` | S |
| # | Step | Status |
|---|---|---|
| 2.1 | `writing/` skeleton + templates | done |
| 2.2 | `writing/STYLE.md` | done — **digested from the vault handbook, not reconstructed** (below) |
| 2.3 | Extract `skill_bible.json` prose → `writing/voices/*.md` | done — 11 sheets, lossless round-trip |
| 2.4 | Sync script + EditMode drift test | done — `tools/writing/sync_voices.py`, `VoiceSheetSyncTests` |
| 2.5 | Character sheets | done — Bartender, Chevalier Cassian Thal, Bradford Kane |
| 2.6 | `README.md` + `YARN-PRIMER.md` | done, plus `GLOSSARY.md` and `lore/candidates.md` |
| 2.7 | SC-101 header rules → scene brief | done — header trimmed to the six rules that bind while editing, rationale moved to the brief |
Phase 2 touches **no Unity asset at all**. It can proceed while the Editor is open and while
Phase 3 is in flight, and it is what unblocks Cowork. Consider doing it first.
Validated: EditMode **42/42** (three new), YarnCheck compiles 9 files / 35 nodes, sheets in sync.
The drift test was verified to actually fail on drift, not merely to pass.
#### Phase 2 — what changed against the plan
Two things, both discovered during execution.
**The handbook exists.** `docs/skill-system-refactor-plan.md` §2 names it, and it is at
`~/Obsidian-Vaults/obsidian-vault/Projects/Active/NightclubArcadia/` — a 874-line
`[[Mystery Writing Handbook]]`, plus `[[Character Sheet Handbook]]`, `[[Skill System Draft]]`,
`[[Lorebook]]`, `[[Candidate System — Design Explanation]]`, scene specs, and `[[Ground Truth]]`.
So §2.2 became a **digest with pointers** rather than a reconstruction, which is both more
accurate and honest about where the authoring home is. The vault remains that home.
**`[[Ground Truth]]` must never enter this repo.** It is the solution document. The premise of
the game is that the protagonist's identity never resolves, and a copy of the answer in a git
history is exactly how that leaks. This is now stated in `writing/README.md` and `CLAUDE.md` §4.1.
One thing surfaced that is worth acting on independently: `[[000_OpeningSceneTemplate]]` records
SC-101's tone check as **BLOCKED** because the one-page Voice Sheet has never been written — the
scene spec could not honestly certify its own tone field. `writing/STYLE.md` §9 now holds that
sheet with four fields explicitly unset. Filling them is about half an hour of decisions and it
unblocks a check that has been stuck for a while.
### Phase 3 — scene restructure (the risky part)
@@ -530,9 +551,10 @@ the world every session.
## 7. Open questions
1. **Does a writing handbook exist outside the repo?** `docs/candidate-system-implementation-plan.md`
says it exists but is not checked in. If there is a document somewhere, importing it beats
reconstructing it (Phase 2.2 assumes reconstruction).
1. ~~Does a writing handbook exist outside the repo?~~ **Answered — yes** (Phase 2 notes). It is in the
Obsidian vault and is now pointed at rather than duplicated. The open part is whether any of
it should eventually move into the repo wholesale; the current answer is no, because the vault
is reachable from writing sessions and duplication would drift.
2. ~~How did the scene become binary?~~ **Answered** (§0.1): Force Text only converts when the
setting changes, so anything that entered binary stays binary. The open part is *how* it
first entered binary — most likely created or imported during a Force Binary window. Adding a