docs(architecture): sprint 37 archetype-trace audit (#878)

Tyre's trace of every live consumer of CharacterArchetype across server
and client, with the cascade-based rationale for full removal. Captured
so future audits don't repeat the same investigation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-22 08:56:21 +02:00
co-authored by Claude Opus 4.6
parent cae3d3ab85
commit 11db2f4b41
+110
View File
@@ -0,0 +1,110 @@
# Sprint 37 #878 — CharacterArchetype audit (D-032 obsolete claim)
**Author:** Tyre (architecture)
**Date:** 2026-04-21
**Ticket:** #878 — Audit and purge dead smuggler/detective character enum (D-032 obsolete)
**Status:** BLOCKED — load-bearing code found, awaiting lead decision before destructive work.
## TL;DR
The ticket's premise — that `CharacterArchetype` (Smuggler/Detective) is dead
code per D-032's "[Obsolete post-D-117]" footnote — is **stale**. The
footnote relied on D-117 (tycoon is the v0.2 bookmark), but `CLAUDE.md`
now declares **"v0.2 target is dropped. No scoping negotiations."** That
revocation is the most recent architectural directive, and it rolls back
the premise that justified marking the enum obsolete.
Recommendation: **do not delete `CharacterArchetype`**. Instead, update
the decision record to clear the stale obsolete footnote, close the
ticket as "no-op — premise superseded," and (optionally) claim a small
D-record documenting the reversal chain.
## Audit
Grep was run against `server/`, `tooling/`, and `tests/`. `CharacterArchetype`
has **five load-bearing consumers** plus content-schema users:
### 1. IPC protocol surface
- `server/src/bridge/types.rs:51-54``StartupMessage.character_archetype: CharacterArchetype`.
Field is serialized into the session handshake. Removing it is a protocol break.
- `server/src/bridge/types.rs:500-518` — enum + `as_monologue_key()` helper + `Default = Detective`.
- Roundtrip tests at lines 1133, 1146, 1157, 1166, 1173, 1184 exercise the field.
### 2. Observer pipeline (D-057, #422) — real runtime behavior
- `server/src/perception/observer/mod.rs:81,117,138,200` — archetype flows through
`apply_phase2_verb_filter`.
- `server/src/perception/observer/mod.rs:657-760``archetype_verb_label()` swaps
container verb labels based on archetype (Smuggler sees `Move`/`Stash`, Detective
sees `Scan`/`Flag`). This is live feature code, not scaffolding.
### 3. Monologue pool selection (D-032, #587, #595)
- `server/src/simulation/monologue.rs:134-152``MonologueState.character: String` is
initialized from `CharacterArchetype.as_monologue_key()` at session start.
Pool partition is by string key, but the string is *derived* from the enum.
### 4. Gauntlet test-world plumbing
- `server/src/test_world/mod.rs:98``pub fn setup_gauntlet(app: &mut App, archetype: CharacterArchetype)`.
- 5 internal callsites (lines 702, 725, 742, 761, 778) plus the external
`archetype_monologue.rs` integration suite.
### 5. Regression test suite
- `server/tests/archetype_monologue.rs` — entire file is a regression guard
against #587 (archetype→monologue character wiring). Seven tests, four
explicitly assert Smuggler vs Detective behavior. Deleting the enum requires
deleting this guard, which is the thing that catches the bug it was built for.
### 6. Content schemas (authoring)
- `server/content/schemas/drama_module.schema.yaml:231,233,234,280,558`
schema enumerates `smuggler | detective | any` for dialogue/monologue
partitioning in drama modules.
## Decision chain (why the ticket premise is stale)
```
D-027 (v0.1 vertical slice = smuggler + detective)
└─ superseded by D-117 (2026-03-05: tycoon is the v0.2 bookmark)
└─ superseded by "v0.2 target is dropped" (CLAUDE.md, current)
```
The obsolete footnote in D-035 line 83 and the `[SUPERSEDED]` header on
D-032 both point at D-117 as the supersession. With v0.2 dropped, we are
back to the v0.1 smuggler/detective frame as the implemented base until
the 6-phase cascade reaches Phase 4 (Player control) — and even then,
the cascade describes a 2-floor test map + character rendering, not a
wholesale character-model replacement.
## Proposed alternative scope for #878
Three options, cheapest first:
### A. Close as no-op + documentation cleanup (recommended)
- Strip the `[Obsolete post-D-117]` footnote from `decisions/content.md:83`
(D-035 tag taxonomy).
- Remove the `[SUPERSEDED]` marker from `decisions/content.md:47` (D-032
header) or add a "supersession reversed" note.
- Optionally claim a new D-record in `decisions/scope.md` documenting
that the v0.2-dropped directive implicitly reverses D-117's character
frame revocation.
- Zero code changes. Build stays green. 30 minutes.
### B. Narrow the ticket to the authoring-side leftovers
- If there are *authoring* artifacts (half-written tycoon monologue
partitioning, stale schema fields) that were added in anticipation of
D-117 and never used, those can be purged. But a quick scan of
`drama_module.schema.yaml` shows the schema is consistent with v0.1 usage.
- Requires a content team review — server-team scope alone cannot
confirm what is live in authoring.
### C. Rename without removing (if lead wants distance from v0.1 framing)
- Rename `CharacterArchetype``PlayerCharacterRole` (or similar) and
its variants to preserve behavior while shedding the "smuggler/detective
investigation framing" language. Higher risk, touches ~45 files, and
doesn't actually change runtime. **Not recommended** unless the lead
specifically wants the naming to match post-cascade vocabulary.
## Recommendation
Go with **Option A**. The enum is architecturally sound, the ticket is
a casualty of the v0.2→cascade pivot, and the cleanup is documentation-
only. I have completed #877 cleanly; I'll park #878 in_progress pending
the lead's call on A/B/C.