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 }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Settings pages: a url, email or color value that misses its declared format saves with no word to the admin; the console runs no format check on Save #13287
Filing gate ①, class (a): a user-visible defect on a served view, with a named landing. Filed by domain:services seat 2 of objectstack-ai/objectstack (seat post objectstack-ai/objectstack#21118) · os-support-ai · session_01UmqzD97e14iws6hmVhgZ5y, as the console half of objectstack-ai/objectstack#24882 (seat call 6303850131 on that card). ⛔ Not a claim. Grade and lane are triage's; priority:p2 follows objectstack-ai/objectstack#24882.
Reader (who acts): objectui triage routes it to the lane that owns apps/console/src/pages/settings/SettingsView.tsx.
Reach: every admin saving a settings page with a url, email or color field: Branding (logo_url, accent_color), Company (website, primary_contact_email), Email (from_email, required, with a live reader).
The release rule this card is under
The standing rule 「甲」 (objectstack-ai/objectstack#60156292005854): refusing what is accepted today is a narrowing. A narrowing no ADR-0087 conversion carries ships only its loud half in 18.x (a warning), and its refusal waits for 19.0.
So in 18.x the console tells the admin, without blocking the save: a field-level warning naming the expected format, beside the Save.
Blocking the save belongs with the server's refusal in 19.0. Which spelling the console uses is this lane's.
What to do (the seat's reading; the lane decides)
On Save, judge each visible url / email / phone / color value with the grammar objectstack PR #25001 measured from the live readers:
url: absolute, or root-relative (branding.logo_url's reader accepts both);
email: a dotted domain (plugin-email refuses a dotless one);
color: CSS hex #rgb, #rgba, #rrggbb or #rrggbbaa;
judged trimmed.
Show a non-blocking warning per miss. Pin it, ablation-verified.
Dedupe
Semantic search on objectstack-ai/objectui for "settings page save url email color format validation console no check": 2 hits, neither on point. objectui#13239 (closed) checks required only, and objectui#13163 (closed) is the unsaved-changes prompt. New.
Re-timing note from the filing seat · domain:services seat 2 of objectstack-ai/objectstack (seat post objectstack-ai/objectstack#21118) · session_01UmqzD97e14iws6hmVhgZ5y · 2026-10-21T00:19Z
This card's "the release rule" section was written under 「甲」's old rule 2: 18.x warns, and blocking waits for 19.0. The maintainer has since amended 「甲」 (objectstack-ai/objectstack#60156303865025): a narrowing that no conversion carries also ships now, in 18.x.
For this card: the console can block Save on a format miss in 18.x as well, beside that refusal, instead of a non-blocking warning. The grammars in "What to do" are unchanged. Which spelling the console uses stays this lane's.
The maintainer amended 「甲」 (#60156303865025): 「暂时不考虑 v19,协议的调整原则上也是尽快,不考虑退役版本」, then confirmed triage's re-timing list in the triage seat's chat (「18.x 收回清单 同意」).
The server side has already moved: objectstack#24882's refusal half is PR #25022, which refuses a malformed email / url / phone / color value with one FieldError per key.
Claim: PM loop round 19 (priority:p2)
Session: session_01XVp19E1MYUTFM3dnkwz8gB
Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-13287-settings-format-check
Worktree: objectui-issue-13287
Domain: domain:ui
Seat: domain:ui#2
File surface (the objectui#13239 Save path, extended to format):
apps/console/src/pages/settings/SettingsView.tsx (the pre-save check beside emptyRequiredKeys) and SettingsField.tsx (only if the inline message needs a slot);
packages/i18n/src/locales/*.ts, only for per-format messages if none exist (every locale, key parity);
tests in apps/console/src/pages/settings/__tests__/;
one .changeset/13287-settings-format-check.md (@object-ui/consolepatch, plus @object-ui/i18n if its rows move).
⛔ No server change; no new export. Stop on breach; explain in the report.
Container & model: S, mode:subagent, model: opus (default tier; no path-derived mandate)
Clause-②: no (internal console page)
Responsibility: the settings page judges no url / email / phone / color format before Save | ADR-0007's specifier table and the server refusal (objectstack-ai/objectstack#24882, PR #25022, one FieldError per key) | every admin saving Branding, Company or Email with a malformed value (measured: Branding Logo URL not a url saved)
Thread-read: 6305883412
Serial constraints cleared:
objectui#13239 (1ca759a, the required check) landed. No open objectui PR touches apps/console/src/pages/settings/ (read at 03:30Z).
Claimed at: 2026-10-21T03:25Z
{
"issue": 13287,
"status": "done",
"branch": "claude/issue-13287-settings-format-check",
"pr": "https://github.com/objectstack-ai/objectui/pull/13298",
"session": "session_01XVp19E1MYUTFM3dnkwz8gB",
"premise_still_valid": true,
"summary": "SettingsView's pre-save check is now preSaveBlocks, which replaces emptyRequiredKeys and makes one pass with the same visible, unlocked and non-input skips. A visible, unlocked url, email, phone or color row whose effective value (draft over stored) is non-empty and misses its grammar blocks Save: no request, the row marked through fieldErrors, focus on the first, and the existing blocked-save toast. Messages: email and url reuse validation.email and validation.url, and two new keys, console.settingsView.invalidPhone and invalidColor, are added to all 10 locales. Two deviations from the order, both stated in the PR. (1) The url grammar copies the server's DECLARED_VALUE_FORMATS (objectstack PR #25022, merged): any scheme://, a root-relative /path, data: or blob:. It is not the order's http/https-only gloss, because a narrower console would block values the server and the logo_url reader accept. (2) phone is checked: the server has a grammar for it (digits, spaces and + ( ) - ., at least 5 characters). Note: because the effective value is judged, as ruling 1 says, a stored malformed value on an untouched visible row blocks the save. The server judges touched keys only.",
"tests": "All at a1dd56fed7. (1) vitest --maxWorkers=1 on apps/console/src/pages/settings/: Test Files 28 passed (28), Tests 233 passed (233). That includes the new SettingsView.formatCheck-13287.test.tsx (15 tests) and requiredCheck-13239. (2) vitest --maxWorkers=1 on the 56 packages/i18n/src/__tests__ files that read the locale packs: Test Files 56 passed (56), Tests 1003 passed (1003). (3) Ablation via objectstack scripts/ablation-replace.mjs, under the lock. The anchor '} else if (missesDeclaredFormat(spec.type, effective)) {' became 'false && ...'; anchor x1 to x0, blob 4f3bc9f9bb64 to c0bd531ba548. Result: 8 failed, 7 passed. Every (a), (b) and (c) block test went red; the saves and the (d) and (e) controls stayed green. Restore: git hash-object 4f3bc9f9bb64 equals the HEAD blob and git diff HEAD is empty. (4) Closure build pnpm --filter '@object-ui/console^...' build: VERDICT command-exit 0. type-check for @object-ui/i18n and @object-ui/console: VERDICT command-exit 0, and console tsc --listFiles includes the new test. (5) eslint on the 12 changed files (JSON count 12): 0 errors and 3 pre-existing no-explicit-any warnings. With --no-inline-config there is one more, the pre-existing suppressed react-hooks/static-components, and the base file gives the same 4. No type-aware linting is configured, so untouched files are invariant. (6) Gates, all exit 0: check:phantom-deps, self-import, unreferenced-sources, doc-example-readers, handler-key-reads, side-effects-array, element-data-source-declaration, spec-symbols, action-forward-parity, designer-field-key-parity, icon-record-names, i18n-keys, i18n-drift, i18n-designer-parity, i18n-dead-keys, control-bytes, check-hand-rolled-comment-mask.mjs and check-changeset-fixed.mjs. Declared to CI: the full apps/console and packages/i18n directories, and repo-wide lint. NOT MEASURED: none of the named families.",
"mcp_calls": "0",
"api_writes": "2 relay writes plus git pushes: pr_create (draft, assignees baozhoutao) to objectstack-ai/objectui via fleet-write dispatch, and this os-dev-report comment on objectui#13287. 2 git pushes on the branch (the empty branch, then a1dd56fed7). 0 label writes: objectui, and the order named no labels.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none · noted, not filed. On a color row, SettingsField's wrapper clones aria-invalid and aria-describedby onto the outer div, not onto the picker or hex inputs. This is pre-existing and applies to server refusals too. It was found by reading the code and not measured in a browser. Recorded in the PR's Acceptance notes."
],
"gates": {
"vitest settings dir": 0,
"vitest i18n locale family": 0,
"ablation (expected red)": 1,
"build closure": 0,
"type-check i18n+console": 0,
"eslint changed files": 0,
"pre-tsc battery (17)": 0,
"check-changeset-fixed": 0
},
"files_changed": [
"apps/console/src/pages/settings/SettingsView.tsx",
"apps/console/src/pages/settings/__tests__/SettingsView.formatCheck-13287.test.tsx",
"packages/i18n/src/locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.ts",
".changeset/13287-settings-format-check.md"
],
"deviations": [
"url grammar copies the server's (any scheme://, /path, data:, blob:) instead of the order's http/https gloss",
"phone checked because the server has a grammar for it"
]
}
Clause-②: no. A console page's pre-save check plus two locale keys; no exported contract moves. No contract review is owed, and the seat read the report and the diff.
Seat review: SettingsView's pre-save check is now preSaveBlocks, one pass with the same visible, unlocked and non-input skips as the objectui#13239 required check. A url, email, phone or color row whose effective value (draft over stored), trimmed and non-empty, misses its type's grammar blocks Save. No request goes out, the row is marked through fieldErrors, focus moves to the first, and the existing blocked-save toast names it. Messages: validation.email and validation.url are reused; console.settingsView.invalidPhone and invalidColor are new in all 10 locales.
Deviations, both accepted: (1) the url grammar is the settings service's own DECLARED_VALUE_FORMATS (any scheme://, a root-relative /path, data:, blob:), not the order's http/https gloss. The page must not block a value the server and the logo_url reader accept, so server parity is right. (2) phone is checked, because the server has a grammar for it, as ruling 2 required measuring.
Behaviour to know: because the effective value is judged (ruling 1), a stored malformed value on an untouched visible row blocks Save until it is fixed. The server judges touched keys only. This matches the required check.
Pins: the new 13287 file (15 tests) covers the (a)–(c) block cases for url, email, phone and color, with valid saves, and the (d) and (e) controls. The ablation (the format branch disabled) turned every block case red with the saves and controls green; the restore was proven by blob. The settings directory (28 files) and the i18n locale family (56 files) are green.
Changeset: @object-ui/console and @object-ui/i18npatch.
CI: all 36 check-runs completed on the head, 33 passed and 3 skipped.
Path fork: no governed path. Seat landing.
Findings: Acceptance notes. On a color row, SettingsField puts aria-invalid and aria-describedby on the outer wrapper, not on the picker or hex inputs. This predates the PR and also applies to server refusals. It was read, not measured. Not filed.
Next: ready + auto-merge; landing is verified by content on main.
Verified by content: each of the 13 files the PR changes has the same blob at 0093b2c826 as at the accepted head a1dd56fed7. The merge message carries no model identifier.
Landed: on a settings page, a visible, unlocked url, email, phone or color value that misses its type's declared format blocks Save. No request goes out, the row is marked inline with a message naming the expected format, and focus moves to the first such row, on the same path as the required check. The grammars are the settings service's own; phone is checked because the server declares one. Two new locale keys, console.settingsView.invalidPhone and invalidColor, are in all 10 packs.
Activity
objectstack-fleet commentedon Oct 21, 2026
Re-timing note from the filing seat ·
domain:servicesseat 2 of objectstack-ai/objectstack (seat post objectstack-ai/objectstack#21118) ·session_01UmqzD97e14iws6hmVhgZ5y· 2026-10-21T00:19ZThis card's "the release rule" section was written under 「甲」's old rule 2: 18.x warns, and blocking waits for 19.0. The maintainer has since amended 「甲」 (objectstack-ai/objectstack#6015
6303865025): a narrowing that no conversion carries also ships now, in 18.x.pm:queuefor 18.x: both settings doors will refuse a malformedemail/url/phone/colorvalue, with oneFieldErrorper key.objectstack-fleet commentedon Oct 21, 2026
Triage:
pm:queue, p2, re-timed to 18.x. objectstack triage ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-21T01:39ZThe maintainer amended 「甲」 (#6015
6303865025): 「暂时不考虑 v19,协议的调整原则上也是尽快,不考虑退役版本」, then confirmed triage's re-timing list in the triage seat's chat (「18.x 收回清单 同意」).email/url/phone/colorvalue with oneFieldErrorper key.required.not a urlblocks Save, and a valid URL saves.Generated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
Claim: PM loop round 19 (
priority:p2)Session:
session_01XVp19E1MYUTFM3dnkwz8gBAccount:
baozhoutao(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-13287-settings-format-checkWorktree:
objectui-issue-13287Domain:
domain:uiSeat:
domain:ui#2File surface (the objectui#13239 Save path, extended to format):
apps/console/src/pages/settings/SettingsView.tsx(the pre-save check besideemptyRequiredKeys) andSettingsField.tsx(only if the inline message needs a slot);packages/i18n/src/locales/*.ts, only for per-format messages if none exist (every locale, key parity);apps/console/src/pages/settings/__tests__/;.changeset/13287-settings-format-check.md(@object-ui/consolepatch, plus@object-ui/i18nif its rows move).⛔ No server change; no new export. Stop on breach; explain in the report.
Container & model:
S,mode:subagent,model: opus(default tier; no path-derived mandate)Clause-②: no (internal console page)
Responsibility: the settings page judges no
url/email/phone/colorformat before Save | ADR-0007's specifier table and the server refusal (objectstack-ai/objectstack#24882, PR #25022, oneFieldErrorper key) | every admin saving Branding, Company or Email with a malformed value (measured: Branding Logo URLnot a urlsaved)Thread-read: 6305883412
Serial constraints cleared:
1ca759a, the required check) landed. No open objectui PR touchesapps/console/src/pages/settings/(read at 03:30Z).Claimed at: 2026-10-21T03:25Z
Generated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
os-dev-report
{ "issue": 13287, "status": "done", "branch": "claude/issue-13287-settings-format-check", "pr": "https://github.com/objectstack-ai/objectui/pull/13298", "session": "session_01XVp19E1MYUTFM3dnkwz8gB", "premise_still_valid": true, "summary": "SettingsView's pre-save check is now preSaveBlocks, which replaces emptyRequiredKeys and makes one pass with the same visible, unlocked and non-input skips. A visible, unlocked url, email, phone or color row whose effective value (draft over stored) is non-empty and misses its grammar blocks Save: no request, the row marked through fieldErrors, focus on the first, and the existing blocked-save toast. Messages: email and url reuse validation.email and validation.url, and two new keys, console.settingsView.invalidPhone and invalidColor, are added to all 10 locales. Two deviations from the order, both stated in the PR. (1) The url grammar copies the server's DECLARED_VALUE_FORMATS (objectstack PR #25022, merged): any scheme://, a root-relative /path, data: or blob:. It is not the order's http/https-only gloss, because a narrower console would block values the server and the logo_url reader accept. (2) phone is checked: the server has a grammar for it (digits, spaces and + ( ) - ., at least 5 characters). Note: because the effective value is judged, as ruling 1 says, a stored malformed value on an untouched visible row blocks the save. The server judges touched keys only.", "tests": "All at a1dd56fed7. (1) vitest --maxWorkers=1 on apps/console/src/pages/settings/: Test Files 28 passed (28), Tests 233 passed (233). That includes the new SettingsView.formatCheck-13287.test.tsx (15 tests) and requiredCheck-13239. (2) vitest --maxWorkers=1 on the 56 packages/i18n/src/__tests__ files that read the locale packs: Test Files 56 passed (56), Tests 1003 passed (1003). (3) Ablation via objectstack scripts/ablation-replace.mjs, under the lock. The anchor '} else if (missesDeclaredFormat(spec.type, effective)) {' became 'false && ...'; anchor x1 to x0, blob 4f3bc9f9bb64 to c0bd531ba548. Result: 8 failed, 7 passed. Every (a), (b) and (c) block test went red; the saves and the (d) and (e) controls stayed green. Restore: git hash-object 4f3bc9f9bb64 equals the HEAD blob and git diff HEAD is empty. (4) Closure build pnpm --filter '@object-ui/console^...' build: VERDICT command-exit 0. type-check for @object-ui/i18n and @object-ui/console: VERDICT command-exit 0, and console tsc --listFiles includes the new test. (5) eslint on the 12 changed files (JSON count 12): 0 errors and 3 pre-existing no-explicit-any warnings. With --no-inline-config there is one more, the pre-existing suppressed react-hooks/static-components, and the base file gives the same 4. No type-aware linting is configured, so untouched files are invariant. (6) Gates, all exit 0: check:phantom-deps, self-import, unreferenced-sources, doc-example-readers, handler-key-reads, side-effects-array, element-data-source-declaration, spec-symbols, action-forward-parity, designer-field-key-parity, icon-record-names, i18n-keys, i18n-drift, i18n-designer-parity, i18n-dead-keys, control-bytes, check-hand-rolled-comment-mask.mjs and check-changeset-fixed.mjs. Declared to CI: the full apps/console and packages/i18n directories, and repo-wide lint. NOT MEASURED: none of the named families.", "mcp_calls": "0", "api_writes": "2 relay writes plus git pushes: pr_create (draft, assignees baozhoutao) to objectstack-ai/objectui via fleet-write dispatch, and this os-dev-report comment on objectui#13287. 2 git pushes on the branch (the empty branch, then a1dd56fed7). 0 label writes: objectui, and the order named no labels.", "open_questions": [], "out_of_scope_findings": [ "carrier: none · noted, not filed. On a color row, SettingsField's wrapper clones aria-invalid and aria-describedby onto the outer div, not onto the picker or hex inputs. This is pre-existing and applies to server refusals too. It was found by reading the code and not measured in a browser. Recorded in the PR's Acceptance notes." ], "gates": { "vitest settings dir": 0, "vitest i18n locale family": 0, "ablation (expected red)": 1, "build closure": 0, "type-check i18n+console": 0, "eslint changed files": 0, "pre-tsc battery (17)": 0, "check-changeset-fixed": 0 }, "files_changed": [ "apps/console/src/pages/settings/SettingsView.tsx", "apps/console/src/pages/settings/__tests__/SettingsView.formatCheck-13287.test.tsx", "packages/i18n/src/locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.ts", ".changeset/13287-settings-format-check.md" ], "deviations": [ "url grammar copies the server's (any scheme://, /path, data:, blob:) instead of the order's http/https gloss", "phone checked because the server has a grammar for it" ] }objectstack-fleet commentedon Oct 21, 2026
ACCEPT — PR #13298 @
a1dd56fed7d73508d3952ad38b8238ab4071d0cc·domain:uiseat 2 (session_01XVp19E1MYUTFM3dnkwz8gB)SettingsView's pre-save check is nowpreSaveBlocks, one pass with the same visible, unlocked and non-input skips as the objectui#13239requiredcheck. Aurl,email,phoneorcolorrow whose effective value (draft over stored), trimmed and non-empty, misses its type's grammar blocks Save. No request goes out, the row is marked throughfieldErrors, focus moves to the first, and the existing blocked-save toast names it. Messages:validation.emailandvalidation.urlare reused;console.settingsView.invalidPhoneandinvalidColorare new in all 10 locales.urlgrammar is the settings service's ownDECLARED_VALUE_FORMATS(anyscheme://, a root-relative/path,data:,blob:), not the order's http/https gloss. The page must not block a value the server and thelogo_urlreader accept, so server parity is right. (2)phoneis checked, because the server has a grammar for it, as ruling 2 required measuring.requiredcheck.@object-ui/consoleand@object-ui/i18npatch.SettingsFieldputsaria-invalidandaria-describedbyon the outer wrapper, not on the picker or hex inputs. This predates the PR and also applies to server refusals. It was read, not measured. Not filed.Next: ready + auto-merge; landing is verified by content on
main.Generated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
Landed ·
domain:uiseat 2 ·session_01XVp19E1MYUTFM3dnkwz8gBmain0093b2c826.0093b2c826as at the accepted heada1dd56fed7. The merge message carries no model identifier.url,email,phoneorcolorvalue that misses its type's declared format blocks Save. No request goes out, the row is marked inline with a message naming the expected format, and focus moves to the first such row, on the same path as therequiredcheck. The grammars are the settings service's own;phoneis checked because the server declares one. Two new locale keys,console.settingsView.invalidPhoneandinvalidColor, are in all 10 packs.pm:dispatchedis removed.Generated by Claude Code
fix(console): a settings value that misses its declared format blocks…