{
  "summary": "Root cause/reproduction finding (public/project-visible surfaces only; no spt-core source inspected): one native OMP bring-up reaches two independent registration paths. The packaged OMP extension explicitly binds the real OMP UUID, while the manifest also asks the broker to resolve identity with `session_id_source = \"post_spawn\"`; the latter produces the synthetic `sess-<pid>-<epoch>` identity. The endpoint ledger therefore contains two rows. Important terminology correction: `boot` is the ledger row's `trigger`, not an adapter. Every observed row has `adapter: \"omp-spt\"`.\n\nObserved fresh-start evidence:\n- OMP transcript header: `2026-07-15T09:59:10.705Z`, session `019f6537-4c71-7000-ab57-ab0d86e9d0a2`.\n- Endpoint ledger: `09:59:11Z` correct UUID, ordinal 0; `09:59:12Z` incorrect `sess-40004-1784109552609931400`, ordinal 1. Both say `trigger:\"boot\"`, `adapter:\"omp-spt\"`.\n- OMP log: listener `READY:emphasys` at `2026-07-15T02:59:13.023-07:00` = `09:59:13.023Z`, PID 54168.\nThus the correct extension bind lands first and the synthetic post-spawn identity follows about one second later.\n\nObserved resume/re-bring-up evidence:\n- Endpoint ledger at `10:29:27Z`: correct existing UUID again (ordinal 2), then incorrect `sess-33500-1784111367400174200` (ordinal 3).\n- OMP listener is ready at `2026-07-15T03:29:27.633-07:00` = `10:29:27.633Z`, PID 28252.\n- `%LOCALAPPDATA%\\spt-core\\owlery\\emphasys\\info.json` is last-writer metadata and currently contains PID 33500 plus synthetic session ID `sess-33500-1784111367400174200`; it does not preserve both registrations.\n- [INFERENCE] This is the native resume path because the correct ledger row reuses the prior OMP UUID and the manifest's resume command passes that ID to `launch-omp --resume`; the observed logs do not themselves label the bring-up `resume`.\n\nExact read-only PowerShell observation commands (no endpoint starts/stops):\n```powershell\n$ledger = \"$env:LOCALAPPDATA\\spt-core\\owlery\\emphasys\\sessions.log\"\nGet-Content $ledger | ForEach-Object { $_ | ConvertFrom-Json } |\n  Select-Object ts,session_id,trigger,cwd,ordinal,adapter\n\nGet-Content \"$env:LOCALAPPDATA\\spt-core\\owlery\\emphasys\\info.json\" |\n  ConvertFrom-Json |\n  Select-Object id,started,pid,session_id,state,adapter\n\nGet-Content \"$HOME\\.omp\\logs\\omp.2026-07-15.log\" |\n  ForEach-Object { $_ | ConvertFrom-Json } |\n  Where-Object { $_.message -in @('omp-spt listener','Session exit recorded') } |\n  Select-Object timestamp,pid,message,sessionId,output\n\n$ompTranscript = \"$HOME\\.omp\\agent\\sessions\\-Documents-projects-omp-spt\\2026-07-15T09-59-10-705Z_019f6537-4c71-7000-ab57-ab0d86e9d0a2.jsonl\"\n(Get-Content $ompTranscript -TotalCount 2)[1] | ConvertFrom-Json |\n  Select-Object timestamp,id,cwd\n```\n\nCanonical deterministic pass/fail assertion over the already-recorded fresh start (read-only and stable even if later rows are appended):\n```powershell\n$ledger = \"$env:LOCALAPPDATA\\spt-core\\owlery\\emphasys\\sessions.log\"\n$rows = Get-Content $ledger | ForEach-Object { $_ | ConvertFrom-Json }\n$from = [DateTimeOffset]'2026-07-15T09:59:10Z'\n$until = [DateTimeOffset]'2026-07-15T09:59:14Z'\n$expected = '019f6537-4c71-7000-ab57-ab0d86e9d0a2'\n$window = @($rows | Where-Object {\n  $ts = [DateTimeOffset]::Parse($_.ts)\n  $ts -ge $from -and $ts -lt $until -and $_.adapter -eq 'omp-spt'\n})\nif ($window.Count -ne 1 -or $window[0].session_id -ne $expected) {\n  $window | Format-Table ts,session_id,trigger,ordinal,adapter\n  throw \"FAIL: one native OMP start must register exactly its OMP session UUID once\"\n}\n'PASS: exactly one endpoint-history registration for the native OMP start'\n```\nIt deterministically FAILS against the observed artifact because the window has two registrations (correct UUID plus synthetic ID). This is stronger than merely rejecting `sess-*`: it asserts the user's observable contract—one native start, one matching OMP session identity.\n\nPublic CLI access gap: the published CLI documentation exposes the interactive `spt endpoint run` picker and its `Resume from history` action, but no machine-readable history-list/read command. `spt api history-log` is explicitly append-only (body on stdin), not a reader. Therefore the file-backed `sessions.log` is the fastest deterministic non-destructive feedback loop on this workstation. `spt endpoint list`/`endpoint-info` do not expose this multi-row ledger. No endpoint was started, stopped, or mutated during this investigation.",
  "files": [
    {
      "path": "adapter/omp-spt.toml",
      "description": "Registration configuration. `[identity]` declares `session_id_source=\"post_spawn\"` and `parent_ancestor_name=\"omp\"`; `[session.self]` and `[session.resume]` launch native OMP with the packaged extension. Psyche init/resume are separate bounded commands with identity env removal."
    },
    {
      "path": "adapter/strings/omp-spt.mjs",
      "description": "Correct registration producer. In `session_start`, reads `ctx.sessionManager.getSessionId()` and invokes `spt api --adapter omp-spt bind <id> --set-session-id <real OMP sid>` before starting the listener."
    },
    {
      "path": "tools/omp-spt/src/launch_omp.rs",
      "description": "Native launch producer path. Fresh argv is `--extension <mjs>`; resume argv is `-r <session_id> --extension <mjs>`. On Windows it spawns validated OMP with inherited stdio and waits, leaving OMP as the PTY UI owner."
    },
    {
      "path": "tools/omp-spt/src/psyche_omp.rs",
      "description": "Psyche exclusion evidence. Bounded fresh turns use `-p`; continuations add `-c`; all use a private `--session-dir` plus `--no-extensions --no-skills --no-rules`. Consequently Psyche does not execute the packaged extension's bind path."
    },
    {
      "path": "tests/omp-extension.mjs",
      "description": "Deterministic project unit seam for the adapter-owned half: `testLifecycleCustodyAndContext` asserts one `session_start` emits exactly `api --adapter omp-spt bind ... --set-session-id session-1`. It proves the extension does not itself issue a second bind, but cannot detect the broker's manifest-driven post-spawn registration."
    },
    {
      "path": "C:/Users/decid/AppData/Local/spt-core/owlery/emphasys/sessions.log",
      "description": "Authoritative append-only observed endpoint-session ledger. Four rows show two registrations per bring-up: correct OMP UUID followed by synthetic `sess-*`; row schema is `ts, session_id, trigger, cwd?, ordinal, adapter`."
    },
    {
      "path": "C:/Users/decid/AppData/Local/spt-core/owlery/emphasys/info.json",
      "description": "Current endpoint snapshot only. Overwritten by the later synthetic registration; shows PID 33500, synthetic session ID, and adapter omp-spt, so it is useful for last-writer correlation but cannot alone demonstrate duplication."
    },
    {
      "path": "C:/Users/decid/.omp/logs/omp.2026-07-15.log",
      "description": "OMP-side timestamps and PIDs. Listener-ready records at 02:59:13.023-07:00 and 03:29:27.633-07:00 correlate with the two ledger registration pairs in UTC."
    },
    {
      "path": "C:/Users/decid/.omp/agent/sessions/-Documents-projects-omp-spt/2026-07-15T09-59-10-705Z_019f6537-4c71-7000-ab57-ab0d86e9d0a2.jsonl",
      "description": "Native OMP transcript; line 2 is the session metadata ground truth: UUID `019f6537-4c71-7000-ab57-ab0d86e9d0a2`, timestamp 09:59:10.705Z, project cwd."
    },
    {
      "path": "https://sabermage.github.io/spt-releases/llms-full.txt",
      "description": "Published public spt-core documentation used only as contract reference. Documents `[identity]` post-spawn resolution, `[session.resume]` selection, interactive Resume-from-history, and write-only `api history-log`; no history-list command was found."
    }
  ],
  "architecture": "Normal native OMP startup:\n`[session.self]` -> broker runs `omp-spt launch-omp ... --extension omp-spt.mjs` -> native OMP creates its UUID -> extension `session_start` explicitly binds endpoint to that UUID (correct ledger row) -> independently, manifest `[identity].session_id_source=\"post_spawn\"` resolves the spawned process and registers a synthetic `sess-<pid>-<epoch>` identity (incorrect second row and last-writer `info.json`). This is the double-registration architecture.\n\nNative OMP resume:\n`[session.resume]` -> broker passes the historical session ID into `launch-omp --resume` -> shim translates it to OMP `-r <sid>` and still loads the extension -> extension binds the resumed real UUID -> the same post-spawn identity path runs again. The ledger's `trigger:\"boot\"` describes endpoint bring-up on both fresh and resume; it does not mean a separate `boot` adapter and does not distinguish fresh from resume.\n\nPsyche lifecycle:\n`[session.psyche_init]`/`[session.psyche_resume]` -> `psyche-omp` runs one bounded OMP turn in a private nested session directory. Fresh omits `-c`; subsequent turns use `-c`. The manifest removes inherited `OWL_SESSION_ID`/`SPT_AGENT_ID`, and the shim passes `--no-extensions`, so Psyche neither loads `omp-spt.mjs` nor performs the explicit endpoint bind. Psyche's fresh/continue lifecycle must not be confused with the native endpoint's boot/resume registration pair.\n\nTesting layers:\n1. Existing fake-command extension test is the pure deterministic seam for proving exactly one adapter-owned explicit bind and its real OMP sid.\n2. The file-window assertion over `sessions.log` + OMP JSONL session header is the deterministic public-core integration seam that catches the actual duplicate. It requires no new endpoint process and no mutation. A fix should make that assertion pass conceptually by leaving only the extension's UUID row; the manifest must not enable a second identity-resolution owner when the extension already provides authoritative `--set-session-id` binding."
}