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
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
Filing gate: ② found while documenting #30314 (PR #30382) from PR #30309's merged code at origin/mainfdad1786e8. Read from code, not measured on a live boot. ⛔ Not a claim. Triage sets lane and grade.
Reader: domain:server (packages/services/service-settings/**, packages/plugins/plugin-auth/**).
Dedupe (open AND closed): OS_AUTH_ALLOWED_IP_RANGES → #30203 (closed, the save refusal + live clear), #30313 (console shows the caller's address), #30314 (docs). None covers clearing the stored value while the env override is in force. New.
reach: an administrator who stored a list that now excludes them (a changed office address, a proxy change, a list saved before #30309's refusal).
type: Bug
While the override is in force, the key is locked. A save to allowed_ip_ranges (including an empty one) is refused with 409 SETTINGS_LOCKED (settings-routes.ts ~375–380). The stored list stays.
So the admin who got back in cannot clear or fix the stored list in Setup → Authentication. When they remove the variable, the stored list applies again at the next restart and locks them out again.
Wanted
An admin recovering through the env override can clear or correct the stored allowed_ip_ranges without leaving the variable set for good. The owning lane picks the shape. For example, a clear (an empty save, or restore-default) is allowed on a locked key, or the refusal names a supported way to drop the stored value.
Claim: PM loop round 6
Session: session_01Utp6Cbvcmv8YWFhFJwzjKL (seat) · dev thread session_01Utp6CZjAtpVuoYZBzB9n5i
Account: os-bill
Branch: claude/project-thread-3koeqm (harness-pinned thread branch; platform exception to claude/issue-<n>-<slug>)
Worktree: objectstack-issue-30385
Domain: domain:server
Seat: domain:server#2
File surface: packages/services/service-settings/src/settings-service.ts (the env-lock branch only), settings-routes.ts / settings-service.types.ts only as needed, tests; packages/plugins/plugin-auth/src/allowed-ip-ranges.ts (refusal copy) and its locale strings; content/docs/permissions/authentication.mdx and docs/HARDENING.md (the recovery sentence only); one changeset .changeset/30385-clear-env-locked-setting.md. ⛔ packages/spec/**, ui/**, apps/**, skills/**, docs/adr/**, .claude/**, content/docs/releases/** (stop on breach; explain in the report)
Container & model: M, mode:thread, model: default tier (opus) — dispatch-gates --tier: no path-derived mandate, effort: xhigh (p1)
Clause-②: yes expected (widening) — a clear of an env-pinned key that was refused 409 is stored; the dev re-declares no if neither the published service-settings surface nor its documented error contract moves; reviewed at CONTRACT_REVIEW_TIER either way
Metadata-protocol: none
Responsibility: an env override in force locks the key against every write, clears included, so the stored allowed-IP list survives the documented env recovery | the env override and the Phase-2 row locks themselves (unchanged) | every administrator recovering from an allowed-IP lockout
Thread-read: 6653992606
Premise: read, to be measured first — at 0e4dfbe2: settings-service.ts ~:2406 throws SettingsLockedError whenever effectiveEnvOverride is in force, for any patch value; settings-routes.ts ~:379 answers 409 SETTINGS_LOCKED
Serial constraints cleared: sibling seat 3 yielded this card (takes #30370, no overlap); this seat's #30312 queued behind it (same applySettings area); PR #30392 (auth-manager.ts, queued) out of surface; PR #30382 (docs) checked before the same lines; pull main before PR and before landing.
Order: project file server-seat2/dispatch-30385.md, delivered as the card thread's opening message.
{
"issue": 30385,
"status": "done",
"branch": "claude/project-thread-3koeqm",
"pr": "https://github.com/objectstack-ai/objectstack/pull/30448",
"session": "session_01Utp6CZjAtpVuoYZBzB9n5i",
"premise_still_valid": true,
"summary": "Premise measured at base 0e4dfbe2 on the real AuthPlugin + SettingsService + settings routes: with a stored allow-list refusing ::1, OS_AUTH_ALLOWED_IP_RANGES='' opens the gate, but '' and null through PUT /api/settings/auth both answer 409 SETTINGS_LOCKED (locked-by-env), resetNamespace skips the key (it resolves env), and removing the variable locks ::1 out again at the next boot. Fix (seat ruling, assumption 2): in setMany's pre-flight the env-lock branch now refuses every write but a clear (null/undefined); the clear goes on to the Phase 2 row locks, the platform-rung rule and the write predicates, then nulls the stored row as every clear does, so the key falls back to its default once the override is removed; the answer still reads source env, locked true. Every other write, '' included, stays 409. The allowed-IP refusal's recovery sentence (en, zh-CN, ja-JP, es-ES) now names the four steps that work, through the settings API because the console renders a pinned field read-only. Docs: HARDENING.md Network row, config-resolution.mdx write-error table (seat-widened surface); round 2 (contract review 6657453112, head 5c0cbbfb): service-settings README Env override (every write but a clear is 409; a clear removes the stored value and changes nothing in force) and the authentication.mdx 'If you are already locked out' bullet, rewritten to the four steps. Depends on an ADR-0007 D6 amendment, which the seat has put to the maintainer.",
"tests": "head 173cc44e: service-settings test Test Files 68 passed (68), Tests 1161 passed (1161), typecheck exit 0; plugin-auth test Test Files 224 passed (224), Tests 3955 passed | 10 skipped (3965), typecheck (tsc + examples + check:test-typecheck) exit 0. New pins: settings-service.test.ts top-level describe, 5 cases (clear under a pin: answer env/locked, reset event, default after the pin lifts; undefined is a clear beside an ordinary write; every other write incl. '' refused locked-by-env, batch stores nothing; upper-rung locked row refuses a clear locked-by-global; own-rung locked row refuses a non-platform clear, platform clear goes through); allowed-ip-ranges.pin.test.ts top-level describe, 1 end-to-end case (stored list refuses ::1, env '' admits, '' is 409 with exact details, null is 200 env/locked, remove env + restart admits ::1). Ablations via scripts/ablation-replace.mjs on settings-service.ts (both suites resolve service-settings from src, no build between; each anchor 1 -> 0, blob changed, restore blob == HEAD, git diff HEAD empty): A clear exemption removed -> service-settings 4 failed | 1 passed, plugin-auth pin 1 failed | 9 passed; B every write through the pin -> 1 failed | 4 passed, pin 1 failed | 9 passed; C clear skips Phase 2 locks -> 2 failed | 3 passed, pin 10 passed.",
"gates": "head 5c0cbbfb (round 2, docs only): dispatch-gates --commands derived 93 for the 10 changed paths; each run with its exit captured before any pipe; all 93 exit 0; --ran: '93 derived famil(ies) accounted for — 93 run, 0 NOT-MEASURED'. Run on commit b4b507a9; the pushed 5c0cbbfb carries the same tree af8723c4, its message reworded only because the pre-push check:commit-card-trailers refused a card trailer. head 173cc44e: dispatch-gates --commands derived 92; each run with its exit captured before any pipe; all 92 exit 0; --ran: '92 derived famil(ies) accounted for — 92 run, 0 NOT-MEASURED'. First round (head c1c43e27) had check:dual-build-cjs-loads and check-plugin-teardown-shape --self-test at exit 3 (no whole-workspace build; shallow checkout); after building the dogfood closure and fetching 621a4876 both exit 0. pnpm lint exit 0. Changeset gates: check-adr-0087-registration, check-empty-changeset, check-changeset-no-major exit 0. CI check-runs: in_progress at report time.",
"dogfood_battery": "173cc44e · os-verify-lock VERDICT command-exit 0 · Test Files 419 passed | 3 skipped (422) · Tests 3492 passed | 36 skipped (3528) · no failures (run because the order asks it; os-dev owes it only on a ! title or a narrowing arm)",
"line_budget": "head 5c0cbbfb: 10 files, +238 / -24 vs merge base 09720e2c (262 changed lines); under the 3000 human-merge threshold (173cc44e: 8 files, +214 / -12)",
"files_changed": [
".changeset/30385-clear-env-locked-setting.md",
"content/docs/permissions/authentication.mdx",
"content/docs/protocol/kernel/config-resolution.mdx",
"docs/HARDENING.md",
"packages/plugins/plugin-auth/src/allowed-ip-ranges.pin.test.ts",
"packages/plugins/plugin-auth/src/allowed-ip-ranges.ts",
"packages/services/service-settings/README.md",
"packages/services/service-settings/src/settings-service.test.ts",
"packages/services/service-settings/src/settings-service.ts",
"packages/services/service-settings/src/settings-service.types.ts"
],
"deviations": [
"content/docs/protocol/kernel/config-resolution.mdx (one table row) added to the file surface by the seat in the card thread: the row said an override in force always refuses a write, which this change makes false.",
"content/docs/permissions/authentication.mdx edited (round 2, head 5c0cbbfb): PR #30382 merged first (2026-11-05T10:10Z, 7d7babb1), so by the seat ruling (whichever lands second rewrites it) this PR rewrote the subsection's 'If you are already locked out' bullet to the four steps. Corrected: round 1 said #30382 was open and left the page untouched, which was stale on the head's own tree (contract review 6657453112 item 9).",
"Round 2 is one docs-only push for the contract review's two must-fixes (README Env override, authentication.mdx). It changes no code, so the suites, typecheck, lint and dogfood were not re-run on 5c0cbbfb; the derived gates were. The branch was not re-merged with origin/main for it (dispatch-gates warns the tree is 21 commits behind; the stale family files are i18n and the dispatch-gates self-test, none of which reads these docs).",
"settings-service.ts edits beyond the env-lock branch are doc comments only: set() and setMany() docblocks (the documented error contract); resetNamespace's docblock left as it was, per the seat (seat 4's card edits nearby functions).",
"Full dogfood and pnpm lint run locally because the order asks; os-dev assigns the first to ! / narrowing PRs and the second to CI.",
"Commit trailers are the model-free pair AGENTS.md prescribes, not the harness's model-named Co-Authored-By line."
],
"mcp_calls": "12 — round 2: mcp__github__issue_read get_comments #30448 (the contract review), mcp__github__pull_request_read get #30448 (the stored body), mcp__github__issue_read get_comments #30385 (this report as stored); round 1: mcp__github__issue_read x3 (get #30385, get_comments #30385 x2), mcp__github__issue_read get_comments #30203, mcp__github__pull_request_read x5 (get #30309, get_comments #30309, get #30382, get_diff #30382, get #30448); no write tool",
"api_writes": "4 relay writes — pr_create #30448 (fleet-write run 42021780433, body read back identical), this os-dev-report comment on #30385 (post-stamped), round 2: issue_patch #30448 body (fleet-write run 42028839823, 12405 bytes read back identical), comment_edit of this report (this edit); plus git pushes to the designated branch",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": [
"class: a · reach: POST /api/settings/auth/reset (built-in reset action, resetNamespace) answers 'Cleared N saved value(s); environment/default configuration is back in effect' while a row stored beneath an OS_* pin survives and applies again when the variable is removed; measured in-process at base 0e4dfbe2 (resetNamespace returned, the stored allowed_ip_ranges was read back once the env was removed) · evidence: resetNamespace builds its null patch from keys whose resolved source is global/tenant/user, and a pinned key resolves env · dedupe words: resetNamespace env locked skipped, reset action pinned key stored row, restore defaults env override",
"carrier: seat (domain:ui) · the console cannot issue the clear: SettingsField disables a locked field and hides Reset to default on it; and the env answer's cascadeChain carries only the env entry, so the console cannot tell whether a stored value lies beneath the pin (a server read to expose it would be the ui card's dependency) · noted, not filed",
"carrier: #30312 · nothing new learned: an env-pinned clear re-runs applySettings with source env, so it never reaches the default-sourced skip #30312 names · noted, not filed"
]
}
Report taken 2026-11-05T11:49Z; corrected 2026-11-05T12:38Z (round 2, head 5c0cbbf).
Ruling confirmed: letter A · ADR-0007 D6 · executed by domain:server#2.
Maintainer: 「同意」 to the recommendation, in the decision thread, 2026-11-05T21:34Z (presentation in project files decisions/30448-ADR-0007-D6-env锁定键允许清除-呈批.md).
resetNamespace and the built-in reset action are not touched here. That a reset says the key is back on env/default while a stored value stays beneath the pin is a separate p3 card; it does not block this one.
ADR-0007 gets a one-line amendment in its own PR (Tier H; reviewers os-zhuang and hotlong): the Status line gains Amended (2026-11-05, #30385 — D6: a clear (null) of an env-pinned key is not refused; it clears the stored value beneath the override and changes nothing in force), the D6 sentence and the REST table each gain the same half-sentence, with its scripts/adr-anchors/ anchor file.
The ui half (a clear control on a locked field, which needs the server to say whether a stored value sits beneath the pin) is a separate domain:ui card, Blocked-by: #30385.
State change: none; the card stays pm:dispatched with the seat until #30448 lands.
Release: session_01Utp6Cbvcmv8YWFhFJwzjKL (domain:server#2) · reason: seat sign-off · to: pm:queue for the next server seat.
Maintainer: 「开发中的尽快收工」, project chat, 2026-11-05T22:01Z.
Resume-from: claude/project-thread-3koeqm@4153daa426dfe5c6c5413c815e56b97e4bc6de53
State at release. The code PR is #30448, draft at that head, mergeable clean. It stays in the shape ruling 6670154789 ratifies (letter A): a clear (null) of an env-pinned key is let through, and resetNamespace / the reset action are not touched. The maintainer's later 「同意」 in another thread has been read as possibly covering reset as well. Unless the maintainer rules otherwise, the reset half stays on #30664; if the maintainer answers A+, the next seat widens #30664, not #30448.
Owed, in order:
The ADR-0007 D6 one-line amendment PR, per item 3 of the ruling (Tier H; reviewers os-zhuang and hotlong).
Claim: re-claim after Release 6670837769, on the maintainer's order that this seat takes the card back and finishes it before signing off.
Maintainer: 「ADR-0007 D6 修订 PR(Tier H)先合,哪个任务你也接手处理完再下班」, seat thread, 2026-11-05T22:22Z.
Session: session_01Utp6Cbvcmv8YWFhFJwzjKL (seat) · ADR dev thread session_01Utp6CaQzHSoRvseiSpfmLn
Account: os-bill
Branch: claude/project-thread-myd9f0 (the ADR PR; harness-pinned thread branch) · code PR #30448 stays on claude/project-thread-3koeqm@4153daa4
Domain: domain:server
Seat: domain:server#2
File surface (ADR PR): docs/adr/0007-settings-manifest-and-kv-store.md (Status line, D6 sentence, REST-table row, per ruling 6670154789 item 3); optionally one scripts/adr-anchors/ file if a gate asks. ⛔ everything else.
Clause-②: no (records behaviour #30448 ships) · Metadata-protocol: none · Tier H: reviewers os-zhuang and hotlong
Order: the ADR PR merges first; then #30448 merges main, gets the seat ACCEPT and is queued. The reset half stays on #30664.
Thread-read: 6670837769
Order file: project files server-seat2/dispatch-30385-adr.md.
Activity
objectstack-fleet commentedon Nov 5, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: first-touch audit · p1 ·
domain:serverkept ·pm:queue· 2026-11-05T09:02Z⛔ Not a claim.
OS_AUTH_ALLOWED_IP_RANGES) cannot clear the stored list. Removing the env var restores the stored list, so the admin is locked out again. A lockout whose documented recovery does not work, so p1, as Authentication settings: turning off email and password with no other sign-in method saves without warning, and everyone is locked out #30202.findingleaves the card now that it is graded.d1d90b70) and the docs card Docs: authentication page should state that an allowed IP ranges save excluding your own address is refused, and how to recover with OS_AUTH_ALLOWED_IP_RANGES #30314, which must state the working recovery.Generated by Claude Code
objectstack-fleet commentedon Nov 5, 2026
domain:server#2 · os-bill · session_01Utp6Cbvcmv8YWFhFJwzjKL
Claim: PM loop round 6
Session:
session_01Utp6Cbvcmv8YWFhFJwzjKL(seat) · dev threadsession_01Utp6CZjAtpVuoYZBzB9n5iAccount:
os-billBranch:
claude/project-thread-3koeqm(harness-pinned thread branch; platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-30385Domain:
domain:serverSeat:
domain:server#2File surface:
packages/services/service-settings/src/settings-service.ts(the env-lock branch only),settings-routes.ts/settings-service.types.tsonly as needed, tests;packages/plugins/plugin-auth/src/allowed-ip-ranges.ts(refusal copy) and its locale strings;content/docs/permissions/authentication.mdxanddocs/HARDENING.md(the recovery sentence only); one changeset.changeset/30385-clear-env-locked-setting.md. ⛔packages/spec/**,ui/**,apps/**,skills/**,docs/adr/**,.claude/**,content/docs/releases/**(stop on breach; explain in the report)Container & model:
M,mode:thread,model: default tier (opus) — dispatch-gates --tier: no path-derived mandate,effort: xhigh(p1)Clause-②: yes expected (widening) — a clear of an env-pinned key that was refused 409 is stored; the dev re-declares
noif neither the published service-settings surface nor its documented error contract moves; reviewed atCONTRACT_REVIEW_TIEReither wayMetadata-protocol: none
Responsibility: an env override in force locks the key against every write, clears included, so the stored allowed-IP list survives the documented env recovery | the env override and the Phase-2 row locks themselves (unchanged) | every administrator recovering from an allowed-IP lockout
Thread-read: 6653992606
Premise: read, to be measured first — at
0e4dfbe2:settings-service.ts~:2406 throwsSettingsLockedErrorwhenevereffectiveEnvOverrideis in force, for any patch value;settings-routes.ts~:379 answers409 SETTINGS_LOCKEDSerial constraints cleared: sibling seat 3 yielded this card (takes #30370, no overlap); this seat's #30312 queued behind it (same
applySettingsarea); PR #30392 (auth-manager.ts, queued) out of surface; PR #30382 (docs) checked before the same lines; pullmainbefore PR and before landing.Order: project file
server-seat2/dispatch-30385.md, delivered as the card thread's opening message.objectstack-fleet commentedon Nov 5, 2026
domain:server#2 · os-bill · session_01Utp6CZjAtpVuoYZBzB9n5i
os-dev-report
{ "issue": 30385, "status": "done", "branch": "claude/project-thread-3koeqm", "pr": "https://github.com/objectstack-ai/objectstack/pull/30448", "session": "session_01Utp6CZjAtpVuoYZBzB9n5i", "premise_still_valid": true, "summary": "Premise measured at base 0e4dfbe2 on the real AuthPlugin + SettingsService + settings routes: with a stored allow-list refusing ::1, OS_AUTH_ALLOWED_IP_RANGES='' opens the gate, but '' and null through PUT /api/settings/auth both answer 409 SETTINGS_LOCKED (locked-by-env), resetNamespace skips the key (it resolves env), and removing the variable locks ::1 out again at the next boot. Fix (seat ruling, assumption 2): in setMany's pre-flight the env-lock branch now refuses every write but a clear (null/undefined); the clear goes on to the Phase 2 row locks, the platform-rung rule and the write predicates, then nulls the stored row as every clear does, so the key falls back to its default once the override is removed; the answer still reads source env, locked true. Every other write, '' included, stays 409. The allowed-IP refusal's recovery sentence (en, zh-CN, ja-JP, es-ES) now names the four steps that work, through the settings API because the console renders a pinned field read-only. Docs: HARDENING.md Network row, config-resolution.mdx write-error table (seat-widened surface); round 2 (contract review 6657453112, head 5c0cbbfb): service-settings README Env override (every write but a clear is 409; a clear removes the stored value and changes nothing in force) and the authentication.mdx 'If you are already locked out' bullet, rewritten to the four steps. Depends on an ADR-0007 D6 amendment, which the seat has put to the maintainer.", "tests": "head 173cc44e: service-settings test Test Files 68 passed (68), Tests 1161 passed (1161), typecheck exit 0; plugin-auth test Test Files 224 passed (224), Tests 3955 passed | 10 skipped (3965), typecheck (tsc + examples + check:test-typecheck) exit 0. New pins: settings-service.test.ts top-level describe, 5 cases (clear under a pin: answer env/locked, reset event, default after the pin lifts; undefined is a clear beside an ordinary write; every other write incl. '' refused locked-by-env, batch stores nothing; upper-rung locked row refuses a clear locked-by-global; own-rung locked row refuses a non-platform clear, platform clear goes through); allowed-ip-ranges.pin.test.ts top-level describe, 1 end-to-end case (stored list refuses ::1, env '' admits, '' is 409 with exact details, null is 200 env/locked, remove env + restart admits ::1). Ablations via scripts/ablation-replace.mjs on settings-service.ts (both suites resolve service-settings from src, no build between; each anchor 1 -> 0, blob changed, restore blob == HEAD, git diff HEAD empty): A clear exemption removed -> service-settings 4 failed | 1 passed, plugin-auth pin 1 failed | 9 passed; B every write through the pin -> 1 failed | 4 passed, pin 1 failed | 9 passed; C clear skips Phase 2 locks -> 2 failed | 3 passed, pin 10 passed.", "gates": "head 5c0cbbfb (round 2, docs only): dispatch-gates --commands derived 93 for the 10 changed paths; each run with its exit captured before any pipe; all 93 exit 0; --ran: '93 derived famil(ies) accounted for — 93 run, 0 NOT-MEASURED'. Run on commit b4b507a9; the pushed 5c0cbbfb carries the same tree af8723c4, its message reworded only because the pre-push check:commit-card-trailers refused a card trailer. head 173cc44e: dispatch-gates --commands derived 92; each run with its exit captured before any pipe; all 92 exit 0; --ran: '92 derived famil(ies) accounted for — 92 run, 0 NOT-MEASURED'. First round (head c1c43e27) had check:dual-build-cjs-loads and check-plugin-teardown-shape --self-test at exit 3 (no whole-workspace build; shallow checkout); after building the dogfood closure and fetching 621a4876 both exit 0. pnpm lint exit 0. Changeset gates: check-adr-0087-registration, check-empty-changeset, check-changeset-no-major exit 0. CI check-runs: in_progress at report time.", "dogfood_battery": "173cc44e · os-verify-lock VERDICT command-exit 0 · Test Files 419 passed | 3 skipped (422) · Tests 3492 passed | 36 skipped (3528) · no failures (run because the order asks it; os-dev owes it only on a ! title or a narrowing arm)", "line_budget": "head 5c0cbbfb: 10 files, +238 / -24 vs merge base 09720e2c (262 changed lines); under the 3000 human-merge threshold (173cc44e: 8 files, +214 / -12)", "files_changed": [ ".changeset/30385-clear-env-locked-setting.md", "content/docs/permissions/authentication.mdx", "content/docs/protocol/kernel/config-resolution.mdx", "docs/HARDENING.md", "packages/plugins/plugin-auth/src/allowed-ip-ranges.pin.test.ts", "packages/plugins/plugin-auth/src/allowed-ip-ranges.ts", "packages/services/service-settings/README.md", "packages/services/service-settings/src/settings-service.test.ts", "packages/services/service-settings/src/settings-service.ts", "packages/services/service-settings/src/settings-service.types.ts" ], "deviations": [ "content/docs/protocol/kernel/config-resolution.mdx (one table row) added to the file surface by the seat in the card thread: the row said an override in force always refuses a write, which this change makes false.", "content/docs/permissions/authentication.mdx edited (round 2, head 5c0cbbfb): PR #30382 merged first (2026-11-05T10:10Z, 7d7babb1), so by the seat ruling (whichever lands second rewrites it) this PR rewrote the subsection's 'If you are already locked out' bullet to the four steps. Corrected: round 1 said #30382 was open and left the page untouched, which was stale on the head's own tree (contract review 6657453112 item 9).", "Round 2 is one docs-only push for the contract review's two must-fixes (README Env override, authentication.mdx). It changes no code, so the suites, typecheck, lint and dogfood were not re-run on 5c0cbbfb; the derived gates were. The branch was not re-merged with origin/main for it (dispatch-gates warns the tree is 21 commits behind; the stale family files are i18n and the dispatch-gates self-test, none of which reads these docs).", "settings-service.ts edits beyond the env-lock branch are doc comments only: set() and setMany() docblocks (the documented error contract); resetNamespace's docblock left as it was, per the seat (seat 4's card edits nearby functions).", "Full dogfood and pnpm lint run locally because the order asks; os-dev assigns the first to ! / narrowing PRs and the second to CI.", "Commit trailers are the model-free pair AGENTS.md prescribes, not the harness's model-named Co-Authored-By line." ], "mcp_calls": "12 — round 2: mcp__github__issue_read get_comments #30448 (the contract review), mcp__github__pull_request_read get #30448 (the stored body), mcp__github__issue_read get_comments #30385 (this report as stored); round 1: mcp__github__issue_read x3 (get #30385, get_comments #30385 x2), mcp__github__issue_read get_comments #30203, mcp__github__pull_request_read x5 (get #30309, get_comments #30309, get #30382, get_diff #30382, get #30448); no write tool", "api_writes": "4 relay writes — pr_create #30448 (fleet-write run 42021780433, body read back identical), this os-dev-report comment on #30385 (post-stamped), round 2: issue_patch #30448 body (fleet-write run 42028839823, 12405 bytes read back identical), comment_edit of this report (this edit); plus git pushes to the designated branch", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "class: a · reach: POST /api/settings/auth/reset (built-in reset action, resetNamespace) answers 'Cleared N saved value(s); environment/default configuration is back in effect' while a row stored beneath an OS_* pin survives and applies again when the variable is removed; measured in-process at base 0e4dfbe2 (resetNamespace returned, the stored allowed_ip_ranges was read back once the env was removed) · evidence: resetNamespace builds its null patch from keys whose resolved source is global/tenant/user, and a pinned key resolves env · dedupe words: resetNamespace env locked skipped, reset action pinned key stored row, restore defaults env override", "carrier: seat (domain:ui) · the console cannot issue the clear: SettingsField disables a locked field and hides Reset to default on it; and the env answer's cascadeChain carries only the env entry, so the console cannot tell whether a stored value lies beneath the pin (a server read to expose it would be the ui card's dependency) · noted, not filed", "carrier: #30312 · nothing new learned: an env-pinned clear re-runs applySettings with source env, so it never reaches the default-sourced skip #30312 names · noted, not filed" ] }Report taken 2026-11-05T11:49Z; corrected 2026-11-05T12:38Z (round 2, head 5c0cbbf).
Generated by Claude Code
Merge origin/main into claude/project-thread-3koeqm
objectstack-fleet commentedon Nov 5, 2026
domain:server#2 · os-bill · session_01Utp6Cbvcmv8YWFhFJwzjKL
Ruling confirmed: letter A · ADR-0007 D6 · executed by
domain:server#2.Maintainer: 「同意」 to the recommendation, in the decision thread, 2026-11-05T21:34Z (presentation in project files
decisions/30448-ADR-0007-D6-env锁定键允许清除-呈批.md).What A binds.
null, andundefinedat the service layer) throughset/setMany/PUTis no longer refused on an env-pinned key; it sets the stored value tonull(wording: "clears the stored value", never "deletes the row"). A non-clear write (an empty string included) is still refused409 locked-by-env. The badge and the audit row do not change.resetNamespaceand the built-in reset action are not touched here. That a reset says the key is back on env/default while a stored value stays beneath the pin is a separate p3 card; it does not block this one.Amended (2026-11-05, #30385 — D6: a clear (null) of an env-pinned key is not refused; it clears the stored value beneath the override and changes nothing in force), the D6 sentence and the REST table each gain the same half-sentence, with itsscripts/adr-anchors/anchor file.mainonce more before landing.domain:uicard,Blocked-by: #30385.State change: none; the card stays
pm:dispatchedwith the seat until #30448 lands.objectstack-fleet commentedon Nov 5, 2026
domain:server#2 · os-bill · session_01Utp6Cbvcmv8YWFhFJwzjKL
Release:
session_01Utp6Cbvcmv8YWFhFJwzjKL(domain:server#2) · reason: seat sign-off · to:pm:queuefor the next server seat.Maintainer: 「开发中的尽快收工」, project chat, 2026-11-05T22:01Z.
Resume-from:
claude/project-thread-3koeqm@4153daa426dfe5c6c5413c815e56b97e4bc6de53State at release. The code PR is #30448, draft at that head, mergeable clean. It stays in the shape ruling 6670154789 ratifies (letter A): a clear (
null) of an env-pinned key is let through, andresetNamespace/ the reset action are not touched. The maintainer's later 「同意」 in another thread has been read as possibly covering reset as well. Unless the maintainer rules otherwise, the reset half stays on #30664; if the maintainer answers A+, the next seat widens #30664, not #30448.Owed, in order:
maininto fix(service-settings): a clear goes through an env pin, so the allowed-IP lockout recovery survives removing the variable #30448, ACCEPT it, and queue it per the skill. It touches no governed path and is not BREAKING.domain:uiclear-control card withBlocked-by: #30385(item 5), then land this card.objectstack-fleet commentedon Nov 5, 2026
domain:server#2 · os-bill · session_01Utp6Cbvcmv8YWFhFJwzjKL
Claim: re-claim after Release 6670837769, on the maintainer's order that this seat takes the card back and finishes it before signing off.
Maintainer: 「ADR-0007 D6 修订 PR(Tier H)先合,哪个任务你也接手处理完再下班」, seat thread, 2026-11-05T22:22Z.
Session:
session_01Utp6Cbvcmv8YWFhFJwzjKL(seat) · ADR dev threadsession_01Utp6CaQzHSoRvseiSpfmLnAccount:
os-billBranch:
claude/project-thread-myd9f0(the ADR PR; harness-pinned thread branch) · code PR #30448 stays onclaude/project-thread-3koeqm@4153daa4Domain:
domain:serverSeat:
domain:server#2File surface (ADR PR):
docs/adr/0007-settings-manifest-and-kv-store.md(Status line, D6 sentence, REST-table row, per ruling 6670154789 item 3); optionally onescripts/adr-anchors/file if a gate asks. ⛔ everything else.Clause-②: no (records behaviour #30448 ships) · Metadata-protocol: none · Tier H: reviewers os-zhuang and hotlong
Order: the ADR PR merges first; then #30448 merges
main, gets the seat ACCEPT and is queued. The reset half stays on #30664.Thread-read: 6670837769
Order file: project files
server-seat2/dispatch-30385-adr.md.objectstack-fleet commentedon Nov 5, 2026
domain:server#2 · os-bill · session_01Utp6Cbvcmv8YWFhFJwzjKL
os-dev-report
{ "issue": 30385, "status": "done", "branch": "claude/project-thread-myd9f0", "pr": "https://github.com/objectstack-ai/objectstack/pull/30698", "session": "session_01Utp6CaQzHSoRvseiSpfmLn", "premise_still_valid": true, "summary": "ADR-0007 D6 amendment (Tier H, docs only) per ruling A (6670154789). Behaviour re-read at PR #30448 head: settings-service.ts pre-flight `const clears = patch[key] === null || typeof patch[key] === 'undefined'; if (!clears && this.effectiveEnvOverride(...)) throw new SettingsLockedError(...)`. Three edits in docs/adr/0007-settings-manifest-and-kv-store.md exactly as ordered: Status line Amended (2026-11-05, #30385); D6 exception sentence with the superseded wording kept inline; REST table PUT row `except a null clear`. Nothing else in the ADR touched (resetNamespace wording, D-tiers, env prefixes out of scope).", "tests": "n/a — docs only, no code.", "gates": "dispatch-gates --commands on 26da6f27: 21 commands, each run with exit captured before any pipe; --ran: '21 derived, 21 run, 0 NOT-MEASURED, 0 UNRUN'. @objectstack/lint check:doc-formula-expressions first refused exit 3 (formula/lint dist missing); built per its own Fix line, re-ran exit 0.", "adr_anchor": "none added — scripts/adr-anchors/ holds no anchor for packages/services/service-settings/src/settings-service.ts, `pnpm check:adr-anchors` exit 0 without one and no derived gate asks for it.", "dogfood_battery": "n/a — docs only, no `!` in the title", "line_budget": "6 changed lines (+3/-3), 1 file", "files_changed": [ "docs/adr/0007-settings-manifest-and-kv-store.md" ], "deviations": [ "Dispatch line numbers L3/L101/L323 matched origin/main a2437b56 exactly.", "Opened draft (relay default; read back draft=true). Reviewers not requested (seat requests os-zhuang + hotlong); no assignee.", "No changeset: `skip-changeset` label rode the pr_create." ], "mcp_calls": "0", "api_writes": "2 — relay pr_create (objectstack-ai/objectstack#30698, run 42123245651); post-stamped comment on #30385 (this report). Plus git push (not a REST write).", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [] }Report taken 2026-11-05T22:39Z.
objectstack-fleet commentedon Nov 6, 2026
domain:server#2 · os-bill · session_01Utp6Cbvcmv8YWFhFJwzjKL
ACCEPT → PR #30448 comment 6674525169 (head
034aee8f), queued after ADR-0007 D6 amendment #30698 merged. The ui half is #30665 (Blocked-by: #30385); the reset half is #30664.