# Open-request implementation plan

> Status: proposed — not started. Owner approval required before Phase 1.
> Scope: the 7 requests open after the 2026-07-21 reconciliation (EV-179).
> Commit: 462de52

## Why this order

Two hard dependencies drive it, and they override "most valuable first":

1. **REQ-151 comes first** because every later phase is verified by the test
   suite, and that suite currently goes red on ~300s runs and green on ~140s
   runs. Fixing verification before doing architectural work means later
   phases are provable rather than argued.
2. **REQ-107 must precede REQ-113.** REQ-113 adds a tool. Under today's
   architecture that means another hand-written MCP handler — deepening the
   exact debt REQ-107 exists to remove. REQ-107 states this explicitly:
   *"REQ-106's import tool is implemented under this architecture, not as
   another hand-written MCP handler."* Building 113 first would have to be
   redone.

---

## Phase 1 — REQ-151: make the suite load-independent

**Problem.** Full runs error at ~300s and pass at ~140s. Confirmed across five
consecutive releases; the same suites pass in isolation. Cause is real port
binds plus fixed subprocess timeouts under contention.

**Touches (this repo only).** `tests/test_prd_ui_serve.py`,
`test_mcp_server.py`, `test_inbound_regressions.py`,
`test_claude_plugin_hooks.py`, `test_fork_version_check.py`,
`test_prd_ui_export.py`.

**Approach.**
- Port binds already use port 0 (ephemeral); verify no test hard-codes 7717
  and add a bind retry where a race is possible.
- Replace fixed `timeout=` values in subprocess calls with a scaled constant
  derived from a base timeout, so contention widens rather than fails.
- Add a marker so a genuine hang still fails fast rather than hanging the run.

**Verification.** Run the full suite under deliberate CPU load and require
green; run it normally and require green.

**Impact if done.** The release gate becomes trustworthy. A gate you learn to
dismiss is worse than no gate — this is the phase that stops "red means look
again" from becoming "red means ignore".

**Risk.** Low. Test-only; no shipped behaviour changes.

---

## Phase 2 — REQ-145: detect wiki ingest falling behind

**Problem.** Proven live, not theoretical: 8 requests implemented in the
2026-07-21 session alone are already absent from `wiki/log.md` (REQ-144, 146,
147, 148, 149, 150, 152, 153) — one day after a nine-request gap was closed by
hand. `prd_status.wiki_backfill_pending` cannot catch it: it measures the
one-time backfill marker AND the ABSENCE of `wiki/index.md`, so it reads false
while ongoing ingest rots.

**Touches.** `scripts/prd_status.py` or `scripts/drift_monitor.py` (surface),
`wiki/log.md` (input), the skill guidance in `project-llm-wiki`. Affects
prd-plugin and every downstream repo that keeps a wiki.

**Approach.**
- A pure function comparing implemented `REQ-*` ids against ids cited in
  `wiki/log.md`, returning the uningested set.
- Bound it to requests implemented **since the wiki existed** — the raw count
  is 71 of 126 and most are pre-wiki noise. The signal is recent drift.
- Surface it in `prd_status` (and drift when enabled), not as a blocker.

**Verification.** Unit tests on the comparison; assert it reports the 8 known
missing ids against real repo state today.

**Impact if done.** Turns "ingest on close" from an instruction agents skip
into a reported condition. This is the mechanism-over-instruction fix with the
receipt already in hand.

**Risk.** Low. Read-only reporting; nothing blocks.

---

## Phase 3 — REQ-107: invert to UTCP-first with the MCP bridge

**Problem.** Authority flows the wrong way. Verified 2026-07-21:

```
mcp/server.cjs (2,527 lines, hand-written, AUTHORITATIVE)
      --describe-->  mcp/tool-metadata.json
      read by     -->  prd_tools.build_manual()
      produces    -->  utcp.json  (49 mcp templates pointing BACK at server.cjs)
```

`@utcp/mcp-bridge ^1.1.0` is a dependency and proven to MOUNT the manual
(IMP-TASK-091 verified round-trip with the official SDK: 57 namespaced tools,
a native cli read and an mcp-bridged validated call). But it **generates
nothing**. This is MCP-first with a UTCP wrapper — the inverse of the official
SDK way, and the owner has confirmed it is wrong.

**What REQ-107 actually requires.** One manual as source of truth for ALL
tools including mutations; the MCP surface generated by the bridge; downstream
`.mcp.json` pointing at the bridge rather than a bespoke server; the
tool-surface catalog as the manual's generator input; the hand-written server
retired as a hand-maintained surface.

**Touches.** `mcp/server.cjs`, `mcp/tool-metadata.json`,
`scripts/prd_tools.py`, `templates/tool-surface.json`, downstream `.mcp.json`,
`scripts/prd_install.py` (what it wires), `package.json`, the UTCP catalog
tests, `wiki/mcp/mcp-state-server.md`. Cross-repo: **ai-collab-v3** mounts our
manual through its hub, so any manual shape change is a contract change for
them and must be announced before it lands.

**Non-negotiable constraint.** Retiring the server must NOT mean losing what
it owns: file locking, duplicate-safe ID allocation, schema validation, atomic
writes. REQ-107 says the manual's call templates run "validated native entry
points that keep" those. So the safety moves *into* native handlers, it does
not evaporate.

**Approach — staged, because a single leap is not verifiable.**

- **3a. Extract the validated handlers.** Lift the mutation logic out of
  `server.cjs` into importable native entry points (Python or Node) that own
  locking/allocation/validation/atomic-write. The server becomes a thin
  adapter over them. No behaviour change; the full suite is the proof.
- **3b. Make the catalog the generator input.** `build_manual()` stops reading
  `tool-metadata.json` and instead emits the manual from
  `templates/tool-surface.json` plus the native entry points' declared
  schemas. Authority inverts here. Parity test flips: the manual is asserted
  as source, and `tool-metadata.json` becomes a derived artifact checked
  against it.
- **3c. Generate the MCP surface via the bridge.** Downstream `.mcp.json`
  points at `@utcp/mcp-bridge` mounting our manual. Prove the round trip with
  the official SDK, as IMP-TASK-091 already did once.
- **3d. Retire the hand-written server.** Only after 3c is green in a real
  downstream install. Keep it importable for one release as a fallback, then
  delete.
- **3e. Announce to ai-collab-v3** before 3c lands, since they mount the
  manual.

**Verification.** Each sub-phase keeps the full suite green. 3c additionally
requires an official-SDK round trip in a freshly installed repo: list tools,
execute one native cli read and one bridged mutation, and confirm the mutation
still locks and validates.

**Impact if done.** One source of truth instead of two surfaces kept in sync
by a parity test. ~2,500 lines of hand-maintained server stop being a
maintenance surface. Every new tool is declared once. It also aligns with the
workspace-wide direction already set in AI-Collab (BR-DEC-130).

**Risk. HIGH — the highest in this plan.** It touches the write path for all
canonical state. Mitigations: staged with the suite green at each step, safety
logic extracted before anything is retired, fallback kept for one release, and
the cross-repo contract announced first.

---

## Phase 4 — REQ-113: request-thread close, built the new way

**Problem.** No validated way to close a request thread. Right now **5 threads
are unresolved and 4 of them belong to requests already `implemented`**
(REQ-135, 146, 147, 148). `message_check` therefore reports `attention`
permanently.

**Touches.** The tool surface (declared once under the Phase 3 architecture),
`scripts/message_check.py`, request state. Affects every repo that runs
message_check.

**Approach.** Declare a `thread.close` capability in the tool-surface catalog;
implement the native handler with a reason and timestamp; `message_check`
counts a closed thread as resolved. No hand-edited state.

**Verification.** Unit tests for the handler; assert the 4 stale threads on
implemented requests close and `unresolved_threads` drops.

**Impact if done.** Restores message_check as a trustworthy signal. This
matters more than its `low` severity suggests: message_check is the dashboard
that catches transport failures, and a permanently-amber dashboard is one
people stop reading — which is exactly how the REQ-125/130–134 transport bugs
survived four rounds.

**Risk.** Low, once Phase 3 is done. Built before Phase 3 it would add to the
debt.

---

## Phase 5 — REQ-072: close as a host limitation

**No implementation.** OpenCode's `session.idle` is a notification, not a
vetoable stop; the host provides no way to block. Already documented as a
known limitation in `wiki/hooks/claude-code-hooks.md`.

**Action.** Record the rationale and close, so it stops appearing as pending
work. Reopen only if OpenCode ships a blocking stop event.

---

## Phase 6 — blocked / needs a decision (no work scheduled)

- **REQ-129 — journal contract.** Half shipped and correctly so: the
  `journal.*` config family landed in 0.16.32 (7 keys, contract validates).
  The remaining half — cross-host lifecycle hook adapters — is deliberately
  deferred; the reply to ai-collab-v3 committed to adapters following once
  they promote past shadow capture. **Blocked on them, not us.** No action
  until they confirm promotion.
- **REQ-104 — workspace chat into the planning pipeline.** From ai-collab-v3,
  `high`. Approved chat decisions graduating into project truth without a
  human relay, plus durable agent identity so capability grants survive runner
  restarts. Touches `mcp/server.cjs`, `scripts/prd_substrate.py`, the method
  docs and the wiki — and requires work on their side too. **Needs an owner
  decision on scope before any design.** Note it also collides with Phase 3:
  if it lands as hand-written MCP handlers it deepens the debt, so it should
  follow Phase 3 or be designed under it.

---

## Summary

| Phase | Request | Risk | Why here |
| --- | --- | --- | --- |
| 1 | REQ-151 flaky suite | low | makes every later phase verifiable |
| 2 | REQ-145 wiki drift detector | low | small, independent, already leaking |
| 3 | REQ-107 UTCP-first inversion | **high** | architectural; must precede new tools |
| 4 | REQ-113 thread close | low | proves Phase 3; restores a trusted signal |
| 5 | REQ-072 | none | close as host limitation |
| 6 | REQ-129 / REQ-104 | — | blocked on ai-collab-v3 / needs owner decision |
