Skip to content

[pull] main from nearai:main - #38

Merged
pull[bot] merged 5 commits into
bryanwills:mainfrom
nearai:main
Jul 5, 2026
Merged

pull[bot] merged 5 commits into
bryanwills:mainfrom
nearai:main

Conversation

@pull

@pull pull Bot commented Jul 5, 2026 •

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

henrypark133 and others added 5 commits July 4, 2026 11:32
…, framework disentanglement, single-run coverage (#5633)

* test(reborn): move roadmap integration suite to tests/integration/ (skeleton + renames)

Commit 1/8 of the integration-suite restructure. Byte-pure moves:
tests/support/reborn/ -> tests/integration/support/, 27 reborn_integration_*.rs
bins -> tests/integration/<name>.rs, 7 reborn_group_* dirs ->
tests/integration/group_<name>/. Cargo [[test]] names stay identical; only
paths move (27 entries added, 7 retargeted). Only content edits: the
#[path] mount lines each move forces (flat bins, group mains, 33 parity/QA
bins) — wiring folded into this commit so every commit builds green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(reborn): split harness.rs into harness/{mod,recorder,options,assembly} + doubles/, extract binary-E2E family to tests/support/reborn_parity_qa/

Commit 2/8. Symbol-preserving split of the 5530-line harness.rs at its final
home: recorder.rs (capability recorder), options.rs (HostRuntimeHarnessOptions,
verbatim), assembly.rs (local_dev_* runtime/filesystem/policy/mount helpers),
doubles/ (14 files, one per substituted production port, rustdoc header names
the production seam), residual core in harness/mod.rs with pub(crate) use
re-exports preserving every surviving reborn_support::harness::<Name> path.
RebornBinaryE2EHarness + SubmittedTurn + RebornHarnessSharedStorage +
HarnessLoopExitEvidencePort + assert_milestone_order + trace_tool_call_response
and model_replay.rs leave to tests/support/reborn_parity_qa/ (their consumers
are exclusively parity/QA); the 33 parity/QA bins mount the new
parity_qa_support tree and repoint only those imports. Only content changes
beyond the moves: use/mod lines, visibility bumps the new module boundaries
force, and per-file dead_code allows replacing the old blanket allow.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(reborn): collapse harness tools-constructor table into ToolsProfile + harness/profiles/ domains

Commit 3/8 — the design commit. HostRuntimeHarnessOptions gains Default;
new ToolsProfile value type (options.rs) captures the shared
new_with_options seven-arg shape plus the four observed post-construct
steps (network-policy override, provider-trust override, asset copy,
auto-approve default), applied in the constructors' existing order by the
one shared ToolsProfile::build() path. Every tools constructor leaves
harness/mod.rs for a per-domain profiles/<domain>.rs file (16 domains):
ToolsProfile rows become <name>_profile() + a thin build wrapper; bespoke
constructors (qa_smoke, core_builtin, github issue trio, mock_mcp,
web_access) move verbatim. The 4-deep core_builtin suffix-variant chain
folds into one CoreBuiltinOptions; the four variants are deleted.
project_tools_with_fault_injection (new since the plan's table) rides in
profiles/project.rs. Thick group pairs (live_approvals,
live_auth_and_approval, profile_tools, outbound_target_tools) adopt
ToolsProfile::build_group_capability_with_base over GroupBaseData with
auto-approve disables kept explicit at call sites;
capability_backend::install() now selects via the same profile fns,
deleting its duplicate constructor-selection table. The six group-builder
runtime setters move to group_options.rs (private child module of
group.rs, group_constructors precedent). Constructor doc comments carried
verbatim. Flip-checked: falsifying the trigger profile's capability set
turns reborn_group_triggers red for the right reason.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(reborn): finish parity/QA disentanglement — qa/delivery/network support to reborn_parity_qa/, drop dead approval.rs

Commit 4/8. git-mv qa_trace.rs, qa_scenarios.rs, delivery.rs, network.rs from
tests/integration/support/ to tests/support/reborn_parity_qa/ (their consumers
are exclusively parity/QA bins) and rewrite those consumers' imports
(qa_recorded_behavior, qa_smoke_scenarios_e2e, qa_doc_grounding, qa_web_fetch,
qa_channel_delivery, outbound_reply_target parity, support_unit_tests).
Delete approval.rs — zero consumers anywhere (pub use GateRef + an unused
alias). classify-test-scope.sh's reborn path arm now matches
tests/integration/* and tests/support/reborn_parity_qa/* instead of the
removed tests/support/reborn/*; fixture updated. New
tests/support/reborn_parity_qa/CLAUDE.md documents the tier split and the
one-way import direction (parity/QA imports FROM tests/integration/support/,
never the reverse — direction grep clean).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* ci(reborn): single-run integration-tier coverage lanes + suite-boundary guard

Commit 6/8. Kills the run-twice shape: the 34 tests/integration/ suites now
run ONCE, instrumented, in a 5-lane reborn-integration-coverage matrix (4
modulo partitions of the 27 flat bins + 1 group lane), features unified to
libsql. Each lane produces its lcov from one combined
'cargo llvm-cov --workspace --features libsql test --test ...' invocation —
the split --no-report + 'report --lcov' shape silently drops all
crates/ironclaw_* files because the standalone report subcommand has no
--workspace flag (verified empirically). New coverage-report job merges lane
lcovs (checked-in Python merger; sums DA per file:line, recomputes LF/LH,
filters to crates/ironclaw_*), applies tests/integration/
coverage-exemptions.toml (seeded empty; every entry needs reason + issue
link), and renders a per-crate table to the job summary + a sticky PR
comment. Informational only — pass/fail gating rides the instrumented lanes;
coverage-report failures warn, never red, the roll-up.

reborn-coverage.yml (the duplicate compile+run) is deleted. Parity/QA
root-partition lanes stay uninstrumented — the harness-only coverage
boundary is enforced by job topology. Instrumented lanes use a dedicated
reborn-integration-cov cache key. Discovery scripts retarget to
tests/integration/ (group and int-tier enumeration; root partitions now
match only the parity/QA bins by construction). New
scripts/ci/check-test-suite-boundaries.sh (invoked next to
classify-test-scope.sh) enforces the one-way support-tree direction, the
parity/QA mount rule, and that tests/support/reborn/ never reappears.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(reborn): repoint living docs to tests/integration/ layout

Commit 7/8. tests/integration/support/CLAUDE.md moves to
tests/integration/CLAUDE.md with surgical fixes for the new reality (harness/
split + profiles/ + doubles/ file map, new mount-line boilerplate for flat
bins and group mains, [[test]] naming convention, binary-E2E family pointer
to tests/support/reborn_parity_qa/CLAUDE.md). Root CLAUDE.md spec table +
testing pointers, the ironclaw-reborn-testing and reborn-feature skills, and
the two living docs/reborn/ pages repoint the same way. Historical dated
plans/specs under docs/superpowers/ deliberately untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(reborn): comment de-bloat across tests/integration/

Commit 8/8. Comment-only pass over all 126 tests/integration/ files
(zero code changes — verified by non-comment diff-line scan). Deleted:
narration/play-by-play, migration/wave/lane provenance, restated
signatures, duplicated profile/wrapper doc blocks, history essays.
Kept, compressed to 1-2 lines: why-pins, mutation-verified notes,
doubles seam contracts, product decisions — invariant + issue/PR ref;
every C-*/E-*/T0-* seam id and DEFERRED/COVERED pointer retained
(regex-checked per lane). ~1,800 comment lines removed net.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(reborn): apply post-PR review findings — explicit ToolsProfile user_id, const dedup, stale-path sweep + guard

Review follow-up (thermo-nuclear + code-review passes on #5633):
- ToolsProfile::new now takes user_id explicitly — the service_label-seeded
  placeholder was a silently-valid wrong value if a profile ever forgot to
  override it; all 15 profile call sites pass their fixed domain user id.
- TEST_CAPABILITY_ID/TEST_CAPABILITY_SURFACE_VERSION deduplicated: binary_e2e
  now imports the doubles-tree constants instead of carrying drift-prone
  copies.
- Stale tests/support/reborn/ references swept from tests/** and Cargo.toml
  (snapshot source headers included); check-test-suite-boundaries.sh gains
  check #4 failing on any reappearance of the retired path under tests/.
  (Doc-comment stragglers inside crates/ are deliberately left for a separate
  docs-only PR — production files stay outside this PR's diff surface.)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(reborn): address #5633 review findings — script hardening, doc repoints, harness re-encapsulation

CI scripts: lcov crate regex accepts relative paths ((?:^|/)crates/) in
merge+summary; exemption module paths must start with crates/ (suffix match
could over-exempt; +A9 regression case); classify-test-scope now marks the
coverage/boundary helper scripts as Reborn scope so helper-only PRs can't
fast-pass the pipeline they drive (+6 regression cases).

Docs/comments: stale pointers to the removed tests/integration/support/
CLAUDE.md now target tests/integration/CLAUDE.md; group-main boilerplate
doc shows the real ../support/mod.rs mount; harness/mod.rs header rewritten
for HostRuntimeCapabilityHarness (binary-E2E contract moved); doubles
headers cite each substituted symbol's actual production file; parity-bin
comment and missing #[allow(dead_code)] mount attr fixed.

Structure (review-accepted): build_group_capability_with_base moved from
ToolsProfile into group_constructors.rs — profile layer no longer imports
group::GroupBaseData, and GroupBaseData/canonical_subject_user return to
module-private. Capability-port assembly moved into harness-owned
create_recording_capability_port; HostRuntimeHarnessCapabilityPortFactory
is a thin trait adapter and 13 harness fields + 2 methods narrowed from
pub(crate) to module-private.

Coverage: live_shell_uses_local_process_port pins the ShellMode::Live
caller path — real LocalHostProcessPort output surfaces in the tool result
while the inert recording port stays untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Maps every reborn run error to recoverable / run-borking, analyzes PR
#4841 coverage, and lays out the path to the two-bucket end state
(SecurityStop | Retriable | Explainable). Headline finding: the
host_runtime disposition layer intends no capability failure to abort,
but the recovery strategy aborts on Dispatcher/InvalidOutput/Unknown —
re-bucketing that class makes "model called a nonexistent tool" and
malformed-output failures recoverable.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
A genuine single-line final answer that mentions a `__`-bearing tool (e.g.
"Tool result from web__fetch: near.ai returned 200 OK") was misclassified as a
replayed provider-transcript artifact and rejected, so the real answer vanished.
Only treat MULTI-line content as a transcript artifact; a weak model echoing
replayed history reproduces multiple lines, which is still caught. Reject tests
updated to multi-line; added a single-line accept test.

(F1 stalled-turn recovery intentionally NOT included: gating the nudge on any
tool call over-fires on pure-failure runs, and the target 3B hang is the runner
queue not draining — a separate P0, not a no-reply-at-exit. Doing F1 right needs
a successful-tool-call signal that state does not yet track.)

cargo test -p ironclaw_agent_loop: 317 passed, 0 failed.

Co-authored-by: Abhishek Vaidyanathan <abhishekvaidyanathan@96:11:14:d5:f7:ba.home>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(migration): add v1/engine-v2 → Reborn state migration tool

New crate `ironclaw_reborn_migration` (library + `ironclaw-reborn-migration`
binary) that converts legacy IronClaw v1 and engine-v2 persisted state into the
Reborn state substrate, recording every unconvertible value in a machine-readable
manifest so nothing is silently dropped.

Reads a v1 database (PostgreSQL or libSQL) via the root `ironclaw` crate — which
is also where engine-v2 mission/project state lives, as JSON blobs in
`memory_documents` — and writes through Reborn domain stores built directly over
a RootFilesystem / triggers DB.

Converts:
- conversations + messages → session threads (ids/timestamps preserved)
- cron routines + cron missions → TriggerRecords; mission threads under
  ThreadScope.mission_id
- memory documents → ironclaw_memory documents
- secrets → decrypt via v1 store, re-encrypt via Reborn SecretStore
- user/channel identities → adopt_migrated_identity
- installed wasm tools/channels → ExtensionInstallation (placeholder manifest)

Gaps recorded in the manifest (no Reborn target): event/webhook/manual trigger
sources, non-cron mission cadences, routine guardrails/notify/run-history,
mission-only fields, jobs, settings, memory versions, heartbeat, extension
manifest fidelity + WASM binary, pairing requests.

Adds a `migration-support` feature + `extension_installation_store_for_migration`
seam to `ironclaw_reborn_composition` (ships zero bytes without the feature), and
read-side channel-store re-exports in `src/channels/wasm`.

Acceptance test (`tests/migration_roundtrip.rs`, libSQL, Docker-free) seeds a
rich v1+engine-v2 fixture, runs the migration, and asserts converted counts, the
exact gap set, triggers read back through the public repo, and on-disk durability
of thread/secret/extension documents. A dry-run case asserts full reporting with
no writes.

Follow-up (documented, deferred per scope): wire run_migration into
`ironclaw-reborn` startup.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(migration): address PR #5627 review — fail-loud on silent drops, TLS, secret redaction

Addresses the CodeRabbit/Copilot/Gemini review on the v1→Reborn migration
tool. Core theme: the crate's "nothing is silently dropped" contract was
not fully upheld, plus a few security/cleanup gaps.

Data integrity (silent drops → recorded losses or propagated errors):
- source: `distinct_user_ids_in` now tolerates only a missing table; every
  other connect/query/row-decode failure propagates instead of being
  swallowed as "0 users" (would have silently dropped every record keyed
  to an undiscovered user). Adds an explicit user-id column arg — the
  `users` table keys on `id`, not `user_id` (the old code silently ate the
  "no such column" error).
- automations: unparseable engine-thread blobs and parseable-but-orphaned
  threads (referenced by no mission) are recorded; dry-run mission threads
  now record the same per-message losses as the real write path.
- extensions: `tool_credential_bindings` propagates capability read errors
  and records unconvertible secret names; the synthesized
  ExtensionInstallationId is scoped by owner so per-user same-named installs
  no longer overwrite each other.
- identities: invalid user id in the OAuth path is recorded (matching the
  channel path); `read_channel_identities` tolerates only a missing table
  and records malformed rows.
- secrets: the expiry re-read failure is recorded, not dropped via `.ok()`.
- bad-user-id is now a per-item loss + skip (not a run abort) in threads,
  secrets, automations (routines + missions), and memory.

Security:
- target Postgres now enforces the repo's remote-TLS rule (reject
  sslmode=disable for remote hosts; rustls via ironclaw::db::tls) instead
  of always using NoTls — migration traffic carries decrypted secrets.
- Postgres URLs are held as SecretString (SourceDb/TargetStore) and the
  `Cli` struct drops its `Debug` derive so creds/keys can't leak via `{:?}`.

Cleanup:
- mounts map the system-scope sentinel to `__system__` (mirrors production
  invocation_mount_view) so system-scoped service ops resolve correctly.
- v2_model `now()` → `epoch_fallback()` (it returns the epoch, not "now").
- `V1Source` is now pub(crate); secrets `migrate_one` carries the required
  arch-exempt annotation; CLAUDE.md example drops the absolute /tmp path.
- add a `ironclaw_reborn_migration` BoundaryRule so the v1↔Reborn bridge
  can't grow direct deps on the serving/runtime/engine layers.

Tests: the roundtrip acceptance test now asserts the exact per-domain gap
set (summing to the whole report so a newly-dropped domain fails the
build), seeds tool capabilities to exercise credential-binding + Enabled
activation, and asserts extension/identity idempotency on re-run.

Declined (replied on the PR): error `domain` String→enum (field carries
freeform context, not a strict domain); redacting LossyItem source_id
(operator-only tool needs actionable ids, no secret values exposed);
gemini `expose_secret` (false positive — DecryptedSecret::expose exists).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(migration): address CodeRabbit re-review — mission next_run_at, narrower table-missing, shared user-id helper

Follow-up to the review round on PR #5627:

- automations: a mission with no `next_fire_at` no longer falls back to
  `created_at` (which can be the `epoch_fallback` synthesized for a drifted
  blob → a 1970-dated, immediately-due trigger). The trigger's `next_run_at`
  is now synthesized to the migration time and recorded as a `Degraded` loss
  (`mission_next_run_at`).
- source: `is_missing_table_error` is narrowed to require `relation` alongside
  `does not exist`, so a PostgreSQL *column*-not-found (`column "…" does not
  exist`) is no longer downgraded to an empty user set — keeping the exact
  silent-drop class #21 guards against.
- report: add a shared `MigrationReport::valid_user_id` helper and route the
  six duplicated "validate UserId → record loss → skip" sites (identities x2,
  secrets, memory, routines, missions) through it so the shape can't drift.
- test: assert the serialized `"enabled"` activation token (and absence of
  `"disabled"`) instead of a loose lowercase substring; bump the exact Mission
  gap count to 4 (daily-digest now records the synthesized next_fire_at).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
@pull pull Bot locked and limited conversation to collaborators Jul 5, 2026
@pull pull Bot added the ⤵️ pull label Jul 5, 2026
@pull
pull Bot merged commit 209da7d into bryanwills:main Jul 5, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants