Skip to content

feat(extension-runtime): Train B rollup — unified extension runtime P0–P7b - #6090

Closed
BenKurrek wants to merge 2 commits into
codex/nea25-generic-extension-runtimefrom
nea25/runtime-rollup
Closed

BenKurrek wants to merge 2 commits into
codex/nea25-generic-extension-runtimefrom
nea25/runtime-rollup

Conversation

@BenKurrek

Copy link
Copy Markdown
Collaborator

What this is

A tree-identical, non-destructive squash of the 9-phase IronClaw runtime train
(Train B — branches nea25/09-generic-runtime … nea25/17-finalize) into a single
commit on the docs bridge codex/nea25-generic-extension-runtime. The rollup commit's
tree is byte-identical to nea25/17-finalize (tip f8cbc88): both sides have tree
hash 1b2a43c96871633ba04c797122eb80c3547cf7ab, and git diff nea25/17-finalize is
empty. No code is lost; every phase branch remains alive.

This exists so the remaining P6 owner-call fixes and finalization can land on one
branch instead of being cascaded through nine.

The model (design law: docs/reborn/extension-runtime/)

Every integration (Slack, Gmail, GitHub, Telegram, …) is an ordinary installable
extension package. A generic runtime installs, activates, dispatches, and removes
extensions using only their manifest plus two adapter seams (ToolAdapter,
ChannelAdapter) and one recipe-driven auth engine — no generic crate contains a
concrete product name, protocol type, route, or behavior branch. ~34k lines of
per-vendor Slack machinery deleted.

Phases (from implementation.md §13)

Phase PR Content
P0 #5993 Architecture gates (specificity scanner + dependency-direction gate + retired-taxonomy gate; allowlist enumerating today's violations) + acme-messenger fixture
P1 #5995 Manifest v3 (inline [channel], [auth.*], [mcp]) + VendorId rename + recipe types + resolved record/digest + v2 normalization + first-party manifest rewrite
P2 #5996 ToolAdapter/ChannelAdapter + ExtensionEntrypoint + loaders (native/wasm/mcp) + ExtensionHost, installation state machine, immutable active snapshot; tool dispatch cutover
P3 #6008 AuthEngine (oauth2_code + api_key) + per-vendor recipes + auth account state machine; delete provider multiplexing (grants storage reused)
P4 #6007 Generic ingress router + declarative verifier (hmac_sha256 / shared_secret_header); Slack + Telegram inbound through adapters
P5 #6012 DeliveryCoordinator (all outbound intents, sole delivery-state writer) + Slack/Telegram outbound; CommunicationPresentationPolicy; generic trace contributions
P6 #6025 (draft) Extraction completion: config/connect UI + frontend replacement + CLI/config cleanup; delete composition/src/slack/** + old adapter crates; H.3–H.6 migrations
P7a #6056 Wire state enums (installation + auth account) + per-vendor accounts-list wire shape (list-first for the multi-account follow-up) + deferred legs
P7b #6065 Finalize: Lane A first-party package inventory as opaque bundles; DEL-2/DEL-5/DEL-8 consolidation; specificity allowlist reduction; VendorId alias deleted; REL docs

Sibling-merge note: the train DAG has a sibling merge (P3 nea25/12-auth-engine was
merged into the P6 line), so the tip's tree already contains both P3 (auth engine,
crates/ironclaw_auth/src/engine/) and P4 (ingress router,
crates/ironclaw_extension_host/src/ingress/router.rs). This squash flattens that DAG
into one diff — both are present and verified in the rollup tree.

Review record & supersession

This PR supersedes and squashes #5993, #5995, #5996, #6008, #6007, #6012, #6056,
#6065. Those 8 phase PRs are commented and closed, but their branches are untouched
— they remain the review record, including their PR bodies' flagged owner calls
(P5/#6012 flags 16; P6/#6025 flags 8). Closing is fully reversible: the branches
are intact and the PRs can be reopened.

P6 (#6025) is deliberately left open — it is still a draft, and its owner-call fixes
land on this branch next (the reason this rollup exists).

Because the diff is ~445 files (+57.7k / −62.6k), a squashed PR is not
unit-reviewable; the phase branches and their PR bodies are the review record.

Base

Head nea25/runtime-rollup, base codex/nea25-generic-extension-runtime — the same
base as P0/#5993 (the docs bridge = Train A tip + the design docs), so this PR's diff is
exactly Train B. It retargets onto main only after Train A merges.

Verification

  • Tree-identical (correctness gate): rollup tree 1b2a43c9… == nea25/17-finalize
    tree 1b2a43c9…; git diff nea25/17-finalize is empty.
  • One commit on codex/nea25-generic-extension-runtime (git rev-list --count = 1).
  • P3 + P4 both present in the tree (auth engine + ingress router).
  • CI: verified via the top-level "Code Style (fmt + clippy)" aggregate on this
    branch; the tree is byte-identical to already-green nea25/17-finalize, so the
    aggregate reproduces green.
  • Backup ref backup/nea25-17-pre-rollup records the pre-rollup tip (f8cbc88).

🤖 Generated with Claude Code

…0–P7b

Tree-identical squash of the 9-phase runtime train (branches nea25/09..17)
into one commit on the docs bridge. Every integration is now an installable
extension package driven by a generic runtime that installs, activates,
dispatches, and removes using only the manifest plus two adapter seams
(ToolAdapter, ChannelAdapter) and one recipe-driven auth engine — no generic
crate names or branches on a concrete extension. ~34k lines of per-vendor
Slack machinery deleted.

Phases (each preserved as a live branch + PR for the review record):

P0  (#5993) Architecture gates: specificity scanner + dependency-direction
    gate + retired-taxonomy gate, allowlist enumerating today's violations;
    acme-messenger fixture assets.
P1  (#5995) Manifest v3 (inline [channel], [auth.*], [mcp]) + VendorId rename
    + recipe types + resolved record/manifest digest + v2 normalization +
    first-party manifest rewrite (H.7).
P2  (#5996) ToolAdapter/ChannelAdapter + ExtensionEntrypoint + loaders
    (native/wasm/mcp) + ExtensionHost, installation state machine, immutable
    active snapshot; tool dispatch cutover to a prebound resolver.
P3  (#6008) AuthEngine (oauth2_code + api_key) + per-vendor recipes + auth
    account state machine; delete provider multiplexing (grants storage reused).
P4  (#6007) Generic ingress router + declarative verifier (hmac_sha256 /
    shared_secret_header); Slack + Telegram inbound through ChannelAdapter.
P5  (#6012) DeliveryCoordinator (all outbound intents, sole delivery-state
    writer) + Slack/Telegram outbound; CommunicationPresentationPolicy;
    generic trace contributions.
P6  (#6025, draft) Extraction completion: config/connect UI + frontend
    replacement + CLI/config cleanup; delete composition/src/slack/** and the
    old adapter crates; H.3–H.6 migrations.
P7a (#6056) Wire state enums (installation + auth account) + per-vendor
    accounts-list wire shape (list-first for the multi-account follow-up) +
    deferred legs.
P7b (#6065) Finalize: Lane A first-party package inventory as opaque bundles;
    DEL-2/DEL-5/DEL-8 consolidation; specificity allowlist reduction; VendorId
    alias deleted (MAN-11); REL docs sweep.

Squash base: codex/nea25-generic-extension-runtime (docs bridge = Train A tip
+ the design docs in docs/reborn/extension-runtime/). Tree byte-identical to
nea25/17-finalize (f8cbc88); no code lost, every phase branch remains intact.

Supersedes and squashes #5993 #5995 #5996 #6008 #6007 #6012 #6056 #6065.
P6/#6025 stays open — its owner-call fixes land on this branch next.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 14, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 73c6dfdf-9c78-4805-844e-d1f9f2335521

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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 added scope: agent Agent core (agent loop, router, scheduler) scope: channel/web Web gateway channel scope: sandbox Docker sandbox scope: ci CI/CD workflows scope: docs Documentation scope: dependencies Dependency updates size: XL 500+ changed lines risk: medium Business logic, config, or moderate-risk modules contributor: core 20+ merged PRs labels Jul 14, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request implements a significant architectural refactor of the extension system, transitioning to a unified manifest v3 format and introducing the ironclaw_extension_host crate to manage extension lifecycles, active snapshots, and ingress routing. Key changes include replacing the ProductAdapter trait with a more robust adapter system, centralizing auth logic into a recipe-driven engine, and adding new architectural gates for specificity and manifest reparsing. The reviewer correctly identified an improvement opportunity regarding the usage of the rand crate in the new keepalive sweep logic, recommending the use of rand::thread_rng() and gen_range for better practice.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +455 to +459
use rand::RngExt as _;
let max_nanos = max.as_nanos().min(u64::MAX as u128);
let nanos = rand::rng().random_range(0..=max_nanos);
let nanos = u64::try_from(nanos).unwrap_or(u64::MAX);
Duration::from_nanos(nanos)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The RngExt trait and random_range method are deprecated in recent versions of the rand crate. It's recommended to use the Rng trait and the gen_range method instead. Using rand::thread_rng() is also more explicit than rand::rng().

Suggested change
use rand::RngExt as _;
let max_nanos = max.as_nanos().min(u64::MAX as u128);
let nanos = rand::rng().random_range(0..=max_nanos);
let nanos = u64::try_from(nanos).unwrap_or(u64::MAX);
Duration::from_nanos(nanos)
use rand::Rng;
let max_nanos = max.as_nanos().min(u64::MAX as u128);
let nanos = rand::thread_rng().gen_range(0..=max_nanos);
let nanos = u64::try_from(nanos).unwrap_or(u64::MAX);
Duration::from_nanos(nanos)

… + REL-4 doc sweep

Post-audit corrections to the runtime-train acceptance ledger and docs.
No production logic changed (only a test-support doc-comment).

Checklist (docs/reborn/extension-runtime/checklist.md):
- Un-tick the two overstated rows with honest notes:
  - LIFE-12: shared-vendor grant policy is a P6-deferred no-op stub
    (FacadeOwnedRemovalHooks::revoke_and_delete_grants); only the empty-case
    removal context is pinned, so preserve/remove-on-last-consumer is unproven.
  - DEL-9: the deletion script passes locally (--trees-only green) but no CI
    workflow invokes it; the dependency-direction half runs via the
    ironclaw_architecture arch test. The "in CI" clause is unmet (tracked with REL-5).
- Tick MAN-8 (reserved trigger/file kinds, wire-pinned, no binding path) and
  MAN-9 (reborn_code_never_references_retired_taxonomy, green) with named
  evidence. Annotate MAN-6/MAN-7 as PARTIAL (missing ceiling-rejection /
  activation-caller tests) rather than tick.
- Refresh dead/stale citations: drop nonexistent slack_host_beta.rs and
  RuntimeHttpEgressUnavailable (OUT-4); correct slack_serve/e2e_tests.rs ->
  channel_host/e2e_tests.rs and 24 -> 28 count (ING-12, OUT-1); replace two
  retired OUT-2 test names; correct OUT-9 "both-DB store suite" (libsql-only);
  narrow AUTH-1's composition sub-note (allowlist-gated, tracked by DEL-8).

Tally unchanged at 99 checked / 20 open -- now the correct rows.

REL-4 docs:
- CHANGELOG [Unreleased]: add entries for the VendorId rename + manifest-v3,
  the unified delivery coordinator, and the auth-engine/provider-spec deletion.
- Correct hard-stale deleted-symbol refs in contracts/{host-api,extensions,
  communication-delivery-resolution,product-adapters}.md and FEATURE_PARITY.md
  (RuntimeCredentialAccountProviderId -> VendorId; ProductAdapter -> ChannelAdapter;
  drop nonexistent ironclaw_channel_adapter crate).
- Add RETIRED banners to telegram-v2.md and _contract-freeze-index.md.
- Clean a stale HostOAuthProviderSpec doc-comment (test_support).
Editorial/borderline tiers (retired-doc bodies, generic prose, manifest wire
tokens that may be live contract ids) were flagged for review, not touched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copy link
Copy Markdown
Member

Closing this because it still updates legacy top-level src/ runtime/extension paths as part of the extension-runtime rollup. Product work has moved to the Reborn workspace under crates/, so this PR is outdated as an implementation path.

The Reborn extension-runtime direction is already tracked broadly in #1741.

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

Labels

contributor: core 20+ merged PRs risk: medium Business logic, config, or moderate-risk modules scope: agent Agent core (agent loop, router, scheduler) scope: channel/web Web gateway channel scope: ci CI/CD workflows scope: dependencies Dependency updates scope: docs Documentation scope: sandbox Docker sandbox size: XL 500+ changed lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants