fix+release(v0.4.1): D74 post-Phase-4 hotfix batch — 5 maintainer-review findings (#46)

* fix+release(v0.4.1): D74 post-Phase-4 hotfix batch — maintainer-review findings

Patch release fixing 5 issues caught by maintainer post-v0.4.0 independent
review (main / v0.4.0 / commit ee4d945). All five are real runtime bugs
the per-D-day fresh-context opus reviewers missed because they checked
spec text instead of runtime contracts (default auth.allow_anonymous:
false, real /health payload shape, real /cache/stats payload shape, real
/v0/management/dashboard-data payload shape).

Phase 4 process learning: every implementation D-day MUST include at
least one test that boots the server with default production config and
exercises the new feature end-to-end. D74 Suite 36 pins the wire-
contract shapes so a future D-day refactor can't silently re-break the
CLI / plugin / docs.

## P1-1 — olp doctor false-negative on auth-required /health

lib/doctor.mjs: buildBuiltinChecks() accepts opts.authHeaders and passes
to httpGet for both server.running + server.version probes. The
server.running check now distinguishes 401/403 ("server up, bearer token
missing or invalid — set OLP_API_KEY") from "server unreachable" so the
kind discriminator routes to a clean fix-auth path instead of fix_server
when operator just forgot to export the env var.

bin/olp.mjs cmdDoctor: threads authHeaders() through to runDoctor.

## P1-2 — olp-connect token validation + shell-quoting

bin/olp-connect: validate_olp_token() enforces ^olp_[A-Za-z0-9_-]{43}$
(per ADR 0007 § 3 token format) at THREE input sites: --key arg,
/health.anonymousKey server-advertised consumption, interactive prompt
fallback. shell_quote() POSIX-single-quote-wraps with embedded-quote
escape per:
  foo'bar  →  'foo'\''bar'
Applied to all rc-file writes + dry-run output. systemd
environment.d/olp.conf write additionally rejects embedded newlines.
Hostile or malformed keys can no longer persist as shell startup
injection.

## P2-3 — olp usage + olp cache human formatter wire-contract fix

bin/olp.mjs cmdUsage previously read body.usage_24h.requests /
body.providers / body.top_fallback_chains — none of which exist in the
real server payload (server.mjs:2027 + lib/audit-query.mjs). Users saw
"requests: ?" + missing per-provider quota + missing top-chains. Now
reads body.window_24h.request_count / body.cache_hit_24h.hit_rate /
body.quota / body.top_fallback_chains_24h.

bin/olp.mjs cmdCache previously read body.entries / body.bytes /
body.maxBytes (OCP-era field names). Real CacheStore.stats() returns
{hits, misses, size, inflightCount}. Now reads body.size /
body.inflightCount + computes hit rate from hits/(hits+misses).

## P2-4 — olp-plugin/ fmtHealth iterates providers.status

olp-plugin/index.js: previously walked Object.entries(body.providers)
which surfaced `enabled` / `available` / `status` as pseudo-providers
(chat showed "🟢 status" instead of "🟢 anthropic"). Now extracts the
real provider map from body.providers.status, renders enabled/available
counts in a header line, lists per-provider names with activeSpawns when
present. Falls back to flat body.providers.* for older OCP shape
(backwards compat).

## P3-5 — stale v0.3.0-era doc strings updated

README.md: header status line + Implementation Status § now reflect
v0.4.0 shipped + Phase 5 open. Known-limitations Phase 3 line moved out
of "pending v0.3.0" state; new Phase 4 line added with full deliverable
list.

server.mjs: startup banner no longer hardcodes "Phase 1 in progress"
(now just lists version + provider count). Banner derives state from
VERSION so future Phase boundaries don't need touch-ups here.

## Test count

696 (v0.4.0) → 704 (v0.4.1). +8 D74 regression tests in Suite 36:

- 36a: runDoctor accepts authHeaders + threads to checks
- 36b: server.running distinguishes 401 (auth) from "server down"
- 36c: olp-connect rejects malformed --key (validator fires before rc write)
- 36d: olp-connect accepts properly-formed olp_ token
- 36e: CacheStore.stats() shape pin + cmdCache source pin
- 36f: dashboard-data payload shape pin + cmdUsage source pin
- 36g: olp-plugin fmtHealth iterates providers.status not providers.*
- 36h: server.mjs banner doesn't hardcode stale phase

## Authority

- Maintainer independent review of main / v0.4.0 / commit ee4d945
  (2026-05-26 session — 5 findings P1×2 + P2×2 + P3×1)
- Iron Rule 第二律 (evidence over "should work") — runtime smoke
  against default production config now mandatory per Suite 36 pattern
- CLAUDE.md release_kit.phase_rolling_mode cross-Phase discipline
  ("hotfix to a shipped Phase N deliverable → bump patch, tag, release
  before next push")
- ADR 0007 § 3 (token format ^olp_[A-Za-z0-9_-]{43}$) — D74 P1-2
  validator authority

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix: Suite 36 paths use import.meta.dirname for CI portability (was hardcoded /Users/taodeng/olp/)

---------

Co-authored-by: dtzp555 <dtzp555@gmail.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
dtzp555-max
2026-05-26 10:43:12 +10:00
committed by GitHub
co-authored by taodeng Claude Opus 4.7
parent ee4d9459aa
commit f3716a19fd
9 changed files with 390 additions and 35 deletions
+6 -4
View File
@@ -2,7 +2,7 @@
A personal- and family-scale multi-provider LLM proxy. One HTTP endpoint, many subscriptions behind it, automatic routing, automatic fallback, content-addressed caching — so your IDEs and family clients keep working as long as *any* of your subscriptions has quota left.
> **Status:** v0.3.0 shipped (2026-05-25) — Phase 1 multi-provider proxy core (v0.1.0 + v0.1.1) + Phase 2 multi-key auth + audit + owner gating + keygen CLI (v0.2.0) + Phase 3 Dashboard + audit query layer + daily audit rotation (v0.3.0). Phase 4 (per-key per-provider auth + audit retention + SQLite hybrid + provider-cost weights) is the next planned milestone. Sections marked _placeholder_ land alongside the relevant phase of work (see [phase plan](#phase-plan)).
> **Status:** v0.4.0 shipped (2026-05-26) — Phase 1 multi-provider proxy core (v0.1.0 + v0.1.1) + Phase 2 multi-key auth + audit + owner gating + keygen CLI (v0.2.0) + Phase 3 Dashboard + audit query layer + daily audit rotation (v0.3.0) + Phase 4 Operator + Client UX (v0.4.0): SSE heartbeat / `olp` Node CLI + `olp doctor` framework / `olp-connect` zero-config LAN setup / `/health.anonymousKey` opt-in / `/olp` Telegram-Discord plugin / 6-IDE integration docs. Phase 5 scope is open — candidates per ADR 0010 § Out-of-Phase-4-scope: `/v1/messages` (gated on ADR 0009 P0 outcome + named family CC user), context-window-exceeded fallback trigger, per-(provider, model) live stats. Sections marked _placeholder_ land alongside the relevant phase of work (see [phase plan](#phase-plan)).
---
@@ -252,9 +252,9 @@ Use a dedicated bot key — not the maintainer's personal owner key — so revoc
---
## Implementation status (as of 2026-05-25, post-v0.2.0)
## Implementation status (as of 2026-05-26, post-v0.4.0)
Phase 1 closed at v0.1.1 (multi-provider proxy core + pre-Phase-2 cleanup). Phase 2 closed at v0.2.0 (multi-key auth + audit + owner gating + keygen CLI; ADR 0007 § 10 all 11 acceptance criteria shipped). Phase 3 closed at v0.3.0 (Dashboard + `lib/audit-query.mjs` + daily audit rotation; ADR 0008 § 10 all 15 acceptance criteria shipped). Phase 4 (per-key per-provider auth + audit retention + SQLite hybrid + provider-cost weights) is the next planned milestone. This table reflects what is currently shipped vs. what is designed for later phases.
Phase 1 closed at v0.1.1 (multi-provider proxy core + pre-Phase-2 cleanup). Phase 2 closed at v0.2.0 (multi-key auth + audit + owner gating + keygen CLI; ADR 0007 § 10 all 11 acceptance criteria shipped). Phase 3 closed at v0.3.0 (Dashboard + `lib/audit-query.mjs` + daily audit rotation; ADR 0008 § 10 all 15 acceptance criteria shipped). Phase 4 closed at v0.4.0 (Operator + Client UX per ADR 0010: SSE heartbeat + `recentErrors[20]` + `/v0/management/status` / `olp` Node CLI + `olp doctor` framework + ADR 0002 Amendment 7 / `olp-connect` bash + `/health.anonymousKey` + ADR 0011 / `olp-plugin/` Telegram-Discord + 6-IDE integration docs). Phase 5 scope is open — candidates per ADR 0010 § Out-of-Phase-4-scope. This table reflects what is currently shipped vs. what is designed for later phases.
| File / artifact | Status | Notes |
|---|---|---|
@@ -289,7 +289,9 @@ Behaviors that work correctly at personal/family scale but have ratified follow-
- **Soft triggers configured but inert.** `routing.soft_triggers` in `~/.olp/config.json` is honored by the engine's evaluation logic but `quotaStatus()` polling is not wired (ADR 0004 Amendment 2). A startup warning fires if the field is non-empty so the inert state is visible.
- **Multi-key auth + owner gating + keygen CLI shipped at v0.2.0 (D44 + D45 + D46 + D47).** `lib/keys.mjs` (core), `lib/audit.mjs` (audit), owner-vs-guest `/health` payload trimming + `X-OLP-Fallback-Detail` policy gating, `bin/olp-keys.mjs` (keygen CLI). All 11 ADR 0007 § 10 acceptance criteria covered. v0.2.0 maintainer-merged 2026-05-25.
- **Phase 3 (Dashboard + audit query layer + rotation) shipped to main (D48-D54); v0.3.0 release pending.** `docs/adr/0008-dashboard-and-audit-query.md` ratified at D48. `lib/audit-query.mjs` (D49) implements the 5-function aggregate query API (in-memory ndjson scan, PII-guarded). 4 new owner-only_block endpoints at D50 (`/dashboard`, `/v0/management/dashboard-data`, `/v0/management/quota`, `/cache/stats`). `dashboard.html` full multi-panel UI at D51 (vanilla HTML+JS+fetch, 30s poll with visibilitychange pause). Daily audit rotation at D52 (synchronous on first append after UTC midnight; `audit-YYYY-MM-DD.ndjson` naming) + optional `bin/olp-audit-rotate.mjs` cron tool. `tried_providers` schema semantic fix at D53 (D45 P2 deferral). Phase 3 close to v0.3.0 is maintainer-triggered per CLAUDE.md `release_kit.phase_close_trigger`.
- **Phase 3 (Dashboard + audit query layer + rotation) shipped at v0.3.0 (D48D54).** `docs/adr/0008-dashboard-and-audit-query.md` + `lib/audit-query.mjs` (D49) + 4 owner-only_block endpoints (D50) + `dashboard.html` (D51) + daily audit rotation (D52) + `tried_providers` schema fix (D53). All 15 ADR 0008 § 10 acceptance criteria covered.
- **Phase 4 (Operator + Client UX) shipped at v0.4.0 (D60 → D73).** ADR 0010 (charter) + ADR 0011 (anonymous-key trusted-LAN limits) + ADR 0002 Amendment 7 (provider `doctorChecks()` contract). Default `OLP_PORT` 3456 → 4567 so OLP and OCP can co-host. SSE heartbeat (D61) + `recentErrors[20]` + `/v0/management/status` (D62-D63). `bin/olp.mjs` Node CLI + `bin/olp-keys.mjs` + `lib/doctor.mjs` framework with `next_action.ai_executable[]` (D64-D67). `bin/olp-connect` bash zero-config IDE auto-config + opt-in `/health.anonymousKey` (D68-D70). `olp-plugin/` OpenClaw `/olp` Telegram-Discord plugin (read-only, no chat mutations) + 6 IDE integration docs at `docs/integrations/*.md` (D71-D73). Test count 623 → 696.
**Bootstrap workflow (D47):** for first-run / production setup: