# M125 — closing 4 vapor gaps

An audit of prior M125 PRs revealed 4 places where specs / dead code / lies shipped instead of working code. This PR finishes each one with verified end-to-end tests.

Gap 1 references/boot-sequence.md described fictional portless API
FIXED

### Before — fictional

portless start --domain $SUBDOMAIN --tls --lan --background
portless ls --json | jq ...
portless stop --domain $SUBDOMAIN

### After — verified portless 0.10.x

portless proxy start (no --domain flag)
portless <name> <cmd> (wraps, not sidecar)
portless list (text, not JSON)
portless get <name> (canonical URL)
Gap 2 references/state-schema.md described wrong shape
FIXED

    // Before — described 4 keys, actual file has 2-3 (wrapper-fused)
    processes: {
      portless?:  { pid, command },
      devServer?: { pid, command },
      emulate?:    { pid, command },
      agentBrowser:{ sessionName }
    }
    // After — matches what boot.sh actually writes
    processes: {
      portlessWrapper: { pid, command },  // owns dev server lifecycle
      agentBrowser:    { sessionName },
      emulate?:        { pid, command }
    }

Gap 3 posttool/expect/snapshot-recorder was dead code
FIXED

    // Hook regex: /ROUTE\|([^\n|]+)/ and /ARIA\|(.+)/
    // Reality: /ork:expect emits RUN_COMPLETED|passed but NEVER ROUTE| or ARIA|
    //          → hook fired, found neither tag, exited silent on every run

    Patches:
    1. expect/scripts/report.sh — pass-through ROUTE| and ARIA| tags from stdin
    2. expect-agent.md — emit ROUTE|<path> before route's first STEP_START
                         emit ARIA|<capped json> after route's last STEP_DONE

    Smoke test (synthetic input):
    $ cat input.json | node bin/run-hook.mjs posttool/expect/snapshot-recorder
    {"continue":true,"hookSpecificOutput":{"additionalContext":
      "ARIA snapshot recorded: route=/dashboard commit=0ce30edd."}}
    $ cat .claude/state/expect-snapshots/dashboard/0ce30edd*.json
    {
      "route": "/dashboard",
      "parentCommit": "0ce30eddea2a3e17ae02eb7c93b70b633c72f181",
      "capturedAt": "2026-04-27T20:10:50.368Z",
      "ariaSummary": "{\"role\":\"WebArea\",\"name\":\"Dashboard\"}"
    }

Gap 4/ork:emulate-seed --auto was spec-only (no scripts/ dir)
FIXED

    New: src/skills/emulate-seed/scripts/auto-discover.sh

    3 modes:
      (default)  report mappings on stderr
      --json     emit machine-readable JSON
      --apply    write emulate.config.yaml (refuses overwrite without --force)

    Verified end-to-end against synthetic package.json:
      next-auth + stripe + @vercel/blob + @octokit/rest

    Output:
    Detected:
      @octokit/rest  →  github · Any GitHub API client
      next-auth      →  google-oauth, apple-auth, microsoft-entra
      stripe         →  stripe
      @vercel/blob   →  aws · @vercel/blob is S3-compatible

    Union: apple-auth, aws, github, google-oauth, microsoft-entra, stripe

    --apply writes valid YAML:
      services:
        apple-auth: {}
        aws: {}
        github: {}
        google-oauth: {}
        microsoft-entra: {}
        stripe: {}

## Verification — all green

    npm run build                  ✓ 108 skills, 37 agents, 27 commands
    bash scripts/stamp-counts.sh --check   ✓ idempotent
    npm run test:mdx               ✓ 256/0
    bash bin/validate-counts.sh    ✓ 107 / 37 / 185, version 7.73.0

    End-to-end smoke tests:
      /ork:dev boot/stop/status    ✓ already verified in #1536
      emulate-seed --auto          ✓ synthetic + real test
      snapshot-recorder hook       ✓ writes per-(route,commit) JSON
      expect protocol              ✓ ROUTE/ARIA tags pass through report.sh