feat(schema): forward-compatible .basou format version gate (M4 pre-freeze)#153
Merged
Conversation
…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>
888f8e0 to
04d1cb2
Compare
…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
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
First M4 (semver-1.0 freeze) increment, settling the format-versioning policy
from
decision_01KWE3VYJN(decouple + gate).What
Replace the
.basouschema_version/basou_versionliteral0.1.0witha forward-compatible format-major acceptor:
0.x.y— a newer minor/patch parses, because the entity schemasare loose and preserve unknown fields (additive-compatible).
1.x.y+) with an explicit "upgrade basou"error instead of a cryptic field-level parse failure.
1.0.0does not bump it — it stays0until 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 unrecoverablehard break. This is the one M4 piece that must land pre-freeze.
Scope
shared.schema.ts:SchemaVersionSchema→z.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/statusbasou_versionreuse the same acceptor (format stamp,not the product version; flagged as a consolidation candidate for the freeze).
const→pattern).source.version(session / session-import) untouched — a separatesource-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 typecheckok;pnpm lintexit 0pnpm -r test:coverage: core 1262 / sdk 18 / cli 936; all above floor