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
Upload links: refuse at issue a field whose readonlyWhen holds now (carries the issue-time readonlyWhen half of #32734) #32768
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.
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
create_upload_link cannot judge readonlyWhen at issue without writing: the engine's update preview (engine.validate, ValidateDataResponse) documents that it does not run readonlyWhen, and getRecordFieldAccess excludes conditional read-only and the approval lock. No write-free readonlyWhen judgement is exported.
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/mcpcreate_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.
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.
In this fleet p0 marks main or merge-queue red and the release window's blockers (「阻塞卡升 p0」). These six cards are MCP approval and upload capability work, not 18.4.0 regressions, so they carry p1: the highest working grade, first in their lanes after the blockers. That keeps the intent of the 07:27Z regrade (「…这些也都开始处理.这样我们审批相关的MCP就非常好用了.」) without holding the cut.
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 (#32686pm:queue, #32747pm:blocked). The thread merges origin/main once #32932 lands if it lands first
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
{
"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"
]
}
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).
Activity
objectstack-fleet commentedon Nov 12, 2026
domain:server#4 · os-sales · session_01L6bhgWRcTEB3toGxnWvuvX
Unblocked · 2026-11-12T18:31Z:
Blocked-by: #32734closed by PR #32779 (merged 9af0766). Back topm:queue. Samearea:filesdoor as #32754 (claimed bydomain:server#4): serial behind it, then #32783.Generated by Claude Code
os-bob commentedon Nov 13, 2026
Re-grade on the maintainer's instruction:
priority:p1→priority:p0. State unchanged (pm:queue, unassigned). Written by a test session, not a seat.area:filesdoor as Attachments: a member cannot attach a file to their own record (create_upload_link attachments:true answers 403 "cannot create sys_attachment"), though they can edit the record #32754 (p0, dispatched todomain:server#4), so it still follows Attachments: a member cannot attach a file to their own record (create_upload_link attachments:true answers 403 "cannot create sys_attachment"), though they can edit the record #32754 there. [Decision] How should an MCP agent create a record whose required file field must be filled (e.g. an expense line with a required e-invoice)? #32686 now also touches the upload-link door at p0, and the lane orders the two.Generated by Claude Code
objectstack-fleet commentedon Nov 13, 2026
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.
mainor merge-queue red and the release window's blockers (「阻塞卡升 p0」). These six cards are MCP approval and upload capability work, not 18.4.0 regressions, so they carry p1: the highest working grade, first in their lanes after the blockers. That keeps the intent of the 07:27Z regrade (「…这些也都开始处理.这样我们审批相关的MCP就非常好用了.」) without holding the cut.Generated by Claude Code
objectstack-fleet commentedon Nov 13, 2026
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:03ZSession:
session_016WV4cwqTK71kjQzHae8T5JAccount:
os-elon-muskBranch: the card thread's designated
claude/project-thread-*branch, written in its whole re-posted claim before the first pushWorktree: the card thread's own checkout
Domain:
domain:serverSeat:
domain:server#8File surface:
packages/objectql/src/**(one write-free "is this field writable on this record now" judgement that runs the engine's ownreadonlyWhen, and the update preview's documented limit if it moves),packages/mcp/src/file-content.tsand thecreate_upload_linktool 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 unlessdispatch-gates.mjs --tierderives more),effort: highClause-②: yes (narrowing)
Metadata-protocol: none
Declaration note:
create_upload_linkgains a refusal at issue (a field whosereadonlyWhenholds now is refused with the wordsupdate_recordgives, 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 soResponsibility:
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:4390still documents that INSERT does not runreadonlyWhen, andcreate_upload_linkinpackages/mcp/src/file-content.tsjudges no conditional lock; #32734, theBlocked-by:, is closed)Serial constraints cleared: seat 4's serial note 6832415816 was on the
area:filesdoor of #32754; its PR #32932 touchesservice-storage,plugin-securityandspeconly, none ofpackages/objectqlorpackages/mcp; no in-flight claim namescreate_upload_link(#32686pm:queue, #32747pm:blocked). The thread merges origin/main once #32932 lands if it lands firstobjectstack-fleet commentedon Nov 13, 2026
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 branchSession:
session_016WV4czfTdXkf83P5ogS9TTAccount:
os-elon-muskBranch:
claude/project-thread-4h9gy8Worktree: the card thread's own checkout
Domain:
domain:serverSeat:
domain:server#8File surface:
packages/objectql/src/**(one write-free "is this field writable on this record now" judgement,ObjectQL#judgeFieldWriteLock, built on the update's ownreadonlyWhenstrip; the update preview's documented limit does not move),packages/services/service-storage/src/record-file-access.tsand its integration test (ADDED by this re-post, measured: the issue-time refusals ofcreate_upload_linklive increateUploadLinkAsthere, where #32734 put the staticreadonlyand approval-lock refusals;packages/mcp/src/file-content.tsonly declares the bridge types and holds no engine),packages/mcp/src/mcp-http-tools.ts(thecreate_upload_linktool's description sentence only;file-content.tsis 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 unlessdispatch-gates.mjs --tierderives more),effort: highClause-②: yes (narrowing)
Metadata-protocol: none
Declaration note:
create_upload_linkgains a refusal at issue (a field whosereadonlyWhenholds now is refused403 FIELD_NOT_ACCESSIBLEin 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 publishedreadonlyWhenlimit stays as written, so no published preview surface widensResponsibility:
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 doorcreateUploadLinkAsjudges staticreadonlyand the approval lock, and no conditional lock;engine-validate.tsstill namesreadonlyWhenas 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-storagefiles it touches:attachment-access-hooks.ts,attachment-files-opt-in.ts,attachment-member-grant.ts,storage-service-plugin.tsand tests); the thread merges origin/main once more if it lands firstobjectstack-fleet commentedon Nov 13, 2026
triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH
Path: none
Triage: first-touch audit (pre-labeled card) ·
p0confirmed · 2026-11-13T08:23Z⛔ Not a claim; the claim (if any) is unchanged.
Generated by Claude Code
objectstack-fleet commentedon Nov 13, 2026
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
objectstack-fleet commentedon Nov 13, 2026
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_linkwill refuse at issue a file field whosereadonlyWhenholds.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).