Skip to content

feat(schema): forward-compatible .basou format version gate (M4 pre-freeze)#153

Merged
takashi-matsuyama merged 2 commits into
mainfrom
feat/schema-version-gate
Jul 1, 2026
Merged

feat(schema): forward-compatible .basou format version gate (M4 pre-freeze)#153
takashi-matsuyama merged 2 commits into
mainfrom
feat/schema-version-gate

Conversation

@takashi-matsuyama

Copy link
Copy Markdown
Member

First M4 (semver-1.0 freeze) increment, settling the format-versioning policy
from decision_01KWE3VYJN (decouple + gate).

What

Replace the .basou schema_version / basou_version literal 0.1.0 with
a forward-compatible format-major acceptor:

  • Accept any 0.x.y — a newer minor/patch parses, because the entity schemas
    are loose and preserve unknown fields (additive-compatible).
  • Gate a higher/unknown major (1.x.y+) with an explicit "upgrade basou"
    error instead of a cryptic field-level parse failure.
  • The format major is decoupled from the npm/product version: product
    1.0.0 does not bump it — it stays 0 until the format itself changes.

Why before the freeze

The gate behavior is itself part of the frozen on-disk format contract. It
cannot be retrofitted onto a frozen literal: durable files (manifest /
session / event / approval / task) carry no migration path, so freezing at
z.literal("0.1.0") would make any future format-major bump an unrecoverable
hard break. This is the one M4 piece that must land pre-freeze.

Scope

  • shared.schema.ts: SchemaVersionSchemaz.string().regex(/^0\.\d+\.\d+$/)
    with a friendly gate message. Regex (not a refine) so the published JSON
    Schema carries pattern (cross-language validators enforce the same major).
  • manifest / status basou_version reuse the same acceptor (format stamp,
    not the product version; flagged as a consolidation candidate for the freeze).
  • Regenerated the 8 published JSON Schemas (constpattern).
  • Left source.version (session / session-import) untouched — a separate
    source-attribution axis, out of this decision's scope. Flagged as a follow-up:
    do we also forward-compat-gate it, or is a literal fine there?

Verification

  • pnpm -r build / pnpm typecheck ok; pnpm lint exit 0
  • pnpm -r test:coverage: core 1262 / sdk 18 / cli 936; all above floor
  • json-schema drift guard passes (generated == committed)

…reeze)

Replace the `SchemaVersionSchema = z.literal("0.1.0")` (and the manifest /
status `basou_version` literal) with a format-major acceptor: accept any
`0.x.y` (a newer minor/patch parses because the entity schemas are loose and
preserve unknown fields) and gate a higher/unknown major (`1.x.y`+) with an
explicit "upgrade basou" error instead of a cryptic field-level parse failure.

Why now: the gate behavior is part of the frozen on-disk format contract, so it
must be defined BEFORE the semver-1.0 freeze -- it cannot be retrofitted onto a
frozen literal (a future format-major bump would otherwise be an unrecoverable
hard break, since durable files carry no migration path). The format major is
decoupled from the npm/product version: product 1.0.0 does not bump it; it stays
0 until the format changes incompatibly.

- shared.schema.ts: SchemaVersionSchema is now `z.string().regex(/^0\.\d+\.\d+$/)`
  with a friendly gate message; the regex (not a refine) is emitted into the
  published JSON Schema `pattern` so cross-language validators enforce the same
  major.
- manifest/status basou_version reuse the same acceptor (a format stamp, not the
  product version; noted as a consolidation candidate for the freeze pass).
- Regenerated the 8 published JSON Schemas: `const: "0.1.0"` -> `pattern`.
- Left the source-attribution `source.version` literal untouched (a separate
  axis, out of this decision's scope; flagged for a follow-up).

Settles decision_01KWE3VYJN (M4 format versioning policy: decouple + gate).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@takashi-matsuyama takashi-matsuyama force-pushed the feat/schema-version-gate branch from 888f8e0 to 04d1cb2 Compare July 1, 2026 07:36
…ew fixes)

Applies the three verified findings from the adversarial review of the version
gate:

1. (high) The forward-compat promise was false outside ManifestSchema: session
   / task / approval used default z.object (STRIP), and finalizeSessionYaml
   reparses and overwrites, so a future 0.x file's unknown fields would be
   silently dropped on read+rewrite. Make those durable entity schemas
   looseObject (like manifest) so unknown fields are preserved -- this is what
   makes accepting a higher minor safe. Event schemas are left as-is (their
   rewrite path, chainRawJsonLines, preserves raw records, and they carry
   deliberate .strict() variants).

2. (medium) The gate leaked into cache schemas: task-index and status's own
   schema_version used SchemaVersionSchema, so their published JSON Schema
   loosened to a pattern while the runtime exact-matches and rebuilds. Add a
   distinct CacheVersionSchema (exact literal) for rebuildable caches; keep
   status.workspace.basou_version on the durable gate (it mirrors the manifest).

3. (medium) The "upgrade basou" guidance was buried: basou status wraps a
   manifest read failure as a generic pathless message. Surface the gate issue
   message specifically (it is value-free, so unlike a raw ZodError it is safe
   to print) while other validation errors stay wrapped.

Regenerated the published JSON Schemas. Tests: session preserves an unknown
field; status pins its cache schema_version but gates workspace.basou_version;
basou status surfaces the upgrade message for a too-new manifest.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@takashi-matsuyama takashi-matsuyama merged commit 3ccd636 into main Jul 1, 2026
7 checks passed
@takashi-matsuyama takashi-matsuyama deleted the feat/schema-version-gate branch July 1, 2026 09:29
takashi-matsuyama added a commit that referenced this pull request Jul 1, 2026
Bump packages/{basou,core,cli,sdk} to 0.31.0 and finalize the CHANGELOG
section. Bundles the M4 (API/format freeze) pass:

- Portfolio view live repo links (#152).
- .basou format version gate — forward-compatible format major (#153).
- Remove project.repository_url; --repo-url kept as a deprecated no-op (#154).
- semver 1.0 compatibility & stability policy doc (#155).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
takashi-matsuyama added a commit that referenced this pull request Jul 1, 2026
Bump packages/{basou,core,cli,sdk} to 0.31.0 and finalize the CHANGELOG
section. Bundles the M4 (API/format freeze) pass:

- Portfolio view live repo links (#152).
- .basou format version gate: forward-compatible format major (#153).
- Remove project.repository_url; --repo-url kept as a deprecated no-op (#154).
- semver 1.0 compatibility and stability policy doc (#155).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
takashi-matsuyama added a commit that referenced this pull request Jul 1, 2026
Bump packages/{basou,core,cli,sdk} to 0.31.0 and finalize the CHANGELOG
section. Bundles the M4 (API/format freeze) pass:

- Portfolio view live repo links (#152).
- .basou format version gate: forward-compatible format major (#153).
- Remove project.repository_url; --repo-url kept as a deprecated no-op (#154).
- semver 1.0 compatibility and stability policy doc (#155).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant