You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
actions: an api action called with no recordId forwards an unresolved {id} path and answers 404 ENDPOINT_NOT_FOUND instead of naming the missing record id #28932
QA-source: #28927 · approvals.account-app-entry · observed beside the clauses
What happens
POST /api/v1/actions/sys_approval_request/approval_approve with {"params":{}} (no recordId), or with "recordId":"", answers 404 ENDPOINT_NOT_FOUND "Not found". The caller is told the endpoint does not exist, when the real problem is the missing record id the action's target path needs. The same call with a real request id answers 200 (the #28657 fix holds), and with an unknown id answers 404 REQUEST_NOT_FOUND.
Measured at framework 7fa9873f (main, 2026-11-02) on a stock showcase boot, as a non-admin pending approver (the #28657 persona).
buildApiActionRequest in packages/runtime/src/action-execution.ts substitutes {field} tokens only when a subject row is present, and its unresolved-token guard checks only ${…} and {{ forms, so the forward goes out with {id} literally in the path and the router answers 404.
Read fresh. The card was observed beside approvals.account-app-entry, but the defect is on the generic action door, not on that capability. buildApiActionRequest (packages/runtime/src/action-execution.ts) forwards a literal {id} when no recordId is given, so the door answers 404 ENDPOINT_NOT_FOUND instead of a 400 naming the missing id. That is a user-visible behaviour defect, so it is p2 in domain:server, and with the location and repro named it goes to pm:queue.
Claim: PM loop round 1 · card thread · 2026-11-02T05:20Z
Session: session_01R1q2xdtYgU6FKrZ7LgjPCC (the seat); the card thread is session_01FEkQ5nNCtq276yJtjqKq8B (a new card thread, fresh from main62b3ec36)
Account: os-project-manager (the seat's linked user; the card's assignee)
Branch: claude/project-thread-4yqy8a (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
Worktree: the card thread's own container checkout
Domain: domain:server
Seat: domain:server#1
Ruling-ref: triage#1 graded the card p2 (05:06Z): a generic action-door defect. Route (the dispatching seat's call): buildApiActionRequest refuses a target path whose {field} token is unresolved with 400 naming recordId, before any forward. Dispatched in the seat-1 split of the server queue under 「队列进了很多任务,抓紧派发」 (Leehom, 2026-11-02T05:15Z) and 「定级你可以自己决定」 (Leehom, 2026-11-01T12:11Z).
File surface: buildApiActionRequest and its unresolved-token guard in packages/runtime/src/action-execution.ts; their tests and changesets. ⛔ No packages/spec/**, no new error code, no new gate.
Container & model: S, mode:thread, model and effort as the thread was opened
Clause-②: no (expected: a call that was already refused 404 is refused 400 naming the missing id; the accept set does not change; the dev measures)
Metadata-protocol: per AGENTS.md, measured by the dev (likely none)
Responsibility: the code is the api action forward of @objectstack/runtime · the platform path is a record-anchored api action called with no recordId answering ENDPOINT_NOT_FOUND · reached by every REST or MCP caller of POST /api/v1/actions/:object/:action
Thread-read: none
Premise: holds on main7fa9873f (the card's repro)
Serial constraints cleared: #28657 landed. #28943 (seat 1, another thread) edits the credential table in the same file, so merge origin/main once if it lands first.
Resume-from: none — fresh from origin/main
State: pm:queue → pm:dispatched, assigned to os-project-manager, recorded by this claim.
os-dev-report
{
"issue": 28932,
"status": "done",
"branch": "claude/project-thread-4yqy8a",
"pr": "#29005",
"session": "session_01FEkQ5nNCtq276yJtjqKq8B",
"premise_still_valid": true,
"summary": "buildApiActionRequest (packages/runtime/src/action-execution.ts) now refuses a target record token it cannot fill before any forward: an unresolved ${ctx.recordId} (an empty recordId counts as none) and any {field} token left in the path answer 400 VALIDATION_ERROR naming recordId when no record was named, otherwise the field the row lacks. Both doors (REST /actions and MCP run_action) share it; no new error code, no spec change. Step-1 measurement: every record-token api target in objectstack names {id} alone (9 sys_approval_request actions, 2 sys_api_key, 1 dev console page); 2 datasource actions use ${ctx.recordId}; examples/ and hotcrm have none.",
"tests": "Head f71c6e2, base f7c545a. Unit packages/runtime/src/domains/api-action-forward.test.ts: 73/73 green; with action-execution.ts from base 4 failed / 69 passed (the 4 refusal tests; controls green). Real stack packages/verify/src/action-door-api-forward-denied-subject.test.ts: 5/5 green; with runtime dist rebuilt from base 1 failed / 4 passed, reading 404 ENDPOINT_NOT_FOUND 'Not found' (the card's repro). Ablation from committed HEAD via scripts/ablation-replace.mjs (both guard lines, anchor 1 to 0 each): unit 4 failed / 69 passed; verify after runtime build + ablation-dist-preflight 'marker present in 2 built files': 1 failed / 4 passed (400 FILTER_TOKEN_UNKNOWN, not VALIDATION_ERROR). Restore: git diff HEAD 0 bytes, blob 12811782c09a equal to HEAD, rebuilt, preflight --absent 'marker absent from all 12 built files', tree clean. Full pnpm --filter @objectstack/runtime test: 513 files, 8272 passed, 19 skipped (lock VERDICT command-exit 0). runtime typecheck exit 0 (test-typecheck ledger held 27/188/68); verify typecheck exit 0; eslint --no-inline-config packages/runtime packages/verify exit 0.",
"gates": "dispatch-gates --commands at f71c6e2: 61 commands, each run with exit captured before any pipe (record /mnt/project-files/pm-orders/server/28932-gates-ran.txt). 60 exit 0. check:dual-build-cjs-loads exit 3 PREREQUISITE NOT MET (needs a full repo build; only the verify closure was built) = NOT MEASURED, left to CI. check-plugin-teardown-shape --self-test exit 3 on the shallow clone, exit 0 (48 cases) after git fetch --depth=1 of the commit it reads; exit 0 recorded. dispatch-gates --ran: 61 derived, 60 run, 1 NOT-MEASURED, 0 UNRUN. CI check-runs on the PR: in_progress at report time.",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"mcp_calls": "0",
"api_writes": "2 relay writes plus 1 git push: git push of claude/project-thread-4yqy8a; fleet-write pr_create (run 41397679904, PR #29005, no assignees, no labels); this os-dev-report comment via post-stamped",
"open_questions": [],
"out_of_scope_findings": [
"none — the one adjacent shape (a scope-less ${name} or a double-brace name target whose {name} matched no row field, forwarded blanked on main) is closed by the same guard and noted in the PR's Acceptance notes; no such target exists in objectstack, examples/ or hotcrm"
]
}
PR #29005 merged by the merge queue as 2bfdc4261e on main (Fixes #28932; Clause-②: no, with no contract review owed; ACCEPT 6570373416). The card closed on the merge.
Landed: an api action whose target names its record is refused 400 VALIDATION_ERROR naming recordId (or the field the row lacks) before any forward, on the REST action door and MCP run_action, instead of being forwarded to a path that answers 404 ENDPOINT_NOT_FOUND. @objectstack/runtime patch, Metadata-protocol: none.
Release: branch claude/project-thread-4yqy8a merged; nothing unpushed. pm:dispatched removed and the card unassigned.
Activity
objectstack-fleet commentedon Nov 2, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: priority:p2 · domain:server · pm:queue · 2026-11-02T05:06Z
⛔ Not a claim.
approvals.account-app-entry, but the defect is on the generic action door, not on that capability.buildApiActionRequest(packages/runtime/src/action-execution.ts) forwards a literal{id}when no recordId is given, so the door answers 404 ENDPOINT_NOT_FOUND instead of a 400 naming the missing id. That is a user-visible behaviour defect, so it is p2 indomain:server, and with the location and repro named it goes topm:queue.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:server#1 · os-project-manager · session_01R1q2xdtYgU6FKrZ7LgjPCC
Claim: PM loop round 1 · card thread · 2026-11-02T05:20Z
Session:
session_01R1q2xdtYgU6FKrZ7LgjPCC(the seat); the card thread issession_01FEkQ5nNCtq276yJtjqKq8B(a new card thread, fresh frommain62b3ec36)Account:
os-project-manager(the seat's linked user; the card's assignee)Branch:
claude/project-thread-4yqy8a(the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)Worktree: the card thread's own container checkout
Domain:
domain:serverSeat:
domain:server#1Ruling-ref: triage#1 graded the card p2 (05:06Z): a generic action-door defect. Route (the dispatching seat's call):
buildApiActionRequestrefuses a target path whose{field}token is unresolved with400namingrecordId, before any forward. Dispatched in the seat-1 split of the server queue under 「队列进了很多任务,抓紧派发」 (Leehom, 2026-11-02T05:15Z) and 「定级你可以自己决定」 (Leehom, 2026-11-01T12:11Z).File surface:
buildApiActionRequestand its unresolved-token guard inpackages/runtime/src/action-execution.ts; their tests and changesets. ⛔ Nopackages/spec/**, no new error code, no new gate.Container & model:
S,mode:thread, model and effort as the thread was openedClause-②: no (expected: a call that was already refused
404is refused400naming the missing id; the accept set does not change; the dev measures)Metadata-protocol: per AGENTS.md, measured by the dev (likely none)
Responsibility: the code is the
apiaction forward of@objectstack/runtime· the platform path is a record-anchoredapiaction called with norecordIdansweringENDPOINT_NOT_FOUND· reached by every REST or MCP caller ofPOST /api/v1/actions/:object/:actionThread-read: none
Premise: holds on
main7fa9873f(the card's repro)Serial constraints cleared: #28657 landed. #28943 (seat 1, another thread) edits the credential table in the same file, so merge
origin/mainonce if it lands first.Resume-from: none — fresh from
origin/mainState:
pm:queue→pm:dispatched, assigned toos-project-manager, recorded by this claim.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:server#1 · os-project-manager · session_01FEkQ5nNCtq276yJtjqKq8B
os-dev-report
{
"issue": 28932,
"status": "done",
"branch": "claude/project-thread-4yqy8a",
"pr": "#29005",
"session": "session_01FEkQ5nNCtq276yJtjqKq8B",
"premise_still_valid": true,
"summary": "buildApiActionRequest (packages/runtime/src/action-execution.ts) now refuses a target record token it cannot fill before any forward: an unresolved ${ctx.recordId} (an empty recordId counts as none) and any {field} token left in the path answer 400 VALIDATION_ERROR naming
recordIdwhen no record was named, otherwise the field the row lacks. Both doors (REST /actions and MCP run_action) share it; no new error code, no spec change. Step-1 measurement: every record-token api target in objectstack names {id} alone (9 sys_approval_request actions, 2 sys_api_key, 1 dev console page); 2 datasource actions use ${ctx.recordId}; examples/ and hotcrm have none.","tests": "Head f71c6e2, base f7c545a. Unit packages/runtime/src/domains/api-action-forward.test.ts: 73/73 green; with action-execution.ts from base 4 failed / 69 passed (the 4 refusal tests; controls green). Real stack packages/verify/src/action-door-api-forward-denied-subject.test.ts: 5/5 green; with runtime dist rebuilt from base 1 failed / 4 passed, reading 404 ENDPOINT_NOT_FOUND 'Not found' (the card's repro). Ablation from committed HEAD via scripts/ablation-replace.mjs (both guard lines, anchor 1 to 0 each): unit 4 failed / 69 passed; verify after runtime build + ablation-dist-preflight 'marker present in 2 built files': 1 failed / 4 passed (400 FILTER_TOKEN_UNKNOWN, not VALIDATION_ERROR). Restore: git diff HEAD 0 bytes, blob 12811782c09a equal to HEAD, rebuilt, preflight --absent 'marker absent from all 12 built files', tree clean. Full pnpm --filter @objectstack/runtime test: 513 files, 8272 passed, 19 skipped (lock VERDICT command-exit 0). runtime typecheck exit 0 (test-typecheck ledger held 27/188/68); verify typecheck exit 0; eslint --no-inline-config packages/runtime packages/verify exit 0.",
"gates": "dispatch-gates --commands at f71c6e2: 61 commands, each run with exit captured before any pipe (record /mnt/project-files/pm-orders/server/28932-gates-ran.txt). 60 exit 0. check:dual-build-cjs-loads exit 3 PREREQUISITE NOT MET (needs a full repo build; only the verify closure was built) = NOT MEASURED, left to CI. check-plugin-teardown-shape --self-test exit 3 on the shallow clone, exit 0 (48 cases) after git fetch --depth=1 of the commit it reads; exit 0 recorded. dispatch-gates --ran: 61 derived, 60 run, 1 NOT-MEASURED, 0 UNRUN. CI check-runs on the PR: in_progress at report time.",
"dogfood_battery": "n/a — no
!in the PR title and no (narrowing) arm","mcp_calls": "0",
"api_writes": "2 relay writes plus 1 git push: git push of claude/project-thread-4yqy8a; fleet-write pr_create (run 41397679904, PR #29005, no assignees, no labels); this os-dev-report comment via post-stamped",
"open_questions": [],
"out_of_scope_findings": [
"none — the one adjacent shape (a scope-less ${name} or a double-brace name target whose {name} matched no row field, forwarded blanked on main) is closed by the same guard and noted in the PR's Acceptance notes; no such target exists in objectstack, examples/ or hotcrm"
]
}
Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:server#1 · os-project-manager · session_01R1q2xdtYgU6FKrZ7LgjPCC
Landing record · #28932 · PR #29005
PR #29005 merged by the merge queue as
2bfdc4261eonmain(Fixes #28932;Clause-②: no, with no contract review owed; ACCEPT6570373416). The card closed on the merge.git ls-remote origin 'refs/heads/gh-readonly-queue/main/pr-29005-*'origin/mainby contentgit diff --quiet 2bfdc4261e origin/main --the PR's 4 filesgit merge-base --is-ancestor 2bfdc4261e origin/mainapiaction whosetargetnames its record is refused400 VALIDATION_ERRORnamingrecordId(or the field the row lacks) before any forward, on the REST action door and MCPrun_action, instead of being forwarded to a path that answers404 ENDPOINT_NOT_FOUND.@objectstack/runtimepatch,Metadata-protocol: none.Release: branch
claude/project-thread-4yqy8amerged; nothing unpushed.pm:dispatchedremoved and the card unassigned.Generated by Claude Code