The AS4 dual-lens review approved the port as exact and required a
docs-only fix round:
- Ground truth §2b row 1: the Society gate is PRESENCE of Int 281
(AppraisalProfile::InqInt @0x005B3830 returns found/not-found), not
value!=0; the color rule is same-bit-first (@0x004b49fd/@0x004b4a49/
@0x004b4a8b) so a multi-bit local player still resolves green on a
match; the ??? arm precedes the Radiant Blood test.
- Ruling R5 corrected: the row model carries CreatureAppraisalValueStyle
but ResolveColor is a deliberate no-op until AP-110's FontInfo-list
residual lands — the Society green/red is model-only and invisible at
the connected gate; AS6's script must not gate on row colors.
- Ledger: AS4 land 4ade9b04; true full-solution hermetic count is 15,528
(the AS4 commit body's 15,410 was a mis-report; the review re-ran and
reconciled 15,483 + 45 new = 15,528).
- #442 filed: pre-existing parallel-load flake in the shadow-caster
zero-allocation pin, surfaced by the review's full-solution run;
isolation evidence recorded; unrelated to Campaign AS.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
9.3 KiB
Campaign AS — assess/examination window retail parity (player targets)
Status: EXECUTING — AS1 research synthesis complete 2026-08-25; slices final.
Owner report (2026-08-25, side-by-side screenshots, acdream vs retail, both assessing the player "Dww"): acdream's examination window on a PLAYER target is missing retail's identity block and body/config sections.
Missing vs retail:
- Identity block under the title bar: gender + heritage ("Female Aluvian"), current display title ("War Mage"), PK status ("Non-Player Killer") — none of it rendered by acdream.
- Per-bodypart armor levels: retail shows three grouped rows — "Head/Chest/Groin AL: x/y/z", "Bicep/Wrist/Hand AL: x/y/z", "Thigh/Shin/Foot AL: x/y/z". Absent in acdream.
- Target-configurable extras: retail only shows what the assessed player configured to show (date of birth, age, number of deaths, chess rank, fishing skill, damage/crit ratings, …). acdream shows a "Dmg/CritDmg Rating:" line but not the rest of the family.
- Allegiance/faction lines: allegiance name/patron/faction shown when the target has them. Absent in acdream.
Explicit owner rulings:
- The animated 3D paperdoll is an INTENTIONAL acdream deviation
(register row AD-114, filed at AS2). Retail's examine preview clone is
NOT a static tinted preview — it is INDEPENDENTLY ANIMATED, just
decoupled from the live target:
BasicCreatureExamineUI::Init @0x004AB9C0clones the selected object viaCPhysicsObj::makeObject @0x005144B0(which runsMorphToExistingObjectthenplay_script_internal(setup->default_script_id)), sets the clone's heading to 191.367905°, andCreatureMode::Render @0x004529D0runsupdate_positionon it every frame. acdream's deviation is that our preview mirrors the target's LIVE motion instead of playing its own private, decoupled cycle. Keep ours. (Retail's preview colors are also buggy on the owner's reference setup, so porting the decoupled clone would not even be a faithfulness win.) - Retail comparison is the oracle for text composition; all strings come from DAT StringTables per the decomp — never hardcoded English literals.
- All UI work goes through the standard GUI classes (UiLabel / UiPanel / UiScrollablePanel / retail chrome) — no bespoke widgets, no quick fixes.
Execution model (set by owner)
- Fable plans and coordinates (this doc + slice contracts + synthesis).
- Sonnet implements each slice against a pinned contract.
- Opus runs the dual-lens review per slice — retail-faithfulness lens + architecture lens — followed by a fix round; slice is REVIEW-CLOSED only after the re-review accepts the fixes.
- Commit to the worktree branch (
claude/windmill-seam-and-solid-polys) as slices land, full hermetic suite green each time (Lane!=InstalledDat&Lane!=PreparedPackage&Lane!=Live&Lane!=Manual&Lane!=Timing&Lane!=Windows&Lane!=Linux&Lane!=SystemFont&Purpose!=Diagnostic&Status!=KnownFailure). - Do NOT push to gitea until the owner says so.
- Campaign stops when all slices are REVIEW-CLOSED and the connected-gate script is written and waiting on the owner's drive.
Ground truth sources
docs/research/named-retail/acclient_2013_pseudo_c.txt— the retail examination window class, line composition, StringTable keys, 0x00C9 client-side parse.references/ACE/— what our live server actually sends per flag, and the target-option gating rules.references/Chorizite.ACProtocol/— field-order cross-check.- Campaign CT sealed verdicts (
claude-memory/project_character_panel_campaign.md) — the heritage/title composition and PK bitfield rules already ported for the character panel; REUSE, do not re-derive. - Research synthesis doc (AS1 output):
docs/research/2026-08-25-campaign-as-ground-truth.md.
Slices (FINAL — re-cut at AS1: the 0x00C9 parse is already complete and
the appraisal profile is session-scoped UI presentation state flowing through the established router seam, so the skeleton's wire and runtime-owner slices are unnecessary; all work is App-side composition)
Oracle for every slice:
docs/research/2026-08-25-campaign-as-ground-truth.md (AS1 synthesis) —
its §2 line-composition tables, §3 wire truth, §4 gap ledger G1–G10, and
§5 rulings R1–R8 are BINDING on implementers and reviewers. Deviating from
a ruling requires a plan-doc amendment, not an implementer judgment call.
- AS1 — ground truth synthesis (DONE, Fable). Three research lenses merged; gap ledger G1–G10; rulings R1–R8.
- AS2 — header identity block (Sonnet). Fix the element mis-mapping in
AppraisalUiController.ApplyCreature(character: true)per ground truth §2a:0x10000150← composed gender+heritage (reuseCharacterIdentityText, including retail's heritage-id overrides and the creature fallback when heritage==0);0x10000151← current display title viaCharacterTitleResolver(Int 261, fallback String 5 Template);0x10000152← PK line from the assessedClientObject's PWD bits (PlayerKillerStatusBitfield, ruling R7);0x1000053A← String 47 AllegianceName gated on Int 30 ≥ 1, DELETING the invented "Assessment incomplete" literal. First-everAppraisalView.Charactercontroller tests (G10). Register: file the animated-paperdoll AD row (owner-ruled intentional deviation 2026-08-25) in this commit. - AS3 — armor-level rows + extras-list plumbing (Sonnet). Plumb
Parsed.ArmorLevelsinto the extras composer (signature change from barePropertyBundle); emit the spacer + three grouped AL rows before the rating rows per ground truth §2b rows 3–7, including the*%d≥9999 unenchantable rendering, retail's per-row rating gates (307|313|314 · 308|315|316 · 350|351), spacer discipline per ruling R4, and the* = Unenchantablelegend per ruling R3 (unconditional, gate-verified). Ordering pinned by tests. - AS4 — society/allegiance/fellowship + configurable extras (Sonnet).
Ground truth §2b rows 1–2 and 8–14: the Society row with rank bands and
the local-vs-target faction color rule; the Monarch/Patron/Followers
cascade; Fellowship; Arrived in Dereth; Time in Dereth (locate or port
ClientUISystem::DeltaTimeToString— grep for an existing port first); Chess Rank; Fishing Skill; Deaths ("Has never died" at ≤0); Titles Earned. Register: narrow AP-110 ("exhaustive character detail regions" clause retires) in this commit. - AS5 — allegiance rank-title table (Sonnet). Port the 17-function
heritage×gender
AllegianceSystem::GetTitle @0x005B8DD0table (census per AP-109's corrected 2026-08-25 text: 11 heritages → 17 functions, ~170 strings; Gearknight/Tumerok male-only reused, Lugian female-only reused, Penumbraen aliases Shadowbound, Olthoi excluded by the unsigned range check) +AllegianceData::GetFullName @0x005B6950; wire the examination title bar (rank fromprops.GetInt(0x1E), ruling R8) AND the character panel's name line (closing AP-109's residual). Register: retire AP-109 in this commit. - AS6 — connected gate script (Fable). User-driven script
docs/research/2026-08-25-campaign-as-test-script.md; two-client where needed (allegiance/fellowship/PK lines, deception-failure rendering); includes the R3 legend retail-side-by-side check and the owner's configurable-extras toggle matrix.
Slices AS2→AS3→AS4 are SERIAL (all touch AppraisalUiController /
CreatureAppraisalRows — coupled-file rule); AS5 may run after AS4's
review closes. Each slice: Sonnet implements → full hermetic suite green →
commit → Opus dual-lens review (retail-faithfulness + architecture) → fix
round → narrow re-review → REVIEW-CLOSED.
Ledger
| Slice | State | Land / fix commits | Notes |
|---|---|---|---|
| AS1 | DONE 2026-08-25 | (docs commit) | 3-agent research; ground-truth doc committed |
| AS2 | REVIEW-CLOSED 2026-08-25 | f8a22589 / cc5290af |
port exact per dual-lens review; 6 findings (docs/test/refactor) fixed; +AD-114 (animated paperdoll), +AD-115 (title clear-vs-stale), PK bits promoted to PublicWeenieFlags; carried follow-up chip: 3 more Core PK-bit copies |
| AS3 | REVIEW-CLOSED 2026-08-25 | 1616cd3d (no fix round) |
APPROVE first pass — trio/legend/monster-path exact by offset-level decomp verification; R3 flattening theory disproven at source; ratings adjudication: pre-AS3 code already retail-exact. 5 NITs: 12 (legend-order comment), 11 (stronger refresh test) fold into AS4; 14/15 done in the close commit; 13 (geometry-keyed test helper) noted |
| AS4 | fix round (docs-only) applied, re-review pending | 4ade9b04 + docs fix commit |
port exact per dual-lens review (presence-gate adjudicated FOR the implementer at InqInt @0x005B3830; Time-in-Dereth = pre-existing RetailDurationText @0x00565E10 port, correct reuse); fix round was oracle-doc corrections + records only, NO code change. True full-solution hermetic count 15,528 (the commit's 15,410 was a mis-report). AS6 carry-note: the Society green/red colorIdx is MODEL-ONLY (ResolveColor no-op pending AP-110 FontInfo residual) — the gate script must NOT gate on row colors. Pre-existing parallel-load flake surfaced (shadow-caster zero-alloc pin) — filed in ISSUES, unrelated to AS4 |
| AS4 | pending AS3 review-close | — | |
| AS5 | pending AS4 review-close | — | |
| AS6 | pending AS5 review-close | — |