# Campaign OP — retail four-tab Options panel > **For agentic workers:** slices are executed by ONE Sonnet implementer at a > time against this contract, then dual-lens Opus-reviewed, per the binding > process rules in §8. The four research docs in §1 are the spec's data > appendix — implementers MUST read the cited sections before coding; every > table this plan references by section number is committed there in full. **Status: CODE-COMPLETE 2026-08-11, PARKED 2026-08-11 (user direction) — all nine slices landed and reviewed; OP1/OP2/OP7/OP9 CLOSED; OP3–OP6 + OP8 owe their connected user gates.** Four connected gate rounds ran before parking; every finding was root-caused and fixed same-day: #372 (blank tabs + click diagnostics), #374 (dropdown pointer routing; #376 split out), #375 (keyboard string resolver + parked prototypes + tab activation), #371 (viewport clip), the AD-78 store-only dimming (user-directed), and the gate-4 batch #378–#382 (dropdown chrome, chat-only opacity scope, slider captions from DAT catalog 0x78000000, the AP-205 footer field, the AP-206 state-cascade fix). **Resume point: the gate-4 fixes (`c1218426`..`d1c60df9`) are committed and probe-verified but have NOT been seen by human eyes — the user's re-check of those five plus the full §OP3–§OP6/§OP8 script is the remaining work. Launch with `ACDREAM_RETAIL_UI=1`.** Gate script: `docs/research/2026-08-11-campaign-op-test-script.md`. Open tail: #373, #376, #377 (fullscreen startup crash — settings.json workaround noted in the issue), AP-198/199/202/203/205/206, the Shift-chord display cosmetics and the radar-text-over-panel z-order noted in session.** **Goal:** retail's four-tab in-game Options panel (Gameplay Options / Character / Chat / Config), retail-faithful mechanics end-to-end: authored LayoutDescs, the real option storage/wire split (`0x0005` single-option vs the batched `0x01A1` PlayerModule blob), retail Apply/Reset/Defaults semantics, live consumers where acdream has the subsystem and honest store-only + register rows where it doesn't, plus the headless-bot `characterOptions` seam. Campaign handoff: `docs/research/2026-08-10-settings-track-handoff.md`. **Architecture:** the panel is retained retail UI exactly like Campaign CH's chat windows — LayoutDesc `0x2100002B` imported through `LayoutImporter`, mounted in the `gmFloatyPanelUI` host `0x2100006E` under `RetailWindowManager`, driven by a focused controller. All option storage/policy is Runtime-owned (`RuntimeCharacterOptionsState` widened to the full retail table); the graphical panel and the headless host are both consumers of the one generation-gated `IRuntimeCharacterCommands` seam (CH3's precedent). Wire builders live in `AcDream.Core.Net` beside the existing `0x0005` codec. **Tech stack:** existing retained UI stack (`DatWidgetFactory`, `LayoutImporter`, `UiRoot`, `RetailWindowManager`), `AcDream.Runtime` gameplay owners, `AcDream.Core.Net` message builders, `DatCollection` for DAT reads. No new dependencies. --- ## 1. Research base (committed; the spec's data appendix) | Doc | What it pins | |---|---| | `docs/research/2026-08-10-options-panel-structure.md` (lane A) | Layout `0x2100002B` structural inventory (§10.1), tab table property `0x2E`, row-template mechanism (ListBox `P0x64` + `AddItemFromTemplateList`), Apply/Reset/Defaults + visibility semantics (§6, §10.4), Chat tab's 13 checkbox masks + defaults (§8), Config tab's 27 rows + `UserPreferences.ini` keys (§9), open path (F11 action `0x1000001A`, toolbar button `0x1000019B`) | | `docs/research/2026-08-10-character-options-map.md` (lane B) | The 50-row / 6-group Character-tab inventory with per-row storage bit, wire route, ACE handling, acdream consumer state (§2–§5); implement-vs-store split (§7.1); bot tiers (§5.2) | | `docs/research/2026-08-10-set-character-options-wire.md` (lane C) | The `0x01A1` body = `PlayerModule::Pack` field order (§2.3–§2.7), header invariant `0x460`, the 21-id auto-save table (§3.2), 480 s timer + logout + Apply flush triggers (§3.3–§3.5), ACE acceptance/landmines (§5), CH3 builder post-mortem (§6) | | `docs/research/2026-08-10-keyboard-config-and-gameplay-tab.md` (lane D) | The seven Gameplay-tab button behaviours with byte-verified strings (§1–§4), `gmKeyboardUI` structure + DAT ActionMap storage (§5–§6), per-button implementability (§7.1), Config-tab ordered dump (§7.3) | Coordinator-verified during planning (this session): toolbar button `0x1000019B` authors `P0x12 = 0x1000001A` (committed fixture); `retail-default.keymap.txt:148` binds `ToggleOptionsPanel` to `DIK_F11`; `PlayerModulePackHeader` verbatim at `acclient.h:7835`; the headless local-write gap at `src/AcDream.Runtime/Session/DirectGameRuntimeCommandAdapter.cs` (`SetSingleOption`) vs `src/AcDream.App/Net/LiveSessionRuntimeFactory.cs:347`; **U1 closed**: `UIOption::InqDefaultGameplayOptionProperty @0x004ef8d0` resolves per-option defaults from the DAT `DBPropertyCollection` at `DBCache::GetDIDFromEnumStatic(0x16, 2)` — the Defaults button restores DAT-authored values. ## 2. Design decisions (stated, per the campaign directive; reactable at gates) - **D1 — the retail Options panel is acdream's one in-client settings surface.** Lane D established the F11 `SettingsPanel` was never rendered post-V11 (`ToggleSettingsPanel()` no-op; only `IPanelRenderer` is a test fake). Retail's own F11 IS `ToggleOptionsPanel`. So: F11 + the toolbar button open THIS panel; acdream's client-only settings live on the **Config tab** (retail's own client-settings tab — its 27 rows are `UserPreferences.ini` preferences, nothing on the wire), backed by acdream's existing settings store. The old `SettingsPanel`/`SettingsVM` IPanel surface is retired in OP9; its tested keybind model feeds OP8. - **D2 — retail's wire split ships exactly.** The 21 auto-save ids send `0x0005` immediately; the rest dirty the module and ride the real `0x01A1` blob with retail's three flush triggers (Apply, logout, 480 s timer). No "send everything as 0x0005" shortcut (lane C: the split is load-bearing in both directions). - **D3 — the 50th Character row ships.** "Listen to PK death messages" is 2015-client; the DAT string exists (`0x0D16E9A3`), ACE maps id `0x34` ↔ `CharacterOptions2 0x02000000` but never reads it. Ship the row (user-gate axiom: the user's retail memory includes it), wire+store only, register row for the ACE-sourced 2013-unverifiable mapping. - **D4 — Configure Keyboard is the campaign's rebind screen** (it is the ONLY rebind screen — D1). Port `gmKeyboardUI`'s shape and DAT ActionMap data (lane D Option C) but persist to `keybinds.json`; retail `.keymap` file interchange is a register-row deferral. - **D5 — dead-endpoint buttons short-circuit to their own retail failure strings.** Urgent Assistance / Report Abuse open a defunct `support.turbine.com` URL in retail; acdream skips the browser launch and emits the button's own byte-verified failure notice through the interface-text seam (retail text, not invented), register rows filed. In-Game Help mirrors retail-with-missing-`ACHelpPlugin.dll` behaviour. - **D6 — Exit to Character Selection behaves as Exit Game** (+ register row) until a pre-world character-select flow exists, but retail's confirmation dialog (`ID_Client_EndCharacterSessionConfirm`) and mid-air refusal ("Cannot log off while in mid-air.", byte-verified) ship now. - **D7 — Group C re-points to server truth.** The seven currently-live `settings.json`-backed options (lane B §7.1 group C) become server-bit-authoritative per CH3 precedent (reseed from PlayerDescription; local-write-then-send). `GameplaySettings`' 16 server-shadowing booleans die in OP9. - **D8 — bots declare options by NAME.** The K1 strict config gains an optional `characterOptions` block accepting exactly the lane-B tier-1+2 names; unknown names fail load (ACE throws on unknown ids — never let one reach the wire). Diff-then-send after PlayerDescription seeds state; idempotent on reconnect. ## 3. Slice map Dependencies: OP1 → (OP4, OP7); OP2 → (OP3, OP4, OP5, OP6, OP8); OP3 → OP4/5/6 (the shell hosts the tabs). OP7 needs only OP1. Execution order below is the default; OP7 may run any time after OP1 when the tree is free. | Slice | Contract (summary) | Gate | |---|---|---| | OP1 | Runtime option map + dirty model + the real `0x01A1` builder + headless local-write fix | automated only | | OP2 | Type 8 tab control + Type 5 template-list ListBox + remaining `UIOption_*` widget mappings + fixtures | automated only | | OP3 | Panel shell + open paths + Gameplay tab end-to-end | user (connected) | | OP4 | Character tab: 50 rows, consumers, Apply/Reset/Defaults | user (connected) | | OP5 | Chat tab: opacity sliders + 5 per-window filter blocks | user (connected) | | OP6 | Config tab: 27 rows over the client settings store | user (connected) | | OP7 | Headless `characterOptions` block | automated + bot-vs-ACE run | | OP8 | Configure Keyboard screen | user (connected) | | OP9 | Closeout: retire dead surfaces, bookkeeping, test script | user (final matrix) | --- ## 4. Slice contracts ### OP1 — the Runtime option map, dirty model, and the real blob **Files.** - Modify `src/AcDream.Runtime/Gameplay/RuntimeCharacterState.cs` (`RuntimeCharacterOptionsState`, `:628`): widen to the full table. - Create `src/AcDream.Runtime/Gameplay/CharacterOptionTable.cs`: the ONE typed table `PlayerOption id → (word: Options1|Options2, mask, isAutoSave, clientDefault)` for ids `0x00..0x34`, transcribed from lane B §2 (verbatim `acclient.h:4162` enum names) + lane C §3.2 (auto-save column) + D3's `0x34` row. Reject `0x35`/`0x36` and unknown ids at the seam (lane C §5.4.3 — ACE throws). - Modify `src/AcDream.Runtime/GameRuntimeCommands.cs`: add `IRuntimeCharacterCommands.SaveOptions(RuntimeGenerationToken)` (the blob-flush verb) beside `SetSingleOption`. - Modify `src/AcDream.Runtime/Session/DirectGameRuntimeCommandAdapter.cs` and `src/AcDream.App/Runtime/CurrentGameRuntimeCommandAdapter.cs` + `src/AcDream.App/Net/LiveSessionRuntimeFactory.cs:335-350`: move local-write-then-send INTO the shared Runtime seam so BOTH hosts get retail's ordering (fixes the headless gap lanes B+C independently found). The `LiveSessionRuntimeFactory` local closure is deleted, not duplicated. - Create `src/AcDream.Core.Net/Messages/SocialActions.cs` addition: `BuildSetCharacterOptions(...)` per lane C §2.7 EXACTLY — header always `0x460` OR-ed with present optional sections; four unconditional u32s (header, options1, spellbookFilters, options2 in pack order §2.3); echo last-parsed shortcuts / 8 spell lists / desired comps rather than zeroing (§5.3); NEVER set `0x100` (lane C U2); omit `0x200` while acdream packs nothing (safe per §2.5); 4-byte tail pad. - Modify `src/AcDream.Core.Net/WorldSession.cs`: `SendSetCharacterOptions`. - Dirty model in `RuntimeCharacterOptionsState`: `MarkDirty` on any non-auto-save change, `FirstDirtiedAt`, flush triggers = explicit `SaveOptions` command, session logout, and the 480 s timer (retail constant, lane C §3.3) driven from the existing Runtime tick. - Tests: `tests/AcDream.Runtime.Tests/` (table completeness ×53, auto-save split ×53 vs lane B §2's byte-verified column, local-write-then-send on BOTH adapter paths, dirty/flush state machine, unknown-id rejection); `tests/AcDream.Core.Net.Tests/` blob conformance: golden byte vector + round-trip through `PlayerDescriptionParser` (lane C §9 S-c — the CH3 builder died of green tests pinning a wrong shape; the golden vector is non-negotiable). **Register rows (same commit):** `0x34` mapping ACE-sourced (D3); the 480 s autosave if any part is deferred (target: not deferred); `GetDefaultOptionValue @0x005D2A30` vs ctor-default disagreement recorded when the client-default column lands (lane C §8.2 — reproduce, don't fix). **Acceptance:** build + FULL Release suite green; blob golden vector byte-exact; both adapters share one code path for the local write. ### OP2 — the two widget primitives + remaining UIOption mappings **Files.** - Modify `src/AcDream.App/UI/Layout/LayoutImporter.cs` + `src/AcDream.App/UI/Layout/ElementReader.cs`: read tab-table property `0x2E` (struct array `{0x30 button, 0x31 page, 0x32 isDefault}`) and ListBox template-list property `0x64` (entries `{0x63 layout DID, 0x62 element id}`) into `ElementInfo`. - Create `src/AcDream.App/UI/UiTabPanel.cs` (element Type 8 — retail `UIElement_Panel`; renamed from this plan's original `UiTabControl` at the OP2 rework, and a dormant `UiDatElement` subclass per AD-73): tab-button ↔ page-slot switching per lane A §5; default tab honoured. - Create `src/AcDream.App/UI/UiTemplateListBox.cs` (element Type 5 with authored template list): `AddItemFromTemplateList(index)` instantiates a row from the authored template layout/element via `DatWidgetFactory`, scrollbar named by `P0x72`. - Modify `src/AcDream.App/UI/Layout/DatWidgetFactory.cs`: map Types 5/8 and `UIOption_Slider 0x10000037`, `UIOption_Menu 0x10000038`, `UIOption_CheckboxSlider 0x10000036`, `UIOption_CheckboxBitfield64 0x10000044` (LED checkbox `0x10000035` already maps to `BuildCheckbox`). - Modify `tests/AcDream.App.Tests/UI/Layout/RetailLayoutFixtureGenerator.cs` (`Layouts`, `:17`): add `0x2100002B`, `0x2100002A`, `0x21000028`, `0x2100005C`, `0x21000029`. **Coordinator runs the generator** (`ACDREAM_REGENERATE_UI_FIXTURES=1`, serial tree) and commits fixtures. - Conformance tests pin: the tab table (4 entries, Gameplay default), all three template arrays (lane A §10.1), the Character ListBox's 6-header / 49-toggle authored row build, scrollbar linkage. **Acceptance:** build + FULL suite; fixtures committed and pinned; no change to any existing widget's behaviour (the S2/AP-192 outline seams from `aa6635ae` must be preserved in new widget builds). ### OP3 — panel shell + open paths + Gameplay tab (first vertical) **Files.** - Create `src/AcDream.App/UI/Layout/OptionsPanelController.cs`: mounts `0x2100002B` in host `0x2100006E` slot `0x1000018D` (stack key 10) via `RetailWindowManager`; tab control wiring; close button fires `0x1000001A`. - Create `src/AcDream.App/UI/Layout/OptionPageModel.cs`: the `OptionPage`/`PlayerOptionPage` model — per-page option array of `(current, saved, default)` triples + verbs Apply/Reset/Defaults with retail's exact semantics (lane A §10.4): LED click applies immediately (`SetCurrentValue → Apply(1)`); Apply commits baseline + `SaveOptions` flush; Reset reverts to baseline; Defaults applies live without committing and is never disabled; Apply/Reset disable when clean; hide → revert uncommitted; show → apply + commit. Pure logic, unit-tested without DAT. - Input action `ToggleOptionsPanel` (`0x1000001A`, F11) in `src/AcDream.UI.Abstractions/Input/` (`KeyBindings.RetailDefaults()` — the ONLY production table; #358's lesson) + `src/AcDream.App/Input/GameplayInputCommandController.cs` routing + toolbar button `0x1000019B` (already authors `P0x12`). - Gameplay tab (`0x2100002A`, class `gmGameplayOptionsUI`), seven buttons per D5/D6 and lane D §1: Exit Game → the existing graceful-close path; Exit to Char Selection → retail confirm dialog (`RetailDialogFactory`) + mid-air refusal via the interface-text seam, then D6's Exit-Game behaviour; Configure Keyboard → opens OP8's screen; until OP8 lands the button is INERT (authored, clickable, no handler — no invented text, no stub screen), the OP3 gate script says so explicitly, and OP8's gate re-tests it (the campaign cannot close with the button inert); Use Mouse Turning Settings → the six-option macro (lane D §4.4) with its six retail chat lines, camera-mode consumer verified against the camera digest in-slice (register row if the mode is absent); In-Game Help / Urgent Assistance / Report Abuse per D5. **Register rows:** Exit-to-char-select adaptation (D6); UA/RA dead-URL short-circuit (D5); help-plugin behaviour (D5); mouse-turning consumer row if needed. **Gate:** connected — panel opens via F11 AND toolbar; tabs switch with Gameplay default; the seven buttons behave per contract; window drags / resizes / stacks like the CH6 floaties. ### OP4 — the Character tab **Files.** - Create `src/AcDream.App/UI/Layout/CharacterOptionsPageController.cs`: binds layout `0x21000028` root `0x100001F9` ListBox `0x100001FA` through OP2's template mechanism; 6 headers + 50 toggles (D3) in lane B §2's authored order; every row bound by `PlayerOption` id through OP1's table and the shared seam (auto-save ids → `0x0005` on click-apply; batched ids → dirty + blob per OP1). - Defaults: extract the DAT `DBPropertyCollection` (`GetDIDFromEnumStatic(0x16, 2)`, §1 U1-closure) via `DatCollection` at import; conformance-pin extracted values; cross-check overlapping ids against lane B/C's byte-verified default words and RECORD any disagreement as a finding (never silently pick). - Consumers (lane B §7.1): group B one-line binds — timestamps + filter language at `RuntimeCommunicationState.AddText`; daylight (`ForcedDayGroupIndex`), weather, fog; run-as-default in `RuntimeLocalPlayerMovementState`; main-pack default at the pickup path; the UI-display bits at their existing retained controllers. Group C re-pointing per D7. Group A wire+store only. Group D register rows. - Conformance test: all 50 rows ↔ table ↔ storage bit ↔ wire route pinned in both directions (the CH4 registry-conformance pattern — an invented row or a dropped row fails the build). **Register rows:** group D deferrals (salvage, housing, fellowship-share field, PK-deaths already rowed in OP1, mouse-turning row lives in OP3); each group-C re-point that changes an observable default. **Gate:** connected — LED rows toggle + persist across relogin (server echo), timestamps/daylight/fog/weather/run-default observably switch, Apply / Reset / Defaults exercise retail semantics, tab-switch reverts uncommitted edits. ### OP5 — the Chat tab **Files.** Create `src/AcDream.App/UI/Layout/ChatOptionsPageController.cs` binding `0x2100005C` root `0x1000050A`: the two LINKED opacity sliders (bound to the existing `RetailWindowOpacityController` values through `ChatOpacityLink` — AP-190's model, now user-reachable) and the five per-window filter blocks (SetUserData ids 8/2/3/4/5; main window 12 rows, floaties 13 — lane A §8's byte-decoded masks) writing the per-window filter state CH6 already consumes (`ChatWindowState.ShouldDisplay`). The `0x1000008C` per-window blob stays local-only (already-anticipated register row from `2026-08-09-chat-retail-window-shell.md` §6.3 — cite, don't duplicate). **Gate:** connected — filter checkboxes change window routing live; opacity sliders drive the focus fade; settings survive relogin locally. ### OP6 — the Config tab **Files.** Create `src/AcDream.App/UI/Layout/ConfigOptionsPageController.cs` binding `0x21000029` root `0x100001FF`: all 27 rows in lane A §9 / lane D §7.3's authored order, backed by acdream's client settings store (`%LOCALAPPDATA%\acdream\` — the D1 home). Rows with live subsystems bind now: the three volume trios → the audio pipeline, "play sound only when active", mouse-look sensitivity + invert Y, FOV, chat font size/face if the chat pipeline exposes them. Rows without a subsystem (resolution + fullscreen + sync, degrades, texture detail family, multi-pass alpha) persist store-only under ONE register row enumerating them (the goal's "honest store-only handling"); resolution's `SetConfirmChange` flow ships whenever the consumer lands, not now. **Gate:** connected — audio sliders audibly change mix; mouse sensitivity observably changes; store-only rows persist across relaunch. ### OP7 — headless `characterOptions` **Files.** Modify `src/AcDream.Headless/Configuration/HeadlessConfiguration.cs` + `HeadlessConfigurationLoader.cs`: optional `characterOptions` block, strict — keys are exactly the lane B §5.2 tier-1+2 option NAMES, values bool; unknown key = load failure (D8). Modify the session host (`src/AcDream.Headless/Hosting/`) to diff declared vs PlayerDescription-seeded state after LoginComplete and send changes through the shared seam (auto-save ids as `0x0005`, remainder via one `SaveOptions` blob), honouring #368's one-dedicated-update-thread contract. Idempotent on reconnect (retail itself no-ops unchanged options — lane C §3.5). Headless tests: schema rejection, diff-only sends, reconnect idempotence, thread affinity preserved. **Gate:** automated + one live bot-vs-local-ACE run (no graphical client) showing declared options land and survive reconnect. ### OP8 — Configure Keyboard **Files.** Create `src/AcDream.App/UI/Layout/KeyboardConfigController.cs` (+ a `src/AcDream.Core/...` DAT `ActionMap` (DBO type `0x27`) reader if `DatCollection` lacks one): `gmKeyboardUI`'s six ActionClass list boxes via OP2's Type 5 widget, rows = label + tooltip + N key buttons + Clear from the DAT master maps (DIDs `0x14000000`/`0x14000002` — the exact enum→DID pairing is lane D unknown #4, resolved in-slice by dumping both), merged with live `KeyBindings`; left-click key button → `InputDispatcher` modal capture; right-click erases; N-way cross-map conflicts + the non-user-bindable refusal per lane D §5; Save/Cancel; Reset-to-defaults reloads the DAT maps. Persistence: `keybinds.json` (D4). **Register rows:** `.keymap` file interchange not implemented (D4); any retail column/behaviour consciously narrowed. **Gate:** connected — rebind a movement key, conflict prompt on a taken chord, persistence across relaunch, reset restores retail defaults. ### OP9 — closeout - Retire `SettingsPanel`/`SettingsVM`'s IPanel surface + `SettingsDevToolsComposition` wiring + `DevToolsGameplayCommands` no-ops; delete `GameplaySettings`' 16 server-shadowed booleans (lane B §7.2.5), re-scoping true client-only settings into the D1 store. Every deletion checked against consumers; no behaviour regression. - Bookkeeping: plan status flips, ISSUES sweep (#358 retest against OP8's screen — its Ctrl+M lesson lives in `RetailDefaults()`), register reconciliation, CLAUDE.md Current-state paragraph (per `feedback_claude_md_staleness`), memory digest update (`project_chat_digest` addendum or a new settings digest). - Write `docs/research/2026-08-10-campaign-op-test-script.md`: the connected-gate script covering every OP3–OP8 gate item, per-tab, with expected retail behaviours — the campaign's stop condition is this script ready plus all slices code-complete. **Gate:** the user's final connected matrix (their eyes, their pace). --- ## 5. What is explicitly OUT of scope - Packing the `0x200` GameplayOptions blob section (per-window chat state on the wire) — a follow-on (CH6f shape), pre-anchored by lane C U1 and `2026-08-09-chat-retail-window-shell.md` §6.3's register row. - A pre-world character-select flow (D6 adapts; its register row carries the future work). - Retail `.keymap` file read/write (D4 register row). - The `0x21000017` docked `gmPanelUI` host variant — acdream ships the floating host only (register row in OP3 if the review deems it a divergence; retail exposes both). ## 6. Verification discipline Per commit: `dotnet build` + FULL Release suite green (baseline at plan time: 12,611 / 4 skips / 0 failures at `29138430`+). Golden byte vectors for every wire builder. Conformance pins for every authored inventory (row lists, template arrays, tab table, checkbox masks). Register rows in the SAME commit as the deviation. No user-visible placeholder text ever — all user-facing strings resolve from the DAT string tables (`0x23000001`/`0x23000003`) by `compute_str_hash` name, never hard-coded English. ## 7. Review protocol Dual-lens Opus review per slice (mechanism-faithfulness lens × regression/blast-radius lens), fixes applied by the implementer; REJECT → focused re-review; TWO failures → Fable fixes directly (user-directed 2026-08-10). Review findings that feed both a fixer and a re-reviewer are persisted to a committed findings doc BEFORE dispatch. ## 8. Process rules (binding, inherited from Campaign CH via the handoff) Max 3–4 agents in parallel INCLUDING children; every agent prompt carries an explicit no-subagent clause; ONE builder/tester on the tree at a time (read-only research may overlap); agents never launch the graphical client; the user runs all connected gates; screenshots transcribed into docs immediately; ledger placeholders anchored per-row, post-amend SHAs recorded by the coordinator; decomp claims byte-verified against the PDB-paired binary (`check_exe_pdb.py` MATCH first); stalled agents resumed via SendMessage before any redo; agent claims spot-verified at the seams before anything builds on them. ## 9. Ledger | Slice | Status | Commit(s) | Review | Gate | |---|---|---|---|---| | OP1 | CLOSED | `86c0a7e0` + fixes `09029f9f` + residuals `6f48e341` | dual APPROVE-WITH-FIXES (`2026-08-10-op1-review-{mechanism,blast}.md`) → re-review CLOSED (`2026-08-11-op1-rereview.md`); residuals R1/R2/R3 landed | automated only — n/a | | OP2 | CLOSED | `df9c7a35` (REJECTED) → rework `b236a442` → closure (this commit) | dual REJECT (`2026-08-11-op2-review-{mechanism,blast}.md`) → re-review blast CLOSED / mechanism REOPEN-on-one (`2026-08-11-op2-rereview-{mechanism,blast}.md`) → coordinator closure: AP-195 filed, AD-73 addendum, tooltip port, zero-children pin | automated only — n/a | | OP3 | CODE-COMPLETE, gate READY | `9d26ecc6` → fixes `386076af` → residuals `cb334690` | dual APPROVE-WITH-FIXES (`2026-08-11-op3-review-{mechanism,blast}.md`) → re-review REOPEN-narrow (`2026-08-11-op3-rereview.md`) → coordinator residuals landed | connected gate OWED (script §OP3) | | OP4 | CODE-COMPLETE, gate READY | `22b86b9f` → fixes `bc43fb1d` → residuals `ac0304dc` | dual APPROVE-WITH-FIXES (`2026-08-11-op4-review-{mechanism,blast}.md`) → re-review REOPEN-narrow (`2026-08-11-op4-rereview.md`) → coordinator residuals landed | connected gate OWED (script §OP4) | | OP5 | CODE-COMPLETE, gate READY | `e71e5a96` (AP-195 retired) → fixes `6d0b0f92` → residuals `67b0815c` | combined APPROVE-WITH-FIXES (`2026-08-11-op5-review.md`) → re-check CLOSED (`2026-08-11-op5-recheck.md`) → coordinator drag residuals landed | connected gate OWED (script §OP5) | | OP6 | CODE-COMPLETE, gate READY | `f5ac1742` (REJECTED) → rework `472525b9` → doc residuals (coordinator) | REJECT (`2026-08-11-op6-review.md`) → re-review CLOSED, all six caption sites byte-decoded (`2026-08-11-op6-rereview.md`) | connected gate OWED (script §OP6) | | OP7 | CLOSED | `09cb548a` → fixes in `7b60e71b` (shared commit, see its message) | combined-lens APPROVE-WITH-FIXES (`2026-08-11-op7-review.md`); all nine findings closed | live bot-vs-ACE gate PASSED 2026-08-11 (coordinator; evidence in script §OP7) | | OP8 | CODE-COMPLETE, gate READY | `b4edee97` (REJECTED) → rework `b1968ce9` → residuals `f1d50207` → merge `1c5cd969` | dual REJECT (`2026-08-11-op8-review-{mechanism,blast}.md`) → rework → re-review REOPEN-narrow (`2026-08-11-op8-rereview.md`) → coordinator round-2 residuals (inert-row conflict exclusion, DAT-default display, injectivity pin; #373 filed) | connected gate OWED (script §OP8) — merged onto the campaign tip AFTER `057d8cd7` per the re-review's merge note, so the #372 viewport fix covers OP8's six ListBoxes | | OP9 | CLOSED | `371197a3` → review residuals `07f2b3f7` | combined-lens APPROVE-WITH-FIXES (`2026-08-11-op9-review.md`, `289bf5bc`): MUST-FIX 1 (SaveAudio→ApplyAudio live-apply lost its only assertion — restored + failure-ordering pin), SF-2 (code-structure.md seam list), SF-3 (dead residues: private SaveCharacter, ISettingsStorage.SaveCharacter, IngressShutdownRoots.Settings — deleted; SettingsStore's public SaveCharacter kept as the tested storage API), SF-4 (test-delta was −84 = 94 removed/10 added, not the commit message's "−80 exactly"; no live-behavior test in the gap besides MUST-FIX 1's), SF-5 (dangling comment), NIT 6 (AP-196 channel attribution corrected in-register) — all closed by coordinator residuals | closeout gate = the user's final connected matrix over §OP3–§OP8 |