Repository navigation
Commit 93e9e42
fix(spec): the etl-pipeline and unresolvable-where-column migration entries state what the tree does (#20838)
Fixes #20773
Fixes #20467
Clause-②: no
Two ADR-0087 D3 semantic entries no longer said what the tree does. This
PR corrects the text only. It has one commit per card and one shared
`patch` changeset for `@objectstack/spec`. Each entry was edited by hand
at its source, and every generated copy was written by its own
generator.
**Owed before enqueue:** the at-tier contract review by the owning seat.
The review face is `packages/spec/src/**` (non-test). This PR does not
carry that record.
## Card 20773: `etl-pipeline-layer-retired` (protocol 17), commit
`27070673`
The `replacement` text said `syncConfig.schedule` was retired "in 18
under ADR-0049". Measured on base `810d42b6`:
- `packages/spec/src/integration/connector.zod.ts:296` reads:
"`syncConfig.schedule` was DELETED here in @objectstack/spec 17
(ADR-0049 enforce-or-remove ...".
- The deleting commit is `929d9e3f20` ("delete the seven cron-typed
positions outright"). `packages/spec/CHANGELOG.md` lists it as `929d9e3`
at line 8699, under `## 17.5.0` (line 3; the next heading is `## 17.4.0`
at line 14893). The REST compare agrees: the `@objectstack/spec@17.5.0`
tag is 1549 commits ahead of it and 0 behind, and
`@objectstack/spec@17.4.0` is 172 commits behind it, so 17.4.0 does not
contain it.
- No protocol-18 entry or conversion names `syncConfig`: `git grep
syncConfig` over `src/migrations/entries` and `src/conversions` has 0
hits outside this entry.
The sentence now reads "the same measurement that deleted
`syncConfig.schedule` in @objectstack/spec 17 under ADR-0049", which
matches the wording of `connector.zod.ts`. The rest of that
`replacement` paragraph (the `ConnectorSchema.syncConfig` routing) is
untouched, because that rewrite belongs to #20281. The released
`CHANGELOG.md` sentence (line 11485) is left as history.
## Card 20467: `driver-sql-unresolvable-where-column-refused` (protocol
18), commit `f45b0968`
The entry named only a `where` column on `find()` / `findOne()` /
`count()`, and only `INVALID_FILTER` / 400. Measured on base `810d42b6`,
which contains `3e8b492d` (`git merge-base --is-ancestor 3e8b492 HEAD`
exit 0):
- `TursoDriver.remoteReadFault`
(`packages/drivers/driver-turso/src/turso-driver.ts`) classifies every
remote read exit, `aggregate` included, with the local face's own
`SqlDriver.aggregateBackendFault`
(`packages/drivers/driver-sql/src/sql-driver.ts:10768`).
-
`packages/drivers/driver-turso/src/turso-local-remote-missing-table-column-parity.test.ts`
pins both faces to one answer. An aggregate over an absent table gets
`DATABASE_ERROR` / 500. An aggregate grouped by, or summing, a declared
field whose column is absent gets `INVALID_FIELD` / 400. An aggregate
whose `where` names that field gets `INVALID_FILTER` / 400. Before, the
remote face answered `[]` to all three.
What changed in the entry:
- **`surface`** names the `aggregate()` door of the remote face and its
three codes.
- **`replacement`** (the remedy) adds grouping and aggregating, and "so
the object's table exists".
- **`acceptanceCriteria`** adds reports and dashboards that group by, or
aggregate over, a missing column. It quotes the driver's `INVALID_FIELD`
message fragment "has no column for, so the aggregate never ran"
(`unresolvableAggregateColumnRefusal`) and names `DATABASE_ERROR` / 500
for an absent table.
- **`reason`** is not touched.
**Generated copies for this card: `registry.ts` only.**
`spec-changes.json` and `docs/protocol-upgrade-guide.md` project the
chain up to the current protocol (`spec-changes.json` has `"from": 16,
"to": 17`). Neither carries any step-18 entry: `grep -c
driver-sql-unresolvable-where-column-refused` answers 0 in each. The
generators ran and left both files unchanged. The claim's file surface
named them, so this is stated here as measured, not skipped.
## Proof that the generated diff is only the entries' text
`git diff --stat 810d42b f45b096`:
```
.changeset/20773-etl-entry-syncconfig-schedule-deleted-in-17.md | 28 ++++++++++++++++++++++++++++
docs/protocol-upgrade-guide.md | 2 +-
packages/spec/spec-changes.json | 4 ++--
.../spec/src/migrations/entries/semantic/17.etl-pipeline-layer-retired.ts | 4 ++--
.../entries/semantic/18.driver-sql-unresolvable-where-column-refused.ts | 16 ++++++++++++----
packages/spec/src/migrations/registry.ts | 20 ++++++++++++++------
6 files changed, 59 insertions(+), 15 deletions(-)
```
- **Commit `27070673`.** A token diff (`git diff --word-diff=porcelain
--word-diff-regex='[^[:space:]]+'`) shows exactly two swaps, `retired`
to `deleted` and `18` to `@objectstack/spec 17`. They appear in 5
places: the entry, `registry.ts`, `spec-changes.json` twice, and the
upgrade guide. No other token changed.
- **Commit `f45b0968`.** The 16 changed lines of `registry.ts` are
byte-identical, with indentation normalised, to the 16 changed lines of
the entry file (`cmp` exit 0). They sit in 4 hunks at lines 9156 to
9244, inside the entry block that starts at `registry.ts:9151`.
- **Control, one-shot.** With the entry carrying the new sentence, each
generated copy was restored to `810d42b6`, and each gate went red:
`check:migration-registry` exit 1, `check:spec-changes` exit 1,
`check:upgrade-guide` exit 1. `git checkout HEAD --` then restored each
copy. Its blob hash equals HEAD's, and `git diff HEAD` is empty. So
every copy is generator-owned and gated.
## Verification at the final head `f45b0968`
- `pnpm --filter @objectstack/spec build`: exit 0. Spec has no workspace
dependencies, so its dependency closure is empty.
- `pnpm --filter @objectstack/spec exec vitest run --project local`: 578
files, 17065 passed, 1 todo. The existing pins over both entries
(`migrations.test.ts`, `cron-typed-positions-retirement.test.ts`) pass
172 of 172.
- `pnpm --filter @objectstack/spec run typecheck` (tsc, scripts
typecheck, test typecheck): exit 0.
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derives 83 commands. All 83 were run, each
with its exit code captured to a file before any pipe. The `--ran`
reconciliation reads: 83 derived, 81 run, 2 NOT-MEASURED, 0 UNRUN. The
named families all exit 0: `check-adr-0087-registration --base
origin/main` ("this PR adds no declared-breaking changeset"),
`check:migration-registry`, `check:spec-changes`, `check:upgrade-guide`,
`check:generated` ("All 15 generated artifacts are up to date"),
`check:doc-authoring`, `check:changeset-no-major`,
`check-empty-changeset` and `check:nul-bytes`.
- **NOT MEASURED, 2 gates. CI runs both.**
- `node scripts/check-plugin-teardown-shape.mjs --self-test` exits 3.
Its positive control is pinned to commit `621a4876`, which this shallow
clone cannot reach. It only checks the checker's own health.
- `pnpm check:dual-build-cjs-loads` exits 3. It needs every package's
`dist/`, which a text-only spec diff does not build.
- Two other gates first exited 3 and were cleared by building their
prerequisites (`@objectstack/formula`, `@objectstack/lint`,
`@objectstack/objectql`). Both then passed:
`check:doc-formula-expressions` 0 and `check:lean-entry-closure` 0.
- **eslint, narrowed to the changed files.** `eslint --no-inline-config
--format json` over the 6 changed paths at `f45b0968` returns 6 results.
eslint's own config lints the 3 `.ts` files, with 0 errors and 0
warnings. It reports the `.md` and `.json` files as "File ignored
because no matching configuration was supplied". `eslint.config.mjs`
never enables type-aware linting (no `parserOptions.project`, as it
states at lines 326 to 328), so this diff cannot change a verdict on a
file it did not touch. The full `pnpm lint` run belongs to CI.
- **No new test.** The changed text is prose, and no consumer parses the
version phrase or the code list out of it.
## Acceptance notes
- `origin/main` moved 4 commits past the base, to `4b45afae`. None of
those commits touches these six paths (`git diff --name-only 810d42b
origin/main` has no overlap). The branch was not merged, because the
queue rebuilds it on current main.
- The `reason` of `driver-sql-unresolvable-where-column-refused` keeps
its 2026-08-16 addendum sentence "The entry id, surface and prescription
are unchanged — this is a text amendment". That sentence describes that
addendum, while this PR does change `surface`. It is left as history,
because the claim's file surface excludes `reason`. Nobody else is set
to edit that text.
- The docblock table in `turso-driver.ts` (the "remote []" column in
`remoteReadFault`'s doc) is labelled "Measured at base `6e3e5462c`": it
is the before-state of the refusal change, not a stale claim. This is
not a finding.
- Card 20467's body names the upgrade guide as a reader of this entry.
At protocol 17 the guide renders no step-18 entry, so today the entry
reaches authors through `os migrate meta` and `registry.ts` only.
---
_Generated by [Claude
Code](https://claude.ai/code/session_018fxqvRJW12TaHC7DUQ89Y6)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 5cd403e commit 93e9e42
6 files changed
Lines changed: 59 additions & 15 deletions
File tree
- .changeset
- docs
- packages/spec
- src/migrations
- entries/semantic
Lines changed: 28 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
343 | 343 | | |
344 | 344 | | |
345 | 345 | | |
346 | | - | |
| 346 | + | |
347 | 347 | | |
348 | 348 | | |
349 | 349 | | |
| |||
0 commit comments