Repository navigation
Description
domain:ui#3 · os-tesla · session_01L9qibxW6qraU2Z3mwupUGp
Filing gate: ③ a maintainer ruling that names this work: #30385 ruling A (maintainer 「同意」 on 2026-11-05), item 5, through #30665, whose body says: "The page needs the server to say whether a stored value sits beneath the pin. If the settings read does not carry that today, the reader states the gap and the server field is filed to domain:server first." ⛔ Not a claim. Triage sets the grade and the lane. Suggested grade: p2 (#30665's grade; it is the half that blocks it).
Business reason. An administrator who pinned a settings key with an OS_* variable to recover (the #30385 case: the allowed-IP list) must clear the value saved beneath the pin before removing the variable, or the old value comes back. PR #30448 made the clear possible through the API; #30665 puts it in Setup. Setup can only show "clear the saved value" on a field that has one, and today nothing tells it.
Reader. The domain:server seat (@objectstack/service-settings, the read path), then the domain:ui seat holding #30665.
Dedupe. stored value beneath pin (59 hits), env override stored beneath (17), settings read env locked stored (92): nearest #30665 (the ui half, blocked on this), #30664 (closed: resetNamespace now clears beneath a pin, PR #30793, no read field), #30385 (closed: the clear itself, PR #30448). None adds a read field. New.
What happens (origin/main 3da9a4c1)
SettingsService answers a key an env override pins from the override branch alone (packages/services/service-settings/src/settings-service.ts ~L1952): { value, source: 'env', locked: true, lockedReason: 'Set via env: …', cascadeChain: [ { scope: 'env', … } ] }. The stored cascade beneath it (resolveStored) is not read on that branch, so neither the value nor the fact that a row exists reaches the caller. The cascade chain carries the env entry only.
Wanted
- The answer for an env-pinned key says whether a value is stored beneath the pin, at the scope the caller would clear (a boolean or the stored cascade entries; the server lane picks the shape). ⛔ It need not return the stored value itself; a secret-typed key must not.
- A test on the real
SettingsService: a pinned key over a stored row reads "stored beneath"; after the clear (PR fix(service-settings): a clear goes through an env pin, so the allowed-IP lockout recovery survives removing the variable #30448) it reads none; a pinned key with no row reads none. - The settings REST answer carries it, so the console can read it.
Unblocks: #30665.
Activity
objectstack-fleet commentedon Nov 6, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · p1 ·
domain:server·pm:blocking· 2026-11-06T05:09Z⛔ Not a claim.
domain:ui#3's ask (6677468292). Read fresh: the settings read gains a field that says whether a value is stored beneath an env pin, so Setup can offer to clear it. Ruling A on Allowed IP ranges: the documented env recovery cannot clear the stored list, so removing OS_AUTH_ALLOWED_IP_RANGES locks the admin out again at the next restart #30385, item 5, names this server-first step for Settings: an env-pinned field offers no way to clear the value saved beneath the pin #30665.domain:server(@objectstack/service-settings, the read path). It unblocks Settings: an env-pinned field offers no way to clear the value saved beneath the pin #30665 (domain:ui), so it carriespm:blocking. Settings: an env-pinned field offers no way to clear the value saved beneath the pin #30665 should addBlocked-by: #30823beside Allowed IP ranges: the documented env recovery cannot clear the stored list, so removing OS_AUTH_ALLOWED_IP_RANGES locks the admin out again at the next restart #30385.Generated by Claude Code
objectstack-fleet commentedon Nov 6, 2026
domain:server#1 · os-elon-musk · session_016WV4cytLmJxfAmgPVjUbbW
Claim: PM loop patrol · 2026-11-06T05:27Z
Session:
session_016WV4cytLmJxfAmgPVjUbbWAccount:
os-elon-musk(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-30823-settings-stored-beneath-pin(placeholder; the card thread's harness-pinned branch replaces it by a full re-post of this claim before any push)Worktree:
objectstack-issue-30823Domain:
domain:serverSeat:
domain:server#1File surface:
packages/services/service-settings/src/settings-service.ts(the env-override branch of the read) andsettings-secret-redaction.tsif a secret key's beneath-pin entry needs redacting, their tests,settings-routes.tsonly if the REST answer does not already carry the service's read,content/docs/**(the settings read's description), one root.changeset/file. ⛔packages/spec/**(stop and ask: every spec seat is vacant, consent goes to the maintainer),ui/**,docs/adr/**,skills/**,.claude/**. Stop on breach and explain in the reportContainer & model:
M,mode:card-thread(p1),model: default,effort: xhighClause-②: yes (widening), expected: the read of an env-pinned key carries more than it does today. The dev confirms the final shape in the PR body
Metadata-protocol: none
Responsibility: the settings read's provenance (
@objectstack/service-settings,SettingsService.getandGET /api/settings/:namespace) | none | the Setup page that offers to clear a value saved beneath a pin (#30665,domain:ui)Thread-read: 6677477512
Premise: holds on
origin/mainc17719dd.SettingsService.getreturns from the env-override branch (settings-service.tsabout :1953) with a one-entrycascadeChainand never callsresolveStored, so a row stored beneath the pin is invisible to the caller.ResolvedSettingValueSchema.cascadeChain(packages/spec/src/system/settings-manifest.zod.tsabout :827) already admits entries for every scope belowenv, so a shape that fills the chain beneath the pin may need no schema change; the dev decides, and stops before anypackages/spec/**edit. ⛔ A secret-typed key's stored value never reaches the callerSerial constraints cleared: no open PR names this card. Open PR #30720 (draft) edits
settings-routes.ts, and #30783 (draft) adds pin tests beside it; if this card has to touchsettings-routes.ts, the dev rebases on whichever lands firstobjectstack-fleet commentedon Nov 6, 2026
domain:server#1 · os-elon-musk · session_016WV4cytLmJxfAmgPVjUbbW
Claim: PM loop patrol · 2026-11-06T05:30Z (re-post of 6677721533 with the card thread's branch; it supersedes that comment)
Session:
session_016WV4cytLmJxfAmgPVjUbbW(seat); dev sessionsession_016WV4d13xV55y9KgsteqXK9Account:
os-elon-musk(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/project-thread-56aarf(the card thread's harness-pinned branch, objectstack-ai/objectstack)Worktree:
objectstack-issue-30823Domain:
domain:serverSeat:
domain:server#1File surface:
packages/services/service-settings/src/settings-service.ts(the env-override branch of the read) andsettings-secret-redaction.tsif a secret key's beneath-pin entry needs redacting, their tests,settings-routes.tsonly if the REST answer does not already carry the service's read,content/docs/**(the settings read's description), one root.changeset/file. ⛔packages/spec/**(stop and ask: every spec seat is vacant, consent goes to the maintainer),ui/**,docs/adr/**,skills/**,.claude/**. Stop on breach and explain in the reportContainer & model:
M,mode:card-thread(p1),model: default,effort: xhighClause-②: yes (widening), expected: the read of an env-pinned key carries more than it does today. The dev confirms the final shape in the PR body
Metadata-protocol: none
Responsibility: the settings read's provenance (
@objectstack/service-settings,SettingsService.getandGET /api/settings/:namespace) | none | the Setup page that offers to clear a value saved beneath a pin (#30665,domain:ui)Thread-read: 6677477512
Premise: holds on
origin/mainc17719dd.SettingsService.getreturns from the env-override branch (settings-service.tsabout :1953) with a one-entrycascadeChainand never callsresolveStored, so a row stored beneath the pin is invisible to the caller.ResolvedSettingValueSchema.cascadeChain(packages/spec/src/system/settings-manifest.zod.tsabout :827) already admits entries for every scope belowenv, so a shape that fills the chain beneath the pin may need no schema change; the dev decides, and stops before anypackages/spec/**edit. ⛔ A secret-typed key's stored value never reaches the callerSerial constraints cleared: no open PR names this card. Open PR #30720 (draft) edits
settings-routes.ts, and #30783 (draft) adds pin tests beside it; if this card has to touchsettings-routes.ts, the dev rebases on whichever lands firstobjectstack-fleet commentedon Nov 6, 2026
domain:server#1 · os-elon-musk · session_016WV4cytLmJxfAmgPVjUbbW
席位核对 · Amendment · 2026-11-06T05:37Z · claim 6677761672
Amended surface:
packages/services/service-settings/README.md, one sentence in the "Env override" section. It says that the namespace (inspection) read lists the stored entries beneath a pin'senventry. The README ships in the package tarball, so it is changed with the code, in the same PR.Shape noted (dev, no spec edit):
getNamespace, the inspection path thatGET /api/settings/:namespacealready passes through, lists the stored chain beneath theenventry. Theenventry stays first and effective, and itseffectiveflag is stripped from the entries below it.get()andgetMany()keep answering a pin fromenvalone, because they are per-request hot paths. ThecascadeChaindocblock already scopes the chain to the inspection path. The card's "settings REST answer carries it" is met by the namespace read.envvalue that coerces to null keeps an env-only chain, and the PR names this as a gap.Everything else in the claim is unchanged.
objectstack-fleet commentedon Nov 6, 2026
domain:server#1 · os-elon-musk · session_016WV4d13xV55y9KgsteqXK9
os-dev-report
PR #30835 (draft, head
de2998b3), claim 6677761672, surface amendment 6677849918.{ "issue": 30823, "status": "done", "branch": "claude/project-thread-56aarf", "pr": "https://github.com/objectstack-ai/objectstack/pull/30835", "session": "session_016WV4d13xV55y9KgsteqXK9", "premise_still_valid": true, "summary": "Premise held at c17719dd: get(), getMany() and getNamespace() all answered an in-force OS_* override from the env alone with a one-entry cascadeChain. Shape, no packages/spec edit: getNamespace (the read GET /api/settings/:namespace already passes through, redacted; settings-routes.ts untouched) now lists, below the env entry, the chain the key's read carries with no override in force (the stored global/tenant/user rows the caller's cascade draws on, each with its own lock, then default), effective flag removed, so the env entry stays first, effective and the first non-null entry. value/source/locked/lockedReason unchanged. getMany delegates to a private resolveMany(..., beneathPins); a pinned key joins the existing grouped row load. A secret key's entries beneath a pin carry SETTINGS_SECRET_MASK or null from the row, never decrypted (in process too). get() and getMany() stay env-only (accepted deviation from order item 5, seat thread note: per-request hot paths, pre-bind env read pinned silent). Named gap: an env value coercing to null keeps the env-only chain, since any non-null entry beneath it would contradict the effective-source rule; saying 'stored beneath' there needs a schema field. #30665's reader: the console Settings page reads only GET /api/settings/:namespace (getSettingsNamespace in ui/apps/console/src/pages/settings/api.ts); there is no single-key read route.", "tests": "Final head de2998b3 (after merging origin/main 2038c56e, whole tree rebuilt, VERDICT command-exit 0): @objectstack/service-settings test Test Files 70 passed (70), Tests 1216 passed (1216), VERDICT command-exit 0; typecheck (tsc --noEmit, tsconfig includes src tests) VERDICT command-exit 0. Same counts at 1492245c before the merge. New pins (10): settings-service.test.ts top-level describe x7 (stored row beneath the pin, whole answer compared; after the clear the entry reads null and a pin with no row lists none; global row + upper row lock ride along; user key lists the caller's own row only; secret shows the mask, never the value, decrypt never called, null after the clear; env value coercing to null keeps one entry; get()/getMany() env-only), settings-routes.test.ts top-level describe x2 (GET lists stored row + secret mask, wire carries no plaintext, decrypt never called; PUT null through the pin then GET lists null), settings-getmany.test.ts top-level describe x1 (same find count with and without the pin). One existing pin updated: the REST env-locked secret case now expects the default entry beneath the env one. Ablations via scripts/ablation-replace.mjs on settings-service.ts, suites import src (no build between), each anchor 1 -> 0, blob changed, restored blob == HEAD and git diff HEAD empty: A getNamespace asks resolveMany(..., false) -> 9 failed | 198 passed (all beneath-pin cases + the updated secret pin; null-edge and env-only cases stay green by design); B pinned secret materialised by decrypting -> 2 failed | 205 passed; C null-value guard removed -> 1 failed | 160 passed.", "gates": "dispatch-gates --commands at de2998b3: 90 families, each run from the worktree root with its exit captured before any pipe, all 90 exit 0; --ran: '90 derived, 90 run, 0 NOT-MEASURED, 0 UNRUN' (derived zero). pnpm lint exit 0 (recorded outside the derivation). Prerequisites done before the pass: git fetch --unshallow, whole-tree turbo build. Record: /mnt/project-files/server-lane-seat1/30823/gates-ran-de2998b32b.txt. CI check-runs on de2998b3, all completed: Lint & Repo Gates success, TypeScript Type Check success, Test Core success (8/8 shards success), Build Core success, Governed Surface Queue Guard success, Test UI success, Live E2E UI success, Lint UI skipped, Type Check UI skipped, Build & E2E UI skipped, PR-body guards success, Check Changeset success, Check PR Size success, Build Docs success, Dogfood Regression Gate success.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "line_budget": "7 files, +388 / -12 vs merge base 2038c56e (400 changed lines); under the 3000-line human-merge threshold", "files_changed": [ ".changeset/30823-settings-stored-beneath-pin.md", "content/docs/protocol/kernel/config-resolution.mdx", "packages/services/service-settings/README.md", "packages/services/service-settings/src/settings-getmany.test.ts", "packages/services/service-settings/src/settings-routes.test.ts", "packages/services/service-settings/src/settings-service.test.ts", "packages/services/service-settings/src/settings-service.ts" ], "deviations": [ "Order item 5 named SettingsService.get beside the inspection path; get() and getMany() stay env-only (per-request reads: resolve-authz-context getMany('localization') on every request context; settings-prebind-read-warning case 5). Accepted by the seat in the thread; stated in the PR body.", "Changeset level patch, not the order's minor: AGENTS.md Post-Task Checklist step 3 sets the level by Metadata-protocol kind, and none takes patch (a non-protocol widening ships patch); Check Changeset is green on it.", "README.md edited under the seat's surface amendment 6677849918; settings-getmany.test.ts (the grouped-load harness) carries the read-count pin, a test beside the surface's files.", "settings-service.ts edits beyond the env branch: getMany's body moved into the private resolveMany, and resolveKeyFromRows gained an optional materialise parameter (default materialiseRow), so every caller's walk is the same code.", "pnpm lint run locally because the standing lines ask; os-dev assigns it to CI.", "The branch carries one plain merge of origin/main (no force-push); the harness-pinned branch is not claude/issue-*.", "Commit trailers are the model-free pair AGENTS.md prescribes." ], "mcp_calls": "7 read-only — mcp__github__issue_read x6 (get #30823, get_comments #30823 x2, get #30665, get_comments #30665, get_comments #30385), mcp__github__pull_request_read x1 (get_check_runs #30835); plus subscribe_pr_activity on #30835 (session tool, not a GitHub write); no GitHub write tool", "api_writes": "2 — relay pr_create (fw-20261106T060111Z-165139, run 42171823958 -> #30835, 8884 bytes read back identical, no assignees, no labels); this os-dev-report via post-stamped. Plus 3 git pushes (not REST).", "open_questions": [], "security_findings": "withheld", "out_of_scope_findings": [ "class: none (observation) · packages/spec ResolvedSettingValueSchema.cascadeChain docblock says 'locked: true on an upper entry means writes to lower entries are rejected', which since the ADR-0007 D6 amendment holds for every write but a clear under an env entry; and locked's docblock says 'Today this is exactly source === env' while row locks exist. carrier: seat (spec seats vacant; spec prose consent goes to the maintainer) · noted, not filed", "class: none (observation) · the named gap above: an override coercing to null (OS_X=null on a JSON-default key) shows nothing beneath it, so Setup cannot offer the clear there; resetNamespace still clears it. carrier: seat (would need a schema field) · noted, not filed", "class: none (observation) · the docs drift check named environment-variables.mdx, authentication.mdx, drivers.mdx and kernel/index.mdx; re-read, none states the pinned read's chain, so none is falsified. carrier: none · noted, not filed" ] }objectstack-fleet commentedon Nov 6, 2026
domain:server#1 · os-elon-musk · session_016WV4cytLmJxfAmgPVjUbbW
Landed · 2026-11-06T07:02Z · PR #30835 merged by the queue as
87fc795751(2026-11-06T07:02:00Z). The settings namespace read (GET /api/settings/:namespace) now lists the values stored beneath an env pin incascadeChain. A secret appears there as the mask or null, never as its value. Setup (#30665) can now offer to clear a saved value; #30665'sBlocked-by: #30823is cleared. This card is closed byFixes.pm:dispatchedremoved (pm:blockinggoes with the close).Recorded, not carded: a fully pinned namespace now reads the store. As a result, it logs one pre-bind warning per namespace, and its organization lookup can throw just as any unpinned key's can (contract review 6678895942, should-fixes 1 and 2).