Skip to content

Commit fc39f5f

Browse files
committed
feat(scripts): check-changeset-no-major judges the protocol lockstep evidence; the local lockstep test hands the shape to it (ruling 6056808625, E)
When PROTOCOL_VERSION's major is one ahead of @objectstack/spec's stable version, the gate requires Changesets pre mode AND a pending major for the spec package, read from source text with no build, and otherwise refuses naming the remedy. Its own self-test battery covers both directions. The changeset is regraded major now that pre mode is on main. Claude-Session: https://claude.ai/code/session_01LAi5BVvQNiYzepSAcsoFLK Co-authored-by: Claude <noreply@anthropic.com>
1 parent 12b04b4 commit fc39f5f

3 files changed

Lines changed: 321 additions & 34 deletions

File tree

‎.changeset/22130-protocol-18.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
'@objectstack/spec': minor
2+
'@objectstack/spec': major
33
'@objectstack/mcp': patch
44
---
55

@@ -9,7 +9,7 @@ Clause-②: yes (widening: the exported `PROTOCOL_VERSION` moves to `'18.0.0'`,
99

1010
<!-- adr-0087: not-required (already-registered field-malformed-scale-precision-removed, record-chatter-position-vocabulary, element-input-target-variable-removed, element-filter-removed, element-form-removed, field-column-lists-canonicalized, metric-filters-removed, cube-sub-day-granularities-removed, cube-join-sql-and-relationship-removed, record-highlights-field-icon-removed, mapping-lookup-params-removed, translation-component-submit-label-removed, page-component-responsive-removed, object-grid-default-sort-removed, object-kanban-quick-add-removed, permission-allow-restore-purge-removed, form-view-option-default-removed, field-reference-to-alias, connector-error-mapping-removed, connector-connection-timeout-ms-removed, hook-timeout-to-timeout-ms, job-timeout-to-timeout-ms, api-endpoint-cache-ttl-to-cache-ttl-seconds, dashboard-refresh-interval-to-refresh-interval-seconds, connector-resilience-keys-removed, connector-triggers-removed, memory-persistence-auto-save-interval-to-ms, turso-config-timeout-to-timeout-ms, view-page-mount-removed, list-view-sort-string-clause-to-array, page-assigned-profiles-removed, chart-config-aria-removed, dashboard-widget-chart-config-structure-removed, translation-per-app-settings-removed, object-tenancy-organization-field-removed, page-component-filter-record-to-rule-array, view-item-owner-hidden-removed, report-joined-chart-removed, view-overlay-owner-hidden-removed, form-layout-inline-grid-to-vertical, currency-config-precision-removed, permission-rls-tags-removed, action-aria-removed, cube-member-inner-name-removed, flow-decision-mode-inclusive-explicit, view-list-tabs-removed, cube-refresh-key-removed, time-default-utc-suffix-dropped, page-header-breadcrumb-removed, connector-sync-keys-removed, form-view-subform-columns-canonicalized, action-block-endpoint-to-target, form-field-public-picker-removed, dataset-count-measure-empty-field-removed, agent-structured-output-refused-members-removed, translation-widget-sub-caption-removed, agent-memory-long-term-store-removed, agent-lifecycle-removed, object-grid-resizable-columns-removed, page-requires-non-compiled-kind-removed, element-text-variant-heading-levels, object-master-detail-form-detail-sort-field-removed, declared-index-unique-scope, manifest-permissions-string-list-removed) The protocol major moves, and that move publishes the already-registered step-18 chain as the current upgrade path: these are its 64 D2 conversions, which `os migrate meta --from 17` replays together with the step's 319 D3 semantic entries. Each entry was registered by the change that made its break, under that change's own disposition; this diff adds, renames and removes none. What a consumer edits beyond that chain is the manifest's `engines.protocol` range, which is the ADR-0087 D1 handshake's input rather than a metadata shape any conversion can rewrite. The other categories are closed on facts: the package publishes (not unpublished); a consumer has an edit to make (not no-migration-prescription); and an exported value and the load door move, not a TypeScript declaration alone (not runtime-interface-only or type-surface-only). -->
1111

12-
**BREAKING**, shipped as `minor` under the repo's launch-window convention for breaking changes. The protocol major moves in this reviewed change, not in the version pass (ruling record 6049734955, Q1 → B).
12+
**BREAKING**, graded `major`: Changesets is in pre mode (`next`) for the v18 line, so this ships in an `18.0.0-next.N` prerelease. The protocol major moves in this reviewed change, not in the version pass (ruling record 6049734955, Q1 → B). Until that line's first version pass, `PROTOCOL_VERSION` is one major ahead of the package version; `check-changeset-no-major.mjs` admits that only in pre mode with a pending `major` for `@objectstack/spec` (ruling record 6056808625).
1313

1414
- **`PROTOCOL_VERSION` reads `'18.0.0'`** and `PROTOCOL_MAJOR` reads `18`. The ADR-0087 D1 handshake on every load and install door (the app load seam, `POST /api/v1/packages`, `POST /api/v1/marketplace/install-local`) now admits a package whose `engines.protocol` admits major 18, and refuses one pinned to 17 (`'^17'`, `'^17.x.y'`, `'17.x'`) with `OS_PROTOCOL_INCOMPATIBLE` (422), naming `objectstack migrate meta --from 17`.
1515
- **What you change.** Run `objectstack migrate meta --from 17` and resolve what it lists, then declare `engines: { protocol: '^18' }` in the package manifest. `migrate meta` does not edit the range itself.

‎packages/spec/src/kernel/protocol-version.test.ts‎

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@ import { fileURLToPath } from 'node:url';
55
import { describe, expect, it } from 'vitest';
66
import { PROTOCOL_MAJOR, PROTOCOL_VERSION } from './protocol-version';
77

8-
/** The `repo`-project file that judges the pre-mode exception (see the lockstep case). */
9-
const PRE_MODE_CHECK = 'src/kernel/protocol-version-pre-mode.test.ts';
10-
118
describe('PROTOCOL_VERSION', () => {
129
it('is a valid semver string', () => {
1310
expect(PROTOCOL_VERSION).toMatch(/^\d+\.\d+\.\d+$/);
@@ -28,29 +25,22 @@ describe('PROTOCOL_VERSION', () => {
2825
const pkgMajor = Number.parseInt(pkg.version.split('.')[0]!, 10);
2926
if (PROTOCOL_MAJOR === pkgMajor) return;
3027

31-
// ONE exception (ruling record 6049734955 on #22085, Q1 → B): in Changesets
32-
// pre mode with a pending `major` for this package, the protocol major may
33-
// already equal the major that release is about to publish, so the protocol
34-
// move lands in an ordinary pull request with full CI instead of inside the
35-
// version pass. Its evidence is the repository's `.changeset/` directory,
36-
// which this `local` task does not hash (the #16466 split), and this file
37-
// stays `local` because release.yml's post-version check runs it there by
38-
// that project. So the exception is JUDGED in `PRE_MODE_CHECK`, in the
39-
// `repo` project, and this case only recognises its shape: a stable package
40-
// version exactly one major behind. Any other drift is red here.
28+
// ONE exception (ruling record 6049734955 on #22085, Q1 → B; its route,
29+
// ruling record 6056808625, letter E): in Changesets pre mode with a pending
30+
// `major` for this package, the protocol major may already equal the major
31+
// that release is about to publish, so the protocol move lands in an
32+
// ordinary pull request with full CI instead of inside the version pass.
33+
// Its evidence is the repository's `.changeset/` directory, which a `local`
34+
// test may not read (check:cross-package-test-inputs), and this file stays
35+
// `local` because release.yml's post-version check runs it by that project.
36+
// So this case recognises the exception's SHAPE only (a stable package
37+
// version exactly one major behind) and the evidence (pre mode AND a pending
38+
// `major` for @objectstack/spec) is judged by the repository gate
39+
// check-changeset-no-major.mjs, which the Check Changeset job runs on every
40+
// pull request and which refuses the shape without that evidence. Any other
41+
// drift is red here.
4142
const preModeShape = PROTOCOL_MAJOR === pkgMajor + 1 && !pkg.version.includes('-');
42-
if (preModeShape) {
43-
// The hand-off must point at a check that runs: the `repo` project's
44-
// include list is this package's own `vitest.repo-tests.json`.
45-
const listPath = fileURLToPath(new URL('../../vitest.repo-tests.json', import.meta.url));
46-
const repoTests = JSON.parse(readFileSync(listPath, 'utf8')) as string[];
47-
expect(
48-
repoTests,
49-
`PROTOCOL_VERSION ${PROTOCOL_VERSION} is one major ahead of @objectstack/spec@${pkg.version}; ` +
50-
`only ${PRE_MODE_CHECK} (repo project) can confirm the pre-mode exception, and it is not listed`,
51-
).toContain(PRE_MODE_CHECK);
52-
return;
53-
}
43+
if (preModeShape) return;
5444
expect(PROTOCOL_MAJOR).toBe(pkgMajor);
5545
});
5646
});

0 commit comments

Comments
 (0)