Skip to content

refactor(control-plane): move Effect Program authority to TypeScript - #3416

Merged
huangruiteng merged 3 commits into
mainfrom
codex/ts-core-migration-spike
Aug 21, 2026
Merged

refactor(control-plane): move Effect Program authority to TypeScript#3416
huangruiteng merged 3 commits into
mainfrom
codex/ts-core-migration-spike

Conversation

@huangruiteng

Copy link
Copy Markdown
Owner

Outcome

This is the first bounded TypeScript control-plane cutover. It moves the canonical Effect Program, settlement algebra, Turn-journal interpretation, and durable Turn-journal checkpoint effect to TypeScript while preserving the existing Python CLI and adapter APIs.

The repository does not retain two semantic engines:

  • effect_program.ts owns Effect and settlement rules;
  • the Python effect_program.py and settlement_driver.py surfaces are compatibility/callback facades into one managed runtime;
  • transaction phases come from one shared JSON contract;
  • the old Python Turn-journal interpreter, its rule test, and the migration-only embedded Python characterization worker are removed;
  • external JSON is decoded at the TS runtime boundary instead of being trusted through assertions.

The managed runtime is started on demand, reused across CLI calls, bound to loopback with a private token, rotated by a source fingerprint, recovered after stale metadata/start locks or crashes, and released after idle. Users do not manually manage a daemon. loopx doctor projects readiness, lifecycle, and public-safe diagnostic codes.

The TS runtime owns one real durable side effect in this slice: Turn-journal checkpoints use a same-key lock, previous-content CAS, operation identities, atomic replacement, and file fsync. A lost response can therefore be retried without duplicating or overwriting another effect.

Latest-main integration: #3342

This branch is rebased on 6e7dd0a0a / #3342. That change adds the provider-neutral Claude/Kunlun host settlement path and imports SettlementIdentity. Under this cutover, that shipping adapter path becomes a real consumer of the TS authority.

  • no source conflict or adapter API change;
  • the original guard -> completion -> accountable writeback -> spend -> optional terminal-closeout order remains unchanged;
  • all fix(claude): bind completed-turn spend to the selected todo and refresh state #3342 real-CLI and MCP settlement tests pass on the rebased branch;
  • first identity construction starts the runtime in 189.182 ms in an isolated run;
  • warm unique identities measure 0.328 ms p50 / 0.847 ms p95;
  • a coarse 36-test host-settlement suite took 85.46 s on main and 85.47 s on this branch when run concurrently, so no suite-level regression was observed (this is not treated as a sensitive microbenchmark).

Packaging and upgrade contract

  • requires Node.js 22.6 or newer;
  • wheel and sdist include the TS authority, runtime server, journal effects, and shared transaction contract;
  • both artifacts pass the same deep semantic probe in fresh Python environments;
  • install/upgrade/doctor/rollback guidance explains that stopped is a healthy idle state and that missing/unsupported Node fails closed rather than falling back to Python semantics;
  • CI runs TS typecheck/tests on Linux and the runtime integration portfolio on Linux and Windows.

Validation

Contract Result
TS compile + native semantic tests 18/18 passed
Declared minimum Node 22.6.0 18/18 passed
Focused Python Effect/settlement/Turn/runtime/Claude/Kunlun portfolio 173 passed
Pi/OpenCode/OpenCode2 host runtime contracts 80 passed
Pinned old-main Python -> final-head TS characterization 10/10 exact matches; no invariant failures
Repository-configured strict mypy no issues in 12 configured files
Focused Ruff + committed/staged/unstaged diff checks passed
Wheel clean install + deep identity/journal/readiness probe passed
Sdist clean install + same deep probe passed
Premerge canary 18 selected checks passed; 0 failures, skips, warnings, or manual holds
Public/private boundary scan passed
Exact change-quality receipt cqr_74e886dd711b0f29eb77, valid, 0 blockers

The scoped exploratory mypy comparison outside the repository-configured portfolio reports 20 existing errors on the candidate versus 21 on main. It is not used to turn a non-zero exploratory command into a passing oracle; the repository-declared strict mypy command itself passes.

Performance characterization

Measurement Result
isolated runtime cold start 157.484 ms
first host settlement identity including cold start 189.182 ms
warm runtime ping 0.447 ms p50 / 0.799 ms p95
warm unique host settlement identity 0.328 ms p50 / 0.847 ms p95
warm two-RPC bind path 0.590 ms p50 / 0.812 ms p95
runtime crash recovery 146.128 ms
running runtime RSS after burst 86,176 KiB (~84.2 MiB); returns to zero after idle exit
TS durable checkpoint, 100 runs 12.597 ms p50 / 18.610 ms p95
old Python atomic checkpoint, 100 runs 0.755 ms p50 / 2.020 ms p95

The checkpoint difference is deliberate durability work, not attributed to TypeScript alone: the new path adds RPC, file fsync, same-key locking, CAS, and operation-id calculation. This remains an explicit owner-review advisory.

A paired loopx doctor --deep comparison was noisy but showed no material regression: main p50 8,237.619 ms / p95 10,168.998 ms; candidate p50 7,942.542 ms / p95 8,176.975 ms; paired mean delta -1,034.505 ms. Both returned non-zero because unrelated ambient doctor checks were not clean, so this is reported only as comparative timing, not a correctness pass.

Failures, corrections, and excluded evidence

  • An initial focused Python run constrained PATH so aggressively that Node disappeared; nine runtime failures were test-environment errors. The final portfolio uses the normal Node path with only Git configuration isolation and passes 173/173.
  • One old executor unit built a journal without the canonical schema. The fixture now constructs a legal typed journal; production validation was not weakened.
  • The migration-only test that assumed current HEAD must still expose the old Python interpreter was removed together with its embedded old semantic worker. Exact parity was rerun against final HEAD using an external pre-cutover harness, so the evidence remains while the repository avoids dual semantics.
  • An early package probe treated semantic_probe as an object although its contract is the string passed; the corrected wheel and sdist probes both pass.
  • An attempted quota timing fixture did not model a bounded valid quota decision and is excluded from all claims.
  • Native Windows was not available locally. The PR adds the runtime portfolio to the existing Windows CI job; merge should wait for remote Windows and required checks.

Owner review decisions

Please review this PR before any later migration slice. The two intentional costs are:

  1. Node.js 22.6 becomes a required local runtime dependency for control-plane Effect semantics.
  2. Durable journal writes become slower in exchange for crash/retry correctness.

No later core-control-plane migration is included here, and this PR should not be merged until those tradeoffs and the remote CI results are accepted.

Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
@huangruiteng
huangruiteng merged commit a564bfe into main Aug 21, 2026
8 of 9 checks passed
@huangruiteng
huangruiteng deleted the codex/ts-core-migration-spike branch August 21, 2026 13:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant