docs(spec): point ActionSchema.method's worked example at the shipped data door - #15098
Conversation
`ActionSchema.method`'s TSDoc pointed its only worked example of a
`type: 'api'` PATCH at `/api/v1/sys_api_key/{id}`. The shipped data door
is `PATCH /api/v1/data/:object/:id` — `getApiBasePath()` composed with
`crud.dataPrefix` (default `/data`) — so an author copying the example
validated green and 404'd at the click, the same silent shape as an
unregistered handler arriving through a doc example.
The docblock now spells the path structure the router actually mounts,
keeps `sys_api_key` (the error was the structure, not the object), uses
`${ctx.recordId}` per `target`'s own interpolation convention, names the
scoping premise that makes any full path host-dependent, and points a
single-record field write at the declarative `operation: 'update'` +
`patch` form instead.
Comment text only: no schema member, no `.describe()` and no runtime
behaviour moves.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0174WZTU6XcFcS7g2kykC53i
The dispatch expected `skip-changeset` on the premise that a comment-only change publishes nothing. Measured on the built tree, that premise does not hold: `@objectstack/spec`'s `files` array ships `dist/**` and `src/**/*.zod.ts`, and the corrected docblock is present in 13 `.js` + 13 `.mjs` bundles and in the shipped source. So this diff does publish changed bytes from a released package, which AGENTS.md's Post-Task Checklist reserves for a `patch` changeset and explicitly refuses `skip-changeset` for. It reaches no `.d.ts` — measured 0 hits there, and 0 for two control docblocks too, so this package emits no TSDoc into its declarations at all. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0174WZTU6XcFcS7g2kykC53i
ActionSchema.method's worked example at the shipped data door
📓 Docs Drift CheckThis PR changes 1 package(s): 20 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 3 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 128 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 1ce1506e99d0dfe92bcd6c774a8d2a73c41b41de && git checkout 1ce1506e99d0dfe92bcd6c774a8d2a73c41b41de
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 0f94cc7cc1fa937940c71bdeaea1d62ae3ff113f b5bceb76907ccf2e7ad49a4d9880e109025c1524 && git checkout -B drift-repro 0f94cc7cc1fa937940c71bdeaea1d62ae3ff113f && git merge --no-ff b5bceb76907ccf2e7ad49a4d9880e109025c1524
node scripts/docs-audit/affected-docs.mjs --json 0f94cc7cc1fa937940c71bdeaea1d62ae3ff113f
|
|
Landing provenance (PM seat
Generated by Claude Code |
Fixes #14093
Clause ②: no — path limb fires (
packages/spec/src/**), content limb no: comment text onlyWhat was wrong
ActionSchema.method's TSDoc carried the only worked example of atype: 'api'PATCHagainst the data API, and it pointed at
/api/v1/sys_api_key/{id}— a path the routernever mounts. The
/datasegment was missing. Nothing catches the difference atauthoring time:
objectstack validatedoes not checktarget,type: 'api'has noauthor-time route validation, so the action parses green, renders, is clickable, and
404s at the click.
The two readings this correction stands on, cited on the tree at
6665c5c91. The shipped data door composes to
PATCH /api/v1/data/:object/:id.packages/rest/src/rest-server.ts:7664, insideregisterCrudEndpoints:registered at
packages/rest/src/rest-server.ts:7913-7914:basePathisgetApiBasePath()(rest-server.ts:3637-3640—api.apiPath ?? api.basePath + '/' + api.version), andcrud.dataPrefixdefaults to/dataatpackages/spec/src/api/rest-server.zod.ts:252:2. Under required scoping, only the scoped path is registered.
packages/rest/src/rest-server.ts:3717-3722, inregisterRoutes():with
getScopedBasePathat:3646-3647returning`${basePath}/environments/:environmentId`. So a correctly spelled unscoped full path still 404s on such a host — which is why the example now names the premise instead of promising a host-independent path.A third reading fixes the placeholder spelling:
target's own docblock atpackages/spec/src/ui/action.zod.ts:992-997documents${param.X}and${ctx.X}interpolation and names
ctx.recordIdexplicitly. A bare{recordId}isnewTabUrl'sconvention alone.
The change — one docblock, verbatim
Before:
After:
sys_api_keyis deliberately kept — the defect was the path STRUCTURE, not which objectthe example picks. No
.describe()text moves, no schema member moves, and no othermember of
action.zod.tsis touched (theoperation/patchblock from PR #15077included).
packages/restandpackages/runtimeare read-only inputs here.Deviation from the dispatch: a
patchchangeset, notskip-changesetThe dispatch expected
skip-changeseton the premise "comment text; no publishedartifact moves". Measured on the built tree, that premise does not hold, so AGENTS.md
governs and this PR carries a
@objectstack/specpatch changeset instead:packages/spec/package.jsonfilesshipsdistandsrc/**/*.zod.ts..jsand 13.mjsbundles underpackages/spec/dist/after a build (e.g.dist/ui/index.mjs:8045-8072), and in theshipped
src/ui/action.zod.tsitself.Post-Task Checklist §3 reserves that for a
patchchangeset and refusesskip-changesetfor it by name: that label "is for a diff that publishes nothing fromany released package."
Measured counterpoint, recorded because it is the surface most people assume: the
docblock reaches no
.d.ts— 0 hits, and 0 for two control docblocks in the samefile as well, so this package emits no TSDoc into its declarations at all. IDE hover
text is unchanged; the npm tarball's bytes are not.
If the PM prefers the label, the changeset is one file to delete.
Verification record — all at final head
b5bceb76Every exit code captured before any pipe; verdict lines quoted from the gates themselves.
pnpm --filter @objectstack/spec buildcheck-dts-emitted: 34/34 declared declaration file(s) presentpnpm build(whole workspace)Tasks: 72 successful, 72 totalvitest run --maxWorkers=2Test Files 466 passed (466),Tests 12427 passed (12427)pnpm --filter @objectstack/spec typecheckcheck:test-typecheck: OK; edited file proven in-program viatsc --noEmit --listFiles(1 hit)check:generated✓ All 15 generated artifacts are up to date(also green on the pre-edit baseline, so the TSDoc projects into no generated artifact and nothing needed--fix)check:api-surfacecheck:docscheck-system-context-census.mjsOK — 106 elevation read sites in 20 packages across 45 files, all anchored(no--fixneeded)eslint . --no-inline-configdispatch-gates.mjs --commandsunionThe union was re-derived at final head
b5bceb76and is byte-identical to thederivation taken before the changeset landed — same 54 commands, same 2 paths.
The one NOT MEASURED gate, listed as such rather than as a pass:
node scripts/check-test-completeness.mjs— exit 3, structurally unrunnablelocally. Its own text: "this gate grades a saved
turbo run testlog, and no log wasnamed … the local reading for this gate is NOT MEASURED. ⛔ It is not a red, and there
is nothing here to fix." CI tees the log and passes the path, so CI measures it.
Three further gates first returned a prerequisite code and were converted into real
measurements by building rather than being written off:
check-dev-prereqs.mjs(exit 1 → 0 afterpnpm build:✓ 67 package build artifacts present),check:doc-formula-expressions(exit 3 → 0 after building@objectstack/formulathen@objectstack/lint),and
check:dual-build-cjs-loads(exit 3 → 0:102 published require entry point(s) across 66 package(s) load).Reverse verification is not owed for a comment-only change; the before/after docblock
above and the two cited route readings stand in its place.
Notes for the reviewer
needs:contract-reviewlabel is applied.ActionSchema.method's worked example points atype: 'api'PATCH at/api/v1/sys_api_key/{id}— the shipped data API is/api/v1/data/:object/:id, so copying it 404s #14093.Generated by Claude Code
Generated by Claude Code