Skip to content

Commit 101eeed

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/issue-15463-chart-field-unknown-tier
2 parents 5ef3aa7 + 70c9399 commit 101eeed

14 files changed

Lines changed: 2103 additions & 141 deletions
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
"@objectstack/cli": patch
3+
---
4+
5+
`os generate migration` gives a table's own `id` column the shape the platform actually creates.
6+
7+
Both migration generators hardcoded the primary key as a UUID — `"id" UUID PRIMARY KEY DEFAULT gen_random_uuid()` in the SQL format, `table.uuid('id').primary().defaultTo(db.fn.uuid())` in the TypeScript one (the default format). The platform's SQL driver emits `table.string('id').primary()`, which is knex's `varchar(255)`. A platform id is a string, not a uuid, so on Postgres the generated table refused the platform's very first insert with `22P02 invalid input syntax for type uuid`.
8+
9+
The quieter half is the `DEFAULT`, and it is why this was worth correcting rather than working around. The driver emits no database-side default at all — its insert path always supplies the id itself — so `gen_random_uuid()` never fired for a platform write, only for an out-of-band one, handing that row a 36-character uuid this platform's id generator would never mint. One table would then hold two incompatible id shapes, with nothing said.
10+
11+
Both generators now emit the driver's own answer: `"id" VARCHAR(255) PRIMARY KEY` and `table.string('id').primary()`. The correction also closes a contradiction inside the generator file, whose prose already stated that a reference column takes the width of the target's `id` column *because* the driver emits `table.string('id').primary()` — a few hundred lines above the two lines that emitted `uuid`.
12+
13+
`generate-builtin-id-column.pin.test.ts` reads the width from the driver's own `DEFAULT_STRING_VARCHAR_CHARS` rather than transcribing `255`, so the generators cannot drift away from the driver again without a named failure.

docs/qa/platform-checklist/FOLLOW-UPS.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,3 +531,89 @@ Nothing withheld from this PR. The three new auth-adjacent items
531531
access-security.me-permissions-aggregation-parity) assert **shipped guards** already
532532
public in their issues/ADRs; K1–K6 are UX/correctness/discipline findings; no unfixed
533533
privilege escalation is disclosed anywhere in this sweep.
534+
535+
## 10. Scoped sweep 2026-09-04 — the REST-config coverage kinds (#14961)
536+
537+
A **scoped** sweep, not a full one: `check:platform-checklist` was red on `main` with
538+
five capability ledgers UNCLASSIFIED, and the question was "does the checklist cover
539+
these?" rather than "what else is missing?". SWEEP.md permits the scoped shape — run the
540+
relevant angle only — and this run used **angle 3 (routes & runtime)** against
541+
`packages/rest`, `packages/spec/src/api/rest-server.zod.ts` and the five liveness
542+
ledgers. ⚠️ **It was executed SEQUENTIALLY by one reader** (no sub-agent tool in the
543+
session), which SWEEP.md allows as a degraded path with a declaration: the items authored
544+
below stand on their own evidence, but this run supports **no** claim that nothing else
545+
is missing in these areas.
546+
547+
Ledger **260 → 264 items**; `coverage.json` 31 → **35 kinds mapped, 1 waived** (the first
548+
waiver since the 2026-08-17 re-audit reached zero — see §10d for why it is not a
549+
regression to zero-waiver discipline). What follows is what is NOT a checklist item.
550+
551+
### 10a. The kind set had already drifted when the card was dispatched
552+
553+
The card (#14961) names four kinds, measured at `ca3fd4b1` on 2026-09-03. On
554+
`6f944589` (2026-09-04) the gate reported **five**: `realtime_subscription` was enrolled
555+
the same morning. The card's own triage anticipated exactly this ("re-run the gate on
556+
today's `origin/main`: the four kinds may have moved"), and the gap between filing and
557+
dispatch was under 24 hours. ⭐ That is the sharpest available argument for **#11730**
558+
(this gate has no reporting channel): the population it audits drifts faster than a
559+
maintainer-triggered run observes it, and here it drifted *inside the lifetime of the
560+
card filed against it*. Recorded, not acted on — the channel question is #11730's.
561+
562+
### 10b. Product / design findings (decide handling)
563+
564+
| # | finding | evidence | captured in | handling |
565+
|---|---|---|---|---|
566+
| E1 | **`metadata.endpoints.items` gates four routes, three of which its declared meaning does not cover** — its `describe()` says "GET /meta/:type — List items of type", and it also gates `GET {prefix}/diagnostics`, `GET {prefix}/_drafts` and the **`POST {prefix}/_migrate-stored` write door**. An operator switching off a listing read silently disarms a migration door and the cross-type spec-validation sweep. `endpoints.item` is milder but the same shape: it also takes `{prefix}/book/:name/tree`. | `packages/rest/src/rest-server.ts#registerMetadataEndpointsInner` (four `endpoints.items` gates, four `endpoints.item` gates) vs `packages/spec/src/api/rest-server.zod.ts#MetadataEndpointsConfigSchema` (one route named per switch) | api-backend.rest-metadata-config-contract (a clause requires the run to ENUMERATE each switch's real radius) | design/docs — filed as #15542 |
567+
| E2 | **No shipped boot path authors `RestServerConfig` at all.** `os serve` constructs the REST plugin with a fixed config (only `enableProjectScoping` / `projectResolution` are threaded) and the dev plugin calls `createRestApiPlugin()` with none, so `crud` / `metadata` / `batch` / `routes` are reachable only from embedder code (`createRestApiPlugin({ api })`, `createHonoServerPlugin({ restConfig })`). A deployment cannot set `batch.maxBatchSize`, move `crud.dataPrefix`, or opt out of ADR-0106 D8 masking without embedding. | `packages/cli/src/commands/serve.ts` (the fixed construction) · `packages/plugins/plugin-dev/src/dev-plugin.ts` (no config) | the three config items' `knownGaps` — every non-default clause is scored `oracle: test` in a harness, and the run record must say so instead of claiming a reconfigured deployment | capability gap — filed as #15543 |
568+
| E3 | **The MOUNT half of every sub-config switch is unpinned.** `packages/rest/src/rest-sub-config-parse-not-cast.test.ts` pins what a switch normalizes to, and `rest-batch-size-cap.test.ts` pins the cap's effect; nothing asserts that a `false` switch removes its route from the table `getRoutes()` returns. The declared-not-enforced direction — a switch that normalizes correctly and gates nothing — is exactly what no current test would catch. | the two test files above; the gates live in `registerCrudEndpoints` / `registerBatchEndpoints` / `registerMetadataEndpointsInner` | the three config items (the mount clauses, each with the gap named in `knownGaps`) | test gap — filed as #15544 |
569+
570+
### 10c. Checked and CLEAN (so the next sweep does not re-derive)
571+
572+
- The **cross-object `POST {basePath}/batch` is deliberately NOT under
573+
`batch.enableBatchEndpoint`** — the switch gates only the per-object
574+
`POST {dataPrefix}/:object/batch`. Reading the cross-object door as evidence about the
575+
switch is the trap; recorded as a `negative` on the batch item rather than as a defect.
576+
- **All four per-object bulk gates are ANDs with a protocol member**
577+
(`operations.createMany && this.protocol.createManyData`, and so on), so an absent
578+
mount has two possible causes and the route table alone cannot tell them apart. Correct
579+
as designed; the item drives both legs separately.
580+
- **`operations.list` gates two mounts** (the collection GET and `POST /:object/query`);
581+
the query door has no switch of its own. Deliberate, not drift.
582+
- **`crud.dataPrefix` and `metadata.prefix` each move their mounts AND their `/discovery`
583+
advertisement together** (`registerDiscoveryEndpoints` builds `routes.data` /
584+
`routes.metadata` from the same values) — ADR-0076 D12 holds here; asserted positively
585+
on both items rather than left as an assumption.
586+
- **`routes: {}` still constructs** and an unknown key inside a sub-object is stripped —
587+
the non-strict parse that is the whole reason the retired keys are tombstones rather
588+
than deletions. Both are controls on the route-generation item.
589+
590+
### 10d. The one waiver, and what retires it
591+
592+
`realtime_subscription` is **waived**, and the reason is written out in `coverage.json`
593+
rather than summarized here. The short form: `SubscriptionSchema` is a transport-protocol
594+
declaration with zero runtime readers (its ledger records every property `dead` at a
595+
same-day census, and the shipped in-memory adapter reads a different type entirely), and
596+
there is nothing to connect to — `GET /api/v1/discovery` advertises realtime
597+
`enabled: true` with `handlerReady: false` and no realtime route, which is the open
598+
decision **#14646**. An item authored today could only assert absence.
599+
600+
⚠️ **This does not reopen waiver-as-exemption.** SWEEP.md's running total is 6 of 6
601+
waivers ever written turned out stale, and every one of those claimed "no independent
602+
runtime behaviour" about a surface that had some. This one claims the opposite kind of
603+
thing — that the *reader* is missing, measured by a census that names its method and
604+
scope — and it names both of its exits: #14646 mounting a transport (author items, flip
605+
to `items`), or ADR-0049 retiring the schema (the ledger goes, and the ratchet reports
606+
this entry as an ORPHAN to delete). **Re-audit it next sweep like any other waiver.**
607+
608+
### 10e. Note on the gate's own self-test
609+
610+
The card and its triage quote `--self-test: 141 assertions` (from `ca3fd4b1`). On
611+
`6f944589` the same command reports **176** and exits 0. Nothing in this sweep touches
612+
the gate script; the growth is the gate's own, between the two dates. Quote the count
613+
from the run you actually made — this ledger's own history is the argument for that.
614+
615+
(The one `scripts/` edit this sweep does make is additive and the gate asked for it: §10
616+
is the first FOLLOW-UPS section to carry symbol anchors, so
617+
`scripts/checklist-symbol-anchor-baseline.json` gains a `FOLLOW-UPS.md` floor at the
618+
count `--anchor-census` measured. Adding a floor for a newly-anchored file is not
619+
lowering one — that stays maintainer-only.)

0 commit comments

Comments
 (0)