Commit Graph

23 Commits

Author SHA1 Message Date
c6b8a651aa fix(creation-content): four fragments were reading the blurb back to the player
The creation screen shows a race's blurb on its card and the chosen calling's
blurb in the detail panel directly above the DM panel. Blurb and fragment are on
screen at the same moment, inches apart — so a fragment that paraphrases its own
blurb makes the DM sound like it is reciting the card. Four did:

- bonesetter lifted two clauses verbatim ("you set the bone, you say the words")
- reaver re-ran the blurb's door image with the same sentence shape
- hedge_mage re-opened on "what you know" and re-landed the dead teacher
- beastfolk repeated both the claws and the being-judged beat

Each now says the NEXT thing instead: the hour they wake you and which of the
two trades you will not claim credit for; the employer who arranges to be
elsewhere; where you went to fail safely and what the book's gaps cost your
skin; the town that takes your coin and still wants you outside the walls.

beastfolk's rewrite also breaks the race-set monotony — it no longer opens "You
were born" (now unique to human) and drops the shared "X, and you have…" spine,
so clicking the four cards in a row stops reading as one voice.

The parity test guarded presence but could not fail on the three properties that
actually make all 28 race×calling concatenations grammatical. It now asserts
race fragments start uppercase and end with '.', and calling fragments start
lowercase and end with '.' — verified by breaking both and watching all four new
assertions fire.

255 client tests green; content build --check green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 14:11:16 -05:00
e4db022c4b content(creation): the eleven origin fragments
race.fragment + calling.fragment compose the DM origin panel on the creation
screen. Authored prose, not stubs — this is the first sentence the player reads.
Parity-tested: a missing or empty fragment fails the suite.
2026-07-13 14:02:47 -05:00
a668cf98eb refactor(contract)!: class_id -> calling_id, and the log gains race_id
class_id is the rulebook's word; the world has callings — that was the whole §17
reconcile. The contract the Narrator reads should say what the world says. There
are no saves (M9) and no deployed clients, so this is as cheap as it will ever be
and strictly more expensive every milestone after.

race_id reaches the log because the AI must be able to describe the player:
api/app/prompts.py rendered 'a sellsword' and now renders 'a beastfolk cutpurse'.
It humanizes the id (the model must never read 'hedge_mage') and picks the right
article ('an elf', not 'a elf').

LogPlayer's hardcoded CLASSES const is deleted — the roster is Callings.IDS. A
parity test reads the JSON Schema from the client and asserts its enum equals the
code, so the two sides of the HTTP boundary cannot drift.

The deserter allowed three callings that no longer exist. He now allows all seven;
a thematic gate is a content decision for the Greywater authoring.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYa9u7Kdxv5gX4AnwWexy8
2026-07-12 20:27:56 -05:00
a7e153884f feat(content): calling + race blurbs, loaded by ContentDB
Hand-written like items/ — no build-tool namespace needed. Blurbs are content;
mechanics are code, and a test asserts the blurb files carry no hit dice. The
prose is placeholder; swapping it later touches no code, which is what stops the
content BOM from blocking the engine.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYa9u7Kdxv5gX4AnwWexy8
2026-07-12 20:18:19 -05:00
bb8097929a docs(canon): name the last two callings — Reaver, Bloodsworn
All seven callings are now named; no [CANON-TBD] remains in the specs.

Reaver (Barbarian). To reave is to raid — occupational, like Sellsword and
Trapper, naming what he does for money rather than what he is inside. That is
the rule the five mock names already obeyed and that §8's own list broke: a
calling is what a village calls you, not what a rulebook calls you. Bearsark
and Wildman were rejected for naming a condition; Breaker for being generic.

Bloodsworn (Warlock) was not a new coinage — the cosmology minted it a day
after the races spec was written ("what the Margreave calls bloodsworn",
rule.blood-price), and the cosmology spec had already applied it. It is the
exact FTH-axis mirror of Bonesetter: one channels the Warden, one pacts a king
of the Seven. Accepted cost, recorded in the spec: alone among the callings it
names a condition rather than a trade — the villain who pacts Ghaul is
bloodsworn too. A second, occupational word (Cursewright, Hexman) was
considered and rejected as a distinction the player will never feel.

Also retires the stale "reconcile class names" note on M4 and records the two
contract migrations that milestone owes: the canon log's `race` field, and the
deserter origin's dead allowed_classes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYa9u7Kdxv5gX4AnwWexy8
2026-07-12 19:34:26 -05:00
c3e02c7f7d docs(roadmap): currency landed; M4 is next
Both roadmaps still described the copper currency change as pending. It is
merged. The marker moves to M4, M8's line now says what it still owes (the
price table — nothing is priced yet), and a "Landed out of band" section
records the two items that shipped outside a milestone: the currency value
type, and the once-per-reply move cap its review turned up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYa9u7Kdxv5gX4AnwWexy8
2026-07-12 19:25:22 -05:00
a9d9eedb7e feat(currency): copper/silver/gold replace the coin
The three denominations are move tokens, not stored buckets — there is one
integer, so change-making never arises. The deserter is down to 47c: under a
silver, so he cannot cover a bed and the player sees it on turn one.

A parity test guards the code-side ratios against the content-side ids.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYa9u7Kdxv5gX4AnwWexy8
2026-07-12 18:36:08 -05:00
9e8fc55a44 docs(content): create the content roadmap — Spine, BOM, Backlog
Implements the docs restructure half of the content-track design (the
currency item is code and stays unbuilt). Content stops being unbounded:
the work is now a countable checklist with an end.

content/roadmap.md — new. Three sections, only one of which is ever the
work:
  Spine     Greywater Docks + one dungeon, patron Ghaul the Yoke; the
            cosmology touching ground. Plus what is already canon.
  BOM       ~57 discrete pieces for a complete, playable game, per
            milestone. Numbers, not vibes.
  Backlog   Everything the slice does not need. Not a debt — where ideas
            go to be safe.

Its rule: never author anything that is not in the Bill of Materials.

The BOM carries a Fixed/Variable column — the seven-campaign saga spec's
only ask of this table. ~37 fixed / ~20 variable: a second town costs the
20, not the 57. That is also the exact split v2 generation would need.

content/lore/canon-roadmap.md becomes a pointer (older specs and plans
reference the old path). An items-and-prices table does not belong under
lore/.

docs/roadmap.md — M4..M9 each gain a "Content it consumes →" line into
the BOM.

world-building skill — SKILL.md and evals.json now point at
content/roadmap.md, and the skill is told to respect the BOM rule: ideas
that arrive during authoring go to the Backlog, not into the world.

Build + --check green; generated content/world and content/server are
byte-identical. No Python touched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 17:31:30 -05:00
ef335a93c3 docs: land the saga guardrails on the milestones they constrain
Applies the seven-campaign saga direction spec (021c248) to the docs it
was written to protect. No new milestone, no new content, no BOM line.

docs/roadmap.md — a "Guarded direction" section, and a ⛨ saga note on the
four milestones that would otherwise foreclose the shape:
  M3  don't hardcode the title flow so a saga entry path can't be added
  M4  keep construct()'s `creation` a plain Dictionary; the scene must not
      become its only producer
  M5  the level curve is no longer open — L20 across 7 tiers; enemy stat
      blocks carry tier; no scaling multiplier, ever
  M9  the save is two objects (Saga + Campaign); humiliations move to the
      Saga or they die with the campaign

races-and-classes spec — the deferred "XP curve → M5" line now inherits the
ceiling rather than choosing one.

canon-roadmap — what the saga asks of content: a tier field when the
item/quest namespaces land, and a fixed-vs-variable mark on each BOM line
when the BOM is written. Tiers 2-7 and the other six kings go to the
Backlog.

Content build --check green; no generated content touched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 17:23:26 -05:00
2b54dad1fa feat(content): give the specimen a never-gated core secret
The purge left `gate: never` — the rung no disposition unlocks — demonstrated
nowhere. Duncarrow's Crell chain had taught it; specimen.md only taught `warm`.

Adds secret.specimen-drowned-clerk (secrecy 4, gate: never), so the specimen
now shows an ascending 2 -> 4 chain and a reason `never` exists: the NPC holds
it, but saying it aloud would hang him. Mirrored in the skill's worked example,
which now states the rule — if any rung *should* buy the secret, gate it at
`trusted` instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 16:05:04 -05:00
dc4b14d3e5 fix(content): repair client consumers broken by the Duncarrow purge
The purge plan assumed content/world/** was pure build output. The client
reads it: content_db.gd loads content/world/topics/ (now absent, since every
topic was Duncarrow-generated) and its tests asserted on deleted ids.

- content_db: a missing content dir is an empty dir, not an error (§13)
- test_content_db: repoint at cosmology canon; drop deleted npc.mera-fenn
- test_content_db: assert the no-body-on-client invariant structurally, so it
  cannot pass vacuously when the topic set is empty
- schema.md: finish repointing the worked example onto specimen.md's ids
- restore a local real-bible --check smoke test (was only in CI)
- roadmap: record that generated content has client consumers

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 16:00:06 -05:00
fae39d9c79 docs(content): roadmap — Duncarrow purged, ladder in mechanics.md, specimen added
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HuHRPE7VfppUJEaoGBEUqZ
2026-07-12 15:45:21 -05:00
ac8da4e6da feat(content): reparent disposition-ladder to mechanics.md; purge Duncarrow
Move rule.disposition-ladder into content/lore/mechanics.md and delete the
Duncarrow scaffolding (source + 23 generated JSON). Remove the redundant
test_duncarrow.py (routing/secrecy already covered by test_emit.py synthetic
fixtures); repoint a cosmetic slug-test id.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HuHRPE7VfppUJEaoGBEUqZ
2026-07-12 15:30:59 -05:00
c1edcfe015 feat(content): synthetic candidate disposition-gate specimen
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HuHRPE7VfppUJEaoGBEUqZ
2026-07-12 15:26:59 -05:00
1dfa9462ba fix(content): final-review polish — link the-seven roster + roadmap wording
- faction.the-seven now relates down to all seven lords (spec §4 intent;
  bidirectional discoverability), regenerated the-seven.json.
- canon-roadmap: clarify Bloodsworn resolves the warlock's former [CANON-TBD] name.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HuHRPE7VfppUJEaoGBEUqZ
2026-07-12 13:36:19 -05:00
5646bdd42a docs(content): roadmap — Warden/Seven authored, Duncarrow flagged scaffolding
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HuHRPE7VfppUJEaoGBEUqZ
2026-07-12 13:29:59 -05:00
c6d16430de feat(content): the Seven — seven demon kings and their blood
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HuHRPE7VfppUJEaoGBEUqZ
2026-07-12 13:21:14 -05:00
0cf1b27773 feat(content): cosmology frame — the Warden, the Sent, the Seven
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HuHRPE7VfppUJEaoGBEUqZ
2026-07-12 13:16:40 -05:00
7ce5e4584c feat(content): promote Duncarrow; build client/server artifacts
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HuHRPE7VfppUJEaoGBEUqZ
2026-07-11 18:34:33 -05:00
a2c654c047 content: author Fenn + the NPC role prompt body 2026-07-10 12:26:04 -05:00
4aa65c9d4c feat(content): POC deserter origin + world fixtures with id-resolution check 2026-07-09 12:37:29 -05:00
800811dac2 docs: canon log schema + origin seed design
Design spec for the §11 canon log, plus origin seeds as thin initial-state
overlays over a single static world. Three layers (world content / origin seed /
runtime canon log), the in/out boundary (numeric Luck never enters the AI
payload, §7), field-level schemas, new-game construction order, turn-to-turn
maintenance, and JSON storage validated on both client and api.

Folds content/npcs and content/quests under content/world/; adds
content/world/{locations,items} and content/origins. fallback/ kept outside
world/ (authored prose, not id-referenced).

Spec: docs/superpowers/specs/2026-07-09-canon-log-schema-design.md

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 12:03:37 -05:00
d54599e27d first commit 2026-07-09 11:17:54 -05:00