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
storage: the chunked-upload init door refuses an empty filename / mimeType that InitiateChunkedUploadRequestSchema declares acceptable (z.string(), no min(1)) #27801
Filing gate: ① declared and enforced disagree on a published request schema, found by the contract review of PR #27781 (#27549 part a), record 6510724527 (boundary note). Filed by domain:server seat 4 · os-elon-musk · session session_016WV4d1Np3hU7RQnA13YZcL. ⛔ Not a claim. No grade: triage sets the lane and grade.
Business reason. After PR #27781 the chunked-upload init door parses its body with InitiateChunkedUploadRequestSchema, so "declared is enforced" holds for every key except one pre-existing check: the door still refuses an empty filename or mimeType by truthiness, while the schema declares both as bare z.string(), which accepts ''. An author or an AI reading the published schema is told an empty string is valid; the door refuses it.
Where
Door: packages/services/service-storage/src/storage-routes.ts, the POST /api/v1/storage/upload/chunked handler — the presence check !filename || !mimeType that runs beside the schema parse.
One rule, in one direction. Either the schema declares min(1) for both keys (a spec-lane narrowing of the published request schema; the door's check then becomes the schema's own refusal), or the door stops refusing what the schema accepts. The first matches the door's behaviour since before #27549 and the presigned door's handling; triage decides.
Reach
Any signed-in caller of the init door. No in-repo caller sends an empty filename or mimeType (contract review 6510724527 read every caller).
Dedupe
Read the open domain:server and domain:spec titles for chunked, filename, mimeType, InitiateChunkedUpload: no match other than #27549 (its part (b), GetPresignedUrlRequestSchema.size, was split to domain:spec separately). New.
Read fresh. Graded as the schema narrowing:InitiateChunkedUploadRequestSchema.filename and .mimeType declare min(1), so the declaration says what the door has always refused. The door's truthiness check then becomes the schema's own refusal. Contract first; no behaviour change at the door.
It owes Clause-②: no (narrowing), the ADR-0087 disposition, regenerated artefacts and a contract review.
Claim: PM loop round 3 · 2026-10-30T01:07Z
Session: session_017ihL2fi9zfJhUTubyJYb6V
Account: marchtian
Branch: claude/issue-27801-chunked-init-filename-min1
Worktree: objectstack-issue-27801
Domain: domain:spec
Seat: domain:spec#4
Ruling-ref: triage 6511379936 ("Graded as the schema narrowing:InitiateChunkedUploadRequestSchema.filename and .mimeType declare min(1) … Contract first; no behaviour change at the door." "It owes Clause-②: no (narrowing), the ADR-0087 disposition, regenerated artefacts and a contract review.")
File surface: packages/spec/src/api/storage.zod.ts (InitiateChunkedUploadRequestSchema.filename / .mimeType, L197–L198 on 05961150), its spec test, regenerated artefacts (packages/spec/api-surface/**, content/docs/references/api/storage.mdx, JSON schema), packages/services/service-storage/src/storage-routes.ts only where the door's own truthiness check (L1118) meets the schema's refusal, with its test; a @objectstack/spec changeset; ⛔ no change to the door's status or code (stop on breach; explain in the report)
Container & model: S, mode:subagent, model: TIER_DEFAULT (opus) — the quota-exhaustion exemption (claude-fable-5-1 answered HTTP 429; maintainer 「你没有fable了,使用 opus开发完之后等契约复审」), effort: high
Clause-②: no (narrowing)
Metadata-protocol: none
Responsibility: the published request schema accepts an empty filename / mimeType that the chunked-init door refuses | the schema the door already parses since PR #27781 is the path to narrow | any caller or AI reading InitiateChunkedUploadRequestSchema; reached through POST /api/v1/storage/upload/chunked
Thread-read: 6511379936
Premise: holds — on 05961150 both keys are bare z.string() (storage.zod.ts:197–198) and the door refuses !body.filename || !body.mimeType before its schema parse (storage-routes.ts:1118, parse at :1130)
Serial constraints cleared: none (no open PR touches storage.zod.ts or storage-routes.ts; open PR titles and #27826's file list read just before this claim)
{
"issue": 27801,
"status": "done",
"branch": "claude/issue-27801-chunked-init-filename-min1",
"pr": "https://github.com/objectstack-ai/objectstack/pull/27887",
"head": "f5bb94f94e92b0929e3c415f692e4e50cbff8308",
"session": "session_017ihL2fi9zfJhUTubyJYb6V",
"premise_still_valid": true,
"summary": "InitiateChunkedUploadRequestSchema.filename and .mimeType declare min(1), with descriptions reading non-empty. The JSON Schema carries minLength 1 and content/docs/references/api/storage.mdx is regenerated. The door's truthiness check is KEPT unchanged: with min(1) it refuses a strict subset of what the schema refuses (missing, '', null, 0, false), and it runs before the scope gate. Folding it into the parse would reorder an empty filename with an off-vocabulary scope against the scope gate, and would change the message. Status, code, message and ordering stay byte-identical, and a comment at the door records why. Changeset @objectstack/spec patch, fix(spec)!, Clause-② no (narrowing), Metadata-protocol none, adr-0087 not-required (no-migration-prescription), following the 26817 and 27683 precedent. Independent review: none run (quota); the PR waits for the seat's contract-review hand-off.",
"tests": "On f5bb94f94e. spec: vitest src/api/storage.test.ts gave Test Files 1 passed, Tests 65 passed. New: refuses an empty filename / mimeType (success false, one issue, path [key], code too_small) and CONTROL one-character values parse. service-storage: pnpm test gave Test Files 71 passed (71), Tests 1311 passed (1311), and pnpm typecheck exited 0 (test-typecheck OK). New door case: REFUSED 400 INVALID_REQUEST for an empty filename and an empty mimeType, with the schema refusing the same body and neither createFile nor createSession called. Ablation via scripts/ablation-replace.mjs (anchor hit 1, restored to HEAD blob e4b1a7313842, git diff HEAD empty): dropping min(1) on filename failed exactly the empty-filename case (1 failed / 64 passed), and the same held for mimeType. The door is not ablated because its behaviour did not change.",
"gates": "dispatch-gates --commands on f5bb94f94e derived 109 commands. All 109 were run with exit codes captured before any pipe: 106 exited 0, and check:skill-examples, check:dual-build-cjs-loads and check:i18n exited 3 (unbuilt dist) and then 0 after a workspace build. --ran reconciliation with exit codes: 109 derived, 109 run, 0 NOT-MEASURED, 0 UNRUN (a DERIVED zero). check-adr-0087-registration --base origin/main exited 0: [BREAKING+bang+clause-②-narrowing] not-required (no-migration-prescription). spec check:generated --fix regenerated content/docs/references/** only, and all 14 were up to date after the merge with origin/main 755e28500. CI on PR 27887: in_progress at report time (23 check-runs read, none concluded failure).",
"dogfood_battery": "f5bb94f94e · VERDICT command-exit 1 · Test Files 3 failed / 352 passed / 3 skipped (358) · Tests 4 failed / 2864 passed / 20 skipped (2888). All 4 also fail when run alone and are main-red, not this diff. error-sentences-live.dogfood.test.ts (POST /data/OBJECT and /createMany expect no code on a hook refusal) and object-hook-lifecycle-scratch.dogfood.test.ts (acceptance[6]) conflict with 21c4bdd804, which answers HOOK_ABORTED. platform-app-object-entry-views.test.ts names sys_exchange_rate undeclared, after 194e66c028.",
"line_budget": "78 changed lines (+74 / -4) across 6 files, under the 3000 threshold",
"files_changed": [
".changeset/27801-chunked-init-filename-min1.md",
"content/docs/references/api/storage.mdx",
"packages/services/service-storage/src/storage-routes.test.ts",
"packages/services/service-storage/src/storage-routes.ts",
"packages/spec/src/api/storage.test.ts",
"packages/spec/src/api/storage.zod.ts"
],
"deviations": [
"No independent (Fable) review run or substituted, per the order's exception: the PR waits for the seat's contract-review hand-off.",
"test:repo (vitest repo project) not run locally; it belongs to CI Test Core.",
"A first full-build attempt included @objectstack/docs. It was stopped by recorded PIDs within about 1 minute, before it wrote any tracked file (git status clean), and re-run with --filter=!@objectstack/docs.",
"The merge commit was amended before its first push to carry the model-free trailer pair.",
"post-stamped.mjs refuses a comment whose first non-empty line is not a signature, so the seat signature line comes first and the os-dev-report marker is the first line after it."
],
"mcp_calls": "0",
"api_writes": "2: relay pr_create (POST /repos/objectstack-ai/objectstack/dispatches, which ran POST pulls and opened PR 27887 as a draft, body read back identical at 8612 bytes, no assignees, no labels) and this os-dev-report comment (POST /repos/objectstack-ai/objectstack/issues/27801/comments via post-stamped.mjs). git push is not a REST write.",
"open_questions": [],
"out_of_scope_findings": [
"class: b · reach: POST /api/v1/storage/upload/presigned with filename '' or mimeType '' answers 400 INVALID_REQUEST 'filename, mimeType, and size are required', while GetPresignedUrlRequestSchema.safeParse of the same body succeeds (probe on f5bb94f94e) · evidence: storage.zod.ts:67-68 are bare z.string(); storage-routes.ts:968-969 is the truthiness check; the presigned door never parses its body with the schema · Seam: spec:GetPresignedUrlRequestSchema.filename/.mimeType -> runtime:storage-routes.ts POST /upload/presigned · carrier: the spec-lane card split from #27549 part (b) (GetPresignedUrlRequestSchema.size), same family, merge there · dedupe: presigned, GetPresignedUrlRequestSchema, filename min(1), mimeType empty, upload/presigned",
"class: a · reach: main push battery Dogfood Regression Gate (does not run on PR or merge queue); 4 tests red deterministically on f5bb94f94e (merged with origin/main 755e28500) · evidence: error-sentences-live.dogfood.test.ts (2) and object-hook-lifecycle-scratch.dogfood.test.ts (1) assert no code on an undeclared hook abort at the /data door, contradicted by 21c4bdd804 (HOOK_ABORTED); platform-app-object-entry-views.test.ts (1) reports sys_exchange_rate as named but undeclared, after 194e66c028 · carrier: none (seat to route under the main-red convention) · dedupe: HOOK_ABORTED dogfood, error-sentences-live, sys_exchange_rate entry views, object-hook-lifecycle-scratch",
"carrier: none · noted, not filed: a whitespace-only filename / mimeType is admitted by both InitiateChunkedUploadRequestSchema and the init door; they agree, and the order did not ask for it"
]
}
ACCEPT → PR #27887 comment 6513663903 (lane part) + Contract review PASS 6513966766 (CONTRACT_REVIEW_TIER, triage, head f5bb94f9, no must-fix, no should-fix) · 2026-10-30T03:08Z · readied and auto-merge armed by the seat (every check green; check-expected-skips OK, 13 skips in the roster); needs:contract-review removed. The presigned schema's same gap is noted on #27598.
Activity
objectstack-fleet commentedon Oct 29, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: 可对外的 API | none | P②
Triage: p2 ·
domain:spec·area:files· 2026-10-29T23:56Z⛔ Not a claim.
InitiateChunkedUploadRequestSchema.filenameand.mimeTypedeclaremin(1), so the declaration says what the door has always refused. The door's truthiness check then becomes the schema's own refusal. Contract first; no behaviour change at the door.Clause-②: no (narrowing), the ADR-0087 disposition, regenerated artefacts and a contract review.bug,pm:queue.Generated by Claude Code
objectstack-fleet commentedon Oct 30, 2026
domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V
Claim: PM loop round 3 · 2026-10-30T01:07Z
Session:
session_017ihL2fi9zfJhUTubyJYb6VAccount:
marchtianBranch:
claude/issue-27801-chunked-init-filename-min1Worktree:
objectstack-issue-27801Domain:
domain:specSeat:
domain:spec#4Ruling-ref: triage 6511379936 ("Graded as the schema narrowing:
InitiateChunkedUploadRequestSchema.filenameand.mimeTypedeclaremin(1)… Contract first; no behaviour change at the door." "It owesClause-②: no (narrowing), the ADR-0087 disposition, regenerated artefacts and a contract review.")File surface:
packages/spec/src/api/storage.zod.ts(InitiateChunkedUploadRequestSchema.filename/.mimeType, L197–L198 on05961150), its spec test, regenerated artefacts (packages/spec/api-surface/**,content/docs/references/api/storage.mdx, JSON schema),packages/services/service-storage/src/storage-routes.tsonly where the door's own truthiness check (L1118) meets the schema's refusal, with its test; a@objectstack/specchangeset; ⛔ no change to the door's status or code (stop on breach; explain in the report)Container & model:
S,mode:subagent,model: TIER_DEFAULT(opus) — the quota-exhaustion exemption (claude-fable-5-1answered HTTP 429; maintainer 「你没有fable了,使用 opus开发完之后等契约复审」),effort: highClause-②: no (narrowing)
Metadata-protocol: none
Responsibility: the published request schema accepts an empty
filename/mimeTypethat the chunked-init door refuses | the schema the door already parses since PR #27781 is the path to narrow | any caller or AI readingInitiateChunkedUploadRequestSchema; reached throughPOST /api/v1/storage/upload/chunkedThread-read: 6511379936
Premise: holds — on
05961150both keys are barez.string()(storage.zod.ts:197–198) and the door refuses!body.filename || !body.mimeTypebefore its schema parse (storage-routes.ts:1118, parse at :1130)Serial constraints cleared: none (no open PR touches
storage.zod.tsorstorage-routes.ts; open PR titles and #27826's file list read just before this claim)objectstack-fleet commentedon Oct 30, 2026
domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V
os-dev-report
{ "issue": 27801, "status": "done", "branch": "claude/issue-27801-chunked-init-filename-min1", "pr": "https://github.com/objectstack-ai/objectstack/pull/27887", "head": "f5bb94f94e92b0929e3c415f692e4e50cbff8308", "session": "session_017ihL2fi9zfJhUTubyJYb6V", "premise_still_valid": true, "summary": "InitiateChunkedUploadRequestSchema.filename and .mimeType declare min(1), with descriptions reading non-empty. The JSON Schema carries minLength 1 and content/docs/references/api/storage.mdx is regenerated. The door's truthiness check is KEPT unchanged: with min(1) it refuses a strict subset of what the schema refuses (missing, '', null, 0, false), and it runs before the scope gate. Folding it into the parse would reorder an empty filename with an off-vocabulary scope against the scope gate, and would change the message. Status, code, message and ordering stay byte-identical, and a comment at the door records why. Changeset @objectstack/spec patch, fix(spec)!, Clause-② no (narrowing), Metadata-protocol none, adr-0087 not-required (no-migration-prescription), following the 26817 and 27683 precedent. Independent review: none run (quota); the PR waits for the seat's contract-review hand-off.", "tests": "On f5bb94f94e. spec: vitest src/api/storage.test.ts gave Test Files 1 passed, Tests 65 passed. New: refuses an empty filename / mimeType (success false, one issue, path [key], code too_small) and CONTROL one-character values parse. service-storage: pnpm test gave Test Files 71 passed (71), Tests 1311 passed (1311), and pnpm typecheck exited 0 (test-typecheck OK). New door case: REFUSED 400 INVALID_REQUEST for an empty filename and an empty mimeType, with the schema refusing the same body and neither createFile nor createSession called. Ablation via scripts/ablation-replace.mjs (anchor hit 1, restored to HEAD blob e4b1a7313842, git diff HEAD empty): dropping min(1) on filename failed exactly the empty-filename case (1 failed / 64 passed), and the same held for mimeType. The door is not ablated because its behaviour did not change.", "gates": "dispatch-gates --commands on f5bb94f94e derived 109 commands. All 109 were run with exit codes captured before any pipe: 106 exited 0, and check:skill-examples, check:dual-build-cjs-loads and check:i18n exited 3 (unbuilt dist) and then 0 after a workspace build. --ran reconciliation with exit codes: 109 derived, 109 run, 0 NOT-MEASURED, 0 UNRUN (a DERIVED zero). check-adr-0087-registration --base origin/main exited 0: [BREAKING+bang+clause-②-narrowing] not-required (no-migration-prescription). spec check:generated --fix regenerated content/docs/references/** only, and all 14 were up to date after the merge with origin/main 755e28500. CI on PR 27887: in_progress at report time (23 check-runs read, none concluded failure).", "dogfood_battery": "f5bb94f94e · VERDICT command-exit 1 · Test Files 3 failed / 352 passed / 3 skipped (358) · Tests 4 failed / 2864 passed / 20 skipped (2888). All 4 also fail when run alone and are main-red, not this diff. error-sentences-live.dogfood.test.ts (POST /data/OBJECT and /createMany expect no code on a hook refusal) and object-hook-lifecycle-scratch.dogfood.test.ts (acceptance[6]) conflict with 21c4bdd804, which answers HOOK_ABORTED. platform-app-object-entry-views.test.ts names sys_exchange_rate undeclared, after 194e66c028.", "line_budget": "78 changed lines (+74 / -4) across 6 files, under the 3000 threshold", "files_changed": [ ".changeset/27801-chunked-init-filename-min1.md", "content/docs/references/api/storage.mdx", "packages/services/service-storage/src/storage-routes.test.ts", "packages/services/service-storage/src/storage-routes.ts", "packages/spec/src/api/storage.test.ts", "packages/spec/src/api/storage.zod.ts" ], "deviations": [ "No independent (Fable) review run or substituted, per the order's exception: the PR waits for the seat's contract-review hand-off.", "test:repo (vitest repo project) not run locally; it belongs to CI Test Core.", "A first full-build attempt included @objectstack/docs. It was stopped by recorded PIDs within about 1 minute, before it wrote any tracked file (git status clean), and re-run with --filter=!@objectstack/docs.", "The merge commit was amended before its first push to carry the model-free trailer pair.", "post-stamped.mjs refuses a comment whose first non-empty line is not a signature, so the seat signature line comes first and the os-dev-report marker is the first line after it." ], "mcp_calls": "0", "api_writes": "2: relay pr_create (POST /repos/objectstack-ai/objectstack/dispatches, which ran POST pulls and opened PR 27887 as a draft, body read back identical at 8612 bytes, no assignees, no labels) and this os-dev-report comment (POST /repos/objectstack-ai/objectstack/issues/27801/comments via post-stamped.mjs). git push is not a REST write.", "open_questions": [], "out_of_scope_findings": [ "class: b · reach: POST /api/v1/storage/upload/presigned with filename '' or mimeType '' answers 400 INVALID_REQUEST 'filename, mimeType, and size are required', while GetPresignedUrlRequestSchema.safeParse of the same body succeeds (probe on f5bb94f94e) · evidence: storage.zod.ts:67-68 are bare z.string(); storage-routes.ts:968-969 is the truthiness check; the presigned door never parses its body with the schema · Seam: spec:GetPresignedUrlRequestSchema.filename/.mimeType -> runtime:storage-routes.ts POST /upload/presigned · carrier: the spec-lane card split from #27549 part (b) (GetPresignedUrlRequestSchema.size), same family, merge there · dedupe: presigned, GetPresignedUrlRequestSchema, filename min(1), mimeType empty, upload/presigned", "class: a · reach: main push battery Dogfood Regression Gate (does not run on PR or merge queue); 4 tests red deterministically on f5bb94f94e (merged with origin/main 755e28500) · evidence: error-sentences-live.dogfood.test.ts (2) and object-hook-lifecycle-scratch.dogfood.test.ts (1) assert no code on an undeclared hook abort at the /data door, contradicted by 21c4bdd804 (HOOK_ABORTED); platform-app-object-entry-views.test.ts (1) reports sys_exchange_rate as named but undeclared, after 194e66c028 · carrier: none (seat to route under the main-red convention) · dedupe: HOOK_ABORTED dogfood, error-sentences-live, sys_exchange_rate entry views, object-hook-lifecycle-scratch", "carrier: none · noted, not filed: a whitespace-only filename / mimeType is admitted by both InitiateChunkedUploadRequestSchema and the init door; they agree, and the order did not ask for it" ] }objectstack-fleet commentedon Oct 30, 2026
domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V
ACCEPT → PR #27887 comment 6513663903 (lane part) + Contract review PASS 6513966766 (
CONTRACT_REVIEW_TIER, triage, headf5bb94f9, no must-fix, no should-fix) · 2026-10-30T03:08Z · readied and auto-merge armed by the seat (every check green;check-expected-skipsOK, 13 skips in the roster);needs:contract-reviewremoved. The presigned schema's same gap is noted on #27598.