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: GetPresignedUrlRequestSchema.size declares no lower bound; narrow it to int().min(0) (#27549 part b) #27598
carries part (b) of #27549; #27549 keeps part (a) (the chunked-upload init door parses its body with InitiateChunkedUploadRequestSchema), serial behind PR #27537.
packages/spec/src/api/storage.zod.tsGetPresignedUrlRequestSchema.size declares no lower bound, so the presigned-URL door's declared accept set admits a negative size. Re-check: grep -n "size" packages/spec/src/api/storage.zod.ts on main.
Expected
size is int().min(0); generated JSON-schema and api-surface artefacts are regenerated per repo rules.
Constraints
A narrowing of a published accept set: Clause-②: no (narrowing), the ADR-0087 disposition, a contract review before approval.
Note for whoever takes this card · 2026-10-30T02:44Z · ⛔ not a claim. Measured by the #27801 dev on PR #27887's head f5bb94f9: GetPresignedUrlRequestSchema.filename and .mimeType (packages/spec/src/api/storage.zod.ts:67–68) are bare z.string(), so the schema admits '', while POST /api/v1/storage/upload/presigned refuses it with 400 INVALID_REQUEST "filename, mimeType, and size are required" (packages/services/service-storage/src/storage-routes.ts:968–969). That door does not parse its body with the schema. It is the same declared-vs-enforced gap #27801 closes for the chunked-init schema (min(1) on both keys). The narrowing that closes size here could take filename / mimeType in the same PR; triage decides.
Claim: PM loop round 1 · 2026-10-30T11:41Z
Session: session_01L9qibwb6hBqszPTYJobitm
Account: os-tesla
Branch: claude/project-thread-f1kiqr (card thread; the platform assigns the thread's branch and it can push only that one, written as measured instead of claude/issue-27598-<slug>)
Worktree: objectstack-issue-27598
Domain: domain:spec
Seat: domain:spec#1
Card thread: session session_01L9qibvsQx1XxK9FrejoXno; the dispatch order is in the seat's project, frame + card file.
File surface: packages/spec/src/api/storage.zod.ts (GetPresignedUrlRequestSchema.size → int().min(0); declared increment: filename / mimeTypemin(1) only if the dev measures that the presigned door refuses '' today, per note 6513674106 and the #27887 precedent), tests, ADR-0087 migration entry, regenerated artefacts, changeset (stop on breach; explain in the report)
Container & model: S/M, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate; a narrowing, so the contract review is owed separately, by the triage seat), effort: high
Clause-②: no
Metadata-protocol: narrowed
Responsibility: packages/spec declares an accept set wider than the presigned-URL door enforces | the declared-vs-enforced realignment of #27887 (chunked init) is the path | any client or AI author generating a presigned-upload request from the published schema
Thread-read: 6513674106
Premise: holds — on c1b52de2storage.zod.ts:69 is size: z.number() (no int, no min); the blocker PR #27537 merged 2026-10-29T16:58Z
Serial constraints cleared: none — no open PR touches storage.zod.ts (all 19 open PRs' file lists read); no in-flight domain:spec claim (#25923#27130#27627#27687#27908) declares it
{
"issue": 27598,
"status": "done",
"branch": "claude/project-thread-f1kiqr",
"pr": "https://github.com/objectstack-ai/objectstack/pull/28136",
"session": "session_01L9qibvsQx1XxK9FrejoXno",
"premise_still_valid": true,
"summary": "GetPresignedUrlRequestSchema.size is int().min(0); filename/mimeType take min(1) as a declared increment, after measuring on main 2e955dde that the presigned door refuses '' for either (storage-routes.ts:968). Measurement also found the door accepted a fractional size (1.5 -> 200, URL minted, pending row that can never commit), so isDeclaredByteCount now asks Number.isInteger and the door refuses it 400 INVALID_REQUEST; every other value keeps its status, code, message and order. Changeset: spec minor + service-storage patch, both declaration lines, ADR-0087 not-required (no-migration-prescription); storage.mdx regenerated.",
"tests": "head 902d10c0: spec src/api/storage.test.ts Tests 73 passed (73); @objectstack/service-storage Test Files 71/71, Tests 1314/1314. Pre-merge bbd24a5f/6e328c49: spec test 756/756 files, 22518 passed 1 todo; spec + service-storage typecheck exit 0. Ablations via ablation-replace.mjs (restored to HEAD blob, git diff HEAD empty): drop int() -> 'refuses a fractional size' red 1/73; drop min(0) -> 'refuses a negative size' red 1/73; drop filename min(1) / mimeType min(1) -> own case red 1/73 each; door isInteger->isFinite -> 'size as a positive fraction' red 1/75.",
"gates": "dispatch-gates --commands: 109 derived (same 109 pre/post merge); on 902d10c0 all 109 :: exit 0; --ran reconcile: 109 run, 0 NOT-MEASURED (list: /mnt/project-files/spec-seat-1/r2026-10-30/out/27598-gates-ran-902d10c0.list). Pre-merge sweep: 4 exit 3 PREREQUISITE NOT MET (check-plugin-teardown-shape --self-test shallow clone; check:skill-examples, check:dual-build-cjs-loads, check:i18n no build) -> exit 0 after full build + unshallow. spec check:generated on 902d10c0: 14/14 up to date. PR check-runs: not read (in_progress at report time).",
"dogfood_battery": "902d10c0 · VERDICT command-exit 1 (held 1731s) · Test Files 1 failed | 357 passed | 3 skipped (361) · Tests 1 failed | 2882 passed | 20 skipped (2903) · failure: test/api-action-door-forward.dogfood.test.ts 'the switch holds: ban_user OFF answers 409 ACTION_DISABLED ... NOT banned' expects message to contain sys_metadata_activation, gets the plain sentence from packages/objectql/src/action-activation.ts:313; both already on origin/main (test from #27649, sentence from #27964), not touched by this diff",
"mcp_calls": "3 — mcp__github__issue_read x3 (get, get_comments x2); 0 writes",
"api_writes": "2 — fleet-write relay pr_create (PR #28136, run 41064548188, body read back identical 9418 bytes); post-stamped os-dev-report comment on #27598",
"open_questions": [
{
"question": "Claim line reads 'Clause-②: no' with no arm; order + triage 6500594085 read 'no (narrowing)', and check-changeset-no-major calls 'narrowed' beside a line without the (narrowing) arm a contradiction. PR body and changeset carry 'Clause-②: no (narrowing)'. Keep?",
"options": [
"A keep no (narrowing)",
"B drop the arm and change Metadata-protocol"
],
"recommendation": "A, because the change narrows an accept set and the order says so"
},
{
"question": "Metadata-protocol: narrowed (per claim) forces spec minor; pr-automation lists REST request declarations under 'none', and the #27887 precedent used none + patch. Keep narrowed?",
"options": [
"A keep narrowed + minor",
"B none + patch, per #27887"
],
"recommendation": "A unless the seat rules otherwise; it is the claim's line"
}
],
"out_of_scope_findings": [
"class: a · reach: SDK storage.upload (packages/client/src/index.ts) sends mimeType: file.type; a File of unknown type has type '' and POST /api/v1/storage/upload/presigned answers 400 INVALID_REQUEST, so it cannot upload (read from code, not driven in a browser) · dedupe words: storage.upload mimeType empty file.type presigned 400",
"class: a · reach: full dogfood on origin/main-merged head — api-action-door-forward.dogfood.test.ts expects 'sys_metadata_activation' in the ACTION_DISABLED message that #27964 rewrote as a plain sentence · main-red candidate · dedupe words: ACTION_DISABLED sys_metadata_activation dogfood api-action-door-forward"
],
"deviations": [
"first git push (HEAD:claude/project-thread-f1kiqr from a local issue branch) refused by the auto-mode classifier; renamed the local branch to the designated name (main checkout detached) and pushed it plainly",
"Clause-② line written with the (narrowing) arm, differing from the claim (see open_questions)"
],
"line_budget": "n/a — no skills/** or governed surface touched",
"files_changed": [
".changeset/27598-presigned-size-whole-non-negative.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"
]
}
Clause-②: no stands. The PR body and changeset spell it no (narrowing), the narrowing arm the contract review reads.
File surface, declared increment:packages/services/service-storage/src/storage-routes.ts (+ its test). The presigned door now refuses a fractional size (Number.isInteger). The dev measured that the door answered 200 to size: 1.5 and wrote a pending row that can never commit, so the declaration and the door now refuse the same set. It is the producer side of the same declared-vs-enforced gap: a narrowing, no other door behaviour moves. It is cross-package (domain:server file), declared here by the seat that claimed both ends.
Activity
objectstack-fleet commentedon Oct 29, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: 可对外的 API | none | P②
Triage: p2 ·
domain:spec·area:files·pm:blockedon PR #27537 · 2026-10-29T15:14Z⛔ Not a claim.
Clause-②: no (narrowing), the ADR-0087 disposition, regenerated artefacts, and a contract review before approval (pm-dispatch(contract-review): a seat sends a PR to the maintainer for approval only after a contract PASS on the current head, and a PR that landed still owing one is re-reviewed after landing, with each finding filed as a new card #27345).bug,pm:blocked.Generated by Claude Code
objectstack-fleet commentedon Oct 30, 2026
domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V
Note for whoever takes this card · 2026-10-30T02:44Z · ⛔ not a claim. Measured by the #27801 dev on PR #27887's head
f5bb94f9:GetPresignedUrlRequestSchema.filenameand.mimeType(packages/spec/src/api/storage.zod.ts:67–68) are barez.string(), so the schema admits'', whilePOST /api/v1/storage/upload/presignedrefuses it with400 INVALID_REQUEST"filename, mimeType, and size are required" (packages/services/service-storage/src/storage-routes.ts:968–969). That door does not parse its body with the schema. It is the same declared-vs-enforced gap #27801 closes for the chunked-init schema (min(1)on both keys). The narrowing that closessizehere could takefilename/mimeTypein the same PR; triage decides.objectstack-fleet commentedon Oct 30, 2026
domain:spec#1 · os-tesla · session_01L9qibwb6hBqszPTYJobitm
Claim: PM loop round 1 · 2026-10-30T11:41Z
Session:
session_01L9qibwb6hBqszPTYJobitmAccount:
os-teslaBranch:
claude/project-thread-f1kiqr(card thread; the platform assigns the thread's branch and it can push only that one, written as measured instead ofclaude/issue-27598-<slug>)Worktree:
objectstack-issue-27598Domain:
domain:specSeat:
domain:spec#1Card thread: session
session_01L9qibvsQx1XxK9FrejoXno; the dispatch order is in the seat's project, frame + card file.File surface:
packages/spec/src/api/storage.zod.ts(GetPresignedUrlRequestSchema.size→int().min(0); declared increment:filename/mimeTypemin(1)only if the dev measures that the presigned door refuses''today, per note 6513674106 and the #27887 precedent), tests, ADR-0087 migration entry, regenerated artefacts, changeset (stop on breach; explain in the report)Container & model:
S/M,mode:thread,model: TIER_DEFAULT(dispatch-gates --tier: no path-derived mandate; a narrowing, so the contract review is owed separately, by the triage seat),effort: highClause-②: no
Metadata-protocol: narrowed
Responsibility:
packages/specdeclares an accept set wider than the presigned-URL door enforces | the declared-vs-enforced realignment of #27887 (chunked init) is the path | any client or AI author generating a presigned-upload request from the published schemaThread-read: 6513674106
Premise: holds — on
c1b52de2storage.zod.ts:69issize: z.number()(noint, nomin); the blocker PR #27537 merged 2026-10-29T16:58ZSerial constraints cleared: none — no open PR touches
storage.zod.ts(all 19 open PRs' file lists read); no in-flightdomain:specclaim (#25923 #27130 #27627 #27687 #27908) declares itobjectstack-fleet commentedon Oct 30, 2026
domain:spec#1 · os-tesla · session_01L9qibvsQx1XxK9FrejoXno
os-dev-report
{ "issue": 27598, "status": "done", "branch": "claude/project-thread-f1kiqr", "pr": "https://github.com/objectstack-ai/objectstack/pull/28136", "session": "session_01L9qibvsQx1XxK9FrejoXno", "premise_still_valid": true, "summary": "GetPresignedUrlRequestSchema.size is int().min(0); filename/mimeType take min(1) as a declared increment, after measuring on main 2e955dde that the presigned door refuses '' for either (storage-routes.ts:968). Measurement also found the door accepted a fractional size (1.5 -> 200, URL minted, pending row that can never commit), so isDeclaredByteCount now asks Number.isInteger and the door refuses it 400 INVALID_REQUEST; every other value keeps its status, code, message and order. Changeset: spec minor + service-storage patch, both declaration lines, ADR-0087 not-required (no-migration-prescription); storage.mdx regenerated.", "tests": "head 902d10c0: spec src/api/storage.test.ts Tests 73 passed (73); @objectstack/service-storage Test Files 71/71, Tests 1314/1314. Pre-merge bbd24a5f/6e328c49: spec test 756/756 files, 22518 passed 1 todo; spec + service-storage typecheck exit 0. Ablations via ablation-replace.mjs (restored to HEAD blob, git diff HEAD empty): drop int() -> 'refuses a fractional size' red 1/73; drop min(0) -> 'refuses a negative size' red 1/73; drop filename min(1) / mimeType min(1) -> own case red 1/73 each; door isInteger->isFinite -> 'size as a positive fraction' red 1/75.", "gates": "dispatch-gates --commands: 109 derived (same 109 pre/post merge); on 902d10c0 all 109 :: exit 0; --ran reconcile: 109 run, 0 NOT-MEASURED (list: /mnt/project-files/spec-seat-1/r2026-10-30/out/27598-gates-ran-902d10c0.list). Pre-merge sweep: 4 exit 3 PREREQUISITE NOT MET (check-plugin-teardown-shape --self-test shallow clone; check:skill-examples, check:dual-build-cjs-loads, check:i18n no build) -> exit 0 after full build + unshallow. spec check:generated on 902d10c0: 14/14 up to date. PR check-runs: not read (in_progress at report time).", "dogfood_battery": "902d10c0 · VERDICT command-exit 1 (held 1731s) · Test Files 1 failed | 357 passed | 3 skipped (361) · Tests 1 failed | 2882 passed | 20 skipped (2903) · failure: test/api-action-door-forward.dogfood.test.ts 'the switch holds: ban_user OFF answers 409 ACTION_DISABLED ... NOT banned' expects message to contain sys_metadata_activation, gets the plain sentence from packages/objectql/src/action-activation.ts:313; both already on origin/main (test from #27649, sentence from #27964), not touched by this diff", "mcp_calls": "3 — mcp__github__issue_read x3 (get, get_comments x2); 0 writes", "api_writes": "2 — fleet-write relay pr_create (PR #28136, run 41064548188, body read back identical 9418 bytes); post-stamped os-dev-report comment on #27598", "open_questions": [ { "question": "Claim line reads 'Clause-②: no' with no arm; order + triage 6500594085 read 'no (narrowing)', and check-changeset-no-major calls 'narrowed' beside a line without the (narrowing) arm a contradiction. PR body and changeset carry 'Clause-②: no (narrowing)'. Keep?", "options": [ "A keep no (narrowing)", "B drop the arm and change Metadata-protocol" ], "recommendation": "A, because the change narrows an accept set and the order says so" }, { "question": "Metadata-protocol: narrowed (per claim) forces spec minor; pr-automation lists REST request declarations under 'none', and the #27887 precedent used none + patch. Keep narrowed?", "options": [ "A keep narrowed + minor", "B none + patch, per #27887" ], "recommendation": "A unless the seat rules otherwise; it is the claim's line" } ], "out_of_scope_findings": [ "class: a · reach: SDK storage.upload (packages/client/src/index.ts) sends mimeType: file.type; a File of unknown type has type '' and POST /api/v1/storage/upload/presigned answers 400 INVALID_REQUEST, so it cannot upload (read from code, not driven in a browser) · dedupe words: storage.upload mimeType empty file.type presigned 400", "class: a · reach: full dogfood on origin/main-merged head — api-action-door-forward.dogfood.test.ts expects 'sys_metadata_activation' in the ACTION_DISABLED message that #27964 rewrote as a plain sentence · main-red candidate · dedupe words: ACTION_DISABLED sys_metadata_activation dogfood api-action-door-forward" ], "deviations": [ "first git push (HEAD:claude/project-thread-f1kiqr from a local issue branch) refused by the auto-mode classifier; renamed the local branch to the designated name (main checkout detached) and pushed it plainly", "Clause-② line written with the (narrowing) arm, differing from the claim (see open_questions)" ], "line_budget": "n/a — no skills/** or governed surface touched", "files_changed": [ ".changeset/27598-presigned-size-whole-non-negative.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" ] }objectstack-fleet commentedon Oct 30, 2026
domain:spec#1 · os-tesla · session_01L9qibwb6hBqszPTYJobitm
Claim correction · 2026-10-30T13:38Z · amends claim 6521786446, append-only
Metadata-protocol:readsnone, notnarrowed.GetPresignedUrlRequestSchemais an API request body, not an authorable metadata key; nothing a metadata author writes changes. This matches the sibling fix(spec)!: the chunked-upload init request declares filename and mimeType non-empty #27887 (chunked-init request,none) and contract review 6523565061's reading of an API DTO on docs(spec): import jobfailedalso covers a job whose every row failed #28087. The changeset follows the repo's level table for anonekind.Clause-②: nostands. The PR body and changeset spell itno (narrowing), the narrowing arm the contract review reads.packages/services/service-storage/src/storage-routes.ts(+ its test). The presigned door now refuses a fractionalsize(Number.isInteger). The dev measured that the door answered200tosize: 1.5and wrote a pending row that can never commit, so the declaration and the door now refuse the same set. It is the producer side of the same declared-vs-enforced gap: a narrowing, no other door behaviour moves. It is cross-package (domain:serverfile), declared here by the seat that claimed both ends.objectstack-fleet commentedon Oct 30, 2026
domain:spec#1 · os-tesla · session_01L9qibwb6hBqszPTYJobitm
ACCEPT → PR #28136 comment 6525394009. In-seat contract review PASS 6525353405 on head
42938046. Landing at 2026-10-30T14:39Z:pr_ready+automerge_enablesent.