From 5119b427fdaab55ad8504f138d015d70f85c74f6 Mon Sep 17 00:00:00 2001 From: dtzp555 Date: Sun, 24 May 2026 16:56:01 +1000 Subject: [PATCH] =?UTF-8?q?docs:=20D30=20=E2=80=94=20README=20env=20vars?= =?UTF-8?q?=20correctness=20(F7)=20+=20openai-spec-pin.md=20v0.1=20baselin?= =?UTF-8?q?e=20(F20)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cold-audit catch from 2026-05-24 (round 3) Round-3 P3 docs batch. Two unrelated docs items grouped per IDR cleanup convention (D19/D20/D25 precedent). **F7** β€” README Environment Variables table drift. Pre-D30 table documented `OLP_HOME` and `OLP_LOG_LEVEL` β€” neither is read by any code in the repo. The table missed `OLP_CLAUDE_BIN`, `OLP_CODEX_BIN`, `OLP_VIBE_BIN` which the 3 provider plugins DO read to override the path to each provider's CLI binary. `grep -rn "process\.env\.OLP_" server.mjs lib/` returns exactly 4 reads: - `OLP_PORT` (server.mjs:49) - `OLP_CLAUDE_BIN` (anthropic.mjs:69) - `OLP_CODEX_BIN` (codex.mjs:143) - `OLP_VIBE_BIN` (mistral.mjs:240) Fix: README env-vars table now lists exactly these 4 active vars with their actual defaults. `OLP_HOME` + `OLP_LOG_LEVEL` moved to a "πŸ“‹ Planned (Phase 2)" callout block beneath the table, with honest explanations linking to the actual code state (`loadFallbackConfigSync` hardcodes the config path; `logEvent` writes unconditionally). **F20** β€” Author docs/openai-spec-pin.md v0.1 baseline. ALIGNMENT.md Authority 2 + Annual Alignment Audit Β§ Scope both referenced `docs/openai-spec-pin.md` as the artifact the annual audit diffs against. Pre-D30 the file didn't exist (D20 marked it πŸ“‹ Planned). This left the entry-surface audit without a diff baseline β€” v0.1 ships with no provable "the OpenAI spec was THIS on the day OLP implemented its entry surface" anchor. Fix: author a 175-line minimal v0.1 baseline. Every field claim is verified against source (openai-to-ir.mjs + ir-to-openai.mjs + server.mjs). Structure: - POST /v1/chat/completions: 14 supported request fields (model, messages + 6 message-level subfields, stream, temperature, max_tokens, top_p, stop, tools, tool_choice, response_format) + 11 NOT-yet-supported fields (n, seed, frequency_penalty, presence_penalty, logit_bias, logprobs, top_logprobs, user, service_tier, parallel_tool_calls, stream_options) - Response shapes: chat.completion (non-stream), chat.completion.chunk (streaming) β€” verified against irResponseToOpenAINonStream and irChunkToOpenAISSE - `finish_reason` enum: verified against OPENAI_FINISH_REASON_ENUM constant in ir-to-openai.mjs (post-D19 + D26) - Error response shape: HTTP 4xx/5xx + `{error: {message, type}}` β€” verified against `sendError` in server.mjs - GET /v1/models: verified against handleModels (post-D18 + D27 F15) - Streaming SSE semantics: framing, terminator, post-D26 F19 truncation marker The pin also documents the v0.1 β†’ v1.0 forward-looking expansion plan: the "NOT yet supported" fields are explicit candidates for v1.0+ implementation via openai-to-ir.mjs amendments + ADR 0003 updates. ALIGNMENT.md + README Implementation status table both flip the marker from πŸ“‹ Planned to βœ… Shipped (D30) with the 2026-05-24 timestamp. Changes (3 files, +180 / -8): - ALIGNMENT.md +2/-2 (2 markers updated: Authority 2 + Annual Audit) - README.md +11/-6 (env-vars table delta + status table marker flip + Planned callout for OLP_HOME/OLP_LOG_LEVEL) - docs/openai-spec-pin.md (new, 175 lines) Tests: 400/400 unchanged β€” pure docs change. Authority: - F7 β†’ process.env reads verified by direct grep - F20 β†’ OpenAI Chat Completions spec https://platform.openai.com/docs/api-reference/chat/create https://platform.openai.com/docs/api-reference/chat/streaming https://platform.openai.com/docs/api-reference/chat/object https://platform.openai.com/docs/api-reference/models/list - F20 internal source-of-truth: openai-to-ir.mjs + ir-to-openai.mjs + server.mjs (all field claims traced) - ALIGNMENT.md Β§ Authority 2 + Β§ Annual Alignment Audit - CC 开发铁律 v1.6 Β§ 10.x β€” Round-3 Cold Audit caught both items Reviewer (Iron Rule v1.6 Β§ 10.x Mode A, fresh-context opus, independent of drafter): APPROVE. Independent verification: - Grep confirmed exactly 4 process.env.OLP_* reads β€” matches new env vars table - Each new var's default value verified against the plugin code (anthropic.mjs:69 β†’ 'claude'; codex.mjs:143 β†’ 'codex'; mistral.mjs:240 β†’ 'vibe') - All 14 spec-pin supported request fields traced to openAIToIR line references (model L129, messages L45-89, stream L141, temperature L160, max_tokens L152, top_p L168, stop L176, tools L183, tool_choice L187, response_format L191) - All 11 NOT-supported fields confirmed absent via grep - Response shape claims (chat.completion + chat.completion.chunk + /v1/models) all match source code line-by-line - ALIGNMENT.md markers β€” pure markup flip, no rule changes - 400/400 tests pass 3 non-blocking suggestions noted (function_call finish_reason caveat; README slug rendering; ADR 0003 cross-link in spec-pin) β€” all cosmetic, not folded. Co-Authored-By: Claude Opus 4.7 --- ALIGNMENT.md | 4 +- README.md | 13 ++- docs/openai-spec-pin.md | 175 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 186 insertions(+), 6 deletions(-) create mode 100644 docs/openai-spec-pin.md diff --git a/ALIGNMENT.md b/ALIGNMENT.md index 5a50a67..ebfb446 100644 --- a/ALIGNMENT.md +++ b/ALIGNMENT.md @@ -65,7 +65,7 @@ OLP exposes a single external HTTP surface: `/v1/chat/completions` in OpenAI Cha Citation format for entry-surface PRs: OpenAI spec URL + the specific field, parameter, or behaviour. Example: `OpenAI Chat Completions, response_format parameter (https://platform.openai.com/docs/api-reference/chat/create#chat-create-response_format)`. -The spec pin lives in `docs/openai-spec-pin.md` β€” deferred, not yet authored; will land before the first annual audit (target: v1.0). Not required for v0.1 governance bootstrap. +The spec pin lives in `docs/openai-spec-pin.md` β€” βœ… shipped as of D30 (2026-05-24); v0.1 baseline pinning the entry-surface fields OLP currently implements. Re-snapshot annually per Β§ Annual Alignment Audit. ### Authority 3 β€” IR contract (internal interop scope) @@ -156,7 +156,7 @@ In addition to the recurring 14 May audit below, the following one-shot audits a - **Date:** 14 May each year (the anniversary of the Anthropic 2026-05-14 announcement, which is the structural trigger for OLP). - **Scope (per-provider plugin):** For each enabled provider, re-audit the provider CLI version against the pin in the Authorities table above. Re-verify that every spawn invocation, flag, and output-parser expectation in `lib/providers/.mjs` still matches that CLI version's actual behaviour. Update the pin row in this file. -- **Scope (entry surface):** Snapshot OpenAI's `/v1/chat/completions` specification and diff against the pin in `docs/openai-spec-pin.md` (πŸ“‹ deferred β€” not yet authored; must be created before the first annual audit). For each field OLP implements, verify the spec still defines it the same way. Update the pin. +- **Scope (entry surface):** Snapshot OpenAI's `/v1/chat/completions` specification and diff against the pin in `docs/openai-spec-pin.md` (βœ… v0.1 baseline shipped D30). For each field OLP implements, verify the spec still defines it the same way. Update the pin. - **Scope (IR):** Diff the IR documented in ADR 0003 against the implementation in `lib/ir/`. Any drift triggers an amendment or a deletion PR. - **Scope (Risk Tier reclassifications):** For each provider, re-evaluate the risk tier against current ToS, FAQ language, and observed enforcement events from the past year. Reclassifications land as ADR 0006 amendments. - **Output:** A signed audit note committed to `docs/alignment-audits/YYYY-05-14.md` (πŸ“‹ `docs/alignment-audits/` directory does not exist yet; it is created when the first audit is conducted). Inline pin updates go into this file. diff --git a/README.md b/README.md index 8017fde..7c08b20 100644 --- a/README.md +++ b/README.md @@ -114,10 +114,15 @@ _placeholder β€” full table lands per-phase as variables are introduced._ | Variable | Default | Description | |---|---|---| | `OLP_PORT` | `3456` | HTTP listener port. | -| `OLP_HOME` | `~/.olp` | Config, providers, keys, cache, logs root. | -| `OLP_LOG_LEVEL` | `info` | One of `error`, `warn`, `info`, `debug`. | +| `OLP_CLAUDE_BIN` | `claude` (from PATH) | Override path to the `claude` binary (Anthropic provider). Useful when multiple `claude` installs are present. | +| `OLP_CODEX_BIN` | `codex` (from PATH) | Override path to the `codex` binary (OpenAI provider). | +| `OLP_VIBE_BIN` | `vibe` (from PATH) | Override path to the `vibe` binary (Mistral provider). | -Further variables (per-provider auth path overrides, cache size limits, fallback-engine knobs) land with the relevant phase. +> **πŸ“‹ Planned (Phase 2) β€” not yet read by the codebase:** +> - `OLP_HOME` (`~/.olp`) β€” Config, providers, keys, cache, logs root. Currently hardcoded to `~/.olp/config.json` in `loadFallbackConfigSync`; the env override path is a Phase 2 config-layer deliverable. +> - `OLP_LOG_LEVEL` (`info`) β€” Log level filter (`error`/`warn`/`info`/`debug`). `logEvent` currently writes unconditionally; level filtering is a Phase 2 observability deliverable. + +Further variables (per-provider auth path overrides, cache size limits, fallback-engine knobs) land with the relevant phase. See also the [Implementation status](#implementation-status-as-of-2026-05-24) table. --- @@ -155,7 +160,7 @@ Phase 1 is in progress. This table reflects what is currently shipped vs. what i | `lib/keys.mjs` | πŸ“‹ Planned (Phase 2) | Multi-key auth, per-key namespacing, audit log | | `dashboard.html` | πŸ“‹ Planned (Phase 6) | Owner-only multi-provider dashboard | | `docs/provider-caveats.md` | πŸ“‹ Planned (Phase 3+) | Lossy-translation reference; for now documented inline in each plugin header | -| `docs/openai-spec-pin.md` | πŸ“‹ Planned (Phase 1 gate) | OpenAI spec snapshot for annual audit; deferred from v0.1 bootstrap | +| `docs/openai-spec-pin.md` | βœ… Shipped (D30) | OpenAI spec snapshot for annual audit; v0.1 baseline pinned 2026-05-24 | | `docs/alignment-audits/` | πŸ“‹ Planned | Output directory for annual alignment audits (first audit: 2027-05-14) | | `scripts/migrate-from-ocp.mjs` | πŸ“‹ Planned (Phase 7) | OCP β†’ OLP migration tool | | `setup.mjs` | πŸ“‹ Planned | Setup wizard / initial config | diff --git a/docs/openai-spec-pin.md b/docs/openai-spec-pin.md new file mode 100644 index 0000000..70472bf --- /dev/null +++ b/docs/openai-spec-pin.md @@ -0,0 +1,175 @@ +# OpenAI Spec Pin (v0.1 baseline) + +- **Date pinned:** 2026-05-24 (D30) +- **Status:** v0.1 baseline β€” annual audit per ALIGNMENT.md Β§ Annual Alignment Audit +- **Authority:** OpenAI Chat Completions API + Models API + +This document is the spec-diff baseline against which OLP's annual audit will compare +future OpenAI spec changes. It enumerates the specific spec sections OLP currently +implements as the entry surface, verified against `lib/ir/openai-to-ir.mjs` and +`lib/ir/ir-to-openai.mjs` at the time of pinning. + +--- + +## Endpoints implemented + +### POST /v1/chat/completions + +- Spec section: https://platform.openai.com/docs/api-reference/chat/create +- Retrieval timestamp: 2026-05-24 + +**Request body fields supported** (translated into IR by `openAIToIR` in +`lib/ir/openai-to-ir.mjs`): + +| Field | Type | Required | Notes | +|---|---|---|---| +| `model` | string | required | Passed through to IR; validated non-empty | +| `messages` | array | required | Non-empty; each element translated via `translateMessage` | +| `messages[i].role` | string | required | `system` / `user` / `assistant` / `tool`; deprecated `function` normalized to `tool` | +| `messages[i].content` | string\|null | required | `null` normalized to `''` | +| `messages[i].name` | string | optional | Passed through to IR | +| `messages[i].tool_call_id` | string | optional | Passed through to IR | +| `messages[i].tool_calls` | array | optional | `{id, type:'function', function:{name, arguments}}` | +| `messages[i].function_call` | object | optional | Deprecated field; mapped to a single `tool_calls` entry | +| `stream` | boolean | optional | Default `false`; `true` triggers SSE path | +| `temperature` | number | optional | Range `[0, 2]`; passed to IR | +| `max_tokens` | integer | optional | Must be a positive integer; passed to IR | +| `top_p` | number | optional | Range `[0, 1]`; passed to IR | +| `stop` | string \| array | optional | Passed to IR as-is | +| `tools` | array | optional | Only `type:'function'` tools supported; translated via `translateTools` | +| `tools[i].function.name` | string | required (in tool) | Passed through | +| `tools[i].function.description` | string | optional | Passed through if present | +| `tools[i].function.parameters` | object | optional | Passed through if present | +| `tool_choice` | `'auto'`\|`'none'`\|`'required'`\|`{type:'function',function:{name}}` | optional | Passed to IR verbatim | +| `response_format` | object | optional | Passed to IR verbatim | + +**Request body fields NOT yet supported** (silently dropped by entry surface β€” not +read in `openAIToIR`): + +- `n` β€” multiple completions; OLP is single-completion only +- `seed` β€” deterministic sampling +- `frequency_penalty`, `presence_penalty` +- `logit_bias` +- `logprobs`, `top_logprobs` +- `user` +- `service_tier` +- `parallel_tool_calls` +- `stream_options` + +**Response shape (non-streaming)** β€” `object: 'chat.completion'` +(assembled by `irResponseToOpenAINonStream` in `lib/ir/ir-to-openai.mjs`): + +```json +{ + "id": "chatcmpl-", + "object": "chat.completion", + "created": , + "model": "", + "choices": [{ + "index": 0, + "message": { + "role": "assistant", + "content": "", + "tool_calls": [ ... ] + }, + "finish_reason": "" + }], + "usage": { ... } +} +``` + +- `usage` is included only when the provider surfaces token counts on the final chunk. +- `message.tool_calls` is included only when tool calls are present. +- `message.content` is `null` when there is no text content and tool calls are present. + +**Response shape (streaming)** β€” `object: 'chat.completion.chunk'` +(emitted by `irChunkToOpenAISSE` in `lib/ir/ir-to-openai.mjs`): + +```json +data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":,"model":"","choices":[{"index":0,"delta":{"role":"assistant","content":"..."},"finish_reason":null}]} + +data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":,"model":"","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]} + +data: [DONE] +``` + +- `delta` carries `role` (first chunk only), `content` (text chunks), or `tool_calls` (tool call chunks). +- Final stop chunk has `finish_reason` set and empty `delta`. +- `usage` is included in the stop chunk only when the provider surfaces token counts. +- Stream terminator: `data: [DONE]\n\n`. + +**`finish_reason` enum honored** (normalized by `normalizeFinishReason`; non-spec values +normalized to `'stop'`): + +- `stop` β€” natural completion +- `length` β€” truncated at `max_tokens` or synthesized on truncation (D19/D16) +- `tool_calls` β€” model stopped to emit a tool call +- `content_filter` β€” provider-side content filter +- `function_call` β€” deprecated; preserved for backwards compatibility +- `null` β€” in-progress (streaming delta chunks) + +**Error response shape:** + +HTTP 4xx/5xx with body: +```json +{ "error": { "message": "", "type": "" } } +``` + +No invented top-level `error` field on `chat.completion` objects (per ALIGNMENT.md +Rule 2 β€” D12 finding). Errors surface exclusively via HTTP status codes with the above +body shape. + +--- + +### GET /v1/models + +- Spec section: https://platform.openai.com/docs/api-reference/models/list +- Retrieval timestamp: 2026-05-24 + +Response shape (`handleModels` in `server.mjs`): + +```json +{ "object": "list", "data": [ ... ] } +``` + +Each entry: `{ "id": "", "object": "model", "created": , "owned_by": "" }` β€” +no invented fields (per D27 F15). Alias entries are also surfaced as separate list members +(per D27 F15 alias surfacing). + +--- + +### GET /health + +OLP-specific endpoint (not in OpenAI spec). Returns: +```json +{ "ok": true, "version": "", "providers": { "enabled": , "available": } } +``` + +--- + +## Streaming SSE semantics + +- MIME: `text/event-stream` +- Per-chunk framing: `data: \n\n` +- Terminator: `data: [DONE]\n\n` +- Truncation marker: `finish_reason: 'length'` synthesized when the provider generator + exhausts without a natural stop chunk (D26 F19 β€” mirrors D16 buffered-path semantics) +- Response headers on stream: `Content-Type: text/event-stream`, `Cache-Control: no-cache`, + `Connection: keep-alive`, `X-Accel-Buffering: no` plus OLP diagnostic headers + +--- + +## Audit method + +Annual audit (target 2027-05-14): re-fetch each cited URL above, diff against the field +lists above, file an ADR amendment for any newly-shipped OpenAI field or changed semantic +that OLP should implement. Consult `lib/ir/openai-to-ir.mjs` and `lib/ir/ir-to-openai.mjs` +as the implementation source of truth. + +--- + +## Scope note: v0.1 baseline + +This is a minimal baseline. v1.0+ should expand coverage to include the "NOT yet +supported" fields above where OLP intends to support them (via `openAIToIR` amendments + +ADR 0003 updates).