Two knowledge-preservation fixes. No behavior change: server.mjs gains comments
only, verified by `git diff --stat` (comment lines) and an unchanged suite.
#200 — structuredHash and dedupKey compute the same value and must NOT be
collapsed. They take identical arguments and read as obvious duplicate work,
which is how someone "optimises" them into a bug. Their GUARDS differ, verified
line by line rather than asserted:
structuredHash: if (CACHE_TTL > 0 && !conversationId && !hasCacheControl(...))
dedupKey: (!conversationId && !hasCacheControl(...)) <- no CACHE_TTL
CLAUDE_CACHE_TTL defaults to 0, so in the DEFAULT configuration structuredHash
is null while dedupKey must still be computed — it drives #153's single-flight
stampede protection, which is deliberately independent of response caching.
`dedupKey = structuredHash` would silently disable stampede protection by
default, in exactly the concurrent-AI-Task case it exists to bound. The comment
records that, and says what a safe deduplication would look like if anyone
still wants one (compute under the weaker guard, derive under the stronger,
add a stampede test first).
This was first raised in the #194 review as a cosmetic nit and then RETRACTED
by that reviewer after reading the guards — the retraction is the valuable
part, so it goes in the code rather than staying in a PR thread.
#197 — new "Testing: reaching faults inside server.mjs" section in AGENTS.md.
The premise the issue was originally filed on was wrong twice over, and both
errors were mine: first that no live-server harness existed (ltBoot has been
there all along, and I had used it myself in #191), then that a synchronous
fault deep inside spawnClaudeProcess needed a production test hook (it needs
--stack-size, which ltBoot already forwards).
The section documents the fixture, the --stack-size fault lever with the
concrete numbers (~124k element spread threshold at the default stack vs ~24k
at --stack-size=200, which is what fits Linux's 131072-byte MAX_ARG_STRLEN so
the test RUNS in CI instead of skipping), and the three rules that made it hold:
discover the threshold in a child under the same flags, assert the fault
actually fired, and wait for the thing you are about to assert rather than a
proxy for it. Each rule cites the issue that taught it (#193/#199/#203).
Written to be read BEFORE someone concludes a bug class is untestable, since
that conclusion has now been reached wrongly twice in this repo.
cli.js citation: NOT APPLICABLE — comments only, no wire behavior, no code
path, no argv change. Authorized by ADR 0006 as a behaviour-preserving edit;
the field set and every request/response contract are byte-identical.
Tests: 457 passed, 0 failed (unchanged, as expected for a comments-only diff).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017gbqUZ8HfBZpjjbzQ85oH8
Multiple documentation polish items rolled into one PR (one layer:
"docs alignment with current state").
### README.md
- **Uninstall section** added between Server Setup and Client Setup
(was missing — `node uninstall.mjs` exists but went undocumented).
- **OpenClaw definition** added as a footnote on first README mention
(the architecture diagram and Supported Tools table both reference
OpenClaw without ever defining it).
- **Repository Layout section** added before Security — table of
top-level files (server.mjs, setup.mjs, uninstall.mjs, keys.mjs,
models.json, ocp/ocp-connect, dashboard.html, scripts/, .claude/skills/,
ocp-plugin/, docs/adr/, ALIGNMENT.md, AGENTS.md, CLAUDE.md) so a new
contributor knows what each file does.
- **LICENSE link** added to the License section footer.
### docs/adr/README.md (new)
- Index of the three published ADRs (0002, 0003, 0004) with a one-line
description each.
- Explains the `0001` placeholder (early internal proposal that was
superseded; numbering deliberately starts at `0002`).
- Guidance on when to write a new ADR vs. when a commit message suffices.
### Spec/plan housekeeping
- `specs/.gitkeep` removed (the empty `specs/` placeholder confused the
picture; canonical paths are `docs/superpowers/plans/` for active plans
and `docs/superpowers/specs/` for long-lived design docs that other
code references).
- Shipped plans moved to `docs/superpowers/plans/shipped/`:
- `2026-04-10-lan-mode.md` (shipped: README LAN mode section)
- `2026-04-25-47-sse-heartbeat-plan.md` (shipped: v3.12.0 per CHANGELOG)
- `2026-04-25-47-sse-heartbeat-design.md` left in `docs/superpowers/specs/`
unchanged because both `server.mjs:565` and `CHANGELOG.md:7` link to
that exact path; moving it would require a `server.mjs` edit, which
needs `cli.js` citation per ALIGNMENT.md Rule 1.
### AGENTS.md
- Updated "Key files to know" to add `docs/adr/README.md`,
`docs/superpowers/plans/`, and `memory/constitution.md`.
- Note explaining `memory/constitution.md` is spec-kit's standard
location, distinct from `~/.cc-rules/memory/` and `ALIGNMENT.md`.
- Updated "Handoff expectations" item 5 from `docs/superpowers/specs/*/tasks.md`
(which never matched anything — there were no `tasks.md` files there)
to `docs/superpowers/plans/` (excluding `shipped/`).
### Coordination with PR #53
PR #53 is open and adds "Why OCP?", "Comparison", and "Governance"
sections to README. This PR deliberately avoids those areas — only edits
the Supported Tools table footnote, inserts Uninstall before Client Setup,
inserts Repository Layout before Security, and updates the License footer.
No expected merge conflict.
Refs: audit findings M6, M8, M9, M11, L2, L3, L6.
Co-authored-by: dtzp555 <dtzp555@gmail.com>
`test-features.mjs` shipped at v3.8.0 (per CHANGELOG of the keys.mjs
quota+cache work) and is referenced from AGENTS.md as the project's only
test artifact, but until now nothing actually ran it — no `npm test`
script, no CI step. Wiring it up so it runs on every push and PR.
### Changes
- `package.json`: add `"test": "node test-features.mjs"` to scripts.
- `.github/workflows/test.yml` (new): single-job workflow that runs
`npm test` on push to main and on every PR. Uses Node 24 because
`keys.mjs` imports `node:sqlite`, which is stable in Node 23+ (Node
24 is the current LTS; Node 22 would need `--experimental-sqlite`).
No `npm install` step — OCP has zero external runtime dependencies
per `package-lock.json`.
- `AGENTS.md`: note that `test-features.mjs` runs via `npm test` and
is enforced by `.github/workflows/test.yml`.
### Why this is a hard check, not a soft check
`test-features.mjs` is self-contained — it imports `keys.mjs` and
exercises the SQLite-backed key/quota/cache code paths against a
throwaway test DB at `~/.ocp/ocp-test.db`. It does NOT require:
- a live claude CLI binary
- a running OCP server
- any network access
So CI can run it as a real check; no `continue-on-error` needed.
### Local verification
```
$ npm test
[...]
=== Results: 24 passed, 0 failed ===
```
24 assertions cover createKey / listKeys / quota math / cache hash
determinism / cache TTL / clearCache. Exit code is 1 on any failure
(`process.exit(failed > 0 ? 1 : 0)` at the bottom of test-features.mjs).
### Future expansion
If the suite later grows to include tests that DO require a live claude
CLI or a running OCP, mark those steps `continue-on-error: true` (or
split them into a separate job). The comment in `test.yml` documents
this contract.
Refs: audit (test-features.mjs orphan / unrunnable in CI).
Co-authored-by: dtzp555 <dtzp555@gmail.com>
Both `CLAUDE.md` (line 25) and `AGENTS.md` (line 46) previously claimed the
`alignment.yml` blacklist included two tokens — `api/oauth/usage` and
`api/usage`. The actual workflow has a single token in `BLACKLIST`:
`api.anthropic.com/api/oauth/usage`.
Doc-vs-CI drift. Fix is doc-side only — `alignment.yml` itself is unchanged
because adding a second blacklist token (`api/usage`) is a constitutional
change that requires an `ALIGNMENT.md` amendment PR per ALIGNMENT.md
Amendment Procedure.
If `api/usage` should be added to the blacklist, that's a separate PR with
ALIGNMENT.md amendment + reviewer sign-off.
Refs: audit findings (governance doc accuracy).
Co-authored-by: dtzp555 <dtzp555@gmail.com>
Integrates OCP with Tao's cross-device development system (Phase 1 L1).
- AGENTS.md: project-level tool-agnostic instructions (read by Cursor,
OpenCode, Copilot, etc. in addition to Claude Code). Inherits from
~/.cc-rules/AGENTS.md.
- CLAUDE.md: prepends @AGENTS.md + @~/.cc-rules/AGENTS.md imports.
- docs/adr/0002-alignment-constitution.md: captures why ALIGNMENT.md
exists (2026-04-11 drift response).
- docs/adr/0003-models-json-spot.md: captures v3.11.0 SPOT refactor.
- docs/adr/0004-openclaw-auto-sync.md: captures v3.11.0 auto-sync design.
ADRs numbered 0002-0004 because an untracked 0001-cross-device-system.md
already exists locally and was out of scope for this PR.
Governance/docs only. No code change. No version bump (not a release).
Co-authored-by: Tao Deng <dtzp555@gmail.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>