Skip to content

PR 029 P1: Harden termination promise resolution - #33

Draft
LogicDuke wants to merge 1 commit into
repair/pr025-normalization-release-orderfrom
repair/pr029-terminate-thenable-settlement
Draft

PR 029 P1: Harden termination promise resolution#33
LogicDuke wants to merge 1 commit into
repair/pr025-normalization-release-orderfrom
repair/pr029-terminate-thenable-settlement

Conversation

@LogicDuke

@LogicDuke LogicDuke commented Aug 19, 2026

Copy link
Copy Markdown
Owner

Purpose

Stacked validation PR for:

AUDIT-PR029-TERMINATE-RETURNS-THENABLE-DEFEATS-SETTLEMENT

This PR is intentionally narrow and quarantined.

It targets protected parent PR #29:

repair/pr025-normalization-release-order

It does NOT target main.

It does NOT directly target PR #25.

It does NOT directly target protected PR #10.

Finding

Classification:

CURRENT P1

Exact affected parent HEAD:

36f8ae0659f51c0891b93f15a40ea2fab71edd73

The process transport remained vulnerable to persistent mutation of
Promise.prototype.then through implicit Promise assimilation performed by the
JavaScript runtime.

Even though explicit settlement-critical .then(...) sites had already been
hardened, terminate() still returned a Promise from an async function.

Resolving the async function's own Promise capability with that Promise can
perform thenable assimilation and consult a mutable inherited then.

A persistent hostile replacement could therefore leave:

  • the mandatory hardening-failure path pending indefinitely;
  • ordinary timeout settlement pending after the deadline had already been spent.

The stronger Promise.prototype.constructor + then mutation could also push
internal awaits off their native fast path and into hostile thenable
assimilation.

The defect was independently reproduced on exact protected parent HEAD.

It was also verified to exist in the inherited lineage and was not introduced
by PR #29.

Repair

The bounded repair:

  • awaits the platform-specific termination Promise inside terminate() and
    returns only the primitive TerminationScope;
  • introduces protectPromiseResolution(...) for selected internally-created
    Promises that this module later awaits after hostile code may have run;
  • pins a non-configurable, non-writable own constructor equal to captured
    NativePromise;
  • prevents await from falling back into hostile thenable assimilation through
    mutable Promise.prototype.constructor;
  • preserves the native PromiseResolve fast path;
  • avoids consulting Symbol.species on that route;
  • adds no timer;
  • adds no settlement backstop;
  • adds no new scheduler;
  • adds no new process authority;
  • leaves Windows/POSIX termination semantics unchanged;
  • preserves exactly-once public settlement;
  • preserves mandatory release;
  • preserves terminal-cause precedence;
  • preserves prior Error / Symbol.hasInstance / captured-then hardening.

Changed files exactly:

  • src/adapters/process-transport.ts
  • tests/adapters/process-transport.test.ts

Exact quarantine identity

Protected parent PR #29 HEAD:

36f8ae0659f51c0891b93f15a40ea2fab71edd73

Repair commit:

5aa85827c41931f67053190c79bfa628a034f680

Validated patch SHA-256:

B473C5BB0169204193466BD2E6D9D38C9D19091B64A9861D89F6EB0EDFA1C7F7

Patch bytes:

37187

Changed files exactly:

  • src/adapters/process-transport.ts
  • tests/adapters/process-transport.test.ts

The committed patch was mechanically verified byte-for-byte identical to the
candidate that passed fresh independent validation.

Independent validation

Fresh independent validation:

PASS

The validator independently:

  • reproduced the original persistent hostile-then defect on pristine parent HEAD;
  • reproduced the hardening-failure pending case;
  • reproduced the ordinary-timeout pending case;
  • reproduced the constructor+then variant;
  • proved the terminate() return-await mechanism is load-bearing;
  • proved protectPromiseResolution(...) is load-bearing;
  • proved every added protection site is load-bearing;
  • verified the helper is total under staged defineProperty failure;
  • verified behavior when internal Promises are made non-extensible;
  • verified exactly-once settlement;
  • verified mandatory release;
  • verified terminal-cause preservation;
  • verified no SPAWN_FAILED laundering;
  • verified no AgentExchange laundering;
  • verified no unhandled rejection introduced;
  • verified no child abandonment;
  • verified all prior stacked repairs remain intact;
  • found zero new CURRENT P0/P1/P2/P3 candidate defects;
  • reverified the exact patch fingerprint byte-for-byte.

Validation evidence

Focused adversarial tests:

4 passed

Complete process transport:

154 passed, 9 skipped

Adapters suite:

463 passed, 9 skipped

Full suite:

1189 passed, 9 skipped

Typecheck:

PASS

Lint:

PASS

Build:

PASS

git diff --check:

PASS

Validation host:

Windows.

The 9 skipped tests are POSIX-gated tests.

No Windows result is claimed as proof of POSIX runtime behavior.

Public-return observation

Validation separately examined the public Promise returned by
invokeAgentProcess(...) under globally poisoned external Promise semantics.

The transport itself still fulfills or rejects that Promise exactly once.

A caller's own ordinary await may fail to observe an already-settled Promise
after the caller/runtime has globally poisoned Promise semantics.

That condition was independently classified:

NOT REPRODUCIBLE

as an AgentBridge defect.

This PR does not broaden its API surface to address arbitrary external caller
Promise poisoning.

Out-of-scope CURRENT finding

This PR does NOT repair:

AUDIT-PR029-DISCARDED-RUNTERMINATION-REJECTION

Classification:

CURRENT P2

That finding remains separately quarantined and must receive its own bounded
repair track.

Protected invariants

This repair preserves:

  • eventual settlement;
  • exactly-once caller settlement;
  • bounded child release;
  • hardening-failure terminal cause;
  • no SPAWN_FAILED laundering;
  • no AgentExchange laundering;
  • no discarded rejection introduced;
  • Error identity;
  • exact cause retention;
  • Windows/POSIX termination semantics;
  • honest termination scope;
  • raw output behavior;
  • output bounds;
  • environment isolation;
  • cwd/stdin behavior;
  • shell:false;
  • no PID/PGID authority expansion;
  • dormant/unwired process transport;
  • frozen AgentBridge architecture;
  • AgentBridge V1 managed-repository READ-ONLY authority.

Quarantine rule

This DRAFT PR is evidence/proposal only.

Do not merge it because implementation, independent validation, CI, CodeRabbit,
or Codex reports success.

Required before upward integration into PR #29:

Summary by CodeRabbit

  • Bug Fixes
    • Improved process termination reliability when applications modify native Promise behavior.
    • Ensured timeout, cleanup, and termination operations continue to settle correctly and preserve existing error handling.
  • Tests
    • Added coverage for Promise-related mutations during process hardening and timeout scenarios.
    • Verified reliable cleanup, termination attempts, error reporting, and absence of unhandled rejections.

@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5fb519d6-c8cf-4294-bf73-143b0b07bfa6

📥 Commits

Reviewing files that changed from the base of the PR and between 36f8ae0 and 5aa8582.

📒 Files selected for processing (2)
  • src/adapters/process-transport.ts
  • tests/adapters/process-transport.test.ts

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The process transport now protects internally created promises from mutated Promise intrinsics. Termination and cleanup paths await protected promises. New subprocess tests cover hardening failures, timeouts, settlement, cleanup, and intrinsic restoration.

Changes

Process transport promise hardening

Layer / File(s) Summary
Protect internally created promises
src/adapters/process-transport.ts
Adds protectPromiseResolution and applies it to resolved values, exit waits, taskkill operations, and close waits.
Harden termination orchestration
src/adapters/process-transport.ts
Termination awaits the protected platform strategy, returns TerminationScope, and preserves cleanup fallback behavior.
Validate hostile intrinsic scenarios
tests/adapters/process-transport.test.ts
Adds subprocess probes and adversarial tests for persistent then and constructor mutations across failure and timeout paths.

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

Merge Risk: ⚪ Minimal · up to 5aa85

This PR hardens termination promise handling without introducing a demonstrated merge-blocking correctness or availability issue. It is merge-ready after normal checks and review; no actionable merge-blocking risk remains.

Sequence Diagram(s)

sequenceDiagram
  participant runTermination
  participant terminate
  participant PlatformTermination
  participant awaitClose
  runTermination->>terminate: await protected termination promise
  terminate->>PlatformTermination: request platform termination
  PlatformTermination-->>terminate: return TerminationScope
  runTermination->>awaitClose: wait for process close
Loading

Possibly related PRs

Poem

A rabbit guards each promise tight,
From poisoned then through timeout night.
Processes close, errors stay true,
Native constructors pull them through.
Hop, hop—cleanups finish bright!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: hardening termination Promise resolution.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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 repair/pr029-terminate-thenable-settlement

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.

@LogicDuke

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown
✅ 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.

@LogicDuke

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5aa85827c4

ℹ️ 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +239 to +242
} catch {
// Unreachable for a freshly created promise; see the doc comment. Returning
// the promise unchanged keeps this helper total.
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Do not continue with an unprotected non-extensible promise

When a promise is non-extensible, this catch silently returns it without the own constructor, so the settlement hardening is lost. This is reachable by enabling an async_hooks hook after module load and calling Object.preventExtensions(resource) for PROMISE resources; with the persistent Promise.prototype.constructor and then substitutions this patch targets, I reproduced an ordinary timeout remaining pending because waitForExit/terminate awaits assimilate the unprotected promise through the hostile then. The definition failure needs a fallback that preserves settlement rather than treating the promise as protected.

Useful? React with 👍 / 👎.

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