Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3bf0ae1
feat(remote): carry bounded executor and hub runtime adapters
lidge-jun Sep 12, 2026
a318218
style(remote): remove trailing blank line in runner
lidge-jun Sep 12, 2026
e2fc5ab
fix(remote): bound runtime admission and retain cleanup ownership
lidge-jun Sep 12, 2026
31a96b2
docs(devlog): diff-level roadmap for the unimplemented trio stack (#4…
lidge-jun Sep 12, 2026
0268727
docs(devlog): fold wp1 audit findings into trio stack roadmap
lidge-jun Sep 12, 2026
2b533a5
docs(devlog): revalidate folded audit citations against source in wp1 B
lidge-jun Sep 12, 2026
da54017
docs(devlog): fold wp2 audit FAIL findings into L1 emission design
lidge-jun Sep 12, 2026
1893eec
docs(devlog): fold wp2 re-audit residual into L1 adoption points
lidge-jun Sep 12, 2026
923ca3c
feat(responses): persist content-free Codex WS upstream stage records…
lidge-jun Sep 12, 2026
07beb73
docs(structure): record the durable Codex WS stage record ownership (…
lidge-jun Sep 12, 2026
49dba44
fix(responses): refresh the WS stage record with final counters at te…
lidge-jun Sep 13, 2026
77dba07
docs(devlog): fold wp3 audit residual into L2 design
lidge-jun Sep 12, 2026
2c5022c
feat(codex): native-main device reauth API for headless hubs (#3898)
lidge-jun Sep 12, 2026
647e52f
feat(cli): ocx account main reauth --device with registry, docs, and …
lidge-jun Sep 12, 2026
4eed49e
fix(codex): close the cancel/commit race and fence the reauth commit …
lidge-jun Sep 12, 2026
584dadd
test(oauth): name the composite-signal proof and bound the fetch dead…
lidge-jun Sep 12, 2026
d666aef
test(codex): allow the transient cancelled read before publication wi…
lidge-jun Sep 13, 2026
4500ea0
docs(devlog): fold wp4 audit residual into L3 design
lidge-jun Sep 13, 2026
d111f8d
feat(gui): main-card Re-login with device code on the native reauth n…
lidge-jun Sep 13, 2026
7ab4cd4
merge: carry current dev into L1 WS stage instrumentation [skip ci]
lidge-jun Sep 13, 2026
e8ce186
merge: carry L1 WS stage instrumentation and current dev into L2 reau…
lidge-jun Sep 13, 2026
d420a46
merge: carry L2 reauth API and current dev into L3 main-card relogin …
lidge-jun Sep 13, 2026
247dc53
merge: carry the native-main trio and current dev into the remote run…
lidge-jun Sep 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,6 @@ tests/**/.tmp-*
# `git add` three separate times and reached `dev` once — see
# tests/ci-workflows/repo-hygiene.test.ts, which fails if any path here becomes tracked again.
go/

# Rust native helpers keep their reproducible sources and lockfile in git, never local artifacts.
native/**/target/
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ gui/eslint.config.*
gui/bun.lock

# misc
native/remote-workspace-helper/target/
*.test.ts
*.map
.DS_Store
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,25 @@ REMOTE-ARCH-003: Separate persisted enrollment capabilities from current connect
REMOTE-ARCH-006: Use existing required private-file/Windows ACL primitives for new identity and bearer stores. Check permission setup failures and refuse loading/saving secrets when enforcement fails. Do not change global config-store behavior. Record exact selected existing helper in phase-2 P after reading the owner; no best-effort function is accepted as proof.

REMOTE-ARCH-007: Codex real App Server tests depend on OCX_CODEX_BIN; Claude real integration on OCX_CLAUDE_BIN; Pi on OCX_PI_BIN. The Linux confinement case can return without execution unless OCX_REQUIRE_LINUX_REMOTE_WORKSPACE_CONFINEMENT=1 or bwrap is available. Current generic CI alone does not prove those paths. Mock tests prove lifecycle and tool-routing contracts only; native Hub isolation and executor confinement stay explicit final acceptance gaps when not activated. For each adapter separately record denied local tools, inherited plugins/hooks/config, offline refusal and teardown; inspect source plus hosted mocks, no claims of live CLI confinement from flags alone.

## Phase-2 revalidation and exact owner choices

Previous D: wp1 inactive foundation source cycle complete at 726ddc7fc0; final hosted proof remains wp4. Continue in child branch codex/260912-60plus-remote-runtime. Existing public exports and added host-negative coverage are retained.

REMOTE-ARCH-004: storage modules import atomicWriteFile directly from src/config/atomic-write.ts and getConfigDir from src/config/paths.ts, avoiding the broad config.ts barrel. Device CLI orchestration retains explicit runner construction because it computes actual availability after root approval; no import-time probe exists. This is intentional sequential coupling. Server seams in phase 3 use narrow structural connection/session interfaces rather than pulling concrete remote classes into shared request types. No remote module imports server surfaces.

REMOTE-ARCH-006 exact helpers: NEW src/remote-control/workspace-secret-store.ts owns prepareWorkspaceSecretDirectory(directory) and hardenWorkspaceSecretFile(path). On POSIX use chmodSync with propagated failure and lstat directory/file identity/type checks. On Windows call existing src/lib/windows-secret-acl.ts hardenSecretDir/hardenSecretPath with required:true. Reject symlink state targets. All three stores use this before reads and before atomicWriteFile. Existing atomic-write.ts already creates an empty private descriptor, hardens before writing bytes, and scrubs failures; retain it. Tests: NEW tests/clients/remote-workspace-secret-store.test.ts covers owner-only POSIX file mode, unexpected path types/symlinks and failed reads; hosted Windows ACL owner tests remain applicable. No global config behavior changes.

src/lib/windows-atomic-replace.ts change is the new ReplacePublisher literal remote-workspace (the function is already exported). Use existing counter serialization/consumers unchanged: creation at executor write, diagnostic key serialization, dynamic record readers; no closed switch to extend.

NEW tests/clients/remote-workspace-session-binding.test.ts covers session/device/root/capability mismatches with zero execution and a valid positive control, using encrypted messages and independent fixtures. MODIFY agent-wire, hub, sessions and device tests to assert subset negotiation and presence intersection. Platform runner source retains existing fail-closed native paths; remove stale comment claiming supported macOS commands.

### Audit amendment: store-level failure propagation

Hub/Device/Session file-store constructors accept an optional narrow permissions dependency containing prepareDirectory and hardenFile, defaulting to the required production helper. Load returns null for absent files; existing files require directory and file checks before secret reads. Save prepares directory, hardens an existing target, then invokes the existing private atomic writer. For each store, injected directory/file hardening throws must propagate, preserve existing bytes and prevent secret IO. New-state first-run controls return null then save/load valid fixtures. Add all three store cases to remote-workspace-secret-store.test.ts; this injection observes caller ordering rather than relying on ACL-owner tests alone.

### Native containment amendment

Independent source review requires a protected Linux bubblewrap executable outside writable roots, with identity revalidation before use. Custom executable files and their parent chain must not be writable by group/other; canonical system symlinks are resolved before checking. Workspace roots cannot contain the executable; every invocation rechecks. Add source/runner regression fixtures without claiming a local run.

Windows command availability remains disabled in this carry: nativeRemoteWorkspaceCommandRunnerAvailable returns false before invoking the helper, and the official Windows helper rejects public probe/run without allocating OS resources. The candidate Windows implementation remains in original PR history; do not retain callable unverified entrypoints. This matches the fail-closed macOS policy and preserves independently authorized file tools. Update native denial tests and docs; Windows working-command acceptance stays OPEN. A future lifecycle owner and hosted cancellation/cleanup evidence are required before re-enablement. This is a safety limitation, not completion of Windows commands.
108 changes: 108 additions & 0 deletions devlog/_plan/260912_unimplemented_trio_stack/000_plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Trio stack: WS stage instrumentation, native-main device reauth, paginated history recovery

Unit 260912_unimplemented_trio_stack. HOTL loop goalplan slug
`implement-three-unimplemented-opencodex-backlog` (session
01a09616-38e6-72e0-b5bf-99eb10ce58a6). Bottom-up manual stacked-PR chain
against `dev` (lidge-jun/opencodex). No merges, no GitHub native-stack
registration. Every push uses `git push --no-verify`; local product
suite/build/typecheck/install NOT RUN; each PR relies on hosted exact-head
CI and says so in its Verification section.

## Objective

Close the three implementable unimplemented backlog items identified in the
2026-09-12 inventory:

1. Issue #4191 — WS 1006 / response-prelude-timeout diagnosis has no durable
content-free evidence. Ship stage instrumentation only; no fix, no
auto-retransmit fallback.
2. Issue #3898 — headless hub cannot reauth native `__main__` because
deviceauth is pool-only. Ship the native-main device reauth API/CLI, then
the main-card Re-login GUI on top of it.
3. Issue #4311 residual — paginated history still has no writer support and
no recovery for ordinal-corrupted rollouts. Ship the offline recovery
tool with preservation proofs; live writes stay refused.

## Sources

- #4191 body: content-free stage diagnostics list; A/B evidence that the
failure is proxy-path-specific; related #2471, #4083, #3976.
- #3898 body: suggested contract (reuse OpenAI deviceauth, persist to native
main slot, keep `__main__` out of `/api/codex-auth/login`, no codex
binary/keyring requirement, secret-free DTOs).
- #4311 body: ordinal-0 clone defect (now guarded), incident recovery by
ordinal-digit rewrite while Codex was closed, prohibition of N+1 guessing
and live rewrites.
- devlog/_plan/260912_accounts/080_reauth_api.md and 090_reauth_ui.md —
accepted Accounts-lane design drafts this unit adopts for L2/L3.
- devlog/_plan/260912_history_containment/ — refusal contract this unit
must preserve.

## Constraints (hard)

- L1 logs stay content-free: create-frame byte count, send completion,
close code (numeric), elapsed/first-frame timings, frame counters, OCX and
Bun versions. No conversation text, no headers, no close-reason text, no
account identifiers in the new records.
- L1 adds no `responseCommitted === false` auto-retransmit: turn
duplication risk is documented in #4191 discussion.
- L2 keeps `/api/codex-auth/login` rejecting `__main__` (400), keeps pool
Add/Re-login semantics unchanged, and must not route the native flow
through `startLoginFlow("chatgpt")` (scratch-slot overwrite + pool
singleflight collision, src/oauth/index.ts:1899-1973).
- L2 commit to `$CODEX_HOME/auth.json` only under an exclusive claim with
path/hash/inode assertion and same-identity verification; never retains
old identity token beside new credentials; fails safe
(`native_main_unavailable`) when no fence can be established.
- L3 must not reuse `AddCodexAccountModal` or `openReauth("__main__")`;
dedicated hook and dedicated backend namespace only (the pool login route
rejects `__main__` at src/codex/account-id.ts:15-20).
- L4 must not invent last-ordinal+1, must not write to a live rollout, must
not weaken `history_paginated_requires_native_writer` refusal in
preflight/apply/restore paths, and must preserve every non-ordinal byte.
- All layers: focused tests land with the layer; every new test file gets
layout.json `explicit` + tests/fixtures/test-layout-expected.json
entries in the same PR.
- structure/ ownership: any owned source area changed by a layer updates
its structure doc in the same PR (structure/AGENTS.md).

## Work-phase map (dependency order = stack order, bottom first)

| WP | Layer | Branch | PR base | Decade doc |
|----|-------|--------|---------|------------|
| wp2 | L1 #4191 WS stage instrumentation | codex/260912-ws-stage-instrumentation | dev | 010 |
| wp3 | L2 #3898 native-main reauth API/CLI | codex/260912-native-main-reauth-api | wp2 branch | 020 |
| wp4 | L3 #3898 main-card Re-login GUI | codex/260912-native-main-reauth-ui | wp3 branch | 030 |
| wp5 | L4 #4311 paginated history recovery | codex/260912-native-paginated-writer | wp4 branch | 040 |

Dependency logic: L2 and L3 are one feature split at the API/UI seam
(030 depends on 020's route). L1 is independent but touches the shared
request-log schema, so it sits at the bottom where later layers rebase onto
a stable log contract. L4 is the riskiest (user data) and rides on top so
lower layers can land without waiting for it. There is no functional
dependency between L1/L2 and L4; the chain exists to serialize review.

## Verification policy per layer

- Red-first focused tests, then implementation, then green.
- `bun test tests/<domain>/<file>` (or `cd gui && bun test tests/<file>`
for L3) fresh at C, captured via `cxc receipt test`.
- Full local suite/build/typecheck/install: NOT RUN (standing rule); each
PR Verification section labels this and names the hosted exact-head CI
run as the integration evidence. Cancelled/skipped CI never counts as
passing.
- L4 additionally: privacy-relevant paths (rollout bytes) stay in tests
with synthetic fixtures only.

## Open decisions carried to audit

1. L2 hub fence: on a headless hub the native owner never activates
(src/server/index.ts:1026-1046 + src/codex/desired-state.ts:79-81).
020 resolves how commit fencing works there without weakening the
exclusive-claim contract; audit must confirm the chosen fence.
2. L4 scope: true live-write support needs a Codex-owned writer API that
does not exist in this tree. This unit ships the offline recovery tool
and keeps live refusal; the PR description must say so explicitly.
3. L3 screenshot evidence: obtained from hosted CI artifacts or recorded
exemption, per repo PR gate (title/body mentions of gui need a
screenshot).
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Baseline revalidation (wp1 B-phase)

Independent main-session spot check of the citations folded in by the wp1
audit (0268727f82), re-run against the working tree at B. Every folded
reference was opened and read; results below. All verified TRUE.

| Claim | Where verified | Result |
|-------|----------------|--------|
| `assertNativeMainOwner` throws without a held owner entry | src/codex/native-main-owner.ts:302-314 — throws NATIVE_MAIN_OWNER_UNAVAILABLE/BUSY (503) unless snapshot held | TRUE |
| Exclusive claim is owner-independent (FS/SQLite lock) | src/codex/native-main-claim.ts:167 — `withNativeMainExclusiveClaim(context, operation, options)`, claim/release around operation, no owner lookup | TRUE |
| `shouldSyncCodexOnStart` is composed at desired-state.ts:130 | src/codex/desired-state.ts:130 — exported function; comment names the hub rule | TRUE |
| Pool login writes `isMain: false` | src/codex/auth-api.ts:2934,2939 — both update and add paths set `isMain: false` | TRUE |
| Paginated guard throws the structured reason | src/codex/history-provider.ts:1172 — `CodexHistoryIntegrityError("history_paginated_requires_native_writer")` on `ordinal` key or `history_mode === "paginated"` | TRUE |
| State DB resolution | src/codex/paths.ts:106-109 — `resolveCodexStateDbPath` joins sqlite root + state_5.sqlite | TRUE |
| `startLoginFlow` location | src/oauth/index.ts:1899 — export begins | TRUE |
| GUI modal state | gui/src/components/CodexAccountPool.tsx:75 (`showAdd`), :94 (`reauthId`), :651-654 (modal mount) | TRUE |

Consequence for implementation cycles: 020's hub-fence resolution stands
as amended — the native-main reauth fence MUST NOT call
`assertNativeMainOwner`; the owner-independent exclusive claim plus
path/hash/inode and recovery/admission rechecks is the whole fence, and
claim/admission failure alone maps to `native_main_unavailable`.
Loading
Loading