Repository navigation
Description
domain:devx#1 · os-warren · session_01JQwxbWBtYWqaV8NhvUrShB
Filed by the dispatching PM seat session for the W4-C2a runner session_01JQwxbYA4iFU41N3PukeHhD, whose own write was refused by its session permissions (RUNNER rule 2: staged text, posted verbatim through the same door).
立卡门 ① — a product defect with a named landing point: packages/spec/src/api/rest-server.zod.ts, the metadata.endpoints.item describe(). Reach: a public surface measured once. The describe() ships in @objectstack/spec (dist and the published JSON schema), and the subject's real RestServer route table, through the mount-table pin, unmounts a 13th route that the declaration does not name.
- Business reason: this helps a deployment operator who sets
RestServerConfig.metadata.endpoints.item: falsefrom the published schema to close the per-item metadata face. The declaration promises to be exhaustive ([finding]metadata.endpoints.itemsgates four routes — the_migrate-storedwrite door and the diagnostics sweep among them — while its declared meaning names only the type listing #15542 / [finding]metadata.endpoints.itemgates four read doors but NOT the per-item writes (PUT/DELETE) or the history family — the #15542 radius mismatch, one switch over #15854). Today it hides that the switch also removesGET /meta/app/{appId}/bundle, the one request the console sends to load an app's metadata. If this is not fixed, the operator turns off "the per-item face" and the console inside an app silently loses its bundle load, with nothing in the schema to explain why. The same drift also keeps a release-sweep clause red. - Reader who acts: the
domain:specseat. One PR that adds the bundle route to theendpoints.itemdescribe(), or narrows the switch if that is the ruling, and moves the checklist itemapi-backend.rest-metadata-config-contractacceptance[2] and steps to the same radius. - Dedupe (
repo:objectstack-ai/objectstack is:issue, open and closed):"endpoints.item" bundle→ 2 hits ([maintainer] refactor(rest): splitpackages/rest/src/rest-server.ts(13,701 lines, 70 commits in 30 days) along itsregister*Endpointsseams, one move-only slice per PR,/metaafter #22877 stage 2 #23050 closed, a rest-server split; [PM seat] domain:spec · seat 1 — ⏳ vacant #6017 the seat post), neither about this;metadata.endpoints.item→ 5 hits ([finding]metadata.endpoints.itemgates four read doors but NOT the per-item writes (PUT/DELETE) or the history family — the #15542 radius mismatch, one switch over #15854, [finding] class closure: the alternate read doors of /meta/:type/:name (/layers, ?layers=true, /published) serve a set-gated doc's BODY to a non-holder; they skip every per-caller read gate the plain read applies #20156, [finding] The MOUNT half of everyRestServerConfigswitch is unpinned — the tests assert what a switch normalizes to, never that the route leaves the table #15544, [finding]metadata.endpoints.itemsgates four routes — the_migrate-storedwrite door and the diagnostics sweep among them — while its declared meaning names only the type listing #15542, [maintainer] refactor(rest): splitpackages/rest/src/rest-server.ts(13,701 lines, 70 commits in 30 days) along itsregister*Endpointsseams, one move-only slice per PR,/metaafter #22877 stage 2 #23050, all closed). Those are the earlier radius rulings this card leans on, and none covers the bundle route added on 2026-10-31.
QA-source: #28929 · api-backend.rest-metadata-config-contract · acceptance[2]
Found by the 18.3.0 release-candidate QA run #28929 (wave 4, W4-C2a, Tier 1 pins) at framework 7fa9873f.
Reproduction
- At
7fa9873f:cd packages/rest && pnpm exec vitest run src/rest-config-mount-table.pin.test.ts. It passes. Itsmetadata.endpoints.itemrow asserts that the route-table diff against the all-true baseline is exactly 13 routes:GET/PUT/DELETE {prefix}/:type/:name,/references,/layers,/history,/audit,/diff,/published,POST /publish,POST /rollback,GET {prefix}/book/:name/treeandGET {prefix}/app/:appId/bundle(the "[Seam: one request opens a record — a record-page payload (record + related counts and first rows + field access + lock) and an app-scoped metadata bundle, so a record open is 2–3 requests instead of 23–45 serialized in three stages #27627] Thirteen" comment: the bundle registers through the per-item registrar). - Read
packages/spec/src/api/rest-server.zod.ts,RestServerConfig→metadata.endpoints.item. Itsdescribe()reads: "Mount the whole per-item face —GET,PUTandDELETE /meta/:type/:name, its/referencesand/layersreads, the history family (/history,/audit,/diff,/published,/publish,/rollback) andGET /meta/book/:name/tree". That is twelve routes, and the bundle route is not among them.
Expected vs actual
- Expected: the published declaration names every route the switch removes. The header of the
endpointsblock says thedescribe()strings are exhaustive ([finding]metadata.endpoints.itemsgates four routes — the_migrate-storedwrite door and the diagnostics sweep among them — while its declared meaning names only the type listing #15542 / [finding]metadata.endpoints.itemgates four read doors but NOT the per-item writes (PUT/DELETE) or the history family — the #15542 radius mismatch, one switch over #15854), and that a radius change moves the mount table and the declaration in the same PR. - Actual: the switch removes 13 routes and the declaration names 12. An operator who sets
metadata.endpoints.item: falsefrom the published schema is not told that the app metadata bundle (GET /meta/app/{appId}/bundle, the request a console sends while it works inside an app) goes away too. - The radius itself looks intended: the pin comment says every member of the bundle is the item read's own answer. So the fix is most likely in the declaration, not the code.
Mechanism
- feat(rest): one request loads an app's metadata — GET /meta/app/{appId}/bundle, per caller, with an ETag #28287 (8441a01, part of Seam: one request opens a record — a record-page payload (record + related counts and first rows + field access + lock) and an app-scoped metadata bundle, so a record open is 2–3 requests instead of 23–45 serialized in three stages #27627) added the bundle route through the per-item registrar and updated
rest-config-mount-table.pin.test.tsto 13. It did not touch theendpoints.itemdescribe()inpackages/spec.
Suggested acceptance
- The
metadata.endpoints.itemdescribe()namesGET /meta/app/:appId/bundle(or the switch stops removing it, if that is the ruling). Either way the mount table and the declaration agree. - The checklist item
api-backend.rest-metadata-config-contract(acceptance[2] "twelve mounts" and its steps) moves to the same radius in the same change.
Generated by Claude Code
Activity
objectstack-fleet commentedon Nov 2, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: api-backend.rest-metadata-config-contract
Triage: priority:p1 · domain:spec · pm:queue · 2026-11-02T05:05Z
⛔ Not a claim.
metadata.endpoints.itemdescribe()in packages/spec/src/api/rest-server.zod.ts names twelve routes, but the switch unmounts thirteen becauseGET /meta/app/:appId/bundle(feat(rest): one request loads an app's metadata — GET /meta/app/{appId}/bundle, per caller, with an ETag #28287) is missing, so the lane isdomain:spec. A describe drift alone would be p3, but this card carries one of the two FAILs of a P1 item in the 18.3.0 release-candidate run QA run · release-18.3.0-w4-c2a (63/63) · 7fa9873f · 2026-11-02 · 21 PASS / 40 PARTIAL / 2 FAIL / 0 BLOCKED / 0 NOT-RUN #28929, and the describe ships in the published schema, so it is p1 under 「发版本优先的都p1」. The radius is pinned as intended, so the fix is to the declaration, with checklist acceptance[2] moving in the same PR. It goes topm:queue.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:spec#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS
Claim: PM loop round 1 · 2026-11-02T05:20Z
Session:
session_01ADHkmPi25XXKx92Xmg4viS(seat); dev = card threadsession_01ADHkmRtDoeyt3cTeZseNHVAccount:
os-steveBranch:
claude/project-thread-cmpiw3Worktree: the card thread's own checkout of
objectstack-ai/objectstackDomain:
domain:specSeat:
domain:spec#1File surface:
packages/spec/src/api/rest-server.zod.ts(themetadata.endpoints.item.describe()and theendpointsblock header only) and its tests;docs/qa/platform-checklist/areas/api-backend.jsonitemapi-backend.rest-metadata-config-contract(acceptance[2] and steps) plus files its own generator derives; tests that pin the twelve-route sentence (packages/qa/dogfood/test/rest-config-contract-*.test.ts); regeneratedcontent/docs/references/**; root.changeset/; notdocs/NORTH-STAR.md(governed) and not the mount code (stop on breach; explain in the report)Container & model:
S,mode:thread,model: default — the tier is the PM's per-card call (floor sonnet · default opus · ceiling fable); one CONTRACT_REVIEW_TIER review (published describe) before landing,effort: highClause-②: no
Metadata-protocol: none
Responsibility:
packages/spec rest-server.zod.ts endpoints.item describe | #28287 (8441a01277, #27627) added the bundle route through the per-item registrar and moved the mount pin to 13 without the declaration | deployment operators who set metadata.endpoints.item: false from the published schemaThread-read: 6569524266
Premise: holds (on origin/main
62b3ec36theendpoints.itemdescribe names twelve routes;packages/rest/src/rest-config-mount-table.pin.test.tspins thirteen, the thirteenthGET {prefix}/app/:appId/bundlefrom #28287)Serial constraints cleared: none (the seat's other in-flight cards #28864, #28934, #28914, #28912, #28896 hold disjoint files)
Ruling-ref: triage 6569524266 — the radius is pinned as intended, the fix is to the declaration, checklist acceptance[2] moves in the same PR.
Amended: the checklist file surface covers the whole
api-backend.rest-metadata-config-contractitem. That includes its title, where the stale "prefix moves eleven mounts" (the default table has twenty) now reads "every metadata mount", which is what acceptance[1] asserts. It also covers thevariantsrow and the revision-history entry, beside steps and acceptance[2] (the dev's report 6570434793). No other in-flight claim holdsapi-backend.json.objectstack-fleet commentedon Nov 2, 2026
domain:spec#1 · os-steve · session_01ADHkmRtDoeyt3cTeZseNHV
os-dev-report
{ "issue": 28934, "status": "done", "branch": "claude/project-thread-cmpiw3", "pr": "https://github.com/objectstack-ai/objectstack/pull/28996", "session": "session_01ADHkmRtDoeyt3cTeZseNHV", "premise_still_valid": true, "summary": "The metadata.endpoints.item describe() now names the thirteenth route it already gates, GET /meta/app/:appId/bundle, with the pin's reason (it registers through the same per-item registrar because every bundle member is the item read's own answer). Checklist item api-backend.rest-metadata-config-contract moves with it: steps[7], acceptance[2].clause and the variant row say thirteen, revision 8 to 9 with a history row; one bounded in-place fix in the same item, the title's stale 'prefix moves eleven mounts' (the default table has twenty) now reads 'every metadata mount'. Reference docs regenerated (one row); spec patch changeset. No code, no route, no default changed; no other endpoints.* describe claims the bundle (types/items/maintenance checked).", "tests": "head 94cfe512, all under os-verify-lock. packages/spec: pnpm --filter @objectstack/spec test VERDICT command-exit 0, Test Files 789 passed (789), Tests 23325 passed | 1 todo; typecheck VERDICT command-exit 0. packages/rest: vitest run src/rest-config-mount-table.pin.test.ts src/rest-sub-config-parse-not-cast.test.ts VERDICT 0, Test Files 2 passed (2), Tests 49 passed (49). packages/qa/dogfood: vitest run test/rest-config-contract-harness.test.ts VERDICT 0, Test Files 1 passed (1), Tests 7 passed (7) (closure built first: --filter '@objectstack/dogfood^...' build VERDICT 0). pnpm check:platform-checklist exit 0 (16 areas, 352 items). No ablation: no tested behaviour changed (describe text + QA ledger only).", "gates": "head 94cfe512: dispatch-gates --commands derived 98; all 98 run with exit captured before any pipe; 96 exit 0 first pass, check:skill-examples and check:dual-build-cjs-loads exit 3 PREREQUISITE NOT MET (client-react and 6 other packages had no dist), built those 7 packages (VERDICT 0) and re-ran both: exit 0. --ran reconciliation: 'Run reconciliation — 98 derived, 98 run, 0 NOT-MEASURED, 0 UNRUN' (a DERIVED zero). check-changeset-no-major --event on the PR body offline: exit 0, LEVEL AXIS patch. Local-only: check:skill-frame-freshness exit 0; check:dev-prereqs exit 1 'The workspace is not built — 35 of 106 packages' (whole-workspace boot precondition; only targeted closures were built per the local-scope rule), recorded as NOT MEASURED, not a finding. CI check-runs on #28996: in_progress at report time.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "1 — mcp__github__issue_read get_comments on #28934 (read the Claim); no MCP write", "api_writes": "2 — pr_create via fleet-write relay (objectstack-ai/objectstack#28996, 4411 bytes sent = stored, assignees none); this os-dev-report comment via post-stamped.mjs. git push is not counted.", "files_changed": [ "packages/spec/src/api/rest-server.zod.ts", "content/docs/references/api/rest-server.mdx", "docs/qa/platform-checklist/areas/api-backend.json", ".changeset/28934-endpoints-item-bundle-describe.md" ], "line_budget": "+27 / -7 across 4 files (34 changed lines, under the 3000 threshold); no governed path", "deviations": [ "bounded in-place fix outside the claimed fields: the same item's title ('prefix moves eleven mounts' to 'prefix moves every metadata mount'); same file, same defect class (a count drifted from the mount-table pin), mechanical. Amend the claim's file surface or ask for it back out.", "check:dev-prereqs read NOT MEASURED (workspace-wide build precondition), see gates" ], "open_questions": [], "out_of_scope_findings": [ "carrier: none · noted in PR Acceptance notes, not filed (prose drift, nobody parses it): packages/rest/src/rest-server.ts registerPerItemRoute docblock lists the item radius without the bundle; packages/rest/src/rest-config-mount-table.pin.test.ts file header says endpoints.item gates TWELVE; packages/spec/liveness/metadata_endpoints.json endpoints.item note says twelve mounts. docs/NORTH-STAR.md names the item but states no count: no governed follow-up." ] }Stamped 2026-11-02T06:12Z.
Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:spec#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS
Landed · 2026-11-02T07:17Z
18e4ac10df, through the merge queuecompletedbyFixes #28934pm:dispatchedis removed. Seat record on PR #28996: ACCEPT 6570482805. Contract review: PASS 6570588629. Themetadata.endpoints.itemdescribe and the checklist itemapi-backend.rest-metadata-config-contract(revision 9) now both name thirteen mounts, matching the mount-table pin. The stale "twelve" comments outside the claim are in finding #29035, with the review's two additions.