Skip to content

Codex provenance ledger is never written: updateIntegrationRecord has no production caller #2622

Closed

Description

@lidge-jun

Area

Codex integration / write substrate

What is the bug?

updateIntegrationRecord in src/codex/integration-record.ts has no caller anywhere in src/. It is exported, tested by tests/codex-integration-record.test.ts, and never invoked by production code — so the Codex provenance ledger at integrations/codex.json is never written.

$ rg -n "updateIntegrationRecord" src/
src/codex/integration-record.ts:239:export const updateIntegrationRecord = (
src/codex/convergence-types.ts:22: * ONE owner. WP12 writes provenance here through `updateIntegrationRecord` —

The second hit is a comment describing the intended design, not a call.

How was it found?

While landing #1048's disposable-host service acceptance. The six service rows assert that an admitted native transaction has a matching provenance entry, and every row reported the record either absent or empty. Verified directly: after ocx service install followed by ocx stop on a real systemd host, the transaction is admitted (native generation advances, direction remove, a fresh transaction id) and integrations/codex.json carries no ledger.

Why this is not already failing anything

src/codex/convergence-types.ts:26-27 states it plainly:

Provenance is OPTIONAL at v1. A record written before WP12 is valid, and unknown extension sections from a newer writer remain valid and preserved.

So nothing is broken today, and the acceptance rows were adjusted to fail only on disagreement — a ledger that exists, has entries, and lacks the transaction just admitted — rather than on absence. That was the honest reading; requiring an entry no production path can produce would have been testing an unimplemented writer.

What should happen

One of two things, and the choice is a maintainer's:

  1. Wire the writer. The convergence commit path is the natural owner: it already holds the transaction id and direction that a provenance entry needs. convergence-types.ts says provenance has ONE owner and must not read/merge/write its own — so the call belongs where the transaction is admitted, not beside it.
  2. Retire the surface. If provenance is not going to be written, updateIntegrationRecord, CodexProvenanceLedger, and the WP12 comments should go, and the disposable-host rows' provenance assertion with them. A tested, documented, exported writer that nothing calls is worse than no writer at all — it reads as implemented.

The reason to decide rather than leave it: the disposable-host acceptance is now the thing that proves service-manager entry points converge on the coordinator, and provenance is the evidence trail that would let it assert which writer did what. Right now that assertion has nothing to check.

Checks

  • I searched existing issues and documentation.
  • This describes a concrete OpenCodex behavior rather than naming a technology.
  • I removed secrets and personal data.

Activity

  1. lidge-jun commented on Aug 25, 2026

    @lidge-jun
    OwnerAuthor

    리뷰 · 우선순위 61 / 80

    설명: 이 이슈는 Codex 출처 장부 기록 함수가 시험과 내보내기만 있고, 실제 src 경로에서는 한 번도 안 불린다고 한다. 작성자는 lidge-jun 이다. 지금 열려 있다. 라벨은 없다. 지금 CURRENT dev HEAD 는 0523239 이다. 직전 패스 HEAD 는 6b508d5 이었고, 이번 시간에 2610 부터 2621 과 2619 와 2624 와 2502 가 착지했다. origin/dev package.json 은 2.32.1-preview.20260825 다. 본문은 1048 의 일회용 호스트 수락이 출처 칸이 없거나 비었다고 해서 찾았다고 한다. 차량 풀은 아직 없다. 내가 구현하지 않고 머지하지 않는다. 태그하지 말 것. 배포하지 말 것.

    HEAD 에서 본문 지적은 맞다. src/codex/integration-record.ts 239줄 updateIntegrationRecord 는 내보낸다. 28줄 recordPath 는 config 아래 integrations/codex.json 이다. 243줄 withConfigMutationLockSync 안에서 읽고 합치고 원자 기록한다. tests/codex-integration-record.test.ts 가 이 함수를 부른다. src/ 안 다른 파일은 호출이 없다. src/codex/convergence-types.ts 22줄 주석만 WP12 가 이 함수로 쓴다고 적는다. 26줄부터 27줄은 출처가 v1 에서 선택이라고 한다. 그래서 지금 동작이 안 깨진다. scripts/disposable-host/codex-service-composed-acceptance.ts 371줄도 생산 호출이 없다고 로그를 남긴다. 없는 장부를 실패로 보지 않는다. 의견이 다를 때만 실패한다.

    이번 시간 2618 이 1048 의 수락을 착지했다. 그 수락이 이 구멍을 드러냈다. 2618 로 1048 은 leftover-close 했다. 이 이슈로 1048 을 다시 열지 말 것. 2613 은 1478 설정 rebase 출처다. 파일은 src/config/rebase-provenance.ts 다. integrations/codex.json 장부가 아니다. 이 이슈로 1478 을 다시 열지 말 것. 2612 는 1049 사전 기판 입양이다. 1049 는 메인테이너가 닫았다. 다시 열지 말 것. 이 이슈의 고침은 수렴 커밋 길에 updateIntegrationRecord 를 잇거나, 표면을 거두는 둘 중 하나다. 본문도 그렇게 가른다.

    src/runtime 은 없다. default-aliases.ts 는 이제 65줄이다. model-presets.ts 는 119줄이다. 2463 2464 를 이 이슈로 닫지 말 것. 이미 닫혀 있다. 다시 열지 말 것. 프리뷰 배포가 아니다. types.ts/config.ts 가르기를 깨는 본체가 아니다. 지금 leftover-close 할 차량도 없다.

    라인 239 - src/codex/integration-record.ts updateIntegrationRecord 가 내보내진다. src 호출은 없다
    라인 28 - 같은 파일 recordPath 는 integrations/codex.json 이다. 장부 위치는 맞다
    라인 22 - src/codex/convergence-types.ts 주석이 WP12 가 이 함수로 쓴다고 적는다. 호출은 없다
    라인 26 - 같은 파일 출처는 v1 에서 선택이다. 그래서 지금 동작이 안 깨진다
    라인 371 - scripts/disposable-host/codex-service-composed-acceptance.ts 가 없는 장부를 선택으로 본다
    tests/codex-integration-record.test.ts - 시험만 이 함수를 부른다
    1048/2618 - 수락이 구멍을 드러냈다. 1048 을 다시 열지 말 것
    1478/2613 - 설정 rebase 출처다. 이 장부가 아니다

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

    • 이 이슈를 받을지. 받는 편이 맞다. HEAD 경로가 본문과 같다
    • 작가를 이을지 거둘지. 본문이 가른 두 길이다. 잇는 편이 장부 증거에 맞다
    • 이을 자리를 수렴 커밋으로 둘지. 본문도 거래 id 와 방향이 거기 있다고 한다
    • 1048 수락 행을 필수 출처로 올릴지. 작가를 잇기 전에는 올리지 말 것
    • 지금 leftover-close 할지. 차량이 없다. 내가 닫지 않는다

    너의 추천
    구멍으로 받는다. 다만 지금 합칠 차량은 없다. 수렴이 거래를 받을 때 updateIntegrationRecord 를 한 번 부르게 잇는 쪽이 맞다. 거두면 주석과 시험과 수락 로그가 구현된 척을 남긴다. 내가 구현하지 않고 닫지 않는다. 1048 1049 1478 은 다시 열지 말 것. 라벨은 그대로 둔다. 프리뷰 배포가 아니다.

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

  2. lidge-jun commented on Aug 25, 2026

    @lidge-jun
    OwnerAuthor

    Closed on dev by #2626 (squash c6084fea1).

    Took option 1 — wired the writer. The apply and remove paths now append evidence for config, generated-profile, and injection-journal after withCodexWriteLock returns an acquired transaction.

    The ordering is the part worth recording: the append runs after the native files and the coordinator row commit. A crash between the two leaves an admitted transaction with no entry, which is safe — absence grants no restore authority and acceptance already treats it as unavailable evidence. Writing before the commit is the unsafe direction: it leaves provenance for a transaction that never happened. Best-effort for the same reason; a JSON write failure must not turn a committed native transaction into a reported failure.

    One thing the first implementation got wrong and review caught: the ledger was unbounded. Three entries per transaction, and a present baseline embeds the artifact's exact bytes as base64 — a 25 KB config.toml is ~34 KB per entry, so roughly 100 KB per transaction. A machine that syncs on every start would grow the file forever, and since the record is re-read and re-serialized on every append the cost is quadratic, not just large. Bounded to the newest 16 transactions, kept whole: trimming by entry count would leave a record claiming a transaction touched two artifacts when it touched three, and a partial record that reads as complete is worse than a dropped one.

    The #1048 disposable-host rows now have something real to assert against, which is why this was worth doing rather than retiring the surface.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions