Skip to content

ci(reborn): count crate-tier tests in coverage + scoped denominator exemptions - #5658

Merged
henrypark133 merged 8 commits into
mainfrom
w6-metric-truth
Jul 6, 2026
Merged

henrypark133 merged 8 commits into
mainfrom
w6-metric-truth

Conversation

@henrypark133

Copy link
Copy Markdown
Collaborator

Summary

The Reborn coverage number was integration-tier-only, structurally blind to crate-tier test suites — audits showed ironclaw_llm reported 3.62% while carrying 894 crate-tier unit tests, and nine crates reported 0% while all nine have real tests. This PR makes the number tell the truth:

  1. Crate-tier tests now count. The existing crate-tests bucketed matrix job (which already runs cargo test -p <pkg> across the Reborn dependency closure on every PR) is converted in place to cargo llvm-cov -p <pkg> … --lcov … test — same packages, same feature resolution, same --all-targets, same execution, coverage as a byproduct. Per-bucket lcov artifacts merge into the existing coverage-report job.
  2. Denominator scoped to Reborn-reachable code. coverage-exemptions.toml gains a whole-crate crate = form (rationale + tracking-issue required per entry); initial entries exempt the four v1-only crates (embeddings, gateway, oauth, tui — reverse-dependency-audited, covered by the legacy test workflow). Tracked in Coverage scope: v1-only crates exempted from Reborn coverage denominator #5657.

Constraints honored by construction

  • No test re-runs for coverage: no new test-executing job anywhere; the conversion instruments the run that already exists. Int-tier lane untouched.
  • Coverage-calculation step ≤10 min: the coverage-report job is pure download/merge/render, timeout-minutes: 10 (was 15).

Local verification

  • cargo llvm-cov smoke on ironclaw_prompt_envelope (reported 0% today) with the exact new command shape: 13/13 tests pass, measures 97.99% — direct empirical confirmation of the undercount thesis.
  • Coverage-script test suite extended 80→93 cases (crate-form, mixed-form, malformed-entry regressions): 93/93 pass.
  • Merge script verified line-by-line on synthetic lcov (DA counts summed per file:line — overlapping coverage cannot double-count percentages by construction).
  • actionlint + shellcheck/bash -n clean.

Verify on first CI run

  • Wall-clock: job timeout 60→90m, per-package cap 28→40m; composition-core (single heavy package) is the bucket to watch.
  • Instrumented cache key separated (reborn-tests-crates-cov) — first run builds cold.
  • Projected numbers: exemptions alone 29.6%→30.6%; with crate-tier counted, roughly 55–75% (range, not a point estimate — ~55 crates' suites were never audited for density). The 80% target becomes a real conversation after the first post-merge baseline.

Follow-ups (not this PR)

🤖 Generated with Claude Code

henrypark133 and others added 5 commits July 4, 2026 23:36
Convert the existing crate-tests job's per-package `cargo test -p X`
invocation to `cargo llvm-cov -p X ... --lcov ... test` in place —
same test execution, instrumented, coverage as a byproduct, no second
run of anything. Each bucket concatenates its packages' lcov into one
artifact and uploads it for the coverage-report job to merge.

Bump job timeout 60m->90m and the per-package inner `timeout` wrapper
28m->40m for instrumentation overhead headroom (composition-core is
the single-package bucket with the least slack). Use a dedicated
`reborn-tests-crates-cov` cache key so the instrumented build never
shares a cache lineage with the plain `reborn-tests-crates` build.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Wire the new instrumented crate-tests bucket artifacts into the
coverage-report job: add crate-tests to needs, download the
reborn-crate-cov-bucket-* artifact pattern alongside the existing
integration-tier lane pattern, and pass every file to the (already
generic) merge script in one call. No change to
reborn-coverage-merge-lcov.sh.

Tighten timeout-minutes 15->10 to make the <=10-minute coverage-
calculation SLA a checked fact: this job stays pure lcov-text
processing (download, merge, render, upsert comment) with no test
execution anywhere in it, by construction.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Extend the exemptions schema reborn-coverage-summary.sh parses to accept
a whole-crate `crate = "ironclaw_x"` entry alongside the existing
per-file `module = "path"` form (exactly one of the two required per
entry). Both forms are normalized to a single `label` field at parse
time, and every downstream consumer (the is_exempt match, the sort key,
the render row) reads that field uniformly instead of branching on
which key is present.

This is the structural fix, not a two-line patch: the prior code had
two more unconditional `entry["module"]` accesses in the render section
(sort key + table cell) that would KeyError on the first crate-only
entry, since that entry shape has no `module` key at all. Normalizing at
parse time removes every such access site instead of just the ones
found today.

Extends tests/ci/test-reborn-coverage.sh with cases for the crate= form,
a mixed module+crate manifest, and the both-present/neither-present
validation errors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ironclaw_embeddings, ironclaw_gateway, ironclaw_oauth, ironclaw_tui are
consumed exclusively by the root `ironclaw` v1 package (no
crates/*/Cargo.toml depends on any of them, confirmed via a
reverse-dependency audit) and are already exercised by a separate CI
workflow (test.yml, "Tests (Legacy)"). They are not a testing gap, just
out of this report's Reborn-scoped denominator — mechanical effect is
~29.61% -> ~30.6% (172,586 -> ~167,035 line denominator, numerator
unchanged since these lines contributed 0 hits).

Each entry uses the new whole-crate `crate =` exemption form (see the
prior commit) with its reverse-dependency rationale inlined so a
reviewer never has to re-derive it.

NOTE: `issue` fields use the placeholder
https://github.com/nearai/ironclaw/issues/NNNN pending a tracking issue
("v1-only crates excluded from Reborn coverage scope" covering all
four) — file it and replace NNNN before merge.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Issue #5657 was already filed and referenced in every entry's `issue`
field; the leftover "not yet filed" / "NNNN placeholder" comment
contradicted the entries right below it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 5, 2026 06:48

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-5658 July 5, 2026 06:48 Destroyed
@github-actions github-actions Bot added scope: ci CI/CD workflows size: L 200-499 changed lines risk: medium Business logic, config, or moderate-risk modules contributor: core 20+ merged PRs labels Jul 5, 2026
@coderabbitai

coderabbitai Bot commented Jul 5, 2026 •

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

An error occurred during the review process. Please try again later.

📝 Walkthrough

Summary by CodeRabbit

  • Chores
    • Updated the CI coverage pipeline to generate and merge both integration-tier coverage and per-bucket crate coverage into a single LCOV report.
  • New Features
    • Added support for whole-crate coverage exemptions alongside existing file/module-level exemptions.
  • Tests
    • Expanded regression coverage for exemption parsing, rendering, validation, and related “zero-crates”/sticky comment behavior.
  • Documentation
    • Updated the integration-tier coverage exemption manifest format and examples to reflect the module-or-crate rule and reporting behavior.

Walkthrough

Reborn CI now emits crate-bucket LLVM-cov artifacts, merges them with lane coverage, and accepts whole-crate exemptions alongside per-module exemptions in the coverage summary pipeline.

Changes

Reborn coverage pipeline

Layer / File(s) Summary
Instrumented crate-tests coverage generation
.github/workflows/reborn-tests.yml
crate-tests installs LLVM tooling, uses a separate cache lineage, increases timeout, runs cargo llvm-cov per package, writes per-package .lcov files, concatenates bucket output, and uploads bucket artifacts.
Coverage-report merge and roll-up wiring
.github/workflows/reborn-tests.yml
coverage-report depends on crate-tests, downloads lane and bucket artifacts together, merges the combined .lcov set, and updates the roll-up comment text.
Module and crate exemption handling
scripts/ci/reborn-coverage-summary.sh, scripts/ci/test-reborn-coverage.sh, tests/integration/coverage-exemptions.toml
The coverage summary script now parses module or crate exemptions, matches whole-crate LCOV entries, and renders combined exemption output; regression cases cover whole-crate, mixed, and invalid manifests; the integration manifest documents the schema and adds four crate-level exemptions.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related issues

Possibly related PRs

  • nearai/ironclaw#5118: Overlaps on .github/workflows/reborn-tests.yml crate-test cache keying changes.
  • nearai/ironclaw#5430: Touches the same coverage-summary and regression-test paths for exemption handling.
  • nearai/ironclaw#5635: Shares the bucketed crate-test structure that this PR instruments and merges.

Suggested reviewers: serrrfirat

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning It covers summary and verification, but omits required template sections like Change Type, Linked Issue, Security Impact, and Rollback Plan. Add the missing template sections: Change Type, Linked Issue, Validation checkboxes, Security Impact, Reborn checklist, Database Impact, Blast Radius, Rollback Plan, Review Follow-Through, and Review track.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title uses Conventional Commits style and accurately summarizes the coverage and exemption changes.
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.

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.

@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 adds support for whole-crate exemptions in the Reborn coverage summary script, allowing entire crates to be excluded from coverage accounting alongside the existing per-file module exemptions. The parser has been updated to validate that exactly one of module or crate is specified, and entries are normalized using a shared label field. Additionally, comprehensive integration tests have been added to verify these changes, and four legacy v1-only crates have been added to the exemptions configuration. There are no review comments, and I have no feedback to provide.

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.

@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: 6cf662b4c3

ℹ️ 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 thread .github/workflows/reborn-tests.yml Outdated
Comment on lines +327 to +329
cargo llvm-cov -p "$package" ${feature_flags} --all-targets \
--lcov --output-path "coverage/${package}.lcov" \
test -- --nocapture

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reuse llvm-cov artifacts inside bucket loop

In buckets with more than one package, each cargo llvm-cov invocation starts by cleaning its previous coverage build unless --no-clean is passed (the cargo-llvm-cov help documents --no-clean as “Build without cleaning any old build artifacts”). Because this loop invokes llvm-cov once per package, the instrumented target restored/generated for one package is discarded before the next package, so multi-package buckets keep rebuilding instead of sharing the cache and are much more likely to hit the new 40m/90m timeouts. Add --no-clean and clean only profraw data between packages to keep reports isolated without deleting compiled artifacts.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Reviewed via thermo-nuclear-code-quality-review: deferring. --no-clean + selective profraw cleanup is a plausible win but needs empirical validation on an actual multi-package bucket run (build-cache/coverage-isolation correctness can't be verified in this sandbox — no Actions runner). Filing as a follow-up rather than landing speculative caching behavior in a coverage-measurement PR. composition-core (the only bucket that sets CARGO_INCREMENTAL=0) remains single-package today, so no bucket is currently near the 40m/90m timeouts.

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/reborn-tests.yml:
- Around line 306-331: The CARGO_INCREMENTAL setting in the bucket loop is being
exported into the current shell, so it can affect later packages processed by
the same while/done block. Update the logic around the
ironclaw_reborn_composition case in reborn-tests.yml so the variable is scoped
only to that package’s cargo llvm-cov invocation, rather than using a persistent
export. Keep the fix localized to the package-processing loop and ensure no
subsequent packages inherit the setting.

In `@scripts/ci/reborn-coverage-summary.sh`:
- Around line 77-110: The exemption normalization in reborn-coverage-summary.sh
correctly validates and records labels, but crate-based exemptions can still be
silently unused if they never match any parsed lcov crate segment. Update the
lcov parsing flow and the downstream exemption application logic to track which
entries from exempt_crates and exempt_modules are actually matched, then emit a
warning or fail if any exemption remains unapplied by the end. Use the existing
symbols exemptions, exempt_crates, exempt_modules, label, and crate_re to wire
the check into the current parse-time normalization and reporting path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2d7d9f6e-7a1c-4634-925a-84cf36ec5363

📥 Commits

Reviewing files that changed from the base of the PR and between 85c02c2 and 6cf662b.

📒 Files selected for processing (4)
  • .github/workflows/reborn-tests.yml
  • scripts/ci/reborn-coverage-summary.sh
  • scripts/ci/test-reborn-coverage.sh
  • tests/integration/coverage-exemptions.toml

Comment thread .github/workflows/reborn-tests.yml
Comment thread scripts/ci/reborn-coverage-summary.sh Outdated
Comment on lines +77 to +110
# Every entry is normalized to one shared shape right here, at parse time:
# a single `label` field (the per-file path, or "crate: <name>" for the
# whole-crate form) that every downstream consumer — the is_exempt match, the
# sort key, and the render row — reads uniformly instead of each branching on
# which of `module`/`crate` is present. One shape, one branch point; a future
# call site can't reintroduce a `entry["module"]` KeyError on a crate-only
# entry because there is no such site left to write.
exemptions = manifest.get("exemption", [])
exempt_modules: set[str] = set()
exempt_crates: set[str] = set()
for entry in exemptions:
module = entry.get("module")
if not module:
print(f"malformed exemption entry (missing 'module'): {entry}", file=sys.stderr)
crate_name = entry.get("crate")
if module and crate_name:
print(f"malformed exemption entry (exactly one of 'module'/'crate' required, both present): {entry}", file=sys.stderr)
sys.exit(1)
if not module and not crate_name:
print(f"malformed exemption entry (exactly one of 'module'/'crate' required, neither present): {entry}", file=sys.stderr)
sys.exit(1)
label = module if module else f"crate: {crate_name}"
entry["label"] = label
if not entry.get("reason"):
print(f"exemption for '{module}' is missing 'reason'", file=sys.stderr)
print(f"exemption for '{label}' is missing 'reason'", file=sys.stderr)
sys.exit(1)
if not entry.get("issue"):
print(f"exemption for '{module}' is missing 'issue'", file=sys.stderr)
sys.exit(1)
if not module.startswith("crates/"):
print(f"exemption module path '{module}' must be repo-relative and start with 'crates/'", file=sys.stderr)
print(f"exemption for '{label}' is missing 'issue'", file=sys.stderr)
sys.exit(1)
exempt_modules.add(module)
if module:
if not module.startswith("crates/"):
print(f"exemption module path '{module}' must be repo-relative and start with 'crates/'", file=sys.stderr)
sys.exit(1)
exempt_modules.add(module)
else:
exempt_crates.add(crate_name)

@coderabbitai coderabbitai Bot Jul 5, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Exactly-one-of validation and label normalization are solid.

Both-present/neither-present checks, label normalization, and the crates/ prefix check on module are all correctly ordered and fail-fast. One gap: a crate value that never matches any file's crate segment in the lcov (typo, or a name outside the ironclaw_[A-Za-z0-9_]+ pattern used by crate_re) silently becomes a no-op — the entry still renders in the exemptions table implying it took effect, but nothing is actually excluded.

Consider tracking which exempt_crates/exempt_modules entries were actually matched during lcov parsing and warning (or failing) on any that were never applied, to catch typos before they ship.
[recommended_refactor]

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/ci/reborn-coverage-summary.sh` around lines 77 - 110, The exemption
normalization in reborn-coverage-summary.sh correctly validates and records
labels, but crate-based exemptions can still be silently unused if they never
match any parsed lcov crate segment. Update the lcov parsing flow and the
downstream exemption application logic to track which entries from exempt_crates
and exempt_modules are actually matched, then emit a warning or fail if any
exemption remains unapplied by the end. Use the existing symbols exemptions,
exempt_crates, exempt_modules, label, and crate_re to wire the check into the
current parse-time normalization and reporting path.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Valid, but not actioning separately — bundled with the sibling thread on deriving the crate scope from package-matrix instead of hand-exempting. Adding typo-detection instrumentation to a mechanism that thread proposes replacing would be premature; revisit together.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@henrypark133 Understood — makes sense to defer this to the package-matrix thread rather than instrument a mechanism that may get replaced. No further action needed here.

(๑˃̵ᴗ˂̵)و

@railway-app

railway-app Bot commented Jul 5, 2026 •

Copy link
Copy Markdown

🚅 Deployed to the ironclaw-pr-5658 environment in ironclaw-ci-preview

Service Status Web Updated (UTC)
ironclaw ✅ Success (View Logs) Web Jul 5, 2026 at 7:16 am

Compress narrative CI comments (coverage instrumentation rationale,
cache-key separation, lcov merge mechanics, exemption schema/entries)
to dense 1-3 line notes carrying the crux + issue ref, per repo
comment-economy convention.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-5658 July 5, 2026 07:10 Destroyed
@github-actions github-actions Bot added size: M 50-199 changed lines and removed size: L 200-499 changed lines labels Jul 5, 2026

@coderabbitai coderabbitai 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/reborn-tests.yml (1)

280-281: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

cargo-llvm-cov tool version is unpinned.

The install-action commit is pinned, but the tool ref is the bare cargo-llvm-cov name (per taiki-e/install-action's supported shorthand), which resolves to whatever version is current at install time rather than a fixed release. Given the repo's dependency-pinning posture (cargo deny check before adding deps), consider pinning to a specific cargo-llvm-cov@<version> to avoid unannounced tool-version drift silently changing coverage output/format across runs.

♻️ Suggested pin
-      - name: Install cargo-llvm-cov
-        uses: taiki-e/install-action@62b0f2dec647a8e604c6a0fda0e38530180dce20 # cargo-llvm-cov
+      - name: Install cargo-llvm-cov
+        uses: taiki-e/install-action@62b0f2dec647a8e604c6a0fda0e38530180dce20 # cargo-llvm-cov@<pinned-version>
+        with:
+          tool: cargo-llvm-cov@<pinned-version>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/reborn-tests.yml around lines 280 - 281, The Install
cargo-llvm-cov step is using the unpinned shorthand name, so the tool version
can drift between runs. Update the taiki-e/install-action usage in the
reborn-tests workflow to reference a specific cargo-llvm-cov@<version> release
instead of the bare cargo-llvm-cov alias, keeping the existing pinned action
commit intact. This should be done in the workflow job that installs
cargo-llvm-cov so coverage output remains stable.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.github/workflows/reborn-tests.yml:
- Around line 280-281: The Install cargo-llvm-cov step is using the unpinned
shorthand name, so the tool version can drift between runs. Update the
taiki-e/install-action usage in the reborn-tests workflow to reference a
specific cargo-llvm-cov@<version> release instead of the bare cargo-llvm-cov
alias, keeping the existing pinned action commit intact. This should be done in
the workflow job that installs cargo-llvm-cov so coverage output remains stable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6f69d300-71da-4daa-bedb-0b35d6dddee0

📥 Commits

Reviewing files that changed from the base of the PR and between 6cf662b and 1c474bd.

📒 Files selected for processing (3)
  • .github/workflows/reborn-tests.yml
  • scripts/ci/reborn-coverage-summary.sh
  • tests/integration/coverage-exemptions.toml

@github-actions

github-actions Bot commented Jul 5, 2026 •

Copy link
Copy Markdown
Contributor

⚠️ 3 Reborn crate(s) have 0 int-tier coverage (target: 0) — ironclaw_prompt_envelope, ironclaw_scripts, ironclaw_skill_learning

Reborn integration-tier coverage

Line coverage (Reborn crates): 85.29% — 272760 / 319799 lines

Per-crate breakdown (65 crates, lowest-covered first)
Crate Line % Covered / Total
ironclaw_prompt_envelope 0% 0 / 88
ironclaw_scripts 0% 0 / 347
ironclaw_skill_learning 0% 0 / 61
ironclaw_wasm_sandbox_core 7.37% 7 / 95
ironclaw_runtime_policy 33.2% 80 / 241
ironclaw_event_projections 38.57% 599 / 1553
ironclaw_run_state 52.73% 222 / 421
ironclaw_authorization 53.54% 461 / 861
ironclaw_triggers 60.32% 1736 / 2878
ironclaw_observability 61.54% 16 / 26
ironclaw_reborn_cli 64.58% 3988 / 6175
ironclaw_webui_v2 65.47% 2391 / 3652
ironclaw_filesystem 65.86% 3212 / 4877
ironclaw_reborn_migration 67.01% 1172 / 1749
ironclaw_memory 67.12% 747 / 1113
ironclaw_dispatcher 67.15% 92 / 137
ironclaw_mcp 67.42% 569 / 844
ironclaw_trust 72.88% 661 / 907
ironclaw_reborn_event_store 73.27% 940 / 1283
ironclaw_capabilities 74.08% 1658 / 2238
ironclaw_wasm_limiter 74.6% 47 / 63
ironclaw_extractors 74.72% 538 / 720
ironclaw_first_party_extensions 77.62% 5410 / 6970
ironclaw_llm 77.67% 19045 / 24519
ironclaw_product_context 78.57% 11 / 14
ironclaw_network 79.82% 621 / 778
ironclaw_process_sandbox 80.65% 671 / 832
ironclaw_reborn_openai_compat 80.95% 956 / 1181
ironclaw_memory_native 81.86% 3226 / 3941
ironclaw_secrets 82.33% 2716 / 3299
ironclaw_wasm 82.54% 950 / 1151
ironclaw_events 82.69% 1743 / 2108
ironclaw_processes 84.06% 965 / 1148
ironclaw_host_api 84.12% 3105 / 3691
ironclaw_threads 84.72% 3244 / 3829
ironclaw_turns 85.56% 9811 / 11467
ironclaw_wasm_product_adapters 85.6% 1510 / 1764
ironclaw_projects 85.92% 659 / 767
ironclaw_product_adapter_registry 86.12% 515 / 598
ironclaw_product_workflow 86.22% 10652 / 12354
ironclaw_auth 86.32% 2727 / 3159
ironclaw_product_adapters 86.42% 3143 / 3637
ironclaw_common 86.59% 1472 / 1700
ironclaw_event_streams 86.76% 957 / 1103
ironclaw_reborn_config 86.98% 1730 / 1989
ironclaw_hooks 87.25% 9782 / 11211
ironclaw_reborn_traces 87.35% 10325 / 11820
ironclaw_skills 87.36% 4335 / 4962
ironclaw_extensions 88.26% 2631 / 2981
ironclaw_reborn_identity 88.43% 344 / 389
ironclaw_reborn_composition 88.97% 68206 / 76664
ironclaw_host_runtime 89.12% 17249 / 19355
ironclaw_conversations 90.11% 2924 / 3245
ironclaw_slack_v2_adapter 90.25% 1786 / 1979
ironclaw_approvals 90.51% 1507 / 1665
ironclaw_reborn 91.17% 17238 / 18908
ironclaw_reborn_webui_ingress 91.68% 2094 / 2284
ironclaw_loop_support 92.34% 14093 / 15262
ironclaw_attachments 93.06% 630 / 677
ironclaw_telegram_v2_adapter 94.01% 2447 / 2603
ironclaw_resources 94.25% 3625 / 3846
ironclaw_agent_loop 94.49% 8290 / 8773
ironclaw_outbound 94.54% 3517 / 3720
ironclaw_safety 94.78% 3668 / 3870
ironclaw_first_party_extension_ports 95% 3094 / 3257

This signal is informational: coverage never gates the PR — not the percentage, not the per-crate holes, not the 0-coverage callout.

Exemptions (4 entry/entries excluded from the accounting above)
Module / Crate Reason Issue
crate: ironclaw_embeddings v1-only: consumed only by root ironclaw (src/app.rs, src/tools/builtin/memory.rs, src/workspace/mod.rs, src/config/{mod,embeddings}.rs); no crates/* dependents. Covered by "Tests (Legacy)". #5657
crate: ironclaw_gateway v1-only: consumed only by root ironclaw (src/channels/web/platform/static_files.rs, src/channels/web/handlers/frontend.rs); no crates/* dependents. Covered by "Tests (Legacy)". #5657
crate: ironclaw_oauth v1-only: consumed only by root ironclaw (src/auth/oauth.rs); no crates/* dependents. Crate's own doc comment confirms v1-only. Covered by "Tests (Legacy)". #5657
crate: ironclaw_tui v1-only: consumed only by root ironclaw (src/main.rs, src/channels/tui.rs); no crates/* dependents. Crate's own doc comment confirms it bridges INTO v1, not Reborn. Covered by "Tests (Legacy)". #5657

@henrypark133 henrypark133 left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Code Review (multi-agent)

Intent: Make Reborn CI coverage include crate-tier tests and apply scoped denominator exemptions for v1-only crates.

Stats: 3 findings (from 6 raw, 3 after dedup/suppression) across 3 files. Reviewers run: security, bugs, performance, tests, conventions, local-patterns, maintainability, approach. Reviewers failed: none. Body-only: 1.

Suppressed as duplicate: the cargo llvm-cov --no-clean / repeated clean concern is already covered by the current unresolved thread on .github/workflows/reborn-tests.yml:307.

Maintainability

  1. Medium Derive the coverage crate set instead of hand-exempting crates (scripts/ci/reborn-coverage-summary.sh:75-100, confidence 75) — anchor: scripts/ci/reborn-coverage-summary.sh:75
    The summary script now treats whole-crate exemptions as a second owner of the Reborn coverage denominator, while the workflow already computes the Reborn package set from the allowlist plus ironclaw_reborn_cli dependency closure. Those two maintained scopes can drift: if one of these currently-exempt crates becomes reachable from Reborn later, it will remain excluded until someone also edits coverage-exemptions.toml.

Tests

  1. Medium Sticky comment path lacks whole-crate exemption coverage (scripts/ci/test-reborn-coverage.sh:363-370, confidence 75) — anchor: .claude/rules/testing.md:27
    The new tests prove report-mode rendering drops a whole-crate exemption, but the sticky PR comment path also calls reborn-coverage-summary.sh --zero-crates to decide whether to prepend the 0-coverage warning. There is no caller-level comment test showing that a zero-covered crate excluded with crate = is omitted from that warning.

Local Patterns

  1. Low Merged coverage report keeps integration-tier-only names (.github/workflows/reborn-tests.yml:623-638, confidence 75) — anchor: .github/workflows/reborn-tests.yml:623 (no diff position — body only)
    This job now merges integration lane artifacts with crate bucket artifacts, but several user-facing surfaces still say integration-tier: the job name, render step, summary heading, sticky comment callout, merged filename/artifact, and exemptions header. Readers can reasonably infer the reported number still excludes crate-tier tests.

# Normalized to one `label` field here (path, or "crate: <name>") so is_exempt/sort/render never branch on module-vs-crate presence.
exemptions = manifest.get("exemption", [])
exempt_modules: set[str] = set()
exempt_crates: set[str] = set()

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Medium — Derive the coverage crate set instead of hand-exempting crates.

The summary script now treats whole-crate exemptions as a second owner of the Reborn coverage denominator, while the workflow already computes the Reborn package set from the allowlist plus ironclaw_reborn_cli dependency closure. Those two maintained scopes can drift: if one of these currently-exempt crates becomes reachable from Reborn later, it will remain excluded until someone also edits coverage-exemptions.toml.

Fix: Delete the crate = exemption form and pass the package-matrix package list into the summary/comment path as the allowed crate set. Keep coverage-exemptions.toml for exceptional per-file exclusions only.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Reviewed via thermo-nuclear-code-quality-review: agree with the drift concern in principle, deferring the implementation. Threading package-matrix through isn't a net complexity win as-is — it swaps a small, well-tested allow-set mechanism (with per-entry reason/issue audit trail) for a deny-by-omission scheme requiring new cross-job plumbing (package-matrix output -> coverage-report job dependency -> new script arg in both summary.sh and comment.sh), and loses the per-entry rationale visibility in the rendered report unless that's redesigned too. Filing a follow-up to work out how exclusion reasons stay visible under a package-matrix-derived scheme, rather than redesigning the exemption schema in this PR.

reason = "v1-only: consumed exclusively by the root ironclaw package"
issue = "https://github.com/nearai/ironclaw/issues/1"
TOML
capture "${summary_sh}" "${fixtures_dir}/a10_two_crates.lcov" "${fixtures_dir}/a10_crate_exemption.toml"

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Medium — Sticky comment path lacks whole-crate exemption coverage.

The new tests prove report-mode rendering drops a whole-crate exemption, but the sticky PR comment path also calls reborn-coverage-summary.sh --zero-crates to decide whether to prepend the 0-coverage warning. There is no caller-level comment test showing that a zero-covered crate excluded with crate = is omitted from that warning.

Fix: Add a reborn-coverage-comment.sh fake-gh case covering a zero-covered crate excluded by a whole-crate exemption, asserting the sticky comment does not include the 0-coverage callout.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed — added B4 (reborn-coverage-summary.sh --zero-crates) and C9 (reborn-coverage-comment.sh sticky body) covering a whole-crate exemption suppressing a 0-coverage crate from the callout, reusing the A10 fixture. 97/97 now. This stands regardless of how the sibling thread on deriving the crate set resolves.

henrypark133 and others added 2 commits July 6, 2026 08:52
…xempt zero-callout

CARGO_INCREMENTAL=0 was exported into the shared loop shell instead of
scoped to the composition-core invocation, so it would silently leak
onto later packages if that bucket ever stops being single-package.
Also closes a gap flagged in review: the sticky PR comment's 0-coverage
callout had no test proving a whole-crate exemption suppresses it (only
report-mode dropped it).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 6, 2026 16:22
@ironloopai

ironloopai Bot commented Jul 6, 2026 •

Copy link
Copy Markdown
Contributor

✅ IronLoop Review Status

Head: cb63d093c84def9221552a947b47461d3e03f068
Result: 1/1 reviewers completed without blocking findings.
Next: Ready for normal human review and CI checks.
Updated: 2026-07-06T16:24:45.929Z

Current reviewers:

Reviewer State Verdict Findings Last update
ironloop/common-reviewer (reviewer) Completed Approved 0 blocking findings / 0 notes 2026-07-06T16:24:45.861Z
Reviewer summaries
Reviewer Detail
ironloop/common-reviewer (reviewer) Approved; 0 blocking findings; No concrete actionable regressions found in the CI coverage changes. The new whole-crate exemption handling is covered by added shell-test cases, and the workflow wiring for crate…
Recent activity
Time Reviewer State Detail
2026-07-06T16:22:35.184Z ironloop/common-reviewer (reviewer) Queued Accepted review request for head cb63d09.
2026-07-06T16:22:35.184Z ironloop/common-reviewer (reviewer) Queued Waiting for this reviewer lane to become available.
2026-07-06T16:22:35.282Z ironloop/common-reviewer (reviewer) Queued Added to the local review work handoff.
2026-07-06T16:22:36.243Z ironloop/common-reviewer (reviewer) Started Reviewer worker started attempt 1.
2026-07-06T16:22:39.481Z ironloop/common-reviewer (reviewer) Workspace ready Prepared isolated checkout (merge_ref) at bf276b6.
2026-07-06T16:24:16.839Z ironloop/common-reviewer (reviewer) Running Codex is reviewing; process live; elapsed 1m 39s; timeout in 18m 21s; last heartbeat 2026-07-06T16:24:16.839Z. Activity (stderr): ..."\nreason = "v1-only"\nissue = "https://github.com/nearai/ironclaw/issues/1\"\\n')" in /data/.ironloop-runtime….
2026-07-06T16:24:45.861Z ironloop/common-reviewer (reviewer) Result captured Approved; 0 blocking findings.
2026-07-06T16:24:45.861Z ironloop/common-reviewer (reviewer) Completed Review completed and terminal status was persisted.
Available commands
  • @ironloop agents
  • @ironloop review
  • @ironloop review --agent <agent-id-or-alias>
  • @ironloop status
Run metadata

Admission: webhook accepted the request and IronLoop persisted review state before this projection.

@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-5658 July 6, 2026 16:22 Destroyed

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions github-actions Bot added size: L 200-499 changed lines and removed size: M 50-199 changed lines labels Jul 6, 2026

@ironloopai ironloopai 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.

✅ IronLoop Review: reviewer

Verdict: ✅ Approved
Findings: 0 blocking / 0 notes
Next: No reviewer action needed.
Head: cb63d093c84def9221552a947b47461d3e03f068

Run details

Status: Current
Needs human: no
Needs validation: no

**Inline candidates:** 0

Summary

No concrete actionable regressions found in the CI coverage changes. The new whole-crate exemption handling is covered by added shell-test cases, and the workflow wiring for crate bucket LCOV artifacts is consistent with the existing integration coverage merge/report path.

Findings

None.

Developer follow-up

After fixing this feedback:

  1. Push the fix to this PR branch.
  2. Re-run this reviewer with @ironloop review --agent reviewer if you only changed this reviewer's findings.
  3. Re-run all reviewers with @ironloop review when the fix may affect multiple areas.
  4. Use @ironloop status to check queued/running/completed/stale/stalled state while reviewers run.

@henrypark133
henrypark133 merged commit 073cc3d into main Jul 6, 2026
53 checks passed
@henrypark133
henrypark133 deleted the w6-metric-truth branch July 6, 2026 17:23
henrypark133 added a commit that referenced this pull request Jul 6, 2026
… coverage rule (#5718)

* docs: integration-first coverage rule in CLAUDE.md, testing rules, AGENTS.md

Production-wired Reborn behavior must ship with an integration-tier test
asserting at a seam; crate-tier only with stated reason; no test-only
wiring for unwired paths; no ignored tests. Terse rule in CLAUDE.md,
full decision rule in .claude/rules/testing.md, Codex-parity pointer in
AGENTS.md.

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

* refactor(ci): extract shared lcov aggregation into scripts/ci/lib

Move reborn-coverage-summary.sh's exemption-parsing + lcov-aggregation
logic into an importable module so reborn-coverage-ratchet.sh (next
commit) can reuse it instead of reimplementing. Behavior-preserving:
full test-reborn-coverage.sh suite (35 sections, 97 assertions) passes
unchanged.

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

* feat(ci): add coverage-floor.toml schema + reborn-coverage-ratchet.sh (dry-run only)

New committed floor file (deny.toml pattern) with real baseline captured
from the first green main coverage-report run at 073cc3d (#5658,
before #5656's ~42k-line denominator shift): 85.35% (273073/319942
lines), verified byte-identical against the run's own merged-lcov
artifact. enforce=false — dry-run only until a follow-up PR recaptures
post-#5656 and flips the switch.

New reborn-coverage-ratchet.sh reuses the extracted lcov lib (previous
commit) to compare merged coverage against the floor: global aggregate
+ opt-in per-crate floors, percent and/or covered-lines forms (ANDed,
not ORed, so denominator dilution can't mask a numerator regression),
denominator-delta note always printed, unconditional dry-run/enforcing
mode banner. Schema errors (missing fields, floor/exemption conflicts,
duplicate crate entries) exit 1 regardless of enforce.

New R1-R13 section in test-reborn-coverage.sh (33 assertions) covers
the boundary-inclusive check, AND-not-OR semantics, dry-run masking
only the exit code, the divide-by-zero guard for a renamed/removed
crate, and the unconditional banner.

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

* ci(reborn): wire ratchet step into coverage-report + comment; flip roll-up to blocking

New "Render Reborn coverage ratchet" step runs reborn-coverage-ratchet.sh
right after the existing summary step, tee'd into the job summary — same
job, same 10-min budget, no new test execution. The sticky-comment
script grows a required floor-toml arg and renders the ratchet script's
own report output as a "### Coverage ratchet" section at the very top
of the comment body (after the hidden marker, before the 0%-crate
callout) — reborn-coverage-summary.sh's output has no seam to splice
into "before the per-crate table" specifically, so top-of-comment is
the simpler equivalent (highest signal first either way).

reborn-tests roll-up: coverage-report's warn-only block becomes a real
exit 1, since a ratchet violation is now a real regression, not just a
reporting-pipeline bug. Still green throughout the dry-run soak period
(enforce=false in the floor file), and coverage-report is not itself a
required status check (verified live against the repo's ruleset), so
this is the only edit needed to make the gate merge-blocking once
enforce=true lands in a follow-up PR.

Also: the per-crate table's own "never gates" caption is corrected now
that a (currently dry-run) gate exists, and testing.md gains one
honestly-worded sentence naming the ratchet.

test-reborn-coverage.sh's C section grows a permissive floor fixture
(all existing comment-script cases keep testing comment behavior, not
ratchet gating) plus C10 (ratchet section ordering) and C11 (missing
floor manifest guard) — 138 of 138 assertions pass.

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

* refactor(ci): split ratchet R-cases out of test-reborn-coverage.sh

Post-implementation thermo-nuclear review flagged test-reborn-coverage.sh
crossing 1000 lines (815 -> 1108) within this branch once the ratchet
R-section landed — a presumptive blocker per the review's file-size rule.
Move the R1-R13 cases into a sibling file, sourced by the main script so
it keeps sharing the same helpers/fixtures/counters (pure move, no
behavior change): 890 -> 897 lines main script, 138/138 assertions still
pass identically. shellcheck -x clean on both files.

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

* fix(ci): classify-test-scope glob missed the new ratchet-cases sibling

The R-section split (previous commit) added
scripts/ci/test-reborn-coverage-ratchet-cases.sh, but
classify-test-scope.sh's is_shared_test_path glob only listed exact
filenames — a PR touching only the new file wouldn't have been
classified has_reborn_tests=true, silently skipping the Reborn CI
lanes. Widen the glob and pin it with a regression case (confirmed
red before the fix, green after).

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

* ci(reborn): recapture coverage floor post-#5656, flip enforce=true

Recaptured global floor from the first green main coverage-report run
after #5656 (run 28817755166 @ 28da8bd): 273132/320188 = 85.30%.
Denominator moved +246 lines vs 073cc3d — slack-v2-host-beta sources
were already in ironclaw_reborn_composition's counted set; #5656 added
numerator. Ratchet dry-runs green (85.30% >= 84.8% effective floor), so
flip enforce=true in this PR — no separate follow-up.

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

* fix(ci): harden ratchet schema guards, close reborn-scope gap in classifier

Addresses 5 PR #5718 review comments on the coverage ratchet, all
fail-closed schema hardening + regression coverage, no behavior change
for compliant manifests:

- classify-test-scope.sh: scripts/ci/lib/reborn_coverage_lcov.py was
  unmatched by is_reborn_test_path(), so a PR touching only the shared
  lcov lib would skip Reborn CI + coverage (gemini).
- reborn-coverage-ratchet.sh: [global].enforce now requires a native
  TOML bool — a quoted "false" no longer coerces to Python True via
  bool() and silently starts enforcing (coderabbit).
- reborn-coverage-ratchet.sh: a [crate] table (dict) instead of
  [[crate]] (array-of-tables) is now rejected instead of silently
  replaced with an empty list, which would skip the per-crate gate
  entirely (codex P2).
- test-reborn-coverage-ratchet-cases.sh: R16-R18 add regression cases
  for the three existing fail-closed schema branches (missing
  [global], [global] without floor_percent, [[crate]] without name)
  that had no coverage.
- test-reborn-coverage.sh: C12 covers the comment script rendering a
  malformed-but-present floor manifest's schema error into the sticky
  comment while still exiting 0 (visibility-only, never gates).

Verified: 150/150 in test-reborn-coverage.sh (was 138), classifier
suite green, shellcheck -x clean, py_compile clean, and the live
enforce=true gate still exits 0 against the real
tests/integration/coverage-floor.toml with a compliant lcov.

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

This branch was successfully deployed

No deployments
ironclaw-ci-preview / ironclaw-pr-5658 — cb63d093 Deployed Jul 6, 2026 by railway-app[bot]
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: ci CI/CD workflows size: L 200-499 changed lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants