Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .changeset/23050-s12-crud-liveness-citations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@objectstack/spec': patch
---

The liveness ledger's CRUD rows cite the code that reads their keys where it now lives

Clause-②: no (only the rows' evidence paths move and every status stays `live`: `CrudEndpointsConfigSchema` accepts `operations.*` and `dataPrefix` exactly as before, and no state count moves)

- `liveness/crud_endpoints.json`: the five `operations.*` rows and the `dataPrefix` row cited `packages/rest/src/rest-server.ts#registerCrudEndpoints` for the code that gates and prefixes the CRUD mounts. `@objectstack/rest` moved that registrar's body to `packages/rest/src/crud-routes.ts` with no behaviour change, so those six path references follow it.
- The quoted code, the producers, the verdicts and the notes are unchanged.
10 changes: 10 additions & 0 deletions .changeset/23050-s12-crud-routes-move.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@objectstack/rest': patch
---

The CRUD doors' registrar body lives in its own module, with no route, handler or answer changed

Clause-②: no (a move: the six CRUD routes, their order, every handler and every response are unchanged, and the published declarations are byte-identical)

- `RestServer#registerCrudEndpoints` keeps its name, docblock and place. The body that registers `GET`, `POST` and `POST …/query` on `{basePath}{crud.dataPrefix}/:object`, and `GET`, `PATCH` and `DELETE` on `…/:object/:id`, moved unedited to `packages/rest/src/crud-routes.ts`. The five `crud.operations` switches and `crud.dataPrefix` gate and shape the same mounts.
- Nothing to do for a consumer: no export of the package entry, no route, no configuration key and no response moved.
6 changes: 3 additions & 3 deletions docs/qa/platform-checklist/areas/api-backend.json
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@
"packages/spec/src/data/filter.zod.ts#checkFilterConditionComparands (the request-schema refusal of a scalar list comparand on the POST door, #20116 — the $-object spelling, located at query.where.<field>.$nin)",
"packages/spec/src/data/data-engine.zod.ts#lowerFoldedTransportValues (the AST/FilterArray spelling on the POST door, refused at query.where when it cannot be lowered)",
"packages/spec/src/data/data-engine.zod.ts#QueryTransportParamsSchema (`filter` is a declared transport spelling of `where` — why negative[0] no longer probes with it)",
"packages/rest/src/rest-server.ts (POST /data/:object/query answers a FindDataRequestSchema failure 400 VALIDATION_FAILED with fields[] via zodIssuesToFields)",
"packages/rest/src/crud-routes.ts (POST /data/:object/query answers a FindDataRequestSchema failure 400 VALIDATION_FAILED with fields[] via zodIssuesToFields)",
"packages/metadata-protocol/src/protocol.ts#assertProjectionFieldsExist (a dotted fields entry → 400 INVALID_FIELD prescribing expand, #7532)",
"packages/metadata-protocol/src/protocol.ts#assertQueryParamsAreFields (an undeclared leftover key → implicit field filter → 400 INVALID_FIELD, #4134)",
"packages/rest/src/rest-server-repeated-filter-param.test.ts + packages/rest/src/analytics-filter-refusal-envelope.test.ts (the schema-door 400 VALIDATION_FAILED posture since #20116)",
Expand Down Expand Up @@ -1858,7 +1858,7 @@
"packages/objectql/src/in-memory-aggregation.ts#bucketDateValue (the six function arms incl. #11152 boolean-as-number and the #10576 per-aggregation filter; bucketDateValue ISO shapes; the #3839 real-null bucket rule at the module head)",
"packages/spec/src/data/aggregation-policy.ts#emptyGroupValueFor (emptyGroupValueFor — the ruled empty-set identities; objectui#3136)",
"packages/runtime/src/action-execution.ts#engine (the aggregate door: engine-only, at-least-one-aggregation, the raw-rows degradation hazard)",
"packages/rest/src/rest-server.ts#data (POST /data/:object/query — the wire door that accepts groupBy/aggregations)",
"packages/rest/src/crud-routes.ts#data (POST /data/:object/query — the wire door that accepts groupBy/aggregations)",
"packages/metadata-protocol/src/protocol.ts#assertAggregationFieldsExist (assertAggregationFieldsExist — the located unknown-field refusal)",
"#10576, #11152, #3839, #3773"
],
Expand Down Expand Up @@ -2199,7 +2199,7 @@
"source": [
"packages/spec/liveness/crud_endpoints.json (the ADR-0049 ledger this item answers: five live `operations.*` switches + `dataPrefix`, two dead keys)",
"packages/spec/src/api/rest-server.zod.ts#CrudEndpointsConfigSchema (the declared contract, its defaults and the two retiredKey tombstones)",
"packages/rest/src/rest-server.ts#registerCrudEndpoints (the six mounts and their five gates), (normalizeConfig — the parsed sub-config every consumer reads), (parseDeclaredSubConfig — the construction-time refusal), (getRoutes — the route table the mount clauses read) + packages/rest/src/discovery-routes.ts#registerDiscoveryEndpoints (discovery.routes.data built from dataPrefix)",
"packages/rest/src/crud-routes.ts#registerCrudEndpoints (the six mounts and their five gates) + packages/rest/src/rest-server.ts (normalizeConfig — the parsed sub-config every consumer reads), (parseDeclaredSubConfig — the construction-time refusal), (getRoutes — the route table the mount clauses read) + packages/rest/src/discovery-routes.ts#registerDiscoveryEndpoints (discovery.routes.data built from dataPrefix)",
"#14691 (the ADR-0049 retirement of patterns/objectParamStyle) · #11984 (parse-and-consume instead of cast) · ADR-0122 (author state) · ADR-0076 D12 (advertise only what is mounted)",
"sibling clause: api-backend.api-methods-verb-gate (the per-OBJECT exposure gate this config-level switch must stay distinguishable from) · api-backend.route-ledger-live-parity (the routing-404 control technique)"
],
Expand Down
3 changes: 2 additions & 1 deletion packages/qa/dogfood/test/authz-conformance.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1633,7 +1633,8 @@ describe('#9084 — the rest-server.ts transport tripwire keys off mechanics', (
// [#23050 slice 9] Length 9 → 10 (`search-routes.ts`), still 0 over it.
// [#23050 slice 10] Length 10 → 11 (`ui-routes.ts`), still 0 over it.
// [#23050 slice 11] Length 11 → 12 (`form-routes.ts`), still 0 over it.
expect(REST_SERVER_REGISTRAR_FILES).toHaveLength(12);
// [#23050 slice 12] Length 12 → 13 (`crud-routes.ts`), still 0 over it.
expect(REST_SERVER_REGISTRAR_FILES).toHaveLength(13);
expect(REST_SERVER_REGISTRAR_PATHS[0]).toBe(REST_SERVER);
const listed = REST_SERVER_REGISTRAR_PATHS.map((file) => readFileSync(join(REPO_ROOT, file), 'utf8'));
for (const probe of [MECHANICS, ROUTES]) {
Expand Down
23 changes: 19 additions & 4 deletions packages/qa/dogfood/test/authz-probe-blind-spot.census.ts
Original file line number Diff line number Diff line change
Expand Up @@ -537,12 +537,12 @@ export const PROBE_FILE_CENSUS: readonly ProbeFileReading[] = [
'module on the registrar list (`packages/rest/src/rest-server-registrar-files.ts`) — ' +
'`data-action-routes.ts`, `batch-routes.ts`, `approvals-routes.ts`, `sharing-routes.ts`, ' +
'`analytics-routes.ts`, `security-routes.ts`, `discovery-routes.ts`, `email-routes.ts`, ' +
'`search-routes.ts`, `ui-routes.ts` and `form-routes.ts`, the modules the bodies of ' +
'`search-routes.ts`, `ui-routes.ts`, `form-routes.ts` and `crud-routes.ts`, the modules the bodies of ' +
'`registerDataActionEndpoints`, `registerBatchEndpoints`, `registerApprovalsEndpoints`, ' +
'`registerSharingEndpoints`, `registerSharingRuleEndpoints`, `registerAnalyticsEndpoints`, ' +
'`registerSecurityExplainEndpoints`, `registerSecurityEndpoints`, `registerDiscoveryEndpoints`, ' +
'`registerOpenApiEndpoints`, `registerEmailEndpoints`, `registerSearchEndpoints`, ' +
'`registerUiEndpoints` and `registerFormEndpoints` moved to; ' +
'`registerUiEndpoints`, `registerFormEndpoints` and `registerCrudEndpoints` moved to; ' +
'reachable = those inside registerMetadataEndpoints',
// [#15542 / #15854] ⭐ THE POPULATION RULE LEARNED A SECOND SPELLING, and
// the numbers it produces did NOT move: 80 / 19 / 61, exactly as before.
Expand Down Expand Up @@ -801,10 +801,24 @@ export const PROBE_FILE_CENSUS: readonly ProbeFileReading[] = [
// the move commit, before the list learned the module: population 68 and
// `this.routeManager.register(` 61 over eleven files, the two sites out of
// reach.
// [#23050 slice 12] 70 / 19 / 51 UNCHANGED, the same measurement again:
// `registerCrudEndpoints`' body (six registration sites, the list, read,
// create, QueryAST query, update and delete doors under
// `{base}{crud.dataPrefix}`, all outside `registerMetadataEndpoints`, so
// all six in the blind spot) moved to `crud-routes.ts`, which joins the list
// (length 12 -> 13) with its own control. `this.routeManager.register(`
// stays 63 over the thirteen files
// (12 here + 9 + 5 + 7 + 8 + 1 + 6 + 4 + 1 + 1 + 1 + 2 + 6),
// `private register*Endpoints(` stays 16 (the registrar is still declared
// here), and `enforceAuth` 108 -> 112 is RE-ANCHORED, not relaxed: the six
// call sites moved with their routes and are counted in both readings; the
// four new occurrences are this slice's seam, the same two spellings once
// (the host literal's forwarder, two; the host interface's member, two). No
// call site was added.
controls: {
'private register*Endpoints(': 16,
'this.routeManager.register(': 63,
'registrar list length': 12,
'registrar list length': 13,
'data-action-routes.ts: this.routeManager.register(': 9,
'batch-routes.ts: this.routeManager.register(': 5,
'approvals-routes.ts: this.routeManager.register(': 7,
Expand All @@ -816,14 +830,15 @@ export const PROBE_FILE_CENSUS: readonly ProbeFileReading[] = [
'search-routes.ts: this.routeManager.register(': 1,
'ui-routes.ts: this.routeManager.register(': 1,
'form-routes.ts: this.routeManager.register(': 2,
'crud-routes.ts: this.routeManager.register(': 6,
// Both halves of the new rule carry their own control, so neither can go
// silently to zero: a helper deleted and its routes inlined back would
// still read population 80, and only these two controls would notice the
// shape moved and force this provenance to be re-read.
'registerPerItemRoute(': 8,
'const registerPerItemRoute =': 1,
'forwarder slice: this.routeManager.register(': 1,
enforceAuth: 108,
enforceAuth: 112,
},
note:
'The single non-tripwire probe names ONE registrar of 16. The other 15 can never mint a key: ' +
Expand Down
Loading
Loading