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
finding(fields): readFileValue throws URIError for a file URL whose last segment holds a bare % — nameFromUrl calls decodeURIComponent unguarded, on the render path of every file and image cell #10614
Filing-gate category: ① a product defect with a named site and a reproduction. Reader: triage first (route and grade), then the execution seat that claims it.
Filed by the domain:ui seat 5 (session_01KUxVUa7e39aNjhkKi1gsoy) from the out_of_scope_findings (class a) of the objectui#10493 dev report. The at-tier contract review of PR objectui#10575 confirmed the site at source. ⛔ Filed bare, not graded here.
The defect
nameFromUrl in packages/fields/src/widgets/file-value.ts takes a URL's last path segment as the display name and passes it to decodeURIComponent without a guard. A segment holding a bare % (not a valid escape) makes it throw URIError: URI malformed, and readFileValue throws with it.
Reproduction (the dev's, relayed; ⛔ not re-run by the seat)
Both throw at the objectui#10493 base f94cfa5 and at its head. Since PR objectui#10575, a data: URI returns before the decode, so data:text/plain,100% no longer throws.
Reach
@objectstack/spec's FileValueSchema declares url: z.string(), so such a value passes the contract. readFileValue runs during render in FileCellRenderer, ImageCellRenderer (through displayableImagesOf), FileField, FileCell and ImageField. ⛔ The render-time crash itself is NOT MEASURED: whether an error boundary contains it, and what the user sees, is the claimant's first measurement.
Dedupe
Semantic search of this repo, including closed issues:
Triage: lands in packages/fields/src/widgets/file-value.ts (nameFromUrl calls decodeURIComponent unguarded) ⇒ domain:ui; rationale: a contract-valid file value (FileValueSchema.url: z.string()) whose last path segment holds a bare % makes readFileValue throw URIError, and readFileValue runs during render in five file and image faces. A render-path throw on valid data ⇒ p2. How far it reaches (a contained cell, or a blank page) is the claimant's first measurement.
Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01CRZSc7dU8oDStbTbSwhuZe · 2026-09-25T13:38Z. ⛔ Not a claim, ⛔ not a dispatch. Read: this card and its full thread, and objectui origin/main.
Execution note: guard the decode in the ONE helper (fall back to the raw segment on URIError); ⛔ no per-caller try/catch. Pin both reported values, plus a valid escape as the control, and state what a cell showed before the fix.
Claim: PM loop round 6 — domain:ui execution seat 5
Session: session_01KUxVUa7e39aNjhkKi1gsoy
Branch: claude/issue-10614-file-name-bare-percent
Worktree: objectui-issue-10614
Domain: domain:ui
Seat: domain:ui#5
File surface: packages/fields/src/widgets/file-value.ts (nameFromUrl only), pins beside the existing file-value tests, and one .changeset/10614-…md (stop on breach; explain in the report).
Container & model: S, mode:subagent, model: opus (default judgement tier; no path-derived mandate for these objectui paths).
Clause-②: no
Thread-read: 5833345168
Serial constraints cleared: the open-PR file lists were re-read in this act at objectui origin/maineca2760. No open PR touches file-value.ts, and no live pm:dispatched claim names it.
Clause-②: no: a contract-valid file URL stops throwing during render. No schema, export or accept set moves.
Scope
The triage (5833345168): 「guard the decode in the ONE helper (fall back to the raw segment on URIError); ⛔ no per-caller try/catch. Pin both reported values, plus a valid escape as the control, and state what a cell showed before the fix.」 and 「How far it reaches (a contained cell, or a blank page) is the claimant's first measurement.」
Measure first: render a file cell and an image field holding a URL whose last segment has a bare %, and say what the screen showed at the base (a contained cell, an error boundary, or a blank page).
Fix: nameFromUrl falls back to the raw segment on URIError, in the one helper.
Pin: both values the card reports read the raw segment, and do not throw. Control: a valid escape (%20) still decodes.
os-dev-report
{
"issue": 10614,
"status": "done",
"branch": "claude/issue-10614-file-name-bare-percent",
"pr": "#10653",
"session": "session_01KUxVUa7e39aNjhkKi1gsoy (mode:subagent, so this is the parent PM session id, the Claude-Session trailer on every commit)",
"premise_still_valid": true,
"summary": "H1 confirmed at eca2760: nameFromUrl in packages/fields/src/widgets/file-value.ts returned decodeURIComponent(seg) with no guard. H3 applied: in nameFromUrl only, the decode sits in try/catch; on URIError the name is the raw segment, and any other error is rethrown. No caller changed and no caller has its own try/catch. A valid escape decodes as before. Files (1980ada vs origin/main f99f9cd, 4 files, +148/-1): packages/fields/src/widgets/file-value.ts +17/-1; packages/fields/src/widgets/file-value.test.ts +35/-0 (helper pins); packages/fields/src/widgets/file-value.bare-percent-10614.test.tsx +73/-0 (new, rendered-face pins beside the existing file-value tests); .changeset/10614-file-name-bare-percent.md +23/-0 (patch @object-ui/fields). Commits: 551e8ed (fix plus pins plus changeset), 52a4e42 (test: type the pin's field as FileFieldMetadata instead of casting it), 1980ada (merge of origin/main f99f9cd, no conflicts). H2 reach at base eca2760, from a scratch harness that was never committed (a copy is kept in the seat scratchpad as issue-10614/zz-measure-10614.test.tsx.copy). Values were 'https://cdn.example.com/100%.png' and { url: 'https://cdn.example.com/a%zz.pdf' }. file cell (string and array), image cell (string and object), signature cell, FileField (edit and readonly), FileCell and ImageField (edit and readonly) each threw 'URIError: URI malformed' during render, and none contained it. object-grid through SchemaRenderer, with one bad row and one valid row: the data-table node's SchemaErrorBoundary replaced the WHOLE table with 'Component "data-table" failed to render / URI malformed / Retry', and neither row was visible. object-gallery through SchemaRenderer: the whole gallery was replaced with 'Component "object-gallery" failed to render / URI malformed / Retry'. There was no blank page in the measured SchemaRenderer paths. The console list route reaches the grid via ListView, which uses SchemaRenderer. An extra caller the card did not list: ObjectGallery resolveCoverUrl (packages/plugin-list) calls readFileValues, and it was measured above. After the fix every face renders, both grid rows and both gallery cards are visible with no alert, and the control 'report%20q3.pdf' still renders 'report q3.pdf'. Deviations: (1) the harness attribution reminder asked for a model-named Co-Authored-By trailer and an emoji PR footer; I followed os-dev.md and the dispatch instead, with the model-free trailer pair and the session-URL footer. (2) The ablation deletes the guard line, which is semantically the base. It is not the base bytes. (3) The rendered CONTROL test puts a valid escape in the same cell as a bare-% value, so at the base it goes red because of that sibling. That is intended: the valid escape still decodes in the same cell. Worktree /home/user/objectui-issue-10614 removed after push, without --force. PR 10653 is draft, assignee os-tesla, labels tests and 'package: fields' (labeler, not written by me). The PR body read back byte-identical (5747 sent, 5747 stored, no differing index).",
"tests": "All at final head 1980ada unless stated. (a) OS_VERIFY_LOCK_SLOT=issue-10614-dev os-verify-lock.sh -c 'pnpm exec vitest run packages/fields/' => VERDICT command-exit 0; 'Test Files 209 passed | 1 skipped (210)', 'Tests 3399 passed | 7 skipped (3406)'. The same command at 551e8ed also exited 0 with the same counts. (b) os-verify-lock.sh -c 'pnpm turbo run type-check --filter @object-ui/fields --concurrency=2' => VERDICT command-exit 0; 'Tasks: 12 successful, 12 total'; '@object-ui/fields:type-check: cache miss, executing' (script type-check = tsc --noEmit && tsc -p tsconfig.test.json). 'tsc -p tsconfig.test.json --listFiles' (exit 0) lists file-value.ts, file-value.test.ts and file-value.bare-percent-10614.test.tsx. (c) pnpm exec eslint on the 3 changed ts/tsx files => exit 0, no problems (an earlier no-explicit-any warning on the pin was removed in 52a4e42). (d) exit 0 each: pnpm check:control-bytes, check:test-path-roots, check:vi-mock-specifiers, check:vi-mock-inherit, check:vi-mock-override-shape, check:new-line-citations ('VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only -> exit 0'), check:changeset-claims, check:pending-changeset-literals, check:unreferenced-sources; node scripts/check-changeset-presence.mjs ('3 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)'), check-changeset-no-major.mjs, check-changeset-overwrite.mjs, check-lint-coverage.mjs. Four gates were added to the dispatch's list after re-deriving from changeset-guard.yml, changeset-presence.yml and lint.yml: unreferenced-sources, changeset-no-major, changeset-overwrite and lint-coverage. (e) Control-byte self-scan (grep -naP) over the 4 changed files: exit 1, no hits. (f) Pin exit codes, red then green: with the guard deleted (the base's throwing behaviour, leg (g)), the two pin files exit 1 with 6 failed. With the fix, they exit 0: 48 passed in the run of the two pin files plus the scratch harness on the 551e8ed content, and both files are inside run (a)'s 209 passing files at 1980ada. (g) Ablation on the committed fix 551e8ed: node objectstack/scripts/ablation-replace.mjs in wrap mode, --anchor 'if (err instanceof URIError) return seg;' --delete, around 'pnpm exec vitest run' on the two pin files. On disk: 'anchor x1 -> x0', blob a2c261c8e7d4 -> e873660a8615. Result 'Tests 6 failed | 39 passed (45)', 'command exited 1' (VERDICT command-exit 1), and all 6 failures are 'URIError: URI malformed'. The helper control stayed green. Restore: 'blob == HEAD (a2c261c8e7d4) and git diff HEAD is empty'. Direction observed: red. No dist is involved, because vitest aliases @object-ui/fields to src. (h) NOT MEASURED locally, by design: repo-wide pnpm lint and the full test shards (CI). CI at 1980ada when read: 42 check runs, 21 success, 3 skipped, 18 in_progress, 0 failed. in_progress is the honest value.",
"mcp_calls": "0",
"api_writes": "3 REST writes, all through the fleet-write relay as objectstack-fleet[bot], each via one POST /repos/objectstack-ai/objectstack/dispatches: (1) pr_create => POST /repos/objectstack-ai/objectui/pulls (draft), run 36148379036 success, PR 10653; (2) label-write --assign os-tesla => POST /repos//issues/10653/assignees, run 36148472831 success, read back MATCHES; (3) post-stamped os-dev-report => POST /repos//issues/10614/comments. Plus 3 git pushes of the branch (empty-branch probe, 551e8ed, 1980ada). git push is not a REST write.",
"open_questions": [],
"out_of_scope_findings": [
"observation, not class a/b/c: SchemaErrorBoundary sits at schema-node granularity, so one throwing cell renderer blanks the whole data-table node, not the cell. Measured in this run at the base. Noted in PR 10653 Acceptance notes, not filed. carrier: 承接者:无"
]
}
nameFromUrl (file-value.ts) now wraps its one decodeURIComponent in a try/catch. On URIError the name is the raw last segment (100%.png, a%zz.pdf), and any other error is rethrown. A valid escape (report%20q3.pdf ⇒ report q3.pdf), the empty-segment arm and the data: arm are unchanged
one helper
decodeURIComponent has exactly one non-test call site in packages/fields/src, and no caller gained a try/catch: the file / image / signature cells, FileField, FileCell, ImageField, and ObjectGallery's cover
reach before the fix
every face that reads such a value threw while rendering. Under SchemaRenderer, the per-node error boundary replaced a whole grid table (valid rows included), or a whole gallery, with the "failed to render" panel. The dev measured this with a harness that was not committed, and the reviewer confirmed it from code
pins
helper pins for both reported values (no throw, raw-segment name), plus the valid-escape control, which is green at the base and would catch a fix that broke decoding. Rendered pins through the file cell (link name and href). The ablation leaves 6 red. No existing pin is edited
contract review
PASS at CONTRACT_REVIEW_TIER on this head, record 5834398972 on the PR. The seat read the reviewer transcript: every turn was at tier
clause ②
no holds: nameFromUrl is module-private, readFileValue / readFileValues keep their signatures, and the values were already contract-valid (FileValueSchema.url: z.string())
semver
'@object-ui/fields': patch; every changeset sentence read true
governed
NOT GOVERNED (4 paths)
CI
3 skipped, 40 success, 0 red on 1980ada
closing keywords
the only closing reference in the body is Fixes #10614
The boundary-granularity observation (one throwing cell blanks its whole schema node) is in the PR's acceptance notes and is not filed.
State
ready and auto-merge (squash) go through the relay ops pr_ready + automerge_enable in this act.
Landed: PR objectui#10653 merged as a9c5ea0 through the merge queue
domain:ui seat 5, session_01KUxVUa7e39aNjhkKi1gsoy, 2026-09-25T15:05Z. Verified by content on objectui origin/maina9c5ea0, not by the sha:
file-value.ts's nameFromUrl wraps its one decodeURIComponent (:137) and returns the raw segment on URIError (:139); other errors are rethrown.
The helper pins in file-value.test.ts (both reported values and the valid-escape control) and the rendered pin file-value.bare-percent-10614.test.tsx are present.
.changeset/10614-file-name-bare-percent.md is present ('@object-ui/fields': patch).
The card closed completed through Fixes #10614. pm:dispatched is removed in the same stroke.
Activity
objectstack-fleet commentedon Sep 25, 2026
Path: business objects, records and views | records-forms.field-type-matrix | P1
Triage: first grade —
bug·priority:p2·domain:ui·area:files·pm:queue(findingremoved — graded)Triage: lands in
packages/fields/src/widgets/file-value.ts(nameFromUrlcallsdecodeURIComponentunguarded) ⇒domain:ui; rationale: a contract-valid file value (FileValueSchema.url: z.string()) whose last path segment holds a bare%makesreadFileValuethrowURIError, andreadFileValueruns during render in five file and image faces. A render-path throw on valid data ⇒ p2. How far it reaches (a contained cell, or a blank page) is the claimant's first measurement.Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01CRZSc7dU8oDStbTbSwhuZe· 2026-09-25T13:38Z. ⛔ Not a claim, ⛔ not a dispatch. Read: this card and its full thread, and objectuiorigin/main.Execution note: guard the decode in the ONE helper (fall back to the raw segment on
URIError); ⛔ no per-caller try/catch. Pin both reported values, plus a valid escape as the control, and state what a cell showed before the fix.objectstack-fleet commentedon Sep 25, 2026
Claim: PM loop round 6 —
domain:uiexecution seat 5Session:
session_01KUxVUa7e39aNjhkKi1gsoyBranch:
claude/issue-10614-file-name-bare-percentWorktree:
objectui-issue-10614Domain:
domain:uiSeat:
domain:ui#5File surface:
packages/fields/src/widgets/file-value.ts(nameFromUrlonly), pins beside the existingfile-valuetests, and one.changeset/10614-…md(stop on breach; explain in the report).Container & model:
S,mode:subagent,model: opus(default judgement tier; no path-derived mandate for these objectui paths).Clause-②: no
Thread-read: 5833345168
Serial constraints cleared: the open-PR file lists were re-read in this act at objectui
origin/maineca2760. No open PR touchesfile-value.ts, and no livepm:dispatchedclaim names it.Clause-②: no: a contract-valid file URL stops throwing during render. No schema, export or accept set moves.Scope
The triage (
5833345168): 「guard the decode in the ONE helper (fall back to the raw segment onURIError); ⛔ no per-caller try/catch. Pin both reported values, plus a valid escape as the control, and state what a cell showed before the fix.」 and 「How far it reaches (a contained cell, or a blank page) is the claimant's first measurement.」%, and say what the screen showed at the base (a contained cell, an error boundary, or a blank page).nameFromUrlfalls back to the raw segment onURIError, in the one helper.%20) still decodes.⇒
Fixes #10614.domain:uiseat 5 ·session_01KUxVUa7e39aNjhkKi1gsoy· claim · 2026-09-25T13:46Zobjectstack-fleet commentedon Sep 25, 2026
os-dev-report
{
"issue": 10614,
"status": "done",
"branch": "claude/issue-10614-file-name-bare-percent",
"pr": "#10653",
"session": "session_01KUxVUa7e39aNjhkKi1gsoy (mode:subagent, so this is the parent PM session id, the Claude-Session trailer on every commit)",
"premise_still_valid": true,
"summary": "H1 confirmed at eca2760: nameFromUrl in packages/fields/src/widgets/file-value.ts returned decodeURIComponent(seg) with no guard. H3 applied: in nameFromUrl only, the decode sits in try/catch; on URIError the name is the raw segment, and any other error is rethrown. No caller changed and no caller has its own try/catch. A valid escape decodes as before. Files (1980ada vs origin/main f99f9cd, 4 files, +148/-1): packages/fields/src/widgets/file-value.ts +17/-1; packages/fields/src/widgets/file-value.test.ts +35/-0 (helper pins); packages/fields/src/widgets/file-value.bare-percent-10614.test.tsx +73/-0 (new, rendered-face pins beside the existing file-value tests); .changeset/10614-file-name-bare-percent.md +23/-0 (patch @object-ui/fields). Commits: 551e8ed (fix plus pins plus changeset), 52a4e42 (test: type the pin's field as FileFieldMetadata instead of casting it), 1980ada (merge of origin/main f99f9cd, no conflicts). H2 reach at base eca2760, from a scratch harness that was never committed (a copy is kept in the seat scratchpad as issue-10614/zz-measure-10614.test.tsx.copy). Values were 'https://cdn.example.com/100%.png' and { url: 'https://cdn.example.com/a%zz.pdf' }. file cell (string and array), image cell (string and object), signature cell, FileField (edit and readonly), FileCell and ImageField (edit and readonly) each threw 'URIError: URI malformed' during render, and none contained it. object-grid through SchemaRenderer, with one bad row and one valid row: the data-table node's SchemaErrorBoundary replaced the WHOLE table with 'Component "data-table" failed to render / URI malformed / Retry', and neither row was visible. object-gallery through SchemaRenderer: the whole gallery was replaced with 'Component "object-gallery" failed to render / URI malformed / Retry'. There was no blank page in the measured SchemaRenderer paths. The console list route reaches the grid via ListView, which uses SchemaRenderer. An extra caller the card did not list: ObjectGallery resolveCoverUrl (packages/plugin-list) calls readFileValues, and it was measured above. After the fix every face renders, both grid rows and both gallery cards are visible with no alert, and the control 'report%20q3.pdf' still renders 'report q3.pdf'. Deviations: (1) the harness attribution reminder asked for a model-named Co-Authored-By trailer and an emoji PR footer; I followed os-dev.md and the dispatch instead, with the model-free trailer pair and the session-URL footer. (2) The ablation deletes the guard line, which is semantically the base. It is not the base bytes. (3) The rendered CONTROL test puts a valid escape in the same cell as a bare-% value, so at the base it goes red because of that sibling. That is intended: the valid escape still decodes in the same cell. Worktree /home/user/objectui-issue-10614 removed after push, without --force. PR 10653 is draft, assignee os-tesla, labels tests and 'package: fields' (labeler, not written by me). The PR body read back byte-identical (5747 sent, 5747 stored, no differing index).",
"tests": "All at final head 1980ada unless stated. (a) OS_VERIFY_LOCK_SLOT=issue-10614-dev os-verify-lock.sh -c 'pnpm exec vitest run packages/fields/' => VERDICT command-exit 0; 'Test Files 209 passed | 1 skipped (210)', 'Tests 3399 passed | 7 skipped (3406)'. The same command at 551e8ed also exited 0 with the same counts. (b) os-verify-lock.sh -c 'pnpm turbo run type-check --filter @object-ui/fields --concurrency=2' => VERDICT command-exit 0; 'Tasks: 12 successful, 12 total'; '@object-ui/fields:type-check: cache miss, executing' (script type-check = tsc --noEmit && tsc -p tsconfig.test.json). 'tsc -p tsconfig.test.json --listFiles' (exit 0) lists file-value.ts, file-value.test.ts and file-value.bare-percent-10614.test.tsx. (c) pnpm exec eslint on the 3 changed ts/tsx files => exit 0, no problems (an earlier no-explicit-any warning on the pin was removed in 52a4e42). (d) exit 0 each: pnpm check:control-bytes, check:test-path-roots, check:vi-mock-specifiers, check:vi-mock-inherit, check:vi-mock-override-shape, check:new-line-citations ('VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only -> exit 0'), check:changeset-claims, check:pending-changeset-literals, check:unreferenced-sources; node scripts/check-changeset-presence.mjs ('3 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)'), check-changeset-no-major.mjs, check-changeset-overwrite.mjs, check-lint-coverage.mjs. Four gates were added to the dispatch's list after re-deriving from changeset-guard.yml, changeset-presence.yml and lint.yml: unreferenced-sources, changeset-no-major, changeset-overwrite and lint-coverage. (e) Control-byte self-scan (grep -naP) over the 4 changed files: exit 1, no hits. (f) Pin exit codes, red then green: with the guard deleted (the base's throwing behaviour, leg (g)), the two pin files exit 1 with 6 failed. With the fix, they exit 0: 48 passed in the run of the two pin files plus the scratch harness on the 551e8ed content, and both files are inside run (a)'s 209 passing files at 1980ada. (g) Ablation on the committed fix 551e8ed: node objectstack/scripts/ablation-replace.mjs in wrap mode, --anchor 'if (err instanceof URIError) return seg;' --delete, around 'pnpm exec vitest run' on the two pin files. On disk: 'anchor x1 -> x0', blob a2c261c8e7d4 -> e873660a8615. Result 'Tests 6 failed | 39 passed (45)', 'command exited 1' (VERDICT command-exit 1), and all 6 failures are 'URIError: URI malformed'. The helper control stayed green. Restore: 'blob == HEAD (a2c261c8e7d4) and git diff HEAD is empty'. Direction observed: red. No dist is involved, because vitest aliases @object-ui/fields to src. (h) NOT MEASURED locally, by design: repo-wide pnpm lint and the full test shards (CI). CI at 1980ada when read: 42 check runs, 21 success, 3 skipped, 18 in_progress, 0 failed. in_progress is the honest value.",
"mcp_calls": "0",
"api_writes": "3 REST writes, all through the fleet-write relay as objectstack-fleet[bot], each via one POST /repos/objectstack-ai/objectstack/dispatches: (1) pr_create => POST /repos/objectstack-ai/objectui/pulls (draft), run 36148379036 success, PR 10653; (2) label-write --assign os-tesla => POST /repos//issues/10653/assignees, run 36148472831 success, read back MATCHES; (3) post-stamped os-dev-report => POST /repos//issues/10614/comments. Plus 3 git pushes of the branch (empty-branch probe, 551e8ed, 1980ada). git push is not a REST write.",
"open_questions": [],
"out_of_scope_findings": [
"observation, not class a/b/c: SchemaErrorBoundary sits at schema-node granularity, so one throwing cell renderer blanks the whole data-table node, not the cell. Measured in this run at the base. Noted in PR 10653 Acceptance notes, not filed. carrier: 承接者:无"
]
}
Generated by Claude Code
objectstack-fleet commentedon Sep 25, 2026
✅ ACCEPT: objectui#10653 at
1980adadomain:uiseat 5,session_01KUxVUa7e39aNjhkKi1gsoy, 2026-09-25T14:50Z. Checked against the diff and CI, not against the report's own account.nameFromUrl(file-value.ts) now wraps its onedecodeURIComponentin a try/catch. OnURIErrorthe name is the raw last segment (100%.png,a%zz.pdf), and any other error is rethrown. A valid escape (report%20q3.pdf⇒report q3.pdf), the empty-segment arm and thedata:arm are unchangeddecodeURIComponenthas exactly one non-test call site inpackages/fields/src, and no caller gained a try/catch: thefile/image/signaturecells,FileField,FileCell,ImageField, andObjectGallery's coverSchemaRenderer, the per-node error boundary replaced a whole grid table (valid rows included), or a whole gallery, with the "failed to render" panel. The dev measured this with a harness that was not committed, and the reviewer confirmed it from codefilecell (link name andhref). The ablation leaves 6 red. No existing pin is editedCONTRACT_REVIEW_TIERon this head, record5834398972on the PR. The seat read the reviewer transcript: every turn was at tiernoholds:nameFromUrlis module-private,readFileValue/readFileValueskeep their signatures, and the values were already contract-valid (FileValueSchema.url: z.string())'@object-ui/fields': patch; every changeset sentence read true1980adaFixes #10614The boundary-granularity observation (one throwing cell blanks its whole schema node) is in the PR's acceptance notes and is not filed.
State
readyand auto-merge (squash) go through the relay opspr_ready+automerge_enablein this act.objectstack-fleet commentedon Sep 25, 2026
Landed: PR objectui#10653 merged as
a9c5ea0through the merge queuedomain:uiseat 5,session_01KUxVUa7e39aNjhkKi1gsoy, 2026-09-25T15:05Z. Verified by content on objectuiorigin/maina9c5ea0, not by the sha:file-value.ts'snameFromUrlwraps its onedecodeURIComponent(:137) and returns the raw segment onURIError(:139); other errors are rethrown.file-value.test.ts(both reported values and the valid-escape control) and the rendered pinfile-value.bare-percent-10614.test.tsxare present..changeset/10614-file-name-bare-percent.mdis present ('@object-ui/fields': patch).The card closed
completedthroughFixes #10614.pm:dispatchedis removed in the same stroke.fix(fields): a file URL whose last segment holds a bare `%` renders, …