Skip to content

fix(codex): preserve settings when journal injection hashes are missing - #4006

Closed
luvs01 wants to merge 2 commits into
lidge-jun:devfrom
luvs01:agent/journal-hashless-restore-20260908
Closed

fix(codex): preserve settings when journal injection hashes are missing#4006
luvs01 wants to merge 2 commits into
lidge-jun:devfrom
luvs01:agent/journal-hashless-restore-20260908

Conversation

@luvs01

@luvs01 luvs01 commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #4005.

A missing injected-state hash currently lets an older Codex journal overwrite later config bytes or delete a later profile. Classify an already-original artifact separately from a verified injected artifact. If a changed config or profile lacks its own injection hash, preserve both files and the journal and return an explicitly unverified restore result.

Carry that result through automatic reconciliation and native restore so it cannot become successful fallback cleanup. Check a retained routed journal during read-only injection preflight and again before writing, preventing a new injected hash from being attached to an unverified older original. Native configuration can still establish a fresh snapshot. Preserve empty original profiles separately from absence.

Legacy behavior change: hashless journals no longer authorize whole-file restoration of differing current content. Verified hashes keep normal restoration and later-edit cleanup behavior. Already-original files complete without rewriting. External-provider opt-out remains unchanged. This addresses the reproducible missing-hash path discussed alongside #2948, not the unverified cause of that historical incident or all journal liveness/age policies.

The runtime change is limited to journal.ts and its existing injector/restore caller. The Codex guide is synchronized across eight locales; English/Korean CLI references and the configuration invariant describe the refusal and retained recovery evidence.

Verification

  • Head ffdd705561330424b65ddd4cdee2f49ff27d6366 is based on dev commit 7797586a8899c673eab48886a490e85b480c6d72. The rebase preserves all 17 PR files byte-for-byte from reviewed head 572d0b217; none overlap the 23 files changed upstream since the old base. This brings the branch within the automated readiness gate's base-freshness limit.
  • Pinned Bun 1.4.0 on Windows. Six new regressions failed against base source: later config overwrite, later profile deletion, unnecessary config rewrite, empty-profile loss, false native-restore success, and unsafe routed reinjection preflight.
  • Nine new journal cases pass, including the above guards, deleted-vs-empty config, failed client reconciliation, and a positive control for refreshing a configuration classified as native. The empty-profile case also verifies successful restore, retained empty-file presence and journal removal.
  • bun run test -- --timeout 60000 --parallel=1 tests/codex-integration/codex-journal.test.ts: 34 tests / 163 assertions passed on the preceding base. Runtime and test bytes remain unchanged. Normal hashed restoration, changed-config preservation, original-profile recovery, reinjection hash retention and another-process marking remain covered.
  • Full contributor CI on the previous head exposed five normal-recovery cases whose handcrafted journals omitted injected hashes. The fixtures in CLI startup, catalog restore and connected disconnect now record their actual injected config bytes and absent profile. All original assertions remain; matching-client and foreign-owner controls also receive hashes so unverified-state refusal cannot mask ownership regressions. The seven affected cases/control cases passed locally: 48 assertions across those three files. This is covered separately from the hashless-refusal regressions.
  • Before rebase, bun run test -- --timeout 60000 --parallel=1 tests/codex-integration/codex-inject-integration.test.ts tests/codex-integration/codex-inject-write-lock.test.ts: 57 tests / 359 assertions passed. These cover normal and changed profiles, user edits, CRLF, managed defaults, external-provider opt-out, coordination/adoption and held-lock behavior.
  • bun run typecheck, bun run privacy:scan and git diff --check passed on current head ffdd70556.
  • Documentation build passed: 425 pages. All eight rendered guide locales link to the verified canonical recovery anchor; no preview was opened. Independent read-only review found no contradiction in the changed translations.
  • Full contributor CI on 572d0b217 passed all 26 jobs on attempt 2. The first attempt's only failing test was the unrelated native-process probe marker assertion in the macOS control job; its job-only rerun passed. That reproducible fixture race is addressed separately in test(codex): verify timeout termination without racing child timers #4012. Earlier handcrafted-journal fixture failures are retained in the earlier run.
  • CodeRabbit reviewed the runtime change and follow-up commit 572d0b217 with no correctness findings. Its rebased-head verification confirms the same reviewed patch on ffdd70556.
  • Current-head full contributor CI initially failed only Windows shard 6/6: codex-retained-root-serialization.test.ts tried to consume a child's stdout twice and raised a disturbed/locked stream error before the catalog assertion. A deterministic child-exit ordering reproduces that fixture race. The initial isolated fix passed all 7 file cases / 35 assertions both on dev and as a temporary overlay on this PR; the overlay was restored and is not part of this diff. The one job-only rerun passed those catalog cases but failed the xAI fixture: a timed-out case continued into the following case's fetch mock. Both fixture fixes are now in test: stabilize Windows fixture waits and case cleanup #4015, whose final two-file CI-mode run passed 13 tests / 101 assertions. This PR remains draft pending integration and successful current-head CI; no third unchanged retry has been started. The original failures are retained, and the earlier green run on 572d0b217 is not attested as a run on this head.
  • No production configuration, journal, service or account was modified.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

Review readiness checklist

  • All CI tests are green on my local testing.
  • I pushed my PR to the latest dev commit.
  • I resolved all correct Codex and CodeRabbit findings.
  • My PR is ready for review.

@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 0977d426-71c5-48bb-9c1d-4fd9fff31342

📥 Commits

Reviewing files that changed from the base of the PR and between 74f62f9 and 3606919.

📒 Files selected for processing (14)
  • docs-site/src/content/docs/fr/guides/codex-integration.md
  • docs-site/src/content/docs/guides/codex-integration.md
  • docs-site/src/content/docs/ja/guides/codex-integration.md
  • docs-site/src/content/docs/ko/guides/codex-integration.md
  • docs-site/src/content/docs/ko/reference/cli/lifecycle.md
  • docs-site/src/content/docs/reference/cli/lifecycle.md
  • docs-site/src/content/docs/ru/guides/codex-integration.md
  • docs-site/src/content/docs/tr/guides/codex-integration.md
  • docs-site/src/content/docs/zh-cn/guides/codex-integration.md
  • docs-site/src/content/docs/zh-tw/guides/codex-integration.md
  • src/codex/inject.ts
  • src/codex/journal.ts
  • structure/02_config-and-codex-home.md
  • tests/codex-integration/codex-journal.test.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

The change adds verified-baseline checks for Codex journal restore and reinjection. Uncertain hashless states now preserve files and journals, report incomplete recovery, and block routed reinjection. Tests and multilingual documentation cover the updated behavior.

Changes

Codex recovery safeguards

Layer / File(s) Summary
Journal state verification
src/codex/journal.ts:65-332
Journal restoration now detects changed artifacts without injected-state hashes, preserves uncertain files and journals, distinguishes empty from absent profiles, and reports unverified reconciliation.
Injection and native restore gates
src/codex/inject.ts:34, src/codex/inject.ts:1153-1186, src/codex/inject.ts:1748-1753
Injection rejects routed configurations with unverified journal baselines. Native restore returns failure without changing preserved files.
Recovery regression coverage
tests/codex-integration/codex-journal.test.ts:59-684
Tests cover later edits, empty profiles, deleted files, failed restore, rejected reinjection, reconciliation, and marked journal lifecycles.
Recovery behavior documentation
structure/02_config-and-codex-home.md:23-32, docs-site/src/content/docs/**/guides/codex-integration.md, docs-site/src/content/docs/**/reference/cli/lifecycle.md
Documentation describes verified restoration, hashless baseline handling, preserved files and journals, and incomplete recovery across supported languages.

Priority: ➖ Normal — Impact reflects medium issue severity.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to 36069

Hashless journal recovery now preserves uncertain user configuration and reports incomplete restoration rather than overwriting it. No actionable merge risk remains.

Sequence Diagram(s)

sequenceDiagram
  participant CodexCommand
  participant injectCodexConfig
  participant journal.ts
  participant CodexFiles
  CodexCommand->>injectCodexConfig: request injection or restore
  injectCodexConfig->>journal.ts: check journal baseline and hashes
  journal.ts->>CodexFiles: compare saved originals with current files
  journal.ts-->>injectCodexConfig: return verified or unverified state
  injectCodexConfig-->>CodexCommand: complete recovery or failure
Loading

Suggested reviewers: lidge-jun

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 3 files. (11 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The implementation satisfies issue #4005. It preserves changed hashless config and profile artifacts, retains the journal, reports unverified restoration, distinguishes empty profiles from absent prof…
Out of Scope Changes check ✅ Passed The changes remain within scope for issue #4005. Source changes update journal verification, restoration, reconciliation, and reinjection safeguards. Tests cover the affected failure modes. Documentat…
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: Codex settings remain preserved when journal injection hashes are missing. It is concise, specific, and directly matches the implementation and PR objecti…
Full details: Docstring Coverage

Explanation

Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 3 files. (11 skipped: 11 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 8, 2026

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the bug Something isn't working label Sep 8, 2026
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

⏳ DRAFT

  • review readiness checklist open (2/4 boxes ticked).

What to do

  • Tick all four boxes in the PR description once you're done (currently 2/4).

Review readiness checklist

  • ⬜ All CI tests are green on my local testing.
  • ✅ I pushed my PR to the latest dev commit.
  • ✅ I resolved all correct Codex and CodeRabbit findings.
  • ⬜ My PR is ready for review.

2/4 boxes ticked.

This PR stays in draft until every box above is ticked.

Hygiene

Deterministic PR hygiene checks passed.

@luvs01

luvs01 commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please review head 3606919780007fe2d4ca04449cbdc0085ee31e93, especially preservation when either changed artifact lacks its own injected hash, propagation of the unverified result through restore/reconcile, and rejection of routed reinjection before it can attach a new hash to an older snapshot. The complete journal suite passes 34 tests on this head; full contributor CI is starting. Existing issue #4005 remains linked.

@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== HEAD / BASE ==='
git rev-parse HEAD
git merge-base HEAD 74f62f9c2914ead2fba474aa97734e322251bd46 || true

echo '=== CHANGED FILES ==='
git diff --name-status 74f62f9c2914ead2fba474aa97734e322251bd46...HEAD

echo '=== JOURNAL CANDIDATES ==='
fd -t f -i 'journal' .

echo '=== INJECTOR / RESTORE CANDIDATES ==='
fd -t f . | rg -i '(codex.*(inject|restore)|inject.*codex|restore.*codex)'

echo '=== CHANGED SYMBOL REFERENCES ==='
rg -n -C 3 --glob '!node_modules/**' \
  '(unverified|Unverified|injected.*hash|injection.*hash|routed.*journal|restore.*result|RestoreResult|reconcil)' .

Length of output: 200581


🏁 Script executed:

#!/bin/bash
set -euo pipefail

base="74f62f9c2914ead2fba474aa97734e322251bd46"

echo '=== CHANGED FILES ==='
git diff --name-status "${base}...HEAD"

echo '=== RUNTIME DIFF ==='
git diff --unified=80 "${base}...HEAD" -- src/codex/journal.ts src/codex/inject.ts

echo '=== JOURNAL OUTLINE ==='
ast-grep outline src/codex/journal.ts --items all --view expanded

echo '=== INJECT OUTLINE ==='
ast-grep outline src/codex/inject.ts --items all --view expanded

echo '=== JOURNAL API REFERENCES IN SOURCE ==='
rg -n -C 5 --glob '*.ts' --glob '!**/node_modules/**' \
  '\b(reconcileJournal|restoreNativeCodex|restoreCodex|readCodexJournal|writeCodexJournal|injectCodexConfig)\s*\(' \
  src tests/codex-integration

echo '=== CHANGED JOURNAL TEST DIFF ==='
git diff --unified=50 "${base}...HEAD" -- tests/codex-integration/codex-journal.test.ts

Length of output: 138726


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== INJECTION: INPUT SNAPSHOT THROUGH COORDINATED WRITE ==='
nl -ba src/codex/inject.ts | sed -n '884,1435p'

echo '=== NATIVE RESTORE: ASYNC AND SYNCHRONOUS PATHS ==='
nl -ba src/codex/inject.ts | sed -n '1740,2028p'

echo '=== LIFECYCLE CALLER FAILURE HANDLING ==='
nl -ba src/cli/index.ts | sed -n '390,440p'
nl -ba src/server/stop-teardown.ts | sed -n '35,100p'
nl -ba src/client/connect.ts | sed -n '535,575p;670,700p'
nl -ba src/codex/sync.ts | sed -n '140,250p'

echo '=== DOCUMENTATION DIFF ==='
git diff --unified=30 74f62f9c2914ead2fba474aa97734e322251bd46...HEAD -- \
  docs-site/src/content/docs/guides/codex-integration.md \
  docs-site/src/content/docs/reference/cli/lifecycle.md \
  structure/02_config-and-codex-home.md

echo '=== ALL DIRECT RESTORE-JOURNAL-STATE CONSUMERS ==='
rg -n -C 4 --glob '*.ts' '\brestoreJournalState\s*\(' src tests

Length of output: 1301


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== INJECTION: INPUT SNAPSHOT THROUGH COORDINATED WRITE ==='
sed -n '884,1435p' src/codex/inject.ts

echo '=== NATIVE RESTORE: ASYNC AND SYNCHRONOUS PATHS ==='
sed -n '1740,2028p' src/codex/inject.ts

echo '=== LIFECYCLE CALLER FAILURE HANDLING ==='
sed -n '390,440p' src/cli/index.ts
sed -n '35,100p' src/server/stop-teardown.ts
sed -n '535,575p;670,700p' src/client/connect.ts
sed -n '140,250p' src/codex/sync.ts

echo '=== DOCUMENTATION DIFF ==='
git diff --unified=30 74f62f9c2914ead2fba474aa97734e322251bd46...HEAD -- \
  docs-site/src/content/docs/guides/codex-integration.md \
  docs-site/src/content/docs/reference/cli/lifecycle.md \
  structure/02_config-and-codex-home.md

echo '=== ALL DIRECT RESTORE-JOURNAL-STATE CONSUMERS ==='
rg -n -C 4 --glob '*.ts' '\brestoreJournalState\s*\(' src tests

Length of output: 79638


@luvs01 I found no correctness issue in this review.

The changed logic preserves a changed config or profile when its own injected-state hash is missing. src/codex/journal.ts now classifies this state as unverified and does not write either artifact or remove the journal.

The result propagation is correct. src/codex/inject.ts converts unverified into a failed config restore artifact. Both restoreNativeCodexAsync and restoreNativeCodex require that artifact to succeed before they return success: true. reconcileJournal also preserves the journal and returns false for unverified recovery.

The routed reinjection guard is present in both required locations. injectCodexConfig checks before validateOnly, so sync and client preflight fail before catalog work or injection. It checks again in applyNativeArtifacts, after any permitted native snapshot refresh and before config/profile writes or markJournalInjectedState.

The regression coverage in tests/codex-integration/codex-journal.test.ts matches the requested failure modes. It covers changed config, changed profile, already-original bytes without rewrites, empty profiles, false native-restore success, client reconciliation, and routed reinjection refusal.

I performed static source and diff review. I did not execute the test suite in this environment. Full contributor CI is still the remaining verification step.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@lidge-jun

Copy link
Copy Markdown
Owner

리뷰 · 우선순위 66 / 80

이 PR은 이슈 #4005를 고칩니다. 지금 dev HEAD 74f62f9c2(package 2.48.0)의 src/codex/journal.ts restoreJournalState()는 주입 해시가 비어 있으면 config를 ‘안 바뀐 것’으로 보고 예전 원본으로 덮어쓰고, 프로필 해시가 없으면 나중에 생긴 프로필까지 지울 수 있습니다. 조건이 한 줄로 드러납니다. config는 !journal.injectedConfigHash || sha256(currentConfig) === journal.injectedConfigHash 이고, profile은 journal.injectedProfileHash === undefined || … 입니다. 해시가 없으면 왼쪽이 바로 참이라, 중단·레거시 저널이 사용자 편집을 ‘우리 주입이 그대로다’라고 오인합니다. #4005 리뷰에서 말한 그 구멍입니다.

이 변경은 그 판단을 compareJournalState()로 모읍니다. ‘이미 원본과 같다’와 ‘해시로 검증된 주입 상태다’를 나눕니다. 해시가 없고 현재 파일이 원본과도 다르면 unverified: true를 돌려, 파일을 쓰지 않고 저널도 남깁니다. hasUnverifiedJournalBaseline()은 주입 전 스냅샷만 읽어서, 해시 없는 옛 라우티드 저널이 새 주입 해시를 받아 나중에 사용자 편집을 덮어쓰지 못하게 막습니다. src/codex/inject.ts의 주입 경로와 네이티브 복원 경로가 그 결과를 실패로 이어 받아서, 자동 reconcile/ocx stop 폴백이 ‘성공한 복원’처럼 보이게 두지 않습니다. 빈 원본 프로필과 ‘프로필 없음’도 구분합니다(originalProfile: profile !== null ? …).

레거시 동작이 바뀝니다. 해시 없는 저널은 더 이상 ‘다른 현재 내용 전체를 원본으로 되돌릴 권한’이 없습니다. 검증된 해시는 예전처럼 복원·이후 편집 보존을 합니다. 이미 원본인 파일은 다시 쓰지 않고 끝냅니다. 외부 프로바이더 opt-out은 그대로입니다. 런타임 핵심은 journal.ts와 기존 injector/restore 호출부뿐이고, Codex 가이드 8개 로케일과 CLI lifecycle 문서·structure/02_config-and-codex-home.md에 거부·증거 보존을 맞춰 두었습니다.

테스트 쪽이 이 PR의 설득력입니다. tests/codex-integration/codex-journal.test.ts에 해시 없음으로 인한 설정 덮어쓰기·프로필 삭제·불필요한 rewrite·빈 프로필 손실·거짓 네이티브 복원 성공·라우티드 재주입 preflight 등 회귀가 들어갔습니다. 일반 해시 복원 fixture가 주입 해시를 빠뜨려 CI가 깨지던 부분은 CLI/catalog/client 테스트에 실제 주입 바이트를 기록해 고쳤습니다. base는 지금 tip 74f62f9c2이고 MERGEABLE이며, hygiene/label/enforce-target는 통과한 상태입니다. 전체 suite는 작성자도 미완(exit 124)이라 contributor CI를 봐야 합니다. 현재 dev 메인 트레인(수동 bug6 레이어·쿨다운/#3973 쪽)과는 겹치지 않는 독립 안전 수정입니다. types.ts/config.ts 분할 캠페인과도 무관합니다.

라인 단위로 보면 계약은 대체로 맞습니다. 다만 메인테이너가 한 번 더 눌러볼 지점이 있습니다.

src/codex/journal.ts compareJournalState - profileHashKnown이 injectedProfileHash !== undefined라서, 해시 필드가 있는데 값이 null/빈 문자열인 레거시와 ‘필드 없음’을 같은 축으로 묶는지 한 번 확인이 필요합니다. config 쪽은 길이 검사(length > 0)가 있고 profile 쪽은 다릅니다.

src/codex/journal.ts restoreJournalState unverified 분기 - config/profile 한쪽만 unverified여도 쌍 전체를 보존합니다. 의도에 맞지만, 한쪽만 안전한 부분 복원을 기대하는 호출자가 있으면 메시지가 모호할 수 있습니다.

src/codex/inject.ts applyNativeArtifacts - unverified면 throw로 주입을 막습니다. preflight와 write 직전 이중 체크는 좋지만, 중간에 다른 프로세스가 저널을 손댄 레이스는 기존과 같이 남습니다(이 PR 범위 밖).

docs-site/.../codex-integration.md 각 로케일 - 영어·한국어는 거부와 증거 보존을 길게 쓰고, fr/ru/tr 등은 짧은 요약입니다. 의미 충돌은 없어 보이지만, 번역 품질은 로케일 오너 확인이 낫습니다.

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

  • #4005를 이 PR만으로 닫을지, 저널 연령/생존 정책(Journal restore replays an arbitrarily old Codex config, and unclean shutdown is the steady state #2948 계열)은 별 이슈로 둘지
  • unverified일 때 GUI/ocx stop 사용자에게 어떤 문구·다음 행동(수동 백업, 강제 네이티브 스냅샷)을 보여줄지
  • profile 해시 undefined vs null 레거시 기록을 데이터 마이그레이션할지, 코드 가드만으로 둘지
  • 전체 CI 미완 상태에서 merge할지, green 후에 할지

너의 추천
contributor CI가 초록이면 dev에 병합하고 #4005를 닫으세요. 지금 tip과도 충돌 없고, 해시 없는 저널이 설정을 덮는 실사용 구멍을 막습니다. CI가 아직이면 테스트 lane만 기다린 뒤 병합하세요. #2948 전체 사후분석이나 저널 TTL은 이 PR에 넣지 말고 따로 두세요.

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

@luvs01

luvs01 commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please include the follow-up commit 572d0b217a5b0de7027906ffa970644244556773. The runtime and hashless refusal regressions are unchanged from the reviewed 360691978 commit. Three normal-recovery fixture files now record the config bytes and absent profile they actually model; the original assertions remain, and matching/foreign-owner controls also have hashes so the unverified-state guard cannot mask ownership regressions. Seven affected/control cases and 48 assertions pass locally, along with typecheck and privacy scan. Current-head full CI: https://github.com/luvs01/opencodex/actions/runs/34199076801 .

@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

previous="3606919780007fe2d4ca04449cbdc0085ee31e93"
followup="572d0b217a5b0de7027906ffa970644244556773"

echo '=== CHECKOUT HEAD AND COMMIT RELATIONSHIP ==='
git rev-parse HEAD
git merge-base --is-ancestor "$previous" "$followup" && echo "previous_is_ancestor=yes"
git merge-base --is-ancestor "$followup" HEAD && echo "followup_is_in_head=yes"
git show --no-patch --format='followup=%H%nparents=%P%nsubject=%s' "$followup"

echo '=== INCREMENTAL CHANGED FILES ==='
git diff --name-status "$previous" "$followup"

echo '=== INCREMENTAL DIFF ==='
git diff --check "$previous" "$followup"
git diff --unified=80 "$previous" "$followup"

echo '=== TEST FILE STRUCTURE ==='
ast-grep outline tests/codex-integration/codex-journal.test.ts --items all --view expanded

echo '=== TARGETED FIXTURE AND HASH CONTEXT ==='
rg -n -C 8 --glob '*.ts' \
  '(injectedConfigHash|injectedProfileHash|originalConfig|originalProfile|foreign.owner|foreign-owner|matching)' \
  tests/codex-integration/codex-journal.test.ts

echo '=== CURRENT CI RUN ==='
gh run view 34199076801 --repo luvs01/opencodex --json status,conclusion,event,headSha,workflowName,displayTitle,url,jobs

Length of output: 104709


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== JOURNAL HASH CONTRACT ==='
ast-grep outline src/codex/journal.ts --items all --view expanded
rg -n -C 8 --glob '*.ts' \
  '(injectedProfileHash|function markJournalInjectedState|function compareJournalState|function reconcileJournal)' \
  src/codex/journal.ts

echo '=== FOLLOW-UP FIXTURES WITH CURRENT LINE NUMBERS ==='
nl -ba tests/cli/cli-start-journal-order.test.ts | sed -n '45,92p;118,174p'
nl -ba tests/clients/client-connect.test.ts | sed -n '480,570p'
nl -ba tests/clients/client-connect.test.ts | sed -n '890,940p'
nl -ba tests/codex-integration/codex-catalog-restore.test.ts | sed -n '35,95p'

echo '=== ASSERTIONS FOR THE AFFECTED CLIENT CONTROLS ==='
rg -n -A 28 -B 5 --glob '*.ts' \
  'journal ownership conflict preserves|process-owned journal|matching committed api key|foreign' \
  tests/clients/client-connect.test.ts tests/cli/cli-start-journal-order.test.ts tests/codex-integration/codex-catalog-restore.test.ts

echo '=== CURRENT CI RUN STATUS ==='
gh run view 34199076801 --repo luvs01/opencodex \
  --json status,conclusion,headSha,url,jobs \
  --jq '{status, conclusion, headSha, url, jobs: [.jobs[] | {name, status, conclusion}]}'

Length of output: 9077


@luvs01 I found no correctness issue in follow-up commit 572d0b217a5b0de7027906ffa970644244556773.

The commit changes only these normal-recovery fixtures:

  • tests/cli/cli-start-journal-order.test.ts
  • tests/clients/client-connect.test.ts
  • tests/codex-integration/codex-catalog-restore.test.ts

Each fixture now hashes the exact routed config.toml bytes that it writes. Each fixture also records injectedProfileHash: null when the modeled injected profile is absent.

This is consistent with the journal contract. In src/codex/journal.ts Lines 73-90, injectedProfileHash: null means that the absent profile has a known injected-state hash. In src/codex/journal.ts Lines 161-181, markJournalInjectedState() writes the same value for an absent profile.

The matching-client and foreign-owner controls now test journal ownership after the unverified-baseline guard. The guard cannot mask a regression in the ownership checks. The existing assertions remain valid.

I also confirmed that this commit is the current PR head and directly follows the previously reviewed commit. It does not change the runtime restoration or routed-reinjection logic.

The workflow run targets this exact SHA. The completed gates and multiple Linux, macOS, and Windows test jobs passed when checked. Some Windows shards and the macOS control job were still in progress. I cannot confirm the final full-CI conclusion yet.

You are interacting with an AI system.

@luvs01
luvs01 force-pushed the agent/journal-hashless-restore-20260908 branch from 572d0b2 to ffdd705 Compare September 8, 2026 09:12
@luvs01

luvs01 commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please verify rebased head ffdd705561330424b65ddd4cdee2f49ff27d6366 on current dev 7797586a8899c673eab48886a490e85b480c6d72. All 17 PR files are byte-identical to reviewed head 572d0b217, and none overlap the 23 upstream files changed since the old base. The rebase is required by the automated readiness gate's maximum 10-commit base lag; the prior branch had reached 13.

The previous head's full contributor CI passed 26/26 jobs on attempt 2. Current-head CI is https://github.com/luvs01/opencodex/actions/runs/34208728445. Typecheck, privacy scan and diff checks passed on the rebased head; earlier test results remain explicitly bound to their original heads.

@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

old_head="572d0b217a5b0de7027906ffa970644244556773"
new_head="ffdd705561330424b65ddd4cdee2f49ff27d6366"
new_base="7797586a8899c673eab48886a490e85b480c6d72"
repo="lidge-jun/opencodex"
run_id="34208728445"

echo '=== HEAD AND ANCESTRY ==='
printf 'checked_out_head='; git rev-parse HEAD
printf 'new_head='; git rev-parse "$new_head"
printf 'new_base='; git rev-parse "$new_base"
printf 'merge_base(new_base,new_head)='; git merge-base "$new_base" "$new_head"
git merge-base --is-ancestor "$new_base" "$new_head" && echo 'new_base_is_ancestor=yes'
git merge-base --is-ancestor "$old_head" "$new_head" && echo 'old_head_is_ancestor=yes' || echo 'old_head_is_ancestor=no (expected for a rebase)'

echo '=== DIFF INTEGRITY ==='
git diff --check "$new_base...$new_head"

echo '=== PATCH IDENTITY ==='
old_base=$(git merge-base "$old_head" "$new_base")
printf 'old_base='; git rev-parse "$old_base"
old_patch=$(git diff --binary "$old_base...$old_head" | git patch-id --stable | cut -d' ' -f1)
new_patch=$(git diff --binary "$new_base...$new_head" | git patch-id --stable | cut -d' ' -f1)
printf 'old_patch_id=%s\nnew_patch_id=%s\n' "$old_patch" "$new_patch"
[ "$old_patch" = "$new_patch" ] && echo 'patch_identity=equal' || echo 'patch_identity=DIFFERENT'

echo '=== PR FILES AND UPSTREAM FILES ==='
git diff --name-only "$new_base...$new_head" | sort > /tmp/pr-files
git diff --name-only "$old_base...$new_base" | sort > /tmp/upstream-files
printf 'pr_file_count='; wc -l < /tmp/pr-files
printf 'upstream_file_count='; wc -l < /tmp/upstream-files
echo '-- PR files --'; cat /tmp/pr-files
echo '-- overlap --'
comm -12 /tmp/pr-files /tmp/upstream-files || true

echo '=== CURRENT WORKFLOW ==='
gh run view "$run_id" --repo "$repo" \
  --json status,conclusion,headSha,event,workflowName,displayTitle,url,jobs \
  --jq '{status, conclusion, headSha, event, workflowName, displayTitle, url, jobs: [.jobs[] | {name, status, conclusion}]}'

Length of output: 3928


🏁 Script executed:

#!/bin/bash
set -euo pipefail

old_head="572d0b217a5b0de7027906ffa970644244556773"
old_base="74f62f9c2914ead2fba474aa97734e322251bd46"
new_head="ffdd705561330424b65ddd4cdee2f49ff27d6366"
new_base="7797586a8899c673eab48886a490e85b480c6d72"
repo="luvs01/opencodex"
run_id="34208728445"

echo '=== COMPLETE DIFF-STREAM IDENTITY ==='
git diff --binary --full-index "$old_base...$old_head" > /tmp/old.patch
git diff --binary --full-index "$new_base...$new_head" > /tmp/new.patch
printf 'old_diff_sha256='; sha256sum /tmp/old.patch | cut -d' ' -f1
printf 'new_diff_sha256='; sha256sum /tmp/new.patch | cut -d' ' -f1
cmp -s /tmp/old.patch /tmp/new.patch && echo 'diff_stream_identity=equal' || echo 'diff_stream_identity=DIFFERENT'
printf 'old_diff_bytes='; wc -c < /tmp/old.patch
printf 'new_diff_bytes='; wc -c < /tmp/new.patch

echo '=== CURRENT WORKFLOW ==='
gh run view "$run_id" --repo "$repo" \
  --json status,conclusion,headSha,event,workflowName,displayTitle,url,jobs \
  --jq '{status, conclusion, headSha, event, workflowName, displayTitle, url, jobs: [.jobs[] | {name, status, conclusion}]}'

Length of output: 3483


@luvs01 I found no correctness issue in rebased head ffdd705561330424b65ddd4cdee2f49ff27d6366.

The rebase is valid:

  • 7797586a8899c673eab48886a490e85b480c6d72 is the merge base and an ancestor of the rebased head.
  • git diff --check reported no whitespace errors.
  • The rebased PR changes 17 files.
  • The 23 files changed upstream since the old base have no path overlap with the PR files.
  • The stable patch IDs are equal.
  • The complete binary diff streams are byte-identical in practice. Both have SHA-256 94feff9e1e5e0db668e448e06395d58fe62771248403309745ccc95a97a3aba1 and size 51,594 bytes.

Therefore, the static review result for 572d0b217a5b0de7027906ffa970644244556773 applies unchanged to this rebased head. This includes the hashless journal preservation, unverified-result propagation, and routed reinjection safeguards.

The current workflow is correctly bound to ffdd705561330424b65ddd4cdee2f49ff27d6366. It is still in progress. Completed gates passed, including changes, gates, storage policy, API usage, Docker smoke, and the completed keyring and npm-global jobs. The Linux test shards, macOS jobs, Windows jobs, and npm-global Windows job were still running when checked.

The earlier 26/26 contributor-CI result remains evidence for the identical patch, but it is not a completed result for the rebased commit.

You are interacting with an AI system.

lidge-jun added a commit that referenced this pull request Sep 8, 2026
* test(lib): make idle deadline reset timing deterministic

Carried from #4041 (author luvs01) for maintainer-side CI and sequential integration.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* test: stabilize Windows fixture waits and case cleanup

Carried from #4015 (author luvs01) for maintainer-side CI and sequential integration.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* test(codex): verify timeout termination without racing child timers

Carried from #4012 (author luvs01) for maintainer-side CI and sequential integration.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* test(codex): hold prompt-probe admission through document edits

Carried from #4014 (author luvs01) for maintainer-side CI and sequential integration.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* test(clients): bound transaction fixture child completion

Carried from #4004 (author luvs01) for maintainer-side CI and sequential integration.
Closes #4003

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(codex): retain overlapping multiline TOML terminators

Carried from #4039 (author luvs01) for maintainer-side CI and sequential integration.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(cli): reject unsupported caps and report ignored legacy values

Carried from #4043 (author luvs01) for maintainer-side CI and sequential integration.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(codex): share trigger-only delegation guidance with v1

Carried from #4034 (author luvs01) for maintainer-side CI and sequential integration.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(codex): preserve settings when journal injection hashes are missing

Carried from #4006 (author luvs01) for maintainer-side CI and sequential integration.
Closes #4005

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* docs(cli): note that --injection still accepts none and minimal

CodeRabbit review on #4049: the effort reference documents caps only, so the
new rejection of none/minimal reads as a global removal. --injection keeps
both values because it sets the injection effort rather than a cap.

---------

Co-authored-by: t <a@b.com>
Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
@lidge-jun

Copy link
Copy Markdown
Owner

Landed on dev in cfff026 via #4049, which carried all nine PRs of this train as one sequentially reviewed integration branch. Your commit is preserved in the squash body with a Co-authored-by trailer, so the contribution stays attributed to you.

Verification at the exact merged head 8c58bac0863f1f2ca2b430e1177a0e417b474c85: Cross-platform CI run 34256853348 finished with 19 jobs successful and 0 failures, bun x tsc --noEmit exit 0, and 312 focused tests passing across the ten affected files. An independent review confirmed the stacked tree is byte-identical to the union of the nine PR diffs.

Closing this PR because the change is already on dev. Thank you.

@lidge-jun

Copy link
Copy Markdown
Owner

Landed via #4049 at cfff026

@lidge-jun lidge-jun added the landed-via-maintainer Original PR closed after landing via a maintainer merge train label Sep 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working landed-via-maintainer Original PR closed after landing via a maintainer merge train

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants