# PGM parity staged runbook (2026-07-22)

This runbook is for the designated local development Tornado2/PGM target only.
It does not replace the target, path, hash, listener, package, or `OutcomeUnknown`
stops implemented by `scripts/Invoke-LegacyPgmParityRun.ps1`.

## What is different from the older artifact scripts

- A new evidence directory captures the currently registered package, application,
  PGM, executable hashes, process IDs/start times, window handles, TCP listeners,
  the CDP target, and all 33 authoritative cut hashes exactly once. The 33rd cut is
  `6001`; `5006` remains outside this live inventory until its cube video exists.
- Live staging accepts only the registered x64 loose development package whose
  install root is the current workspace's exact
  `src/MBN_STOCK_WEBVIEW.LegacyParityApp/bin/x64/Debug/<tfm>/win-x64/AppX`
  boundary. A Release, customer-installed, or WindowsApps package is rejected.
- The exact package runtime files pinned are
  `MBN_STOCK_WEBVIEW.LegacyParityApp.exe`,
  `MBN_STOCK_WEBVIEW.LegacyParityApp.dll`, and
  `MBN_STOCK_WEBVIEW.Playout.dll`.
- The `S6001AssetIndependent` workflow additionally pins the authoritative and
  runtime copies of `images\주유기merge.png` and `images\35752913_l.jpg` by length
  and SHA-256 before any input. The 13 country videos are not silently substituted.
- The app-side PGM connection must be entirely loopback and must have exactly one
  reciprocal established row owned by the pinned PGM process. A same-numbered
  port on another host cannot pass preflight.
- Every later stage must match all captured identities before the input, after the
  input, and after read-only evidence capture.
- PGM uses a DirectX surface, so evidence capture temporarily raises only the exact
  pinned PGM or app window without activating it, captures its screen rectangle,
  and restores the original top-most state. This prevents unrelated foreground
  windows from being recorded while preserving keyboard focus.
- Every invocation performs at most one staged action. There is no command retry.
- A timeout, `OutcomeUnknown`, probe violation, identity change, or broken Network
  Monitoring anchor creates `STOPPED.json`. That run directory cannot dispatch a
  later command.
- The validation playlist uses only in-memory `legacy-*` rows. It does not load or
  save a temporary named DB playlist. The comparison build still creates and then
  deletes the same temporary comparison pairs required by the application feature.
- A fresh app instance and a fresh evidence directory are required for each primary
  workflow below. `Recovery8001`, `Recovery5077Page2`, and `ThirtyRoutes20To29` are
  constrained recovery workflows and may start only from their exact known states
  and preserved evidence.

## Static and dry checks

Static validation does not inspect or attach to the app/PGM and sends no native
message:

```powershell
powershell.exe -NoProfile -ExecutionPolicy Bypass -File `
  .\scripts\Invoke-LegacyPgmParityRun.ps1 -Action StaticAudit
```

The current accepted static result pins 33 cuts and reports workflow stage counts
`Core5001=6`, `ThirtyRoutes=125`, `PagedBoundary=24`,
`S6001AssetIndependent=18`, `Recovery8001=1`, `Recovery5077Page2=1`, and
`ThirtyRoutes20To29=41`. Static success is implementation evidence only; it is not
an actual PGM result.

After the current package app and the designated development PGM are running and
connected, a dry preflight reads identities only. It does not attach to CDP, write
evidence, or send a native message. Supply the exact local PGM executable at run
time; do not commit that machine-local path:

```powershell
$pgmExecutable = $env:MBN_STOCK_PGM_EXECUTABLE
if ([string]::IsNullOrWhiteSpace($pgmExecutable)) {
  throw 'Set MBN_STOCK_PGM_EXECUTABLE to the designated development PGM executable.'
}

powershell.exe -NoProfile -ExecutionPolicy Bypass -File `
  .\scripts\Invoke-LegacyPgmParityRun.ps1 -Action DryPreflight `
  -ExpectedPgmExecutable $pgmExecutable
```

## Start one workflow

Choose a primary workflow: `Core5001`, `ThirtyRoutes`, `PagedBoundary`, or
`S6001AssetIndependent`. Use a new, nonexistent evidence directory. Initialization
is read-only with respect to the app and PGM; it freezes the identities and captures
the baseline windows and Network Monitoring text. Do not select `Recovery8001`,
`Recovery5077Page2`, or `ThirtyRoutes20To29` unless the stop handling section's
exact recovery prerequisites are already met.

```powershell
$run = Join-Path (Resolve-Path '.').Path `
  'artifacts\pgm-evidence\MBNWEB-YYYYMMDD-PARITY-01'

powershell.exe -NoProfile -ExecutionPolicy Bypass -File `
  .\scripts\Invoke-LegacyPgmParityRun.ps1 -Action Initialize `
  -Workflow Core5001 -EvidenceDirectory $run `
  -ExpectedPgmExecutable $pgmExecutable
```

Inspect always reports the next required stage without sending input:

```powershell
powershell.exe -NoProfile -ExecutionPolicy Bypass -File `
  .\scripts\Invoke-LegacyPgmParityRun.ps1 -Action Inspect `
  -EvidenceDirectory $run
```

Dispatch exactly that one stage:

```powershell
powershell.exe -NoProfile -ExecutionPolicy Bypass -File `
  .\scripts\Invoke-LegacyPgmParityRun.ps1 -Action RunNext `
  -EvidenceDirectory $run
```

Do not loop `RunNext` blindly. Review its result and the new stage directory before
issuing the next invocation. `RunStage` is also available when the action and route
or page index should be written explicitly; it refuses anything out of order.

## Exact workflow sequences

`Core5001` contains six one-shot stages:

1. bootstrap the safety probe and confirm empty connected IDLE;
2. build in-memory 5001/5074 rows;
3. TAKE IN 5001;
4. playlist NEXT to 5074;
5. Page NEXT from 5074 page 1 to page 2;
6. TAKE OUT 5074.

`ThirtyRoutes` contains 125 stages: bootstrap, four in-memory build phases, then
four stages per route (`activate`, fast TAKE IN for the PGM frame, read-only wait
for settled PROGRAM, TAKE OUT) in this order:

```text
5016, 50160, 5078, 8067, 5086, 50860, 5023, 5024, 5077, 5082,
5083, 5084, 5085, 5088, 6067, 8035, 5011, 8003, 5037, 8001,
5026, 5087, 5029, 8032, 5032, 5076, 5079, 5080, 5081, 5025
```

`PagedBoundary` contains 24 stages: bootstrap, build 5077/5088, TAKE IN 5077,
19 individual Page NEXT inputs through page 20, playlist NEXT to 5088 page 1,
and TAKE OUT. It requires exact fresh-read boundaries of 5077 = 120 items / 6 per
page / 20 pages and 5088 = 240 items / 12 per page / 20 pages.

`S6001AssetIndependent` contains 18 stages: bootstrap, one physical double-click
build stage that creates exactly these four `6001` rows, then four stages per row
(`activate`, TAKE IN, read-only settled PROGRAM wait, TAKE OUT):

```text
fixed-072  유가 두바이 지수  DubaiCrude
fixed-073  유가 WTI 지수     WtiCrude
fixed-074  유가 브렌트유 지수 BrentCrude
fixed-075  금 지수           Gold
```

These actions use only the two globally pinned image assets. They do not exercise
or claim parity for the 13 country-video actions. The workflow is implemented and
its static audit passes, but as of this baseline it has **not** been run against
actual PGM. Do not record it as completed until all 18 one-shot stages succeed in a
new evidence directory.

`Recovery8001` contains one TAKE OUT stage. It is valid only after read-only
inspection proves the interrupted `ThirtyRoutes` run stopped in the exact known,
settled `PROGRAM 8001` state with unchanged identities and
`OutcomeUnknown=false`. It must not be used to guess or repair an unclear state.

`Recovery5077Page2` contains one TAKE OUT stage. It is valid only after read-only
inspection proves the exact preserved `PagedBoundary` manifest is settled in
`PROGRAM 5077`, page 2/20, with 120 items, page size 6, one completed refresh,
no pending command, and `OutcomeUnknown=false`. It is not a general PageN repair.

`ThirtyRoutes20To29` contains 41 stages: one read-only manifest reconciliation and
four stages for each route index 20 through 29. It is valid only after the first 20
routes and the exact 30-row in-memory manifest have been preserved and reconciled.

## Completed evidence baseline

The accepted latest 2026-07-22 development PGM baseline is split across these
preserved directories:

- `MBNWEB-20260722-LATEST-CORE-01`: latest combined `Core5001` 6/6;
- `MBNWEB-20260722-THIRTY-02`: routes 0 through 18 completed and route 19 `8001`
  reached a correct PGM frame. The subsequent read-only wait hit the runner's old
  90-second limit because the original 8001 first-refresh interval is 120 seconds.
  The wait sent no SDK command; the app remained in known `PROGRAM 8001` with
  `OutcomeUnknown=false`. This is a runner timeout, not an app or scene failure;
- `MBNWEB-20260722-RECOVERY8001-01`: after read-only confirmation that the 8001
  refresh had settled, one exact TAKE OUT returned the known state to IDLE;
- `MBNWEB-20260722-THIRTY20-29-01`: constrained resume 41/41, completing routes
  20 through 29;
- `MBNWEB-20260722-LATEST-PAGED-04`: latest combined `PagedBoundary` 24/24,
  including 5077 page 1/20,
  all 19 Page NEXT inputs through 20/20, playlist NEXT to 5088 page 1/20, and
  final TAKE OUT/UNLOAD/IDLE.

The older `CORE5001-05` and `PAGED-01` directories remain historical evidence but
are not the latest combined-code approval. The split thirty-route evidence verifies
all 30 entries in that workflow, and `LATEST-CORE-01` verifies the additional
`5001`/`5074` pair, yielding 32 of 34 active runtime routes with actual PGM evidence.
Network request/success counts match and
`FAILURE`, `ERROR`, safety-probe `blocked`, `violation`, and `OutcomeUnknown` are
all zero; no command was retried. `LATEST-PAGED-04` independently fixes the current
PageN/long-run boundary. `s5006` remains blocked by its cube video. In `s6001`, the
13 country-video actions remain asset-blocked, while the four image-only actions
remain actual-PGM pending rather than asset-blocked.

The suspected approximately 65-second 5077 Page NEXT transition was an observation
artifact, not a runtime defect. Each of the 19 Page NEXT stages emitted exactly one
effect, PREPARE, and PLAY; `SCENE_PLAYED` followed PLAY in 144-188 ms. Immediate,
45-second, and 65-second-named captures for pages 9 and 20 are byte-identical, and
all 17 stages with delayed captures match their immediate capture hashes. The
original and packaged `5077.t2s` files also have the same SHA-256:
`845B99DFC499B5BDCD84058D68D91D849D59FB6692CB44784118A99EA68A20E2`.
Do not add waits or change fade units based on the image-view display inconsistency.

## Stop handling

If `STOPPED.json` exists, do not delete or edit it and do not start another command
from that run directory. Preserve the complete directory, inspect the last stage's
`node-stderr.json`, `node-result.json`, `pins-*.json`, Network text, and screenshots,
then diagnose from read-only state. Never resume the stopped directory itself. The
normal path is a fresh app instance and a new evidence directory after the state is
known. `Recovery8001` and `Recovery5077Page2` are the only same-app single-TAKE-OUT
exceptions; `ThirtyRoutes20To29` is the only constrained manifest continuation.
Use each only in a new evidence directory after every exact known-state prerequisite
above has been proved read-only; otherwise close normally and restart fresh.
