# Imminent claude-spt Fix and Publish Proposal

**Priority:** Immediate adapter release  
**Agreed scope:** Repair carrier custody, introduce one shared verified identity resolver for every hook handler, publish v0.21.0, and establish the core identity-only follow-up

## Fix contract

UserPromptSubmit must never invoke endpoint listing, project projection, or Git merely to identify the current endpoint.

## Safety prerequisite: repair session-carrier custody

A bare `SPT_ENDPOINT_ID` fast path is not sufficient. Identity environment leakage and stale carriers are known hazard classes.

Current SessionStart handling can advance `state/session/<id>.sid` even after strict bind/boundary registration fails (`tools/claude-spt/src/hook.rs:698-769`). Before carrier equality can prove the fast path, write the carrier only after the strict registration succeeds.

Required invariant:

`carrier endpoint ID + carrier SID` is authoritative only when written after a successful registration/boundary operation.

## Agreed immediate adapter release

### 1. Shared verified direct identity resolver

Replace the bare `self_id` dependency at its shared seam rather than patching only UserPromptSubmit. The same resolver is called by PreToolUse, Stop, Notification, SessionEnd, SubagentStart, and SessionStart legs. PreToolUse fires on every tool call, and a Stop timeout can prevent the idle transition and recreate the stuck-busy message black-hole class.

For every applicable spt-hosted hook:

1. Read `SPT_ENDPOINT_ID`.
2. Read `state/session/<id>.sid`.
3. Compare it to the hook payload `session_id`.
4. On equality, use `<id>` directly.
5. Make zero `whoami`, endpoint-list, endpoint-info, project-history, or Git calls.

On missing/mismatched proof, do not use the environment ID. Leaked-env nested sessions fail SID equality and fall back safely; successful `/resume` rebind rewrites the carrier and restores the fast path.

### 2. Preserve a safe fallback

Until spt-core ships an identity-only API, keep the current `whoami --json` fallback for:

- harness-hosted/live sessions without `SPT_ENDPOINT_ID`;
- mismatched/missing carrier proof.

This means the imminent adapter release fully fixes ordinary spt-hosted endpoints such as deployah and Doyle while preserving current identity correctness elsewhere. The fallback remains deadline-vulnerable until the core API or PROJECT-INDEX lands; surface a stage trace rather than silently claiming full closure.

### 3. Add stage timing

Write monotonic start/end records to `hook-trace.log` for:

- `skill`;
- `wake`;
- `park-drain`;
- `live-roster`;
- `identity`, with `path=verified-env|core-fallback`;
- `busy`;
- `poll`;
- `nudge`;
- `emit`;
- `total`.

Do not log prompt or message bodies.

### 4. Avoid double-listing on live invocation

`/sptc:live` still intentionally needs roster context. After verified identity is available, it may execute one explicit `endpoint list --show-all`; it must not execute a second list through identity resolution.

## Required spt-core follow-up

Request a narrow read-only core command/API:

`payload session ID -> endpoint ID or null`

Implementation requirements:

- use existing session/roster identity resolution;
- permit the adapter to supply the payload SID explicitly or through a scoped environment override;
- no `cmd_endpoint_list`;
- no registry projection;
- no project history;
- no Git;
- no network;
- JSON contract stable for adapters.

Do not use existing `api endpoint-info`: its reporting path also calls `latest_project_ref` (`api/reporting.rs:953`).

Once the identity-only API reaches claude-spt's minimum core floor, replace the `whoami` fallback and delete the enriched-list dependency entirely.

## Deterministic adapter tests

Use the existing `HookEnv` recorder.

1. **Verified environment path**
   - Set `SPT_ENDPOINT_ID`.
   - Carrier SID equals payload SID.
   - Assert direct ID feeds `state busy` and `poll`.
   - Assert zero `whoami`, list, endpoint-info, project, and Git calls.

2. **Carrier mismatch**
   - Environment ID present; carrier differs.
   - Assert direct path rejected.
   - Assert fallback invoked.
   - Assert wrong endpoint is never marked busy or polled.

3. **Registration refusal custody**
   - Simulate strict bind/boundary failure.
   - Assert carrier file is not advanced.

4. **Registration success custody**
   - Simulate strict success.
   - Assert carrier is atomically updated to the new SID.

5. **Missing environment ID**
   - Assert fallback behavior remains compatible until core API adoption.

6. **Live invocation**
   - Assert exactly one explicit endpoint listing and no identity listing under verified-env mode.

7. **Shared resolver coverage**
   - Assert Stop, PreToolUse, SessionEnd, and SubagentStart use verified-env identity with zero core calls.

## Core integration tests

For the future identity-only API:

1. Put a poison `git` executable first on `PATH`.
2. Resolve a valid session.
3. Assert correct ID and zero Git invocation.
4. Assert complexity remains constant as endpoint, subnet, branch, and registry counts grow.

## Publish acceptance

Before publishing the adapter update:

- run focused hook unit tests;
- run hook-dispatch acceptance for normal and stale plugin dispatch shapes;
- install/update the adapter locally through the normal adapter channel;
- reload plugin hooks if skeleton wiring changes (binary-only change should not require hooks.json changes);
- exercise a non-production isolated hook recorder or test perch, not deployah/Doyle inboxes;
- confirm ordinary verified-env UserPromptSubmit completes comfortably below the external hook limit and spawns no Git processes;
- publish the Windows and supported Linux adapter artifacts together;
- record the remaining harness-hosted fallback limitation in release notes until core identity-only support lands.

## Agreed version and scope

Publish **claude-spt v0.21.0**. The shared resolver changes identity behavior across all hook handlers and adds new trace fields, so a minor release communicates the scope more honestly than a patch bump.

This remains a binary-only adapter update: no `hooks.json` or plugin skeleton change and no plugin reload. Endpoints must bounce to pick up the persistent binary. The core identity-only API and PROJECT-INDEX remain separate spt-core work; this release does not wait for either.
