Skip to content

fix(config): add exclusive initial configuration publication - #3796

Merged
lidge-jun merged 11 commits into
devfrom
codex/track3-config-init-a4b0
Sep 6, 2026
Merged

fix(config): add exclusive initial configuration publication#3796
lidge-jun merged 11 commits into
devfrom
codex/track3-config-init-a4b0

Conversation

@lidge-jun

@lidge-jun lidge-jun commented Sep 6, 2026

Copy link
Copy Markdown
Owner

Summary

  • Add an exclusive configuration initializer that preserves any existing entry and publishes a complete new config through a hard link only when the target is absent. Existing explicit saveConfig updates remain unchanged.
  • Harden the private temporary file before writing credentials, retain descriptor identity, and use unlink-only cleanup. A post-publication or ambiguous filesystem error never truncates a shared inode or deletes the target.
  • Reimplement the no-replace intent and hardening lessons from feat(config): add exclusive initialize-if-missing primitive #3632 (830b09b64f), with collision, partial-publication, permissions, bookkeeping and lock regressions. The real CLI consumer follows in the next dependent PR.

Track 3 manual stack, layer 5, based on #3790. Previous layers: #3786, #3788, #3789. No native stack registration.

Verification

  • Independent Astra high C4 code/security review found no primitive blocker. The dependent consumer layer fixes and covers the separate queued-cancellation finding.
  • git diff --cached --check passed. No local tests, typecheck, builds or suites, per maintainer instruction.
  • Runtime validation: the cumulative exact-source CI evidence is recorded below; lower-layer tests are deferred under the explicit maintainer policy.
  • Atomic no-replacement is not a multi-file power-loss transaction. Unsupported/denied hard links fail explicitly; there is no overwrite fallback. Existing ownership metadata policy is unchanged and no future-uninstall ownership guarantee is added.

Cumulative tested source: 9ea896737bd17085ebb8a69b3320c9cace61889e, based on dev eff908e0fb9452d5ff2952af1c5dafc1c4c35dd9.

  • Cross-platform CI: all 25 jobs successful. Attempt 1 failed only the existing Windows cli-models first-child 15-second watchdog. One unchanged-head rerun of that shard completed 3,489 cases (3,465 pass, 24 skip, 0 fail); the first models case took 943 ms. The initial failure is retained; the slow phase remains unproven and no flakiness fix is claimed.
  • Service lifecycle: Linux, macOS and Windows passed on the same source head.
  • Documentation build: passed after checking out and asserting that exact source. Its isolated workflow-definition commit is different and is not part of this stack; no deployment occurred.
  • Independent scoped code/security and integration reviews: PASS. The two earlier Windows fixture-budget changes retain production behavior and original assertions, backed by readiness controls and quota restart controls. Diagnostic workflows, instrumentation and mutations are excluded from delivery.

The maintainer explicitly authorizes dev admin integration and final-head-first validation for this manual chain: #3786#3788#3789#3790#3796#3802. Lower automatic tests are deferred with [skip ci], not represented as passing. No local tests, typecheck, builds or suites were run; pushes used --no-verify. Merge commits preserve source ancestry and suppress duplicate lower CI; fresh head/base/actor/review checks and resulting tree checks accompany each merge.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed. User-facing consumer documentation follows with the dependent CLI change.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

Co-authored-by: SB Yoon 44089734+yansigit@users.noreply.github.com
Co-authored-by: Yumi automation@sbyoon.com

Landing confirmed: merged into dev as 443310e5dc6c5b1277e2502df89baf97e47196a0. The final chain merge is f89b815090020f52089801b50f569a777bdfdc0a; its tree 846b8ffc383fc0ba99486917bdfb820a0fa432ba equals the tested cumulative source. Source ancestry and every merge were verified after fetching dev.

Summary by CodeRabbit

  • New Features

    • Initial configuration can now be created safely when no configuration exists, while preserving existing files.
    • Memory diagnostics now identify spill-write failure origins and provide cumulative timeout counters.
  • Bug Fixes

    • Improved handling and reporting of configuration-creation races and publication failures.
    • Spill-write diagnostics now distinguish retry timeouts from memoized timeout refusals and accurately reflect recovery behavior.
  • Documentation

    • Expanded management API and Windows memory troubleshooting documentation with diagnostic field definitions, privacy guarantees, and metric behavior.

t and others added 2 commits September 7, 2026 01:53
Add closed origin and cumulative terminal-publication counters without changing ACL decisions, retry limits, memo handling, cancellation or readiness. Refs #3522; runtime recovery remains unresolved. Final stack CI pending.

Co-authored-by: Ingwannu <186453546+Ingwannu@users.noreply.github.com>
Reimplement #3632 with private hardening before bytes, no-replace hard-link publication, descriptor-identity cleanup and no truncation of shared/published inodes. Existing saveConfig updates remain unchanged. Consumer follows in the next stack layer; final CI pending.

Co-authored-by: SB Yoon <44089734+yansigit@users.noreply.github.com>
Co-authored-by: Yumi <automation@sbyoon.com>
@coderabbitai

coderabbitai Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Team

Run ID: ca1d9ec2-932e-41ce-905c-981426c41d25

📥 Commits

Reviewing files that changed from the base of the PR and between 26fa364 and d760f66.

📒 Files selected for processing (11)
  • docs-site/src/content/docs/reference/management-api.md
  • docs-site/src/content/docs/troubleshooting/windows-memory.md
  • src/config.ts
  • src/config/initialize.ts
  • src/lib/windows-secret-acl.ts
  • src/responses/state.ts
  • tests/config/config-mutation-lock.test.ts
  • tests/responses/continuation-dedup.test.ts
  • tests/responses/responses-state.test.ts
  • tests/server/memory-watchdog.test.ts
  • tests/windows/windows-secret-acl.test.ts

📝 Walkthrough

Walkthrough

The change adds atomic no-replace initialization for missing config files and classifies Windows ACL timeout origins in response-state spill metrics. It also expands tests and documents the new management API fields and diagnostic behavior.

Changes

Configuration and spill diagnostics

Layer / File(s) Summary
Initial config publication
src/config.ts, src/config/initialize.ts, tests/config/config-mutation-lock.test.ts
Adds persisted-config state observation and locked initialization. Candidates are validated, written to hardened temporary files, and published with no-replace hard links. Tests cover races, collisions, symlinks, permission failures, cleanup, and post-publication errors.
Spill failure classification and metrics
src/lib/windows-secret-acl.ts, src/responses/state.ts, tests/responses/responses-state.test.ts, tests/windows/windows-secret-acl.test.ts
Tags timeout-memo refusals, distinguishes them from retry-returned timeouts, and exposes the origin with cumulative counters. Tests cover sync and async ACL paths, recovery, bounded cause decoding, privacy filtering, and reset behavior.
Diagnostic surface and documentation
docs-site/src/content/docs/reference/management-api.md, docs-site/src/content/docs/troubleshooting/windows-memory.md, tests/responses/continuation-dedup.test.ts, tests/server/memory-watchdog.test.ts
Documents the new response fields and validates the expanded /api/system/memory response shape.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ConfigInitializer
  participant ConfigMutationLock
  participant InitialConfigPublisher
  participant ConfigGeneration
  ConfigInitializer->>ConfigMutationLock: re-check persisted config state
  ConfigInitializer->>InitialConfigPublisher: publish candidate with no-replace semantics
  InitialConfigPublisher->>ConfigInitializer: return publication result or typed error
  ConfigInitializer->>ConfigGeneration: record owned paths and bump generation
Loading
sequenceDiagram
  participant WindowsSecretAcl
  participant PendingResponseSpill
  participant SpillState
  participant ManagementMemoryEndpoint
  WindowsSecretAcl->>PendingResponseSpill: return classified timeout failure
  PendingResponseSpill->>SpillState: record failure origin and counters
  SpillState->>ManagementMemoryEndpoint: expose sanitized spill diagnostics
Loading

Suggested reviewers: luvs01

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/track3-config-init-a4b0

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

t added 3 commits September 7, 2026 02:20
Final CI 34047664926 / job 101526036510 proved 11 injected publication cases stopped at the existing default-provider validator. Populate the provider in the fixture and separately assert invalid candidates still never publish. Production validation is unchanged.
Final CI 34047664926 macOS job 101526036532 found one remaining 17-field assertion. Assert the complete reviewed 20-field API contract instead of only relaxing its count; unexpected private/replay fields still fail. Production projection is unchanged.
@lidge-jun

Copy link
Copy Markdown
Owner Author

리뷰 · 우선순위 72 / 80

지금 dev의 일반 saveConfig는 원자 교체(temp → rename)라서, 이미 있는 config.json을 업데이트할 때 쓰는 경로입니다. 그런데 ocx init처럼 “없을 때만 처음 만든다”는 요구에는 교체가 위험합니다. 경쟁 조건이나 잘못된 덮어쓰기가 있으면 사용자가 이미 가진 설정·자격 증명 바이트를 날릴 수 있습니다. 열려 있는 #3632(feat(config): add exclusive initialize-if-missing primitive)가 그 의도였고, 이 PR은 그 no-replace·hardening 교훈을 src/config/initialize.ts로 다시 구현합니다. 새 publishInitialConfigNoReplaceO_EXCL temp를 만들고, 비밀 바이트를 쓰기 전에 Windows ACL/fchmod 0600으로 굳힌 뒤, linkSync로만 목적 경로에 게시합니다. 목적지가 이미 있으면 교체하지 않고 exists/invalid로 돌아갑니다. link 실패·불확실 완료 뒤에도 shared inode를 truncate하거나 목적 파일을 unlink하지 않고, cleanup은 자기 temp 이름만 지웁니다. hard link가 거절되면(EOPNOTSUPP/EXDEV/EPERM 등) overwrite fallback 없이 InitialConfigPublicationError로 명시 실패합니다. initializePersistedConfigIfMissing은 mutation lock 아래에서 부재를 다시 확인하고, 유효성 검사 통과 후에만 게시합니다. observeInitialConfigState는 디렉터리·댕글링 심볼릭 링크·깨진 JSON을 “없음”으로 취급하지 않습니다.

경로 확인: src/config/initialize.ts(신규), src/config.ts 훅, tests/config/config-mutation-lock.test.ts만. 허구 파일 없음. base는 #3790 브랜치(codex/track3-windows-spill-origins-a4b0)라 dev가 아닙니다. Track 3 체인 #3786 → #3788 → #3789 → #3790 → #3796 → #3802이고 아래 층이 모두 OPEN이라 바닥 PR 누락은 없습니다. CLI 소비자는 다음 층 #3802입니다. types/config 분할 캠페인과는 “큰 types/config 쪼개기” 무효 대상이 아니라, 오히려 initialize 잎을 빼는 방향과 맞습니다. #3632는 이 층이 랜딩되면 superseded로 닫는 편이 맞습니다.

src/config/initialize.ts publishInitialConfigNoReplace - harden → verify → write → link 순서가 맞다. 게시 후 에러에도 truncate/목표 unlink가 없다.
src/config/initialize.ts identifiesDescriptor / removeOwnedTemp - fd·path ino/dev 일치 시에만 unlink. 심볼릭 링크 스왑·공유 inode 스크럽을 막는다.
src/config.ts initializePersistedConfigIfMissing - lock 안 재확인, 게시 후 bookkeeping 실패는 publication: "published"로 올려 재시도 시 덮어쓰기를 막는다.
observeInitialConfigState - occupied unsafe를 absence로 취급하지 않는다. #3553류 진단 정신과 맞다.
tests/config/config-mutation-lock.test.ts - 충돌·부분 게시·권한·lock 경합·symlink·hardlink 거절 회귀가 두껍다. 로컬 스위트는 안 돌렸고 [skip ci]다.
Track 3 / #3632 - base≠dev. 스택 완전. #3632와 의도 중복.

메인테이너의 판단이 필요한 지점

너의 추천
드래프트 해제 후 Track 3에서 #3790 다음에 머지. #3632 no-replace 의도를 보안 경계까지 다시 박은 핵심 층이고, 기존 saveConfig는 건드리지 않는다. 랜딩 후 #3632는 닫고 Landed via #<landing> 패턴을 쓰면 된다. 단독이 급하면 #3796+#3802만 retarget 가능하나, 아래 spill/docs 층과 이력이 갈라진다. types/config 분할로 닫을 PR이 아니다.

이 댓글은 grok-bot이 작성했습니다

@lidge-jun
lidge-jun changed the base branch from codex/track3-windows-spill-origins-a4b0 to dev September 6, 2026 20:20
@lidge-jun
lidge-jun marked this pull request as ready for review September 6, 2026 20:20
@lidge-jun
lidge-jun requested a review from Ingwannu as a code owner September 6, 2026 20:20
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 6, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-06T20:22:30.062332Z d760f66 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@lidge-jun
lidge-jun merged commit 443310e into dev Sep 6, 2026
18 of 21 checks passed
@lidge-jun
lidge-jun deleted the codex/track3-config-init-a4b0 branch September 6, 2026 20:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant