Files
ocp/models.schema.json
T
a17b6c0ad2 chore(release): v3.26.0 (#212)
* chore(release): v3.26.0 — maxTokens tells the truth, SPOT schema, release-job fix, ltBoot harness

Version 3.25.0 -> 3.26.0 (package.json; server.mjs reads VERSION from it, so /health and
/v1/models follow automatically). CHANGELOG's Unreleased section becomes v3.26.0.

Contents — five merged PRs, each with an independent fresh-context reviewer:

  #208  maxTokens aligned to the CLI registry (#195)      <- the only fleet-visible change
  #205  models.schema.json + CI validation (#196)
  #206  release.yml no-CHANGELOG path fix (#202)
  #204  ltBoot harness hardening + diagnostics (#199, #209)
  #207  cache-key guard comments (#200), AGENTS.md harness docs (#197)

The only user-visible change is advertised metadata: OpenClaw and other clients that read
maxTokens will see 64000/32000 instead of a uniform 16384. OCP's behavior is unchanged --
buildCliArgs passes no output-token flag, and max_completion_tokens appears nowhere in this
repo. No new endpoint, env var, CLI subcommand, or cli.js wire behavior. server.mjs is
untouched across the whole release, so ALIGNMENT.md requires no cli.js citation.

release_kit (Iron Rule 5.5) walked:
  - version_source package.json          bumped
  - changelog CHANGELOG.md               v3.26.0 section written
  - new file / SPOT / schema             models.schema.json documented in README
                                         (Available Models) and AGENTS.md (Key files)
  - Available Models table               no change needed; it carries no maxTokens column
  - Environment Variables / Endpoints    no additions this release
  - bootstrap_quirk_policy               no new one-time migration quirk

Remaining v3.25.0 mentions in README/docs are historical (describing what changed in that
release) and are correct as written; verified rather than bulk-replaced.

Suite: 462 passed, 0 failed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017gbqUZ8HfBZpjjbzQ85oH8

* docs(release): correct a false claim in the v3.26.0 notes and disclose three gaps

Release review found four problems, all in the CHANGELOG text — which for a release PR
IS the deliverable, since release.yml copies it verbatim into the GitHub Release body.

1. "instead of a uniform 16384" was FALSE.

    git show v3.25.0:models.json  ->  six entries 16384, claude-haiku-4-5-20251001 8192
    distinct prior values: [8192, 16384]     uniform? False

Issue #195's own title says "for every Opus/Sonnet entry" — it never claimed haiku. The
framing also understated haiku, which moved from a lower base. Corrected, and stated: every
model except claude-sonnet-4-6 (1.95x) moves by the same 3.91x, haiku included.

(Review called haiku "the largest change in the release". Verified: it is a TIE at 3.91x,
not the largest alone — 16384->64000 is the same multiplier. The entry says so.)

2. models.schema.json contradicted this release's own notes.

It shipped in this release (#205) saying maxTokens "bounds request and compaction budgets".
The CHANGELOG correctly says maxTokens does not affect behavior. The schema's compaction
half is wrong: in OpenClaw 2026.7.1 both the compaction trigger and the summarisation chunk
size derive from contextWindow (minus reserveTokensFloor / softThreshold), never from
maxTokens. Fixed the schema rather than the CHANGELOG, since the CHANGELOG was right.

This makes the release PR touch one non-version file. Deliberate: shipping two canonical
documents that contradict each other is worse than a slightly wider release diff, and the
schema is published in this same release.

3. #203 was omitted, and the ltBoot entry read as "harness flakiness fixed".

42/200 -> 200/200 is true and #203 is still OPEN — with four sightings, one of them on #205
INSIDE this release. The entry made exactly this disclosure for ocp-connect (#210) and not
for the bug the harness was built to chase. Now states it is not fixed, and points at #211.

4. contextWindow is wrong by the same registry this release cites.

    claude-opus-5 / -4-8 / -4-7 / claude-sonnet-5   registry window:1e6   models.json 200000

Publishing "the SPOT tells the truth" with a 5x understatement in the adjacent field is the
kind of thing that ages badly. Unlike maxTokens it is NOT a safe metadata fix —
derivePromptCharBudget takes max(contextWindow) x 3 across ALL entries, so one 1M model
takes MAX_PROMPT_CHARS from 600k to 3M for every model including a genuinely-200k haiku.
Filed as #213 (needs per-model budgets, ADR-level) and disclosed in the notes.

Also: `claude-haiku-4-5` appeared where the models.json id is `claude-haiku-4-5-20251001` —
the exact legacyAlias-vs-id confusion #208's test file exists to prevent. All three
occurrences now use the full id.

Verified: models.schema.json still parses; suite 462 passed, 0 failed; release.yml's awk
extraction on the corrected file yields 6348 bytes, correct section, terminating at v3.25.0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017gbqUZ8HfBZpjjbzQ85oH8

* docs(release): state the correction as fact, not as edit history

Review's style point, taken. The v3.26.0 section has never been published — no tag
exists — so release.yml's copy into the GitHub Release body is the FIRST time any
reader sees this text. "as an earlier draft of this entry claimed" corrects a claim
they never saw; it is internal editing history leaking into a public artifact. The
correction belongs in the commit record, where it already is in full.

Also split the 3.91x ratio into its own sentence — as an appositive it had to reach
back across an interrupting clause to find what it modified.

No factual change. Suite: 462 passed, 0 failed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017gbqUZ8HfBZpjjbzQ85oH8

---------

Co-authored-by: dtzp555 <dtzp555@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 21:28:18 +10:00

66 lines
4.0 KiB
JSON

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://github.com/dtzp555-max/ocp/blob/main/models.schema.json",
"title": "OCP models.json",
"description": "Schema for models.json, the single source of truth for model metadata (ADR 0003). Enforced in CI by test-features.mjs, which validates models.json against this file using the repo's own validateJsonSchema (lib/structured-output.mjs) — no new dependency. ⚠ ONLY A SUBSET OF DRAFT 2020-12 IS ENFORCED: type, required, const, enum, additionalProperties (boolean and schema forms), items, minItems, maxItems, anyOf/allOf/oneOf, $ref, nullable. Anything else — minimum, maxLength, pattern, uniqueItems, propertyNames, not — is SILENTLY IGNORED by that validator, so adding one here buys nothing and misleads the next reader. Add such a constraint as a test in test-features.mjs instead. NOTE: referential integrity (every aliases/legacyAliases target must exist as a models[].id) is likewise not expressible here and is covered by separate tests.",
"type": "object",
"required": ["version", "models", "aliases", "legacyAliases"],
"additionalProperties": false,
"properties": {
"$schema": {
"type": "string",
"description": "Relative path to this file. Editors use it for completion; CI does not read it."
},
"version": {
"const": 1,
"description": "Schema version of this document. Bump only alongside a shape change and an ADR."
},
"models": {
"type": "array",
"minItems": 1,
"description": "Every model OCP advertises on /v1/models, newest first. Order is load-bearing: ocp-connect uses model_ids[0] as a primary fallback.",
"items": {
"type": "object",
"required": ["id", "displayName", "openclawName", "reasoning", "contextWindow", "maxTokens"],
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"description": "Canonical CLI model id, passed verbatim to `claude --model`. Must match the id in the compiled CLI registry."
},
"displayName": {
"type": "string",
"description": "Human label. Also used as the OpenClaw agent alias by scripts/sync-openclaw.mjs."
},
"openclawName": {
"type": "string",
"description": "Label written into OpenClaw's model registry."
},
"reasoning": {
"type": "boolean",
"description": "Whether OpenClaw should treat the model as reasoning-capable."
},
"contextWindow": {
"type": "integer",
"description": "Advertised context window. GLOBAL side effect: MAX_PROMPT_CHARS derives from max(contextWindow) x 3 across ALL entries (lib/prompt.mjs derivePromptCharBudget), so raising this on ONE model raises the truncation ceiling for EVERY model. See ADR 0009. Also feeds OpenClaw's compaction budget."
},
"maxTokens": {
"type": "integer",
"description": "Advertised output cap. OCP does not enforce it: buildCliArgs passes no output-token flag to the CLI. It is propagated to OpenClaw (via setup.mjs / scripts/sync-openclaw.mjs) where it bounds REQUEST budgets only. It does NOT affect compaction: both the compaction trigger and the summarisation chunk size derive from contextWindow (minus reserveTokensFloor / softThreshold), never from this field. Verified against OpenClaw 2026.7.1."
}
}
}
},
"aliases": {
"type": "object",
"description": "Short name -> canonical models[].id. Client-addressable, so a repoint changes routing for every request using the alias. Cache keys resolve these before hashing (server.mjs cacheModel).",
"additionalProperties": { "type": "string" }
},
"legacyAliases": {
"type": "object",
"description": "Retired ids kept resolvable for backward compatibility -> canonical models[].id. Also client-addressable and also resolved in cache keys.",
"additionalProperties": { "type": "string" }
}
}
}