Skip to content

docs(game): resolve DD-006 via character builder; adopt Bayes-Nash model (DD-013)#69

Merged
hyperpolymath merged 1 commit into
mainfrom
docs/dd-006-character-builder
Jul 16, 2026
Merged

docs(game): resolve DD-006 via character builder; adopt Bayes-Nash model (DD-013)#69
hyperpolymath merged 1 commit into
mainfrom
docs/dd-006-character-builder

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Resolves DD-006 and adds DD-013. Framework only — no content drafted yet.

DD-006 — resolved as neither horn

Not named figures, not flat archetypes. Ship an immutable archetypal Core plus a character builder; the player supplies the name at their own table and nothing is printed.

This is a stronger position than the previously-logged compromise (archetype mechanics + named figures as printed flavour text), which still shipped the name — keeping the likeness exposure it was trying to avoid while gaining little.

Layer Visibility Content
Core public the archetypal essence — a type, never a person
Aspects hidden 2 strengths, 1 weakness, 1 appeal/antipathy pair
Name player's own supplied at the table, never printed
Private objective hidden quiet parallel goal that tugs against the commons

The four original roles are preserved verbatim as presets — nothing designed is lost. Isabella / Gandhi / Musk / Green Activist become sample fully-built characters over four Cores: the Chartered Extractor, the Nonviolent Mobiliser, the Off-World Plutocrat, the Steward.

DD-013 — public Core, hidden aspects (Bayes–Nash)

Hidden aspects and private payoffs mean nobody knows anyone's payoff function, only a distribution over it. That is a Bayesian game, solved by the Bayes–Nash equilibrium (Harsanyi's extension of Nash to hidden types); the reveal dial is a signalling game (Spence).

The point: this makes the character system load-bearing on the theme rather than decoration — the game's central concept is upgraded from complete-information Nash to Bayes–Nash, through the characters. Players need never hear the word "Bayesian"; they will just find they are reading each other rather than reading a stat block.

Core stays public so the table stays legible — fully hidden information stalls a kitchen-table game and breaks the eXchange pillar (DD-011), which needs players to read each other enough to bargain at all.

Game title deliberately parked. DD-001 unchanged — recorded only so the reasoning survives and isn't re-litigated by accident.

Knock-ons

  • DD-008 — the builder is the complexity dial (presets for beginners, builder for advanced; same system, two depths). Character-layer question settled; counts/weight still need playtesting.
  • Design rule — private objectives must be incentive-misaligned with the commons (DD-007), never orthogonal to it. An orthogonal objective is a solitaire task that pulls attention off the table; a misaligned one deepens the exact dilemma the game is about.
  • Legal seamarchetype, not portrait: printed Cores stay free of uniquely-identifying specifics (real company names, quotes, one-to-one biography). Freeing the name is what licenses the satire rather than suppressing it.

Status / next

Framework only. Aspect pools and the private-objective deck are Phase 1 drafting, alongside the 78-card catalogue. Balance critics should Monte-Carlo the aspect pools for dominant builds before a playtest is spent finding them.

Agreed by Jonathan and Joshua, 2026-07-16. Marked draft for Joshua's review.

🤖 Generated with Claude Code

…del (DD-013)

Resolve DD-006 as neither horn of the original question. Ship an immutable
archetypal Core plus a character builder; the player supplies the name at the
table and nothing is printed. This is a stronger position than the previous
"archetype mechanics + named flavour text" compromise, which still shipped the
name and so kept the likeness exposure it meant to avoid.

Add DD-013: Core is public, aspects and private objective are hidden. This makes
the game one of incomplete information, whose solution concept is the Bayes-Nash
equilibrium (Harsanyi) with the reveal dial as a signalling game (Spence). The
character system therefore becomes load-bearing on the theme rather than
cosmetic. Game title is deliberately parked, DD-001 unchanged.

Also:
- DD-008: the builder doubles as the complexity dial (presets vs. builder), so
  the character-layer question is settled; counts/weight still need playtesting.
- Design rule: private objectives must tug against the commons (DD-007), never
  run orthogonal to it. Misaligned, never independent.
- player-roles.adoc restructured around the layer model. The four original roles
  are preserved verbatim as presets; four Cores named; worked builder example.

Framework only. Aspect pools and the private-objective deck are Phase 1 drafting.
Agreed by Jonathan and Joshua, 2026-07-16.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@hyperpolymath
hyperpolymath marked this pull request as ready for review July 16, 2026 18:18
@hyperpolymath
hyperpolymath merged commit a93311e into main Jul 16, 2026
30 of 34 checks passed
@hyperpolymath
hyperpolymath deleted the docs/dd-006-character-builder branch July 16, 2026 18:18
hyperpolymath added a commit that referenced this pull request Jul 16, 2026
…ation budget (#70)

Follow-on to #69. Two bookkeeping fixes and one genuinely new proposal
for you and Joshua to rule on.

## DD-009 was stale, not open

I reported to Jonathan that DD-009 (game length) was the unruled blocker
on Phase 1. **That was wrong, and this PR corrects it.** The ruling had
already been made — `CANONICAL-MODEL.adoc` landed the three-preset
**length dial** in #68, whose title even claims DD-009. The DD entry and
tracker just never recorded it.

| Preset | Eras | Turns | Time target |
|---|---|---|---|
| Short — "Skirmish" | 2 | ~5–6 | 60–90 min |
| Standard — "Ascent" | 3 | ~9–10 | 120–180 min |
| Extended — "Legacy" | 4 | 32 | 4–6 hr, multi-session |

The original entry asked "how many turns?" as if one number had to serve
every table. Length is a *dial*, like complexity (DD-008). 32 turns was
never wrong — it was the *Extended* preset, mislabelled as the only one.
**No new decision is taken here**; this is the log catching up with the
model.

## The half of the risk that survives

The 25–35 min/turn figure (`gameplay-storyboard.adoc:463`) is a
**full-weight Industrial** turn. Short targets 60–90 min over ~5–6 turns
= **10–15 min/turn**, i.e. a **~2–3× reduction**, expected from
Core-only weight plus the leaner-turn levers.

**That ~2–3× is assumed, not measured** — the most load-bearing untested
number in the design. If the levers only deliver 1.5×, Short lands at
100–140 min and the target is gone. So: *time a Core-weight turn first,
before balance, before content.* Now flagged in DD-009 and WAY-FORWARD.

## Contradiction fixed

WAY-FORWARD said Short = "2 eras / **~12 turns**"; CANONICAL-MODEL says
"**~5–6**". Canonical is the declared single source of truth, so it
wins. Phase 0 also marked DONE — its bullets were pending
recommendations that #68/#69 have since executed.

## DD-014 — The Information Budget (OPEN, ruling pending)

The one new idea, deliberately logged as **proposed, not decided**.

Hidden information is a *budget*, not a free good. DD-013 spent most of
it on characters (hidden aspects + private objective). So DD-011
("agreements public or private?") and DD-012 ("research public or
private?") should lean **public** — each further hidden layer is charged
to the same account.

Bayes–Nash needs *both*: enough hidden information to make types
uncertain, and enough public information to update from. Hide everything
and an opponent watching you defect cannot tell _thin-skinned_ from
_research failed_ from _private objective paid_. Priors never move;
inference becomes guesswork. **More hidden information does not mean
more Bayes–Nash — past a point it means less.** `player-roles.adoc` §8
already says hidden aspects must create *inference, not confusion*;
DD-014 generalises that from characters to the whole design.

If adopted, it **constrains** DD-011/DD-012 rather than resolving them —
binding duration, defection penalty, and randomness model all stay open.

Also logged: **do private objectives (DD-006) and eXperiment (DD-012)
collapse into one subsystem?** Both are hidden, asymmetric-payoff
machinery existing to obscure your payoff function. Unresolved — worth
settling before either is drafted in Phase 1.

## Verification

Installed `asciidoctor` (it was missing, which is why #69 shipped
without a render check) and rendered all four docs — **zero warnings**.
Confirmed the DD-009 table, DD-014 section, 9 tracker rows, and that the
WAY-FORWARD NOTE renders as a real admonition without swallowing the
following bullet. This also retroactively validates the #69 files.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
hyperpolymath added a commit that referenced this pull request Jul 16, 2026
Found while verifying #70. Two toolchain defects, both pre-existing on
`main`.

## 1. `just` is completely broken on main

`build/contractile.just:136` writes a literal grep pattern unescaped:

```just
! grep -rl '{{[A-Z_]*}}' --include='*.a2ml' ...
```

`just` parses `{{` as an interpolation, hits `[A-Z_]*`, and **aborts
before running anything**. Not just that recipe — *every* recipe. `just
--list`, `just docs`, `just quality`, all 124 of them:

```
error: expected '&&', '!=', ... but found '*'
   ——▶ build/contractile.just:136:25
```

`{{{{` is just's escape for a literal `{{`. The file header says it's
hand-maintained ("hand-expanded to match Xfile.a2ml checks"), so the fix
won't be clobbered by regeneration. After: **124 recipes list and run.**

Unbreaking it also revealed that `dust-no-placeholder-tokens` **fails**
— it was never able to run. Six files carry unfilled `{{PLACEHOLDER}}`
tokens (`container/README.adoc`, `container/0.1-AI-MANIFEST.a2ml`,
`.machine_readable/agent_instructions/methodology.a2ml`,
`docs/status/TEST-NEEDS.adoc`; two more — `PLACEHOLDERS.adoc`,
`Dustfile.a2ml` — contain the pattern legitimately). **Not fixed here**
— pre-existing, needs your judgement on the values.
`openssf-compliance.yml` misses them because it only scans a curated
`REQUIRED_FILES` list.

## 2. Nothing checked that `.adoc` files actually parse

`check-no-md-in-docs.sh` enforces AsciiDoc by **extension**. CI's `docs`
job only checked files **exist**. Nothing checked they **render** — an
unterminated block or malformed table produces mangled output and ships
silently. That gap is why #69 shipped on my hand-counted delimiters
rather than a real check.

Adds `scripts/check-docs-render.sh` (house style, matching
`check-no-md-in-docs.sh`), renders every `.adoc` at
`--failure-level=WARN`. Wired into `just docs-check`, `just quality`,
and CI's docs job. Also `just docs-html` for local reading.

Verified it fails correctly, not just passes:

| | result |
|---|---|
| repo as-is | `PASS: 125 .adoc render cleanly (6 quarantined)` → exit 0
|
| with a deliberately broken file | `FAIL: unterminated table block` →
exit 1 |

## The 6 quarantined files — a real finding

They're **Markdown wearing an `.adoc` extension**: a `= Title` line
bolted onto a Markdown body (`#` headings, `<!-- -->` comments, `|` pipe
tables). They satisfy `check-no-md-in-docs.sh` by extension while still
being Markdown — the estate rule met in letter, not substance.

They're in an `ALLOWED` list rather than silently skipped, so the list
is visible and meant to shrink. **All 6 are RSR boilerplate — no
game-design doc is affected.**

Worth knowing: the render gate only catches the *tip*. Asciidoctor
accepts `##`+ as Markdown-compat headings, so a file can be wholly
Markdown and still render "clean" —
`docs/governance/MAINTENANCE-CHECKLIST.adoc` has 53 Markdown headings
and passes. At least ten files are affected. A proper conversion is a
separate job.

## CI impact

None beyond the new gate. No workflow invokes `just quality` or the
`dust-*` recipes, so unbreaking `just` cannot turn anything red. (Note
`main` is already partly red independently: Governance = failure, Secret
Scanner = startup_failure.)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant