Commit Graph

244 Commits

Author SHA1 Message Date
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
c106dbbd37 feat(currency): money moves through the bounded vocabulary (§6)
give_item(gold) is +10,000c and does NOT mark gifts_given — that gate is a
global one-shot keyed by item id, so marking money would let an NPC pay you
exactly once per campaign. accept_item(<denom>) is offered only for the
denominations the purse can actually pay.

The eight moves do not grow. MoveValidator is untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYa9u7Kdxv5gX4AnwWexy8
2026-07-12 18:32:14 -05:00
8a71671df7 feat(currency): purse_copper on GameState, with grant/take routing
One int holds all money. grant/take are the sole routing point — currency ids
go to the purse, everything else to inventory. Money is never an inventory row.

The 'coin' stand-in in the two unrelated inventory tests becomes
worn_shortsword; they were never about money.
2026-07-12 18:29:10 -05:00
2a372bff2f feat(currency): the Currency value type — copper, ratios, formatting
One integer, stored in copper. The ratios are rules and live in code; prices
are content and land in M8. format() suppresses empty denominations so being
broke reads as '47c', not '0g 0s 47c'.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYa9u7Kdxv5gX4AnwWexy8
2026-07-12 18:26:22 -05:00
a90cc16463 docs(plan): copper-based currency, six tasks
TDD, one test cycle per task, green suite at every boundary. Task 4 carries
the content swap and the generated-tree check (the Duncarrow lesson).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYa9u7Kdxv5gX4AnwWexy8
2026-07-12 17:58:44 -05:00
37ec1bb1be docs(spec): copper-based currency with real denominations
Money stops being a flat `coin` and becomes copper, stored as a single
int, formatted only at the display edge.

The approved model (1g = 100s = 10,000c, store everything in copper) said
money should stay an inventory item under one `copper` id. It can't. §6 is
what kills it: `give_item(x)` adds exactly 1 and carries no quantity, and
`gifts_given` is a global one-shot keyed by item id — so a single `copper`
id would be givable once, for one copper, for the whole campaign.

So the purse is one int on GameState, and the three denominations are
content items that exist only to let a bounded move name a unit —
give_item(gold) is +10,000c. Three ids, not three buckets: the
change-making problem never arises because there is only ever one number.
A quantity arg on the move was rejected — it hands the model an unbounded
integer to invent, which is the §2 line.

Currency routes to the purse and never enters `inventory`, so it can't
appear in an inventory grid by construction. No filter needed.

Prices remain content and remain M8.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYa9u7Kdxv5gX4AnwWexy8
2026-07-12 17:52:13 -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
021c2480d8 docs(spec): character reuse + the seven-campaign arc
A direction spec: one character, seven campaigns (one per demon king),
one saga — then it ends. The character, companions, deeds and level carry
between campaigns; the world does not.

Deliberately adds no milestone and no BOM line. Its real payload is a set
of guardrails on milestones that are about to be built blank and would
otherwise foreclose the shape:

- M5 owes a level curve — design it to a ceiling of 20 across 7 tiers,
  with tiered enemy stat blocks and never a scaling multiplier.
- M9 owes a save format — two objects (Saga + Campaign), not one blob.
  Humiliations move to the Saga or they die with the campaign.
- M3/M4 — don't foreclose a saga entry path; don't couple construct() to
  the creation scene.
- Build tool — add tier:1..7 when the item/quest namespaces land.

Difficulty is fixed at world-construction time from the campaign index,
never during play. That prohibition is the whole design; a world that
re-levels with the player is a treadmill.

The canon-log contract does not change: party[].disposition,
humiliations[] and established_facts[] already exist, and player still
admits no number. The Saga becomes the source; the canon log a projection
of it. The seam is one optional fourth arg to NewGame.construct().

Greywater at tier 1 under Ghaul is, unintentionally, already campaign 1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 17:16:50 -05:00
c171299cb4 docs(spec): content track — demand-driven, bounded by the slice
Content (lore, economy, items, quests, map) was untracked and unbounded.
Bound it: a second roadmap (content/roadmap.md) with Spine / Bill of
Materials / Backlog, demand-driven by the milestone that consumes it.

- Vertical slice = one town + one dungeon (adopt + deepen Greywater).
- Ghaul the Yoke is the ledger chain's patron, so the quest chain and
  the cosmology are one object, not two.
- Economy splits per §18: the loop is code (M8), the numbers are content.
  Currency = 1g/100s/10,000c, copper as the stored atom; lands before M7.
- Build tool needs `item` + `quest` namespaces; locations already exist.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 16:29:29 -05:00
0e8aa5efbd Merge chore/remove-ci-workflow into dev
Remove the GitHub Actions workflow (repo is on Gitea; it never ran). The
--check gate now lives in pytest (test_real_content.py), and the world-building
skill's verify step states there is no CI and adds the client suite — since
content/world/ is a client input, not just build output.
2026-07-12 16:13:32 -05:00
ccff2fdbf2 chore: remove the GitHub Actions workflow — there is no CI
The repo lives on a Gitea server and CI/CD is a long way off, so
.github/workflows/content-build.yml never ran. A workflow nobody executes is
worse than none: it read as a safety net that wasn't there.

Removing it moves the `--check` gate somewhere real. It is now enforced by
tools/content_build/tests/test_real_content.py, which runs check() against the
live bible under pytest — so the gate is a test you actually run, not a job
that never fired.

The world-building skill's verify step now says plainly that nothing runs these
for you, and adds the client suite to the checklist: content/world/ is a CLIENT
INPUT (content_db.gd loads it, test_content_db.gd asserts on it), so a content
change can break the client. That is exactly what the Duncarrow purge did, and
with no CI there is nothing else to catch it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 16:13:32 -05:00
997fef1803 Merge feature/duncarrow-purge into dev
Some checks failed
content-build / build (push) Failing after 2s
Delete the Duncarrow scaffolding; preserve the infrastructure it carried.

- rule.disposition-ladder reparented into content/lore/mechanics.md (required
  exactly once by the build; moved atomically with the deletion)
- content/lore/specimen.md: synthetic status=candidate disposition-gate specimen
  (validated by --check, emitted nowhere), teaching both an earned warm reveal
  and a never-gated core secret
- duncarrow.md + 23 generated JSON + test_duncarrow.py removed
- world-building skill repointed: structure -> specimen.md, voice -> cosmology.md;
  3 evals rewritten cosmology-aware
- repaired the client consumers the purge broke: content_db no longer errors on
  an absent content dir, and the no-body-on-client secrecy guard is asserted
  structurally so it cannot pass vacuously

--check exit 0, pytest 45, client GUT 149/149.
2026-07-12 16:06:44 -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
894bde959e docs(skills): drop deleted-content trigger examples from world-building description
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 15:42:06 -05:00
602edbf257 docs(skills): repoint world-building off Duncarrow (specimen + cosmology); rewrite evals
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HuHRPE7VfppUJEaoGBEUqZ
2026-07-12 15:39:41 -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
2bf4ae43d1 docs(plan): Duncarrow purge implementation plan
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HuHRPE7VfppUJEaoGBEUqZ
2026-07-12 15:22:01 -05:00
9aa06d59d7 docs(spec): Duncarrow purge — decouple scaffolding from infrastructure
Delete the Duncarrow scaffolding while preserving the schema/disposition-gate
infrastructure it carries: reparent rule.disposition-ladder into a new
mechanics.md, stand up a synthetic status:candidate specimen (validated but
never emitted), repoint the skill/tests/evals. Zero real game content; the
in-flight NPC redesign and the hand-authored POC seed JSON stay out of scope.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HuHRPE7VfppUJEaoGBEUqZ
2026-07-12 15:11:14 -05:00
df5ed2b525 Merge feature/cosmology-theme into dev
Some checks failed
content-build / build (push) Failing after 5s
Overarching cosmology: the Warden (distant good god), the Sent, and the
Seven demon kings, authored as canon; world-building skill updated to
reconcile all future content against the backdrop (incl. FTH-axis
Bonesetter/Bloodsworn calling mapping). Duncarrow decoupled as
scaffolding, not removed. Build --check exit 0, pytest 47/47.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HuHRPE7VfppUJEaoGBEUqZ
2026-07-12 14:39:28 -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
6c542e3669 feat(skills): world-building carries the cosmology backdrop
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HuHRPE7VfppUJEaoGBEUqZ
2026-07-12 13:26:08 -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
ce9db1d9c8 docs(plan): cosmology + world-building theme implementation plan
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HuHRPE7VfppUJEaoGBEUqZ
2026-07-12 12:08:38 -05:00
d15a8fdcab docs(spec): divide FTH callings along the war (Bonesetter/Bloodsworn)
Adds the FTH-axis calling mapping to the cosmology spec: Bonesetter
channels the Warden, the Bloodsworn (names the [CANON-TBD] warlock
calling) pacts one of the Seven, Hedge-Mage is a pointed outsider,
martials unaligned. Luck-immunity intent kept as flavor and flagged for
the M5/Improviser reconcile (§7-sensitive), not built here.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HuHRPE7VfppUJEaoGBEUqZ
2026-07-12 12:01:28 -05:00
8f137aba20 docs(spec): cosmology — the Warden and the Seven (overarching theme)
Establishes the good-god/seven-demon-lords cosmology as the game's
overarching content theme, mapped onto the content schema as canon
entities, with the world-building skill updated to reconcile all future
authoring against it. Duncarrow scaffolding decoupled now, purged in a
follow-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HuHRPE7VfppUJEaoGBEUqZ
2026-07-12 11:49:33 -05:00
58dd7be7cf Merge fix/commit-godot-uid-files into dev 2026-07-12 11:19:47 -05:00
4780ab4802 fix(client): commit missing Godot .uid files for considering-indicator scripts
The scripts were tracked but their .gd.uid siblings weren't. Godot 4.4+ .uid
files pin each script's uid://, so leaving them out lets each clone regenerate
different uids and break uid:// references in scenes/resources. Matches the 159
.uid files already tracked in the repo.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HuHRPE7VfppUJEaoGBEUqZ
2026-07-12 11:19:47 -05:00
86a4ebc105 Merge feature/world-building-skill into dev 2026-07-12 11:15:34 -05:00
b15bd2bb1e feat(skills): add project-local world-building skill
Author gritty, disposition-gated Margreave content (lore bible + hand-authored
quest/item/location/origin JSON) that reconciles against existing canon before
writing, holds the world's hard-by-default / warm-when-earned NPC tone, and keeps
the content_build --check gate green.

- SKILL.md: read-before-write workflow, read-only on existing canon (propose
  diffs, require approval), build+check+pytest as the done bar.
- references/schema.md: full bible + JSON contract, secrecy scale, gate model.
- references/tone.md: tone contract + NPC disposition-warmth model.
- scripts/canon_index.py: dumps existing ids for reconciliation.
- evals/: 3 test cases (all green in isolated-worktree runs).

Un-ignore /.claude/skills/ so project skills are versioned like code; all other
.claude/ dirs (root + nested api/client) stay ignored.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HuHRPE7VfppUJEaoGBEUqZ
2026-07-12 11:15:34 -05:00
a3506f7f02 docs(spec): NPC addressing design (runtime cycle)
Lock the NPC identifier: full namespaced id (npc.mera-fenn) is canonical
everywhere — stored data, client dict key, and the /npc/speak wire. The API
load_npc changes from a filename lookup to an id-indexed load (matching the
client's ContentDB), reads persona from content/server, and resolves the
client's reveal-set fact_ids to topic bodies. Legacy Fenn keeps working; no
migration required. First task of the runtime-consumption cycle.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HuHRPE7VfppUJEaoGBEUqZ
2026-07-12 01:58:30 -05:00
bbaa59fad4 Merge feature/content-build-tool into dev
Some checks failed
content-build / build (push) Failing after 6s
Content & canon build tool: compiles content/lore/*.md (Markdown bible +
fenced YAML) into validated client (content/world) + server-only
(content/server) JSON, split by role so spoilers/personas never ship in the
client. Validation gate aborts on schema violations; --check is the CI
freshness/validity gate. Promotes Duncarrow as the acceptance test (secret
body proven server-only). ContentDB loads the new canon/ + topics/ dirs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HuHRPE7VfppUJEaoGBEUqZ
2026-07-11 20:40:06 -05:00
c09b6e89a0 test(content-build): cover generated-npc orphan detection in shared npcs dir 2026-07-11 19:06:00 -05:00
f84e55ab4b fix(content-build): --check orphan detection; canon secrecy-0 + value-type guards
- --check now detects orphaned/stale build artifacts in build-owned dirs
  (client canon/ + topics/ fully owned; client npcs/ shared with legacy
  hand-authored files, only npc.* ids are treated as build-owned)
- resolve() enforces the schema rule that canon entities must be secrecy 0
- resolve() and ladder_rungs() guard against malformed value TYPES (non-int
  secrecy, non-list related/rungs) raising BuildError instead of crashing

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HuHRPE7VfppUJEaoGBEUqZ
2026-07-11 19:01:28 -05:00
c2d67be76a ci: content-build tests + --check gate
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HuHRPE7VfppUJEaoGBEUqZ
2026-07-11 18:51:11 -05:00
a160d3e967 feat(client): ContentDB loads canon/ + topics/ built dirs
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HuHRPE7VfppUJEaoGBEUqZ
2026-07-11 18:46:55 -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
11c4d6dcd7 feat(content-build): CLI build + --check staleness gate 2026-07-11 18:27:48 -05:00
973af41a6e test(content-build): assert candidate entries excluded from build_trees 2026-07-11 18:25:43 -05:00
0542516312 feat(content-build): emit routing + secrecy lint + writer 2026-07-11 18:19:26 -05:00
e3c35614e7 test(content-build): cover status, empty-knows, non-npc start_disposition, empty-rungs
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 18:16:18 -05:00
9141cd1e9f feat(content-build): validation gate (rungs + resolve) 2026-07-11 18:09:47 -05:00
f21d7be4d9 feat(content-build): typed Entry model + category predicates 2026-07-11 18:05:26 -05:00
bd293c1701 feat(content-build): scaffold package + Markdown yaml-block parser 2026-07-11 18:01:45 -05:00
40c3a7fc4b docs(plan): content & canon build tool implementation plan
8 TDD tasks: package scaffold + parser, Entry model, validation gate
(rungs+resolve), emit routing + secrecy lint, CLI --check, Duncarrow
promotion (acceptance test), client ContentDB canon/topics dirs, CI gate.
Branches off dev per s18; runtime consumption + Fenn migration + export
packaging explicitly deferred.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HuHRPE7VfppUJEaoGBEUqZ
2026-07-11 17:53:44 -05:00