Files
ocp/docs/adr
taodengandClaude <claude-opus> <noreply@anthropic.com> 6394ca3265 fix(tui): pass CLAUDE_CODE_OAUTH_TOKEN to spawned claude + reap defunct sessions
Root cause (PI231 incident): tmux does not forward the parent's env to the
pane, so the TUI claude never saw CLAUDE_CODE_OAUTH_TOKEN and fell back to
~/.claude/.credentials.json, whose single-use refresh token got corrupted to an
empty string by the per-request spawn + kill-session teardown racing claude's
token rotation -> permanent "Please run /login" 401 (re-login re-corrupted on
the next spawn). Connected leak: the pane's claude is a child of the tmux server
(not node), so kill-session left <defunct> zombies the server never reaped (25
over 30 days; tmux kill-server dropped it 25->3).

Fix 1: buildTuiCmd now adds CLAUDE_CODE_OAUTH_TOKEN=<shq-escaped> to the pane
env prefix when the env is set, so claude authenticates via the long-lived token
and never touches the credentials.json refresh path (matching stable hosts).
Unset -> no token added (credentials.json-only hosts unaffected).

Fix 2: reapStaleTuiSessions kill-servers after clearing our own sessions ONLY
when no foreign tmux session remains (never disrupts a co-hosted olp-tui-*).
kill-server is the only node-reachable action that ACTUALLY reaps -- server exit
reparents survivors to init, which waitpids them; a per-session kill cannot,
since node is not the zombies' parent. Added a 15-min periodic reap (server.mjs)
gated on TUI_MODE and on the TUI path being idle. Residual: a request whose pane
is created in the idle-check/kill-server window fails cleanly via the existing
honesty gates (documented).

ALIGNMENT: Class B (OCP-owned TUI spawn). cli.js does NOT perform either
operation -- there is no cli.js analogue for "how the TUI pane authenticates" or
"reaping tmux-server-owned zombies"; authorized by ADR 0007 (PR-C amendment) per
ALIGNMENT.md's Class B citation requirement. No Class A wire surface, no endpoint
shape, no alignment.yml token, and no models.json entry touched.

Tests: +6 in test-features.mjs (buildTuiCmd token set/unset/shq-injection;
reaper kill-server ours-only / foreign-present / no-server). 241 passed, 0 failed.

Co-Authored-By: Claude <claude-opus> <noreply@anthropic.com>
2026-06-13 12:19:51 +10:00
..

Architecture Decision Records

This directory holds the OCP Architecture Decision Records (ADRs) — short documents that capture the why behind structural choices.

Read these before proposing governance, SPOT (single-source-of-truth), or process changes.

Numbering

ADRs start at 0002. The first one (0001) was reserved for an early internal proposal that was superseded before publication; 0002 is deliberately the first published record so the archived 0001 slot remains a placeholder rather than being silently renumbered.

New ADRs increment from the highest existing number. Filenames are NNNN-<short-slug>.md.

Index

ADR Title What it covers
0002 Alignment Constitution The ALIGNMENT.md constitution: why every server.mjs change requires cli.js citation + independent reviewer + CI blacklist pass. Background: the 2026-04-11 drift incident.
0003 models.json as SPOT Why model IDs / aliases / context windows live in a single JSON file (not duplicated in server.mjs and setup.mjs arrays). v3.11.0 refactor.
0004 OpenClaw Auto-Sync Why scripts/sync-openclaw.mjs runs on ocp update, what its scope boundary is (writes only models.providers["claude-local"].models and agents.defaults.models["claude-local/*"]), and the idempotency contract.
0005 No Multi-Provider Why OCP stays single-provider (Anthropic-via-cli.js) and does not extend to OpenAI / Gemini / OpenRouter. Cost estimate: ~7 weeks for a v1 that buys neither moat nor commercial readiness. Separate commercial work starts in a separate repo.
0006 OpenAI Shim Scope The Class A / Class B taxonomy. Class A endpoints (cli.js-mirror) keep Rules 15 verbatim; Class B endpoints (OCP-owned compatibility surface — /v1/chat/completions, /v1/models, admin endpoints) are anchored to OpenAI's spec (B.1) or to an authorizing ADR (B.2). Triggered by PR #99 (external response_format honoring). Grandfathers the existing B.2 inventory at v3.16.4.

When to write a new ADR

Open one whenever:

  • A structural rule is being added or changed (e.g., new SPOT, new boundary, new CI guardrail).
  • A decision encodes a lesson from an incident or drift.
  • A future contributor reading the code alone could plausibly undo or re-litigate the choice.

Skip ADRs for routine implementation choices (algorithm pick, naming) — those belong in commit messages.

Format

Keep ADRs short — Context / Decision / Consequences is the standard skeleton. Cite incidents, PRs, or commits where useful.