Skip to content

create_upload_link: say which target and which read-only declaration get no link; close the upload-link relay's code and docblock #32783

Closed

Description

@objectstack-fleet

domain:server#4 · os-sales · session_01L6bhgWRcTEB3toGxnWvuvX

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.

Blocked-by: #32734

维护者速读

  • 改什么:create_upload_link 的工具说明把"锁定记录、只读字段不发链接"写成了对所有目标都成立;实际只对字段目标成立(附件列表在锁定记录上照常可附),"只读"也只指 readonly 声明,不含 readonlyWhen。另把上传链接拒绝转发处的错误码收成平台闭合词表,并补全注释。
  • 为什么:代理按工具说明决定要不要给用户发链接,现在的说法会让它误以为锁定记录不能加附件。
  • 风险:说明文字与一处错误码归一;不改判定规则。
  • 先看:packages/mcp/src/mcp-http-tools.ts 的 create_upload_link 描述;packages/services/service-storage/src/storage-routes.ts 的 relayUploadLinkRefusal。
  • 验证:描述句与代码分支一致;转发的 error.code 取闭合码,与同文件 relayAttachFailure 同法,有 pin。
  • 需要你做的:无。

Do

  1. S1. create_upload_link's description: say the lock and the read-only refusals apply to a field target (an attachments: true link to a locked record is issued and attaches), and that "read-only" means the readonly declaration; a readonlyWhen field is judged when the upload arrives (until Upload links: refuse at issue a field whose readonlyWhen holds now (carries the issue-time readonlyWhen half of #32734) #32768 lands, then reword with it).
  2. N2. relayUploadLinkRefusal answers the resolver's closed code (with demotedDeclaredCode beside it), as relayAttachFailure in the same file does under the [Decision] The dispatcher's error.code has a limb authored by TENANTS at runtime — registration cannot close it, and ADR-0112 does not say what should happen there #9106 ruling, instead of the thrown spelling under a cast. Pin: a 4xx throw carrying an unregistered code is answered with a registered one.
  3. 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).
  4. N1 (the page shows the RECORD_LOCKED: prefix and API names) is page wording: carried by Upload-link page: English-only in a zh-CN deployment, and it names neither the record nor the field the file goes to #32712, noted there.

Clause-②: no. Metadata-protocol: none.


Generated by Claude Code

Activity

  1. added
    enhancementNew feature or request
    pm:queueReady for the PM dispatch loop
    area:filesFiles — upload, download, signed URLs, access derived from the parent record
    domain:serverDomain lane — seat card indexed by label:pm:seat
    on Nov 12, 2026
  2. objectstack-fleet commented on Nov 13, 2026

    @objectstack-fleet
    ContributorAuthor

    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

  3. objectstack-fleet commented on Nov 13, 2026

    @objectstack-fleet
    ContributorAuthor

    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_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

  4. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 13, 2026
  5. objectstack-fleet commented on Nov 13, 2026

    @objectstack-fleet
    ContributorAuthor

    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"
      ]
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:filesFiles — upload, download, signed URLs, access derived from the parent recorddomain:serverDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions