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
create_upload_link: say which target and which read-only declaration get no link; close the upload-link relay's code and docblock #32783
Follow-up of #32734 (PR #32779), from its contract review at 5bd8b5dc (record 6830676963 on PR #32779: should-fix S1, nits N2 and N3). Filed under the maintainer's rule: small review findings get their own card under the source card, not another PR round. It does not block #32779.
N3. Its docblock names all three limbs of declaredStatus (status, statusCode, the validation shape → 400), and a test pins the validation shape's 400 (the PR's Acceptance notes state it; nothing pins it).
Line: agents over MCP · create_upload_link tool description · every locked-record attachment request · read
Why: The tool description tells agents locked records get no attachment link, so an agent wrongly refuses over MCP; base p3, raised once by the MCP focus rule.
Claim: PM loop round 4, card thread · 2026-11-13T17:28Z · MCP p2 under the maintainer's 「mcp 相关 p2 任务也可以派发处理」 (2026-11-13T15:50:52Z)
Session: session_01L9qibwbZycGiSpGfzuw3UC
Account: os-tesla
Branch: claude/project-thread-wp6iex
Worktree: objectstack-issue-32783
Domain: domain:server
Seat: domain:server#7
File surface: packages/mcp/src/mcp-http-tools.ts (the create_upload_link description only), packages/mcp/src/skill-md.ts and ui/apps/console/src/pages/developer/objectstack-skill.ts (only where they restate it), packages/services/service-storage/src/storage-routes.ts (relayUploadLinkRefusal and its docblock), their tests, content/docs pages that restate the description, one root changeset. Stop on breach.
Container & model: S, mode:thread, model: default (dispatch-gates --tier: no path-derived mandate; PM default), effort: medium
Clause-②: no — description wording plus the relay's code put onto the closed vocabulary; no accept-set change
Metadata-protocol: none
Responsibility: the over-broad sentence is in the MCP create_upload_link description (packages/mcp) and the open-coded code is in relayUploadLinkRefusal (service-storage), both objectstack | relayAttachFailure in the same file already answers the closed code under the #9106 ruling | every MCP agent deciding whether to offer an attachment link on a locked record reads it today
Thread-read: 6847862450
Premise: re-measure — filed at 5bd8b5dc; #32768 (readonlyWhen judged at issue) and #32686 (new-record limb) have landed since, so the dev reads each description sentence against origin/main before editing
Serial constraints cleared: mcp-http-tools.ts is shared with #32442 (server#5) and this seat's #32872 (PR #33134) and #31699: edits stay on the create_upload_link description; land serially, merge main after a sibling lands
{
"issue": 32783,
"status": "done",
"branch": "claude/project-thread-wp6iex",
"pr": "https://github.com/objectstack-ai/objectstack/pull/33142",
"session": "session_01L9qibwbZycGiSpGfzuw3UC",
"premise_still_valid": true,
"summary": "Measured each create_upload_link description sentence at origin/main 67188849: #32768 had already added readonlyWhen at issue, so the over-broad part left was the lock: only a field link is refused RECORD_LOCKED, while an attachments link to a locked record is issued and attaches (measured). The description and content/docs/ai/connect-mcp.mdx now scope the lock and read-only refusals to a field link; the served skill text does not restate them and is unchanged. relayUploadLinkRefusal answers the resolver's closed code with demotedDeclaredCode beside it (as relayAttachFailure does, #9106 ruling read in packages/types/src/thrown-http-error.ts module note), its 503 arm still keyed on the spelled SERVICE_UNAVAILABLE, and its docblock names all three declaredStatus limbs; a new suite pins the unregistered-code demotion, the 503 arm and the validation shape's 400.",
"tests": "head 9292068c: service-storage test 83/83 files, 1554/1554 tests; mcp test 63/63 files, 1104/1104; typecheck (both) exit 0; new suite storage-routes.upload-link-refusal-relay.test.ts 7/7. Ablations via ablation-replace.mjs on src (suite imports ./storage-routes.js directly): N2 closed code put back to e.code cast -> 2 failed (GET+PUT, expected 'CLAIM_DESK_SAYS_NO' to be 'RESOURCE_CONFLICT'); 503 arm read off thrown.code -> 1 failed (expected 503 to be 500); blob restored e1f86c0c before/after, git diff HEAD empty. Measurement (throwaway case, not committed): attachments link on a locked claim landed a sys_attachment; field link refused 409 RECORD_LOCKED.",
"gates": "dispatch-gates --commands (5 paths, 102 commands) each run with stdin from /dev/null, exit captured to disk: 99 exit 0 first run; check:skill-examples, check:i18n, check:dual-build-cjs-loads exit 3 PREREQUISITE NOT MET, then exit 0 after their named builds. --ran with exits: 102 derived, 102 run, 0 NOT-MEASURED (derived zero). pnpm lint exit 0. check-nul-bytes exit 0. Record: /mnt/project-files/server-seat-7/r2026-11-13/out/32783-gates-ran-9292068c.list. CI check-runs: 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 pr_create (objectstack#33142, run 43482101731), this os-dev-report comment via post-stamped; plus git push (not REST)",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": [
"carrier: none · noted, not filed · record-file-access.ts module docblock still says readonlyWhen has no judgement a door can ask without writing (stale since #32768 judgeFieldWriteLock); comment drift, in PR Acceptance notes",
"carrier: none · noted, not filed · relayUploadLinkRefusal answers VALIDATION_FAILED without details.fields (relayAttachFailure passes them); in PR Acceptance notes"
]
}
Activity
objectstack-fleet commentedon Nov 13, 2026
triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH
Path: none
Triage: first-touch audit (pre-labeled card) ·
p3→p2· 2026-11-13T08:21Z⛔ Not a claim; the claim (if any) is unchanged.
Generated by Claude Code
objectstack-fleet commentedon Nov 13, 2026
domain:server#7 · os-tesla · session_01L9qibzuZJBQY4wUQFJbkfx
Claim: PM loop round 4, card thread · 2026-11-13T17:28Z · MCP p2 under the maintainer's 「mcp 相关 p2 任务也可以派发处理」 (2026-11-13T15:50:52Z)
Session:
session_01L9qibwbZycGiSpGfzuw3UCAccount:
os-teslaBranch:
claude/project-thread-wp6iexWorktree:
objectstack-issue-32783Domain:
domain:serverSeat:
domain:server#7File surface:
packages/mcp/src/mcp-http-tools.ts(thecreate_upload_linkdescription only),packages/mcp/src/skill-md.tsandui/apps/console/src/pages/developer/objectstack-skill.ts(only where they restate it),packages/services/service-storage/src/storage-routes.ts(relayUploadLinkRefusaland its docblock), their tests,content/docspages that restate the description, one root changeset. Stop on breach.Container & model:
S,mode:thread,model: default (dispatch-gates --tier: no path-derived mandate; PM default),effort: mediumClause-②: no — description wording plus the relay's code put onto the closed vocabulary; no accept-set change
Metadata-protocol: none
Responsibility: the over-broad sentence is in the MCP
create_upload_linkdescription (packages/mcp) and the open-coded code is inrelayUploadLinkRefusal(service-storage), both objectstack |relayAttachFailurein the same file already answers the closed code under the #9106 ruling | every MCP agent deciding whether to offer an attachment link on a locked record reads it todayThread-read: 6847862450
Premise: re-measure — filed at
5bd8b5dc; #32768 (readonlyWhen judged at issue) and #32686 (new-record limb) have landed since, so the dev reads each description sentence againstorigin/mainbefore editingSerial constraints cleared:
mcp-http-tools.tsis shared with #32442 (server#5) and this seat's #32872 (PR #33134) and #31699: edits stay on thecreate_upload_linkdescription; land serially, merge main after a sibling landsobjectstack-fleet commentedon Nov 13, 2026
domain:server#7 · os-tesla · session_01L9qibwbZycGiSpGfzuw3UC
os-dev-report
{ "issue": 32783, "status": "done", "branch": "claude/project-thread-wp6iex", "pr": "https://github.com/objectstack-ai/objectstack/pull/33142", "session": "session_01L9qibwbZycGiSpGfzuw3UC", "premise_still_valid": true, "summary": "Measured each create_upload_link description sentence at origin/main 67188849: #32768 had already added readonlyWhen at issue, so the over-broad part left was the lock: only a field link is refused RECORD_LOCKED, while an attachments link to a locked record is issued and attaches (measured). The description and content/docs/ai/connect-mcp.mdx now scope the lock and read-only refusals to a field link; the served skill text does not restate them and is unchanged. relayUploadLinkRefusal answers the resolver's closed code with demotedDeclaredCode beside it (as relayAttachFailure does, #9106 ruling read in packages/types/src/thrown-http-error.ts module note), its 503 arm still keyed on the spelled SERVICE_UNAVAILABLE, and its docblock names all three declaredStatus limbs; a new suite pins the unregistered-code demotion, the 503 arm and the validation shape's 400.", "tests": "head 9292068c: service-storage test 83/83 files, 1554/1554 tests; mcp test 63/63 files, 1104/1104; typecheck (both) exit 0; new suite storage-routes.upload-link-refusal-relay.test.ts 7/7. Ablations via ablation-replace.mjs on src (suite imports ./storage-routes.js directly): N2 closed code put back to e.code cast -> 2 failed (GET+PUT, expected 'CLAIM_DESK_SAYS_NO' to be 'RESOURCE_CONFLICT'); 503 arm read off thrown.code -> 1 failed (expected 503 to be 500); blob restored e1f86c0c before/after, git diff HEAD empty. Measurement (throwaway case, not committed): attachments link on a locked claim landed a sys_attachment; field link refused 409 RECORD_LOCKED.", "gates": "dispatch-gates --commands (5 paths, 102 commands) each run with stdin from /dev/null, exit captured to disk: 99 exit 0 first run; check:skill-examples, check:i18n, check:dual-build-cjs-loads exit 3 PREREQUISITE NOT MET, then exit 0 after their named builds. --ran with exits: 102 derived, 102 run, 0 NOT-MEASURED (derived zero). pnpm lint exit 0. check-nul-bytes exit 0. Record: /mnt/project-files/server-seat-7/r2026-11-13/out/32783-gates-ran-9292068c.list. CI check-runs: 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 pr_create (objectstack#33142, run 43482101731), this os-dev-report comment via post-stamped; plus git push (not REST)", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "carrier: none · noted, not filed · record-file-access.ts module docblock still says readonlyWhen has no judgement a door can ask without writing (stale since #32768 judgeFieldWriteLock); comment drift, in PR Acceptance notes", "carrier: none · noted, not filed · relayUploadLinkRefusal answers VALIDATION_FAILED without details.fields (relayAttachFailure passes them); in PR Acceptance notes" ] }