Uh oh!
There was an error while loading. Please reload this page.
fix(core,cli): os test record action types reach the served route; a zero-match glob states its posture - #7982
Conversation
…ro-match glob states its posture (#7848) Item 1 — `HttpTestAdapter` built `${baseUrl}/api/data/:object` while a stock server serves `{apiPath}/data/:object` with `apiPath` = `/api/v1`, so all five record-shaped `TestActionTypeSchema` members 404'd, and `update_record` issued `PUT` where the route is `PATCH`. The prefix is now derived from the two schemas `RestServer` itself resolves from (`RestApiConfigSchema` + `CrudEndpointsConfigSchema.dataPrefix`) rather than written down a second time, `update_record` PATCHes with `id` peeled off the body, and record ids are percent-encoded. Item 2 — a zero-match glob still exits 0 (a repo that legitimately ships no suites must not start failing CI), but the posture is now declared: `--help` states it, `--fail-on-empty` opts into the strict reading, and `Found N test suites.` is emitted on every run including `Found 0 test suites.` Both exit-code arms are asserted over a real child process; the adapter's URLs and verbs are pinned against the spec schemas rather than a copied literal. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D1z19epfecapa69CqwZ3Mm
…paired adapter (#7848) The item's own `negative` clause said a future run finding the record action types PASSING "means the adapter was repaired, which is a revision of this item rather than a silent green" — so this is that revision (revision 2, with its history entry). The five-404s knownGap is replaced by the narrower one that survives (the record types address the DEFAULT mount only, so a host that moves it with `api.apiPath`/`crud.dataPrefix` still needs `api_call`), the variants carry their new routes and response shapes, and the zero-match negative records the now-declared posture plus `--fail-on-empty`. Also: the core test's fetch mock takes `input: unknown` — this package's tsc program has no DOM lib, so `RequestInfo` does not resolve and the debt ratchet catches it (it compiles *.test.ts, which the package `typecheck` skips). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D1z19epfecapa69CqwZ3Mm
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📓 Docs Drift CheckThis PR changes 3 package(s): 116 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
⛔ 8 release-owned page(s) also reference the affected code. These are read-only:
|
hotlong
commented
Aug 12, 2026
PM review — Every acceptance point from the claim comment is met, and three are met better than asked. The base path is derived, and the pin is derived too. The "before" column is a real run, not the card's text carried forward. Fix committed, adapter reverted, core rebuilt, same suite against the same booted server — with one scenario per member and no shared setup, so no member's verdict is inferred from a sibling's. The exit-code arms are asserted over a real child process, with the right reason given: The proposal came back "no", with evidence — which closes the questionI asked whether A measured "no" is worth more than a speculative "yes" — the question is now closed rather than deferred to the next person's intuition. Recommendation accepted: exit 0 stays the default,
Two things I want on the recordThe checklist item revised itself as designed. The surviving limit is stated, not smoothed over. The record action types resolve the default mount only; a host setting Ledger discipline held: Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#7848
Two defects on the same surface, both measured on a booted showcase. Landing sites are the ones the PM claim comment established, not the triage comment's: item 1 is
packages/core/src/qa/http-adapter.ts(the CLI only imports the adapter), item 2 ispackages/cli/src/commands/test.ts.Item 1 — 5 of the 8 declared action types could not reach a stock server
HttpTestAdapterbuilt${baseUrl}/api/data/:object. A stock server serves{apiPath}/data/:objectwithapiPath=/api/v1, so every record-shapedTestActionTypeSchemamember was one version segment short — andupdate_recordwas wrong twice, issuingPUTat a route that has noPUTsibling.The base path is derived, not re-written
Per the claim comment's instruction, the prefix is taken from where the server's own resolution takes it rather than hard-coded a second time.
RestServercomposes it asgetApiBasePath()+crud.dataPrefix, i.e.api.apiPath ?? ${api.basePath}/${api.version}then+ dataPrefix(packages/rest/src/rest-server.ts:3853,:6741). Both pieces are declared inpackages/specwith defaults, and the adapter now asks those two schemas:base_path_source:@objectstack/spec/api—RestApiConfigSchema+CrudEndpointsConfigSchema. No literal/api/v1/datasurvives in the adapter, and the unit pin asserts the adapter's URLs against that same derivation rather than against a copied string — a pin that hard-codes what it guards goes green the day the schema moves and the adapter does not.Known limit, stated rather than papered over: this is the DEFAULT only. The adapter is handed an origin, not a deployment's config, so a host that sets
api.apiPathorcrud.dataPrefixis still out of reach for the record action types;api_calltakes the path you give it and remains the escape hatch. Filed as a follow-up rather than widened here (see Out-of-scope findings).Re-run action-type matrix
Booted showcase (
pnpm dev -- --fresh -p 41847, seeded admin, session token), one scenario per member with no shared setup, so no member's verdict is inferred from a sibling — the "before" column is a real reverse-verification run (fix committed first,git checkout origin/main -- packages/core/src/qa/http-adapter.ts, core rebuilt, same suite, same server), not the card's text copied forward.create_recordHTTP Error 404: {"error":"Not found"}POST /api/v1/data/:object→{ object, id, record }read_recordGET /api/v1/data/:object/:id, asserted onrecord.nameupdate_recordPUTwhere the route isPATCHPATCH /api/v1/data/:object/:id, asserted onrecord.colordelete_recordDELETE /api/v1/data/:object/:id→{ object, id, success }query_recordsPOST /api/v1/data/:object/query→{ object, records }api_callwaitrun_scriptUnsupported action type in HttpAdapter: run_scriptBefore:
FAILED: 6 scenarios failed. 2 passed.After:FAILED: 1 scenarios failed. 7 passed.— the one failure isrun_script, refusing by name.The repo's shipped suite (
examples/app-showcase/qa/platform-smoke.test.json, allapi_call) still passes against the same boot:SUCCESS: All 2 scenarios passed., exit 0.Two smaller corrections ride with the verb fix, both needed for the round-trip:
update_recordpeelsidoff the PATCH body (it addresses the record; posting it back is a column write), and record ids are percent-encoded.Item 2 — the smaller ask, landed; the bigger one proposed below, not landed
The default exit status is unchanged: a zero-match glob still exits 0. What changes is that the posture is declared instead of accidental.
--helpstates the posture and names the opt-out.--fail-on-emptyis the opt-in strict reading.Found N test suites.is emitted on every run,Found 0 test suites.included. It was previously printed only when N was positive — missing from exactly the run where a caller needs it to tell "every suite passed" from "there were no suites". The spelling now lives in one exported function so an edit to the prose has to notice it is editing a machine-readable surface.Both exit-code arms are asserted, over a real child process (
bin/run-dev.js+ tsx, the patternmigrate-exit-code.e2e.test.tsuses) —process.exitinside a vitest worker is not an exit status. "Exits 0" is exactly the behaviour nobody writes a test for, which is how #7347'scoverage.jsonblindness survived.Proposal — should the hard fail become the DEFAULT? Measured evidence says no
The claim comment asked one question: do
create-objectstacktemplates always ship a suite? Measured on this tree:blanktemplate (packages/create-objectstack/src/templates/blank/) ships 13 files and noqa/directory at all —find … -name '*.test.json'returns nothing;package.jsondeclaresdev/start/build/validate/typecheckand notestscript, so nothing in a scaffolded project invokesos testtoday;todo,compliance,content, …) are fetched from the separateobjectstack-ai/templatesrepo and were not measured here — but they cannot rescue the default, because the bundled one is the fallback every offline/default scaffold gets.So the premise that could have justified a hard-fail default is false: a freshly scaffolded project has zero suites, and flipping the default would make
os testfail out of the box for the most common starting state. Recommendation: keep exit 0 as the default and leave--fail-on-emptyas the opt-in. Recorded here so the question is closed with a measurement rather than re-opened on intuition; happy to be overruled by a reviewer who weighs the CI-rot risk higher.Also updated, because they would otherwise lie
docs/qa/platform-checklist/areas/cli.json→cli.qa-suite-executionrevision 2. The item's ownnegativeclause said a run finding the record types PASSING "means the adapter was repaired, which is a revision of this item rather than a silent green". This is that revision: the negative is inverted (a 404 is now the regression), the five-404sknownGapis replaced by the narrower surviving one (default mount only), thevariantscarry the real routes and response shapes, and the zero-match negative records the declared posture.pnpm check:platform-checklistgreen.content/docs/deployment/cli.mdx— the flag, the empty-match posture, and the record-action-type mount limit.packages/spec/liveness/qa.json— thetagsrow no longer claimsos testhas "exactly two flags"; its argument (nothing filters on tags) is untouched.Verification
pnpm typecheck— clean.pnpm check:type-check-debt—none above its recorded number. It caught a real one: the new core test's fetch mock typedinput: RequestInfo, which does not resolve in a package whose tsc program has no DOM lib. Fixed in the test (input: unknown); the ledger was not raised.pnpm --filter @objectstack/core test— 33 files, 786 tests.pnpm --filter @objectstack/cli test— 114 files, 1253 tests.pnpm check:platform-checklist,pnpm --filter @objectstack/spec check:liveness— green.origin/mainmerged in and the targeted suites re-run after it.Out-of-scope findings
HttpTestAdaptercannot reach a deployment that re-prefixes its API. The record action types resolve the DEFAULT mount;api.apiPath/crud.dataPrefixmove it out from under them. The architecturally right fix is the one@objectstack/clientuses — readroutes.datafrom/discoveryand fall back to the convention — which is a larger change than this card's closed scope. Recorded in the checklist item'sknownGapsand will be filed as its own issue.run_scriptremains declared with no adapter branch — untouched here by instruction, already carried inpackages/spec/liveness/qa.json.Generated by Claude Code