Skip to content

Upload links: refuse at issue a field whose readonlyWhen holds now (carries the issue-time readonlyWhen half of #32734) #32768

Closed

Description

@objectstack-fleet

domain:server#4 · os-sales · session_01L6bhgWRcTEB3toGxnWvuvX

Carries the issue-time readonlyWhen half of #32734's first expected item; #32734 keeps the record-lock and static readonly refusal at issue, the consume-side refusal and the page text.

Filing category: ① product defect (in-flight split, references/execution-duties.md in-scope sub-issue; priority inherited).

Blocked-by: #32734

Business reason

An agent asked to attach an invoice to an approved expense claim (a field read-only by readonlyWhen) still hands out an upload link. After #32734 the page refuses with the reason and keeps no file, but the person only learns it after picking and sending the file.

What is missing

Expected

  • One write-free judgement of "is this field writable on this record now" that runs readonlyWhen (the engine's own, ⛔ no second CEL evaluation in service-storage or packages/mcp), and create_upload_link refuses with the same reason update_record gives.
  • If the fix changes the update preview's documented limit, that is the engine contract's text: the claimer reads it first and states whether it widens a published surface (Clause-②).

Reader who acts: the domain:server engine face (packages/objectql validate preview), then packages/mcp create_upload_link.
Dedupe: parent #32734; repo:objectstack-ai/objectstack is:issue validate preview readonlyWhen → 37 hits, the only open ones this card and a seat post (#18549); none on this.


Generated by Claude Code

Activity

  1. added
    bugSomething isn't working
    priority:p1High: required for production / M2
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    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 12, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-sales · session_01L6bhgWRcTEB3toGxnWvuvX

    Unblocked · 2026-11-12T18:31Z: Blocked-by: #32734 closed by PR #32779 (merged 9af0766). Back to pm:queue. Same area:files door as #32754 (claimed by domain:server#4): serial behind it, then #32783.


    Generated by Claude Code

  3. added
    pm:queueReady for the PM dispatch loop
    and removed
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    on Nov 12, 2026
  4. added
    priority:p0Queue-jump: outranks batch and breaks the round — never exempts claiming or same-file serial
    and removed
    priority:p1High: required for production / M2
    on Nov 13, 2026
  5. os-bob commented on Nov 13, 2026

    @os-bob
    Contributor

    Re-grade on the maintainer's instruction: priority:p1 → priority:p0. State unchanged (pm:queue, unassigned). Written by a test session, not a seat.


    Generated by Claude Code

  6. objectstack-fleet commented on Nov 13, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH

    Path: none

    Triage: p0 → p1 · not an 18.4.0 blocker · 2026-11-13T07:56Z

    ⛔ Not a claim; the claim and state are unchanged, and the work continues.


    Generated by Claude Code

  7. added
    priority:p1High: required for production / M2
    and removed
    priority:p0Queue-jump: outranks batch and breaks the round — never exempts claiming or same-file serial
    on Nov 13, 2026
  8. objectstack-fleet commented on Nov 13, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#8 · os-elon-musk · session_016WV4cwqTK71kjQzHae8T5J

    Claim: PM loop round 3 (p1, pm:queue; card ≡ 2 (mod 3); MCP capability family of the tracking epic #32897, which has no seat of its own; triage#1 ruling 6847514611 on mailbox #32829 lets the family proceed now) · 2026-11-13T08:03Z
    Session: session_016WV4cwqTK71kjQzHae8T5J
    Account: os-elon-musk
    Branch: the card thread's designated claude/project-thread-* branch, written in its whole re-posted claim before the first push
    Worktree: the card thread's own checkout
    Domain: domain:server
    Seat: domain:server#8
    File surface: packages/objectql/src/** (one write-free "is this field writable on this record now" judgement that runs the engine's own readonlyWhen, and the update preview's documented limit if it moves), packages/mcp/src/file-content.ts and the create_upload_link tool beside it, tests beside them, packages/qa/dogfood/test/** (one pin), content/docs/** where the upload link's refusals are documented, .changeset/** (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: opus (TIER_DEFAULT unless dispatch-gates.mjs --tier derives more), effort: high
    Clause-②: yes (narrowing)
    Metadata-protocol: none
    Declaration note: create_upload_link gains a refusal at issue (a field whose readonlyWhen holds now is refused with the words update_record gives, where a link was issued and the page refused later), a narrowing of what the tool issues; the engine gains one write-free judgement (widening). If the thread measures that the update preview's published limit moves, the re-posted claim says so
    Responsibility: n/a — gap, issue-time half of #32734 (in-flight split by domain:server#4)
    Thread-read: 6847407315
    Premise: holds (measured on origin/main 12b1446: engine.ts:4390 still documents that INSERT does not run readonlyWhen, and create_upload_link in packages/mcp/src/file-content.ts judges no conditional lock; #32734, the Blocked-by:, is closed)
    Serial constraints cleared: seat 4's serial note 6832415816 was on the area:files door of #32754; its PR #32932 touches service-storage, plugin-security and spec only, none of packages/objectql or packages/mcp; no in-flight claim names create_upload_link (#32686 pm:queue, #32747 pm:blocked). The thread merges origin/main once #32932 lands if it lands first

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

    @objectstack-fleet
    ContributorAuthor

    domain:server#8 · os-elon-musk · session_016WV4czfTdXkf83P5ogS9TT

    Claim: PM loop round 3 (p1, pm:queue; card ≡ 2 (mod 3); MCP capability family of the tracking epic #32897, which has no seat of its own; triage#1 ruling 6847514611 on mailbox #32829 lets the family proceed now) · 2026-11-13T08:20Z — card-thread re-post of claim 6847540308 with its branch
    Session: session_016WV4czfTdXkf83P5ogS9TT
    Account: os-elon-musk
    Branch: claude/project-thread-4h9gy8
    Worktree: the card thread's own checkout
    Domain: domain:server
    Seat: domain:server#8
    File surface: packages/objectql/src/** (one write-free "is this field writable on this record now" judgement, ObjectQL#judgeFieldWriteLock, built on the update's own readonlyWhen strip; the update preview's documented limit does not move), packages/services/service-storage/src/record-file-access.ts and its integration test (ADDED by this re-post, measured: the issue-time refusals of create_upload_link live in createUploadLinkAs there, where #32734 put the static readonly and approval-lock refusals; packages/mcp/src/file-content.ts only declares the bridge types and holds no engine), packages/mcp/src/mcp-http-tools.ts (the create_upload_link tool's description sentence only; file-content.ts is not touched), packages/qa/dogfood/test/** (one pin), content/docs/** where the upload link's refusals are documented, .changeset/** (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: opus (TIER_DEFAULT unless dispatch-gates.mjs --tier derives more), effort: high
    Clause-②: yes (narrowing)
    Metadata-protocol: none
    Declaration note: create_upload_link gains a refusal at issue (a field whose readonlyWhen holds now is refused 403 FIELD_NOT_ACCESSIBLE in the words the update's strict refusal uses for that lock, where a link was issued and the upload refused later), a narrowing of what the tool issues; the engine gains one write-free judgement (widening). Measured: the update preview (engine.validate, ValidateDataResponse) is not changed and its published readonlyWhen limit stays as written, so no published preview surface widens
    Responsibility: n/a — gap, issue-time half of #32734 (in-flight split by domain:server#4)
    Thread-read: 6847540308
    Premise: holds (re-measured on origin/main 12b1446 by this thread: create_upload_link's mint door createUploadLinkAs judges static readonly and the approval lock, and no conditional lock; engine-validate.ts still names readonlyWhen as a limit the preview does not run)
    Serial constraints cleared: PR #32932 (area:files, #32754) is still open and touches none of these files (service-storage files it touches: attachment-access-hooks.ts, attachment-files-opt-in.ts, attachment-member-grant.ts, storage-service-plugin.ts and tests); the thread merges origin/main once more if it lands first

  11. objectstack-fleet commented on Nov 13, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH

    Path: none

    Triage: first-touch audit (pre-labeled card) · p0 confirmed · 2026-11-13T08:23Z

    ⛔ Not a claim; the claim (if any) is unchanged.


    Generated by Claude Code

  12. objectstack-fleet commented on Nov 13, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#8 · os-elon-musk · session_016WV4czfTdXkf83P5ogS9TT
    os-dev-report

    {
      "issue": 32768,
      "status": "done",
      "branch": "claude/project-thread-4h9gy8",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/33079",
      "session": "session_016WV4czfTdXkf83P5ogS9TT",
      "premise_still_valid": true,
      "summary": "ObjectQL gains judgeFieldWriteLock(object, id, field, { context }), the one write-free judgement of whether a field takes a caller's write on a record now for its readonlyWhen lock, built on the update's own stripReadonlyWhenFields over the update's prior-row read and master-detail header; it answers the drop reason (readonly_when) and the strict refusal's phrase. createUploadLinkAs (service-storage) asks it for a file-field target and refuses 403 FIELD_NOT_ACCESSIBLE in those words, writing no link row; the attachments target is unchanged; static readonly and the approval lock are unchanged. Measured surface correction, declared on re-post 6847846915: the issue-time refusals live in service-storage record-file-access.ts, not packages/mcp/src/file-content.ts (types only, untouched); mcp-http-tools.ts gets one description sentence. The update preview (engine.validate / ValidateDataResponse) is not changed, so its published readonlyWhen limit does not move and no preview surface widens.",
      "tests": "objectql test 594/594 files, 12784/12784 tests; service-storage test 79/79, 1486/1486; mcp test 63/63, 1096/1096; typecheck objectql, service-storage, mcp exit 0; engine-field-write-lock.test.ts 7/7 at c3e09f34; record-file-access.integration.test.ts 36/36 at d9c65672; dogfood showcase-mcp-record-files 15/15. Ablation via ablation-replace.mjs on record-file-access.ts (refusal line x1->x0, blob a771bfae->d5ac8211): integration test 1 failed | 35 passed (the new issue-time pin), restored blob == HEAD, git diff HEAD empty; the suite runs package source, no dist leg.",
      "gates": "dispatch-gates --commands 104 families; --ran record with exit codes: 104 accounted, 101 run, 3 NOT MEASURED (exit 3 PREREQUISITE NOT MET: check-plugin-teardown-shape --self-test needs an unshallow clone; check:skill-examples needs client-react dist; check:dual-build-cjs-loads needs unbuilt packages outside the closure). Reds found and fixed on branch: check:tenant-audit-census (RecordFileEngine as a type literal fell out of the census; now an interface extending IDataEngine, 310 sites) and check:objectql-double-limit (new test double ignored limit); both exit 0 at c3e09f34, plus check:engine-double-contract, check:nul-bytes, check-platform-checklist --changed-from origin/main (21 anchors, 0 lost); pnpm lint exit 0. PR check-runs: in_progress at report time. Record: /mnt/project-files/server-lane-seat8/32768/gates-ran-c3e09f34.txt",
      "dogfood_battery": "d9c65672 · VERDICT command-exit 0 · Test Files 458 passed | 3 skipped (461) · Tests 3845 passed | 42 skipped (3887) · no failures; c3e09f34 after it changes only the objectql unit test double",
      "mcp_calls": "0",
      "api_writes": "3 via the fleet-write relay — POST issues/32768/comments (claim re-post 6847846915), POST pulls (pr_create #33079), POST issues/32768/comments (this report)",
      "open_questions": [],
      "security_findings": "withheld",
      "out_of_scope_findings": [
        "carrier: none · out of scope per the order, report only: several files per link (#32747), upload before the record exists (#32686); consume-side refusal and page text already done in #32734"
      ]
    }

    Generated by Claude Code

  13. objectstack-fleet commented on Nov 13, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#8 · os-elon-musk · session_016WV4cwqTK71kjQzHae8T5J

    Ruling recorded · 2026-11-13T09:51Z: the maintainer agreed to the narrowing in PR #33079. He chose option A, 「同意收紧」, on the seat's decision card. create_upload_link will refuse at issue a file field whose readonlyWhen holds.

    Landing: the contract review passed (6849553232, delta note 6849591863). Once CI is green, the seat accepts and lands after the 18.4.0 merge freeze lifts (#32908; Version Packages PR #29963).

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 recordbugSomething isn't workingdomain:serverDomain lane — seat card indexed by label:pm:seatpriority:p1High: required for production / M2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions