Skip to content

Commit ee9bf03

Browse files
committed
Merge origin/main into claude/issue-18719-retracted-claim-leaves-the-pool
2 parents fdd09cd + e2050ce commit ee9bf03

7 files changed

Lines changed: 2165 additions & 37 deletions

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
'@objectstack/core': patch
3+
'@objectstack/plugin-auth': patch
4+
'@objectstack/organizations': patch
5+
---
6+
7+
Build freshness: these three packages now write the repo's build-input content
8+
stamp as the last step of their own build, and are checked for freshness (not
9+
merely existence) by `check:dev-prereqs`.
10+
11+
What changes for a consumer: each tarball now carries two extra inert metadata
12+
files inside `dist/``.build-input-hash` and `.build-input-hash-dts`, the same
13+
pair `@objectstack/spec` has always shipped. Nothing is imported, executed or
14+
resolved from them, no export moves and no runtime behaviour changes.
15+
16+
Why: a sibling checkout that links these packages by `link:` compiles against
17+
their `dist/`, so a dist built from an older tree surfaces as a type error
18+
naming an import nobody touched, with the symbol present in `src/` the whole
19+
time. A HEAD-versus-pin comparison is silent through that; a content stamp
20+
written by the build itself is not.

packages/core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
}
2020
},
2121
"scripts": {
22-
"build": "tsup && node ../../scripts/check-dts-emitted.mjs",
22+
"build": "tsup && node ../../scripts/check-dts-emitted.mjs && node ../../scripts/check-dev-prereqs.mjs --stamp",
2323
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.examples.json && pnpm check:test-typecheck",
2424
"check:test-typecheck": "tsx ../../scripts/check-test-typecheck.mts --self-test && tsx ../../scripts/check-test-typecheck.mts --package packages/core --project tsconfig.test.json",
2525
"gen:test-typecheck-debt": "tsx ../../scripts/check-test-typecheck.mts --update --package packages/core --project tsconfig.test.json",

packages/plugins/organizations/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
}
1515
},
1616
"scripts": {
17-
"build": "tsup --config ../../../tsup.config.ts && node ../../../scripts/check-dts-emitted.mjs",
17+
"build": "tsup --config ../../../tsup.config.ts && node ../../../scripts/check-dts-emitted.mjs && node ../../../scripts/check-dev-prereqs.mjs --stamp",
1818
"test": "vitest run",
1919
"typecheck": "tsc --noEmit && pnpm check:test-typecheck",
2020
"check:test-typecheck": "tsx ../../../scripts/check-test-typecheck.mts --self-test && tsx ../../../scripts/check-test-typecheck.mts --package packages/plugins/organizations --project tsconfig.test.json"

packages/plugins/plugin-auth/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
}
2020
},
2121
"scripts": {
22-
"build": "tsup && node ../../../scripts/check-dts-emitted.mjs",
22+
"build": "tsup && node ../../../scripts/check-dts-emitted.mjs && node ../../../scripts/check-dev-prereqs.mjs --stamp",
2323
"test": "vitest run",
2424
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.examples.json && pnpm check:test-typecheck",
2525
"check:test-typecheck": "tsx ../../../scripts/check-test-typecheck.mts --self-test && tsx ../../../scripts/check-test-typecheck.mts --package packages/plugins/plugin-auth --project tsconfig.test.json",

scripts/check-dev-prereqs.mjs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,31 @@
202202
* how every package builds, for packages whose stale dist fails loudly instead
203203
* of lying. AGENTS.md §9's stale-artefact table names exactly one dist that
204204
* presents as *other people's* contract drift, and it is `packages/spec`.
205+
*
206+
* A SECOND ADMISSION CRITERION, read from one repo further out (#16529). A
207+
* sibling checkout links `@objectstack/*` by `link:` — objectstack-ai/cloud
208+
* does it for 184 specifiers — and compiles against the linked package's
209+
* `dist/`. A stale dist there surfaces as `TS2305 … has no exported member
210+
* …` naming an import nobody touched, with the symbol present in `src/` the
211+
* whole time: row one's lie, read across a repository boundary. The consumer
212+
* cannot close it from its side — its preflight compares the sibling's HEAD
213+
* against its pin, and a sibling sitting EXACTLY on the pin whose dist was
214+
* built from an older commit is silent through that comparison. So a package a
215+
* sibling checkout actually links is admitted here too, and the stamp its build
216+
* already writes is what that preflight reads.
217+
* ⛔ That reading does NOT make this file's stamp a cross-repo contract. It is
218+
* internal dev tooling shared by sibling checkouts — both repositories are
219+
* ours, the format may change without notice, and when it does the sibling's
220+
* preflight reds once and is fixed in the same breath. No version number, no
221+
* stable-location promise, no docs page (maintainer ruling on #16529).
222+
* ⚠ THIS LIST IS SHORT OF THAT CLOSURE, declared rather than inherited: the
223+
* three entries under criterion 2 are the ones that ruling names; the remainder
224+
* of the 184-specifier closure is not derivable from inside this repository.
225+
* ⛔ "Every workspace package that emits a `dist/`" is a DIFFERENT set and not
226+
* a stand-in for it — it would add a build step for packages no reader links.
227+
* The shortfall is monotone-safe: the coverage error fires only on LISTED
228+
* packages, so a short list checks less and can never false-red.
229+
*
205230
* Adding the next amplifier is two lines: its path in AMPLIFIERS, and `--stamp`
206231
* at the end of its build script — and NEITHER half can be forgotten, because
207232
* a listed package whose build script does not stamp fails this gate as a
@@ -355,14 +380,23 @@ const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
355380

356381
/**
357382
* Packages whose dist is checked for FRESHNESS and not merely existence, as
358-
* workspace-relative POSIX paths. See the header for the admission criterion
359-
* ("a stale dist that presents as somebody else's contract drift") and for why
360-
* this is a declared list rather than every package.
383+
* workspace-relative POSIX paths. See the header for the TWO admission criteria
384+
* ("a stale dist that presents as somebody else's contract drift", and "a
385+
* sibling checkout links it") and for why this is a declared list rather than
386+
* every package.
361387
*
362388
* Every entry MUST end its `build` script with STAMP_INVOCATION; a listed
363389
* package that does not is a coverage error, not a silent pass.
364390
*/
365-
const AMPLIFIERS = ['packages/spec'];
391+
const AMPLIFIERS = [
392+
// Criterion 1 — a stale dist here reads as somebody else's contract drift.
393+
'packages/spec',
394+
// Criterion 2 — linked by `link:` from a sibling checkout, where a stale dist
395+
// is a TS2305 naming an import nobody touched. See the header.
396+
'packages/core',
397+
'packages/plugins/plugin-auth',
398+
'packages/plugins/organizations',
399+
];
366400

367401
/** What an amplifier's build script must END WITH for its stamp to be maintained. */
368402
const STAMP_INVOCATION = 'check-dev-prereqs.mjs --stamp';

0 commit comments

Comments
 (0)