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
spec(settings): a select's options can come from a registered option source, but the manifest doc and listManifests still describe the declared table as the save boundary #30455
Filing gate: ① found by the contract review of PR #30446 (#30286), record 6657571849, should-fix S1. Filed by domain:server seat 4. ⛔ Not a claim. Suggested-grade: p3. ⛔ Serial after PR #30446 merges: it introduces the option source this card documents.
What happens
PR #30446 lets service-settings register an option source for a select key (localization.locale reads the deployment's locale list). The namespace read (GET /api/v1/settings/:namespace) serves the live list and the save judges against it. Two other statements of the table remain:
getManifest(), listManifests() and GET /api/settings still carry the declared options (the old four for locale).
packages/spec/src/system/settings-manifest.zod.ts (around L490–500) still says the declared options are the save boundary for every select without a valueDomain.
A consumer reading the manifest list (the Setup hub, #30206's language row, an SDK caller) is told a table that is not the one the save judges.
Ask
Either name the option-source carve-out in the spec beside valueDomain (the declared table is the fallback when a source is registered), or have listManifests serve sourced options as the namespace read does. Pin whichever is chosen.
Claim: PM loop round 1
Session: session_01Utp6CZMkHvuDeVYgTD73qF (seat) · dev card thread session_01Utp6CZMwT3iajiQDWrXgCn
Account: os-bill
Branch: claude/project-thread-3uylj0 (the card thread's designated push branch, the recorded platform exception to claude/issue-<n>-<slug>)
Worktree: objectstack-issue-30455
Domain: domain:server
Seat: domain:server#4
File surface: service-settings manifest reads (getManifest / listManifests / GET /api/settings) serving a sourced select's options through the namespace read's resolution; the option-source carve-out in packages/spec/src/system/settings-manifest.zod.ts (description only) and its regenerated artifacts; tests; changesets. ⛔ other packages/spec/**, docs/adr/**, .claude/**, repo-root AGENTS.md, ui/**, skills/** (stop on breach; explain in the report)
Container & model: S, mode:thread, model: default judgment tier (opus) — dispatch-gates --tier: no path-derived mandate, effort: default
Clause-②: no — the manifest list now states the table the save already enforces; nothing a caller sends is refused differently
Metadata-protocol: none
Responsibility: the settings manifest list still states a select's declared options where a registered option source decides | none: getManifest / listManifests / GET /api/settings carry the declared four for localization.locale while the namespace read and the save use the live list (contract review record 6657571849, S1) | the Setup hub, an SDK caller reading the manifest list
Thread-read: 6658680630
Premise: holds (PR #30446 merged 2026-11-05T15:17Z, bee98366d)
Serial constraints cleared: seats 2, 3, 5 and 6 answered; seat 2's #30448 (settings-service.ts) and seat 5's #30548 (service-settings manifests and translations) are recorded in the order; second to land merges main.
Dispatch order: /mnt/project-files/server-seat4/dispatch-30455.md (project shared folder). Ruling section: triage 6658680630 (p3); the seat picks "serve the sourced options from the manifest list and name the carve-out in the spec description". Dispatched on the maintainer's 「任务很多,车道尽量跑满并发」. Fixes #30455.
Status: done. Draft PR #30568 carries Fixes #30455, head 1b5ca0e2.
What it does:
The manifest list serves a sourced select's options.SettingsService.getManifest() and listManifests() now go through servedManifest, the one resolution the namespace read already used, with no values in effect, so a key with a registered option source (localization.locale) carries the options a save is judged against; every other key, and a sourced key whose source has no answer, carries its declared table, returned as the registered object itself. GET /api/settings passes the request's language. The registered manifest is never changed.
Spec: the valueDomain TSDoc in settings-manifest.zod.ts names the runtime option source as the other mover of a select's enforcement boundary (declared options = fallback; a runtime registration, not an authorable key). TSDoc only, no .describe() change; check:generated 14 of 14 up to date.
Pin: on a deployment list ['en', 'zh-CN', 'fr-FR', 'vi-VN'], GET /api/settings's locale options equal the namespace read's and getManifest / listManifests answer the same; every listed value saves, the declared ja-JP the list leaves out is refused naming exactly the listed values.
Deviations: none from the order. The session-context step that sets an assignee and requests a review through GitHub MCP was skipped: the order forbids MCP writes and os-dev rule 2 leaves both to the seat. The relay pr_create answered HTTP 500 from POST /pulls twice (runs 42061968319, 42062121265; no PR created, checked by a head-filtered pulls read before each retry); the third (run 42062916869) created #30568 with an identical read-back. The first git push of the merge was refused by the remote (fatal error in commit_refs_rules) and went through on retry.
{
"issue": 30455,
"status": "done",
"branch": "claude/project-thread-3uylj0",
"pr": "https://github.com/objectstack-ai/objectstack/pull/30568",
"session": "session_01Utp6CZMwT3iajiQDWrXgCn",
"premise_still_valid": true,
"summary": "getManifest and listManifests (and so GET /api/settings) now return servedManifest(reg, namespace, {}, display), the namespace read's resolution, so localization.locale's manifest-list options are the i18n service's list the save judges against instead of the declared four. Both take an optional display argument; the list route passes the request locale. The spec valueDomain TSDoc names the option-source carve-out beside valueDomain.",
"tests": "service-settings test 69 files 1172 passed; typecheck exit 0 (os-verify-lock, before the main merge; merged commits touch platform-objects and rest only). localization-locale-options.test.ts 15 passed: one new case (manifest list = namespace read = save boundary on a four-locale deployment), one adjusted (registered manifest unchanged, read once the source has no answer). Ablation via scripts/ablation-replace.mjs: listManifests returning reg.manifest gives 1 of 15 red (the new case); restored, blob 0d3acb6b equal to HEAD, git diff HEAD empty.",
"gates": "At 1b5ca0e2 after pnpm install --frozen-lockfile (exit 0) and turbo build 119/119 (lock VERDICT command-exit 0): dispatch-gates --commands --repo objectstack-ai/objectstack derived 83 families; 83 of 83 exit 0, recorded before any pipe; --ran: 83 derived, 83 run, 0 NOT-MEASURED, exit 0. pnpm lint exit 0. spec build exit 0, check:generated 14/14 up to date. CI check-runs on #30568: not yet reported at report time.",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"line_budget": "source +43 -13 (4 files: settings-service.ts, settings-service.types.ts, settings-routes.ts, settings-manifest.zod.ts), tests +38 -1 (1 file), changeset +14 (1 file); 6 files, +95 -14",
"files_changed": ".changeset/30455-manifest-list-serves-sourced-options.md, packages/services/service-settings/src/{localization-locale-options.test.ts, settings-routes.ts, settings-service.ts, settings-service.types.ts}, packages/spec/src/system/settings-manifest.zod.ts",
"deviations": "none from the order; session-context MCP assignee/reviewer step skipped per the order's no-MCP-write line; relay pr_create HTTP 500 twice before success (no duplicate PR); one push refused by the remote then accepted on retry",
"mcp_calls": "0",
"api_writes": "4 relay dispatches (3 pr_create, of which 2 failed at HTTP 500 creating nothing, 1 created #30568) plus this report comment via post-stamped; 2 git push",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": []
}
MERGED 2026-11-05T17:20Z, merge commit b55d6ab9; Fixes #30455 closes this card. Seat record 6663832030 on head 1b5ca0e2 (not BREAKING, not governed, Clause-②: no).
main source
packages/services/service-settings/src/settings-service.ts:1584 return this.servedManifest(reg, namespace, {}, display); (getManifest; listManifests and GET /api/settings resolve the same way).
The card's label pm:dispatched and the os-bill assignee come off with this comment.
Activity
objectstack-fleet commentedon Nov 5, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · p3 ·
domain:server· 2026-11-05T13:02Z⛔ Not a claim.
getManifest(),listManifests()and the settings-manifest docblock still describe the declaredoptionsas the save boundary of a select that now has a registered option source.Generated by Claude Code
objectstack-fleet commentedon Nov 5, 2026
domain:server#4 · os-bill · session_01Utp6CZMkHvuDeVYgTD73qF
Claim: PM loop round 1
Session:
session_01Utp6CZMkHvuDeVYgTD73qF(seat) · dev card threadsession_01Utp6CZMwT3iajiQDWrXgCnAccount:
os-billBranch:
claude/project-thread-3uylj0(the card thread's designated push branch, the recorded platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-30455Domain:
domain:serverSeat:
domain:server#4File surface:
service-settingsmanifest reads (getManifest/listManifests/GET /api/settings) serving a sourced select's options through the namespace read's resolution; the option-source carve-out inpackages/spec/src/system/settings-manifest.zod.ts(description only) and its regenerated artifacts; tests; changesets. ⛔ otherpackages/spec/**,docs/adr/**,.claude/**, repo-rootAGENTS.md,ui/**,skills/**(stop on breach; explain in the report)Container & model:
S,mode:thread,model: default judgment tier (opus) — dispatch-gates --tier: no path-derived mandate,effort: defaultClause-②: no — the manifest list now states the table the save already enforces; nothing a caller sends is refused differently
Metadata-protocol: none
Responsibility:
the settings manifest list still states a select's declared options where a registered option source decides | none: getManifest / listManifests / GET /api/settings carry the declared four for localization.locale while the namespace read and the save use the live list (contract review record 6657571849, S1) | the Setup hub, an SDK caller reading the manifest listThread-read: 6658680630
Premise: holds (PR #30446 merged 2026-11-05T15:17Z,
bee98366d)Serial constraints cleared: seats 2, 3, 5 and 6 answered; seat 2's #30448 (settings-service.ts) and seat 5's #30548 (service-settings manifests and translations) are recorded in the order; second to land merges
main.Dispatch order:
/mnt/project-files/server-seat4/dispatch-30455.md(project shared folder). Ruling section: triage 6658680630 (p3); the seat picks "serve the sourced options from the manifest list and name the carve-out in the spec description". Dispatched on the maintainer's 「任务很多,车道尽量跑满并发」.Fixes #30455.Posted 2026-11-05T15:22Z.
objectstack-fleet commentedon Nov 5, 2026
domain:server#4 · os-bill · session_01Utp6CZMkHvuDeVYgTD73qF
os-dev-report
Status: done. Draft PR #30568 carries
Fixes #30455, head1b5ca0e2.What it does:
SettingsService.getManifest()andlistManifests()now go throughservedManifest, the one resolution the namespace read already used, with no values in effect, so a key with a registered option source (localization.locale) carries the options a save is judged against; every other key, and a sourced key whose source has no answer, carries its declared table, returned as the registered object itself.GET /api/settingspasses the request's language. The registered manifest is never changed.valueDomainTSDoc insettings-manifest.zod.tsnames the runtime option source as the other mover of a select's enforcement boundary (declaredoptions= fallback; a runtime registration, not an authorable key). TSDoc only, no.describe()change;check:generated14 of 14 up to date.['en', 'zh-CN', 'fr-FR', 'vi-VN'],GET /api/settings'slocaleoptions equal the namespace read's andgetManifest/listManifestsanswer the same; every listed value saves, the declaredja-JPthe list leaves out is refused naming exactly the listed values.Deviations: none from the order. The session-context step that sets an assignee and requests a review through GitHub MCP was skipped: the order forbids MCP writes and os-dev rule 2 leaves both to the seat. The relay
pr_createansweredHTTP 500fromPOST /pullstwice (runs 42061968319, 42062121265; no PR created, checked by a head-filtered pulls read before each retry); the third (run 42062916869) created #30568 with an identical read-back. The firstgit pushof the merge was refused by the remote (fatal error in commit_refs_rules) and went through on retry.{ "issue": 30455, "status": "done", "branch": "claude/project-thread-3uylj0", "pr": "https://github.com/objectstack-ai/objectstack/pull/30568", "session": "session_01Utp6CZMwT3iajiQDWrXgCn", "premise_still_valid": true, "summary": "getManifest and listManifests (and so GET /api/settings) now return servedManifest(reg, namespace, {}, display), the namespace read's resolution, so localization.locale's manifest-list options are the i18n service's list the save judges against instead of the declared four. Both take an optional display argument; the list route passes the request locale. The spec valueDomain TSDoc names the option-source carve-out beside valueDomain.", "tests": "service-settings test 69 files 1172 passed; typecheck exit 0 (os-verify-lock, before the main merge; merged commits touch platform-objects and rest only). localization-locale-options.test.ts 15 passed: one new case (manifest list = namespace read = save boundary on a four-locale deployment), one adjusted (registered manifest unchanged, read once the source has no answer). Ablation via scripts/ablation-replace.mjs: listManifests returning reg.manifest gives 1 of 15 red (the new case); restored, blob 0d3acb6b equal to HEAD, git diff HEAD empty.", "gates": "At 1b5ca0e2 after pnpm install --frozen-lockfile (exit 0) and turbo build 119/119 (lock VERDICT command-exit 0): dispatch-gates --commands --repo objectstack-ai/objectstack derived 83 families; 83 of 83 exit 0, recorded before any pipe; --ran: 83 derived, 83 run, 0 NOT-MEASURED, exit 0. pnpm lint exit 0. spec build exit 0, check:generated 14/14 up to date. CI check-runs on #30568: not yet reported at report time.", "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm", "line_budget": "source +43 -13 (4 files: settings-service.ts, settings-service.types.ts, settings-routes.ts, settings-manifest.zod.ts), tests +38 -1 (1 file), changeset +14 (1 file); 6 files, +95 -14", "files_changed": ".changeset/30455-manifest-list-serves-sourced-options.md, packages/services/service-settings/src/{localization-locale-options.test.ts, settings-routes.ts, settings-service.ts, settings-service.types.ts}, packages/spec/src/system/settings-manifest.zod.ts", "deviations": "none from the order; session-context MCP assignee/reviewer step skipped per the order's no-MCP-write line; relay pr_create HTTP 500 twice before success (no duplicate PR); one push refused by the remote then accepted on retry", "mcp_calls": "0", "api_writes": "4 relay dispatches (3 pr_create, of which 2 failed at HTTP 500 creating nothing, 1 created #30568) plus this report comment via post-stamped; 2 git push", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [] }Report taken 2026-11-05T16:19Z.
objectstack-fleet commentedon Nov 5, 2026
domain:server#4 · os-bill · session_01Utp6CZMkHvuDeVYgTD73qF
Landed · PR #30568 · card closed
b55d6ab9;Fixes #30455closes this card. Seat record 6663832030 on head1b5ca0e2(not BREAKING, not governed,Clause-②: no).mainsourcepackages/services/service-settings/src/settings-service.ts:1584return this.servedManifest(reg, namespace, {}, display);(getManifest;listManifestsandGET /api/settingsresolve the same way).The card's label
pm:dispatchedand theos-billassignee come off with this comment.Posted 2026-11-05T17:20Z.