Skip to content

docs(target-architecture): reconcile the decision record with post-Wave-2 main - #7032

Merged
BenKurrek merged 1 commit into
mainfrom
docs/wave2-truth-audit
Aug 3, 2026
Merged

BenKurrek merged 1 commit into
mainfrom
docs/wave2-truth-audit

Conversation

@BenKurrek

@BenKurrek BenKurrek commented Aug 3, 2026 •

Copy link
Copy Markdown
Collaborator

Wave 2's port-inversion half is fully merged — #6998 (WS2.1), #7002 (WS5 transports), #7018 (the consolidated WS2.2 + WS2.4 + WS5 stack) and #6996 (the #6963 gate closeout). This audits docs/reborn/target-architecture/ against merged main at 3be5f056e and closes every place the decision record no longer matches what shipped.

Standing rule this serves: docs/reborn/target-architecture/ is the single source of truth. A correction that lives only in a PR body, a review thread, or a GitHub issue is not recorded.

Docs-only. 13 .md files, no code, no tests. House style throughout: dated ✎ amendments, prior text quoted verbatim wherever a clause is corrected, nothing rewritten silently.


Per-gap disposition

# Doc → claim Why stale Amendment
1 PROPOSAL §8.1 reading rule 1 — "each layer may use itself and below … the matrix, not the picture, is what CI checks" True, and it is the whole of Wave 2's blind spot stated as a permission. layer_allows_dependency is reflexive at every layer (:4294, products at :4307-4310) and the exception register is only consulted inside the if !layer_allows_dependency(...) branch (:196) — so no LAYER_MATRIX_EXCEPTION can ever exist for a same-layer edge. 72 same-layer edges sit outside the matrix, 10 of them products → products. Every edge Wave 2 exists to kill is in that plane. Amended — the mechanism quoted from source, the 72-edge census, and the operative conclusion: the exception register is not a progress metric for any intra-layer wave. Lists the four genuinely-unpoliced products → products edges so the next audit does not rediscover them.
2 PROPOSAL §8.2 — "the high-signal prohibitions CI pins" Three of its claims are not pinned. (a) "product-API crates never bind sockets" — the rule's own trailing comment describes a WebChat v2 entry that is not there, so webui/src is uncovered, and it is the one crate that would fail (lib.rs:220/238); tracked in #6999. (b) The extension_host row's "✗ product (the restored invariant)" — there is no boundary_rules() entry for ironclaw_extension_host at all; what holds it is a shrink-only residue ratchet, a ratchet toward the invariant. (c) No row exists for extension_manager, which landed in WS2.4. Amended — all three, with the load-bearing consequence named: the re-layer to loops is what finally lets the matrix enforce the extension_host row, a second independent reason §12.1c's ordering binds.
3 PROPOSAL §11.1 ("Keep — already enforced") Names none of the eleven scans this program has itself built. §11.2 then double-counts five of them as still pending, so the two halves of §11 disagree. §11 also contains zero occurrences of "coverage" despite three live coverage gates behind the required check. Amended — full inventory table (scan → what it pins → landing slice) with live baselines, plus the shape worth carrying: six of eleven exist because the matrix could not see the edge, and each is a ratchet, so "gate green" ≠ "rule holds" until residue is zero. Coverage gates named and pointed at their governance row.
4 PROPOSAL §11.2 items 2, 3, 4, 5, 7 Landed but listed as "Add". Item 4 (port-location rule) is fully landed as three scans — the single most misleading entry. Item 7 is stale in both directions: the scan exists and runs in warn mode, so "escaping paths fail" is also wrong. Amended — one block, item by item, separating what landed from the genuine residue: item 2's owning-issue field still does not exist; item 3's line-count size ceiling was never built — and it is now the clause that would bite (product_contracts 13,362 lines, loop_contracts 13,950; the two crates §11 calls "thin").
5 PROPOSAL §8.3 — the exception table + "§11 adds a ratchet" Register verified at 13, unchanged. But: ⚠ conversations → turns reads removes_in = "WS5" and WS5 has partly landed without it falling. The ratchet forbids growth, not lateness, and exception_tracking_defect only rejects placeholder text — nothing in CI notices a milestone passing. The ratchet also landed in WS0, not "adds". Amended — Wave-2-removed-zero recorded as expected-not-shortfall, the live 13 enumerated, the milestone-staleness flagged with two cheap fixes assigned to whoever closes the WS5 product row.
6 PROPOSAL §2.2 — "20 LAYER_MATRIX_EXCEPTIONS (:3557-3702)" The last place in the document reading 20. All three file:line citations in the sentence above it have drifted (:49→:126, :3497→:4010, :129→:197). Amended — 13 at :4065-4157, pin at :4063, citations corrected, and why Wave 2 moved it by zero.
7 PROPOSAL §6.1.3 as-built inventory (Wave 1 audit block) Both headline claims now false — "8 modules" → 24 + gated test_support, and "the product-side ports are deferred by design, not landed" → landed in WS2.1/WS2.2/WS5. §6.1.3 contradicts itself: three inline amendments above say the ports landed; this trailing block is the newest-looking dated note, so it is the one a reader trusts. Superseded, not deleted — full 24-module list, what actually remains deferred (the frozen inventory + four ports at WS2_..._BASELINE = 4), and #7008 given a home (product_wire.rs 1,923→2,058 lines, large_file exemption owner).
8 PROPOSAL §6.8.2 — "OWNED_PREFIXES still names only crates/ironclaw_extension_host/src/hosted_mcp_ … must move with the pipeline" Wrong three ways: the constant is OWNED_SCOPES, it names two scopes, and #6996 rewrote it to (crate, in-crate prefix) pairs resolved through the inventory — its own doc comment now says "these survive a family move". The WS7 risk this warns about is discharged. PLAN's item 2 is the mirror image (prefixes right, mechanism stale). Corrected in both, with the smaller residual obligation stated: only the in-crate src/hosted_mcp_ half travels.
9 CHECKLIST WS5 webui row + §6.9.4 + webui/CLAUDE.md — "228 → 102 symbols", "eleven survivors" 100 / 9. The attachments widened slice in the same PR moved the two symbols the webui row named as belonging to it. The gate's own comment records the correction — "102 when the WS5 transport inversion landed; 100 after…" — and no doc picked it up. Corrected at all four sites, with the durable lesson: when collapsing a stack, diff the numbers as well as the files.
10 CHECKLIST WS5 operator row + §6.1.3 + 2 operator guides — module llm_config Does not exist. #7004 created it; the consolidation found main had already moved the same DTOs into the pre-existing operator_llm, deleted the duplicate and repointed 18 import sites. The dead name propagated to four places; product_contracts/CLAUDE.md — the file they all point at — had it right throughout. Corrected at all four. Counts (5 ports / 27 DTOs) verified exact.
11 CHECKLIST WS2 coverage-gate note (WS2.1, for "every later Wave 2/3 slot") The gate changed twice under it. Its three failure shapes are still real; its advice is not. Amended with both: the pre-existing-uncovered exclusion (which automates its shape-(2) advice — reaching for an exemption first is now wrong), and ⚠ the gate no longer runs on an ordinary PR (#6952: pull_request ∉ FULL_EVENTS). With #6978, a stacked slice gets its coverage verdict for the first time in the merge queue.
12 CHECKLIST WS10 ratchet row — the coverage policy Recorded in no document at all. line_percent = 90.0, branch_percent = 0.0 (changed-coverage-exemptions.toml:9-11), set by #7013, replacing 100/100 from #6889 — branch coverage was gated at a nonzero number for about two days in this program's history. 0.0 means ungated, not "0% required" (branch_pct < 0.0 is unsatisfiable). Also "15 packages" → 16; WS0's 85.54% is history (live global floor 85.11, effective 84.61). Added — with the consequence for this program: WS1/WS2's habit of counting "lines and branch arms restored" no longer describes anything CI enforces on changed code.
13 CHECKLIST WS10 §11.2.2 row — "lowered to 15 by WS1.1" The last place reading 15; the ceiling is 13. Corrected, plus the owning-issue/milestone-check residue.
14 CHECKLIST WS2.4 row + §6.8.3 + §2.4 — manager "≈10.1k / 19 files", host "≈47.8k / 75" Manager is 20 files / 12,315 lines; host 75 / 48,791. The figure went stale inside the PR that wrote it — true at the slice tip (4bb24accb: 19/10,527), then review commits added a 20th module and ~1.8k lines of tests. §2.4's 56,940/93 is now the pre-split high-water mark. Re-measured at all three, naming the three in-repo figures that describe this crate in three different units (this row; coverage-floor.toml's 9,979 source / 5,440 instrumented; #7018's 9,671-line carve) — all honest, none quotable.
15 CHECKLIST WS2.4 row — no pointer to #7011 Five review findings in byte-for-byte moved files, correctly deferred to protect the behavior-free-move claim, with no docs pointer. Added as disposition 6, all five summarized, plus the pattern: a byte-identical move PR should open one issue for what it declined to fix, and the row that moved the code should name it.
16 families/domains.md ×4 "No other crate in the family depends on a sibling" — falsified by attachments → threads, an edge Wave 2 itself created. Attachments' Depends-on omits that and product_contracts (the live [decision]). Conversations still "owns" the external ref pair (unified onto extension_contracts) and its deps omit the new edge. "Never depends on the turn coordinator crate directly" reads as an achieved invariant while conversations/CLAUDE.md mandates that edge. Amended all four, incl. the ProjectScopedAttachmentReader carve-out and its #7010 tracker.
17 families/product.md ×4 Operator "never as a direct dependency on the boot-configuration crate" — false (ironclaw_reborn_config, 5 sites, and its new BoundaryRule does not forbid it); webui's Depends-on omits ironclaw_attachments, the edge WS5 deliberately created; "transports compile against contracts, not ironclaw_assistant" is true of vocabulary and cannot be made true of the manifest without the open §6.1.3-vs-§6.9.4 decision. Amended, separating what WS5 closed (operator's product edge, residue zero) from what is still ahead of the code.
18 families/extensions.md — manager Owns line Omits ironhub, the crate's second-largest module cluster (~3.1k lines / 8 files). PROPOSAL, CHECKLIST and the crate's own CLAUDE.md all record it. Amended, and flags the two Owns entries the split could not reach.
19 crates/AGENTS.md ×3 ironclaw_operator has no row at all — the crate Wave 2 gave AGENTS.md, CLAUDE.md, a BoundaryRule and a purpose-built gate, 9.6k LOC, invisible on the routing map. Conversations row says "session thread contracts", the exact naming trap WS5 removed. The product_contracts row pins implementors "not by this prose" but omits ironclaw_operator and the gate that pins it. Amended — operator row added, quoting WS5's own diagnosis that the absence was causal, not cosmetic.
20 README / PLAN / §9 / §13 No Wave 2 landed markers; extension_manager still tagged NEW with no signal it exists; PLAN's "the inventory moves as a unit, like it arrived" was refuted by the split (5 of 9 moved); package count 67 → 68. Amended — landed markers with the slice→PR map, and PLAN's Wave 2 entry gains five carry-forward corrections.

Verified still accurate

Recorded because the audit is only worth what it checked.

  • PROPOSAL §2.1's package arithmetic — 68 packages / 67 members, WS2.4's amendment exact. Independently re-derived from cargo metadata.
  • The exception register at 13, edge for edge, and git log -G confirms no Wave 2 PR touched it.
  • ironclaw_operator's product dep is gone from the manifest with residue zero — absent from Cargo.toml, 0 occurrences in src/, forbidden by its BoundaryRule, proven through cargo metadata. The first of §8.2's three named product edges to actually close.
  • Five ports / twenty-seven DTOs (only the module name was wrong); 91 constants; 92 routes; openai_compat 23 → 3.
  • The manager's seven-file product residue, and that it is DTOs/constants/port-residues and never a workflow call — verified against the gate, not by grep (raw rg says 9; two are doc comments the scanner strips).
  • The host never depends on the manager, any dependency kind, dev-deps included.
  • §6.1.3's allowed-deps (host_api + extension_contracts, no ironclaw_common) — the two-document reconciliation Wave 1 claimed is real.
  • ProductOperationFailure's six variants; the AppEvent refutation; the whole §6.8.2 shed list still unshed (so CHECKLIST WS2's verify row is correctly unchecked); families/contracts.md fully current — it is where PROPOSAL §6.1.3 is stale.
  • The orphan rule already has a docs home — briefed as a possible gap, it is not one. CHECKLIST WS5's webui row states it ("once a DTO's home is the contracts crate, an impl From<ironclaw_turns::X> for ThatDto has neither side in ironclaw_product and cannot be written there at all"), with the three kernel conversions that became free functions and the two extension traits named; the attachments row applies it to ProjectScopedAttachmentReader; and Split the product_wire DTO family in ironclaw_product_contracts (large_file exemption owner) #7008 records the cost any further product_wire carve pays. I added the §6.1.3 cross-reference so the contracts crate's own entry carries it, and the families/domains.md attachments carve-out now names it too — but the finding itself was correctly recorded when it was made.
  • products → products invisibility was recorded, but only in a slice disposition (CHECKLIST WS2 row 1, disposition 4) — accurate where it sat, and absent from §8 and §11, which is where a reader planning a wave would look. That asymmetry is gap 1 above rather than a contradiction.
  • No architecture test reads docs/reborn/target-architecture/, so this PR cannot break one. (Four tests do read docs: three docs/reborn/contracts/*.md and docs/plans/composition-pubuse.snapshot.)

Briefed premises this audit refuted

Findings a sibling agent is actively changing — deliberately not amended here

Audited against main only. Each of these is real and each belongs to a branch in flight, so amending it here would collide:

  • ws2/decisions — the five open [decision] rows: channel_host.rs ownership (now the binding constraint on the re-layer, 26 of the surviving product symbols), hosted-MCP registration placement, the slack_user destructive boot migration, LlmConfigService's vendor vocabulary in contracts, and §6.1.3-vs-§6.9.4's frozen inventory. My §8.2/§11 amendments state the mechanism behind them and stop short of the calls.
  • ws2/package-colocation — physical moves and renames. I did not touch the family tree layouts in families/*.md, §5's target tree, or WS6's rename list.
  • ws2/strays-followups — CHECKLIST WS2's strays row and its four sub-items.

Expect a merge-down before this lands.

Out of scope for a docs-only PR — code-file defects found in passing

Reported, not fixed:

  1. changed-coverage-exemptions.toml's WS2 header says "Thirteen lines across six files"; its entries list fifteen (1+2+5+2+1+4). Flagged in review on refactor(contracts): consolidate the Wave 2 port-inversion stack (WS2.2, WS2.4, WS5) #7018, not applied before merge.
  2. No detection of an exemption that is never used. The loader is aggressively fail-closed about staleness (stale path aborts the gate before any coverage is read; expired review_after reds it) but an exemption the new pre-existing-uncovered exclusion has made redundant is silently inert. Wanted: report exemptions that matched nothing in a run where base coverage was applied.
  3. .github/workflows/reborn-tests.yml:782-784 still says "While [global].enforce = false … this always exits 0 (dry-run soak period)" — the ratchet has been enforcing since the recapture.
  4. FULL_PR_PATHS lists coverage-floor.toml but not changed-coverage-exemptions.toml, so a PR that only edits the exemption manifest does not run the gate that consumes it.
  5. reborn_restructure_baselines.rs:10-12 says the exception count is "now 15" (13) and the specificity allowlist is 130 (129).
  6. Observation, not a defect — classify-test-scope.sh treats any .md under crates/ as core code. Measured on this PR's own diff: crates/AGENTS.md → docs_only=false, has_core_code=true, so a documentation-only change runs the full Reborn matrix (a .md under docs/ correctly yields docs_only=true). This errs in the fail-safe direction — the exact opposite of the Path-keyed CI gates that survive #6946: six silent + two loud, all blocking the first family git mv #6963 class, where a gate scanned nothing and reported success — so it needs no fix on safety grounds. It is recorded because this program ships guidance edits constantly (PLAN operating principle 3 requires them to travel with the change) and every such PR pays a full-matrix run. If it is ever tightened, the tightening must not let a crate-guide edit unhook the lane that would catch a stale guide.

Verification

  • Docs-only: git diff --name-only origin/main → 13 files, all .md; grep -v '\.md$' is empty.
  • No silent rewrites: git diff --word-diff=porcelain removes 19 distinct tokens, every one either quoted back verbatim by the amendment that replaces it (eleven, session thread, llm_config, SseManager/AppEvent, "External actor/conversation refs, source/reply") or a punctuation shift from inserting an inline note.
  • CARGO_INCREMENTAL=0 cargo test -p ironclaw_architecture → 187 passed, 0 failed (run after the edits; confirmed no suite reads this doc tree).
  • Every amendment carries a file:line citation against merged main or a PR/issue pointer.

🤖 Generated with Claude Code

…ve-2 main

Audits docs/reborn/target-architecture/ (plus crates/AGENTS.md and the
crate guides Wave 2 touched) against merged main at 3be5f05, after
#6996, #6998, #7002 and #7018.

Docs-only: 13 .md files, no code, no tests. House style throughout —
dated amendments, prior text quoted verbatim wherever a clause is
corrected, nothing rewritten silently and no decision record deleted.

The two structural findings the wave produced and nobody had written
down: same-layer edges are invisible to the layer matrix by
construction, so the exception count could never have moved in Wave 2
and each removal needed its own purpose-built shrink-only gate
(PROPOSAL §8.1, §8.2, §11.1); and the changed-line coverage policy —
90% lines, branch coverage ungated since #7013 — was recorded in no
document at all, alongside a stranded-exemption failure mode the new
pre-existing-uncovered exclusion creates (CHECKLIST WS10).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@railway-app

railway-app Bot commented Aug 3, 2026 •

Copy link
Copy Markdown

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

Service Status Web Updated (UTC)
ironclaw ✅ Success (View Logs) Web Aug 3, 2026 at 3:13 am

@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-7032 August 3, 2026 03:06 Destroyed
@github-actions github-actions Bot added scope: docs Documentation size: XS < 10 changed lines (excluding docs) risk: low Changes to docs, tests, or low-risk modules contributor: core 20+ merged PRs labels Aug 3, 2026
@coderabbitai

coderabbitai Bot commented Aug 3, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Documentation
    • Updated architecture documentation to reflect current Wave 1 and Wave 2 progress, dependency relationships, ownership boundaries, and remaining work.
    • Clarified guidance for conversation references, operator integrations, streaming boundaries, attachment capabilities, and extension management.
    • Corrected inventories, coverage expectations, dependency counts, milestone sequencing, and validation status across the target architecture documentation.
    • Recorded newly established components, completed work, unresolved exceptions, and deferred follow-ups.

Walkthrough

The PR updates crate guidance and Reborn target-architecture documentation. It records Wave 2 ownership, dependency, milestone, inventory, exception, coverage, and enforcement findings.

Changes

Architecture documentation audit

Layer / File(s) Summary
Crate guidance and boundary corrections
crates/AGENTS.md, crates/ironclaw_conversations/AGENTS.md, crates/ironclaw_operator/*, crates/ironclaw_reborn_openai_compat/CLAUDE.md, crates/ironclaw_webui/CLAUDE.md
The guidance records operator ports, conversation reference ownership, streaming boundaries, and corrected WebUI residue.
Dependency and ownership records
docs/reborn/target-architecture/families/domains.md, docs/reborn/target-architecture/families/extensions.md, docs/reborn/target-architecture/families/product.md, docs/reborn/target-architecture/PROPOSAL.md
The architecture records current crate dependencies, ownership boundaries, transport caveats, and extension-manager responsibilities.
Wave 2 status and architecture inventory
docs/reborn/target-architecture/README.md, docs/reborn/target-architecture/PLAN.md, docs/reborn/target-architecture/CHECKLIST.md, docs/reborn/target-architecture/PROPOSAL.md
The documents record Wave 2 results, remaining blockers, split measurements, package counts, and exception status.
Architecture gates and coverage governance
docs/reborn/target-architecture/CHECKLIST.md, docs/reborn/target-architecture/PLAN.md, docs/reborn/target-architecture/PROPOSAL.md
The documentation updates gate scopes, coverage rules, exception baselines, enforcement gaps, and scan inventories.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested reviewers: ilblackdragon

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description gives strong change and verification detail but omits most required template sections, including change type, validation, risk, rollback, and review follow-through. Complete the required template sections, or explicitly mark them not applicable with reasons, including change type, validation, test strategy, security, database impact, blast radius, rollback, and review follow-through.
✅ Passed checks (3 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title uses Conventional Commits format and accurately summarizes the documentation reconciliation against post-Wave-2 main.

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.

@ironloopai

ironloopai Bot commented Aug 3, 2026 •

Copy link
Copy Markdown
Contributor

🔎 Review · PR #7032

🔴 Failed

Execution result is invalid

The structured result could not be verified.

Automatic · PR opened · attempt 1 of 3 · failed after 1m 45s

Failure details
  • Repository: nearai/ironclaw
  • Base: main at 3be5f05
  • Head: docs/wave2-truth-audit at 3a8a220
  • Created: Aug 3, 2026, 3:11 AM UTC
  • Updated: Aug 3, 2026, 3:12 AM UTC
  • Run: 460673fd-e353-4e60-b851-8f5edce136a6
  • Latest attempt: 1 · Completed · 69bd2d17-1459-4e75-8ef2-578b2fbab860
  • Failed during: Verification
  • Retryable: No
  • Failure: ca7cbe05-6f58-4fda-8ed7-72828b866f05

@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: 12

🤖 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 `@crates/AGENTS.md`:
- Line 127: Update the stale module reference in
crates/ironclaw_product/CLAUDE.md to use operator_llm::{LlmConfigService,
ActiveModelReader, ...} for the service implementation. Preserve llm_config only
where it refers to the public ProductSurface view or historical text.

In `@crates/ironclaw_conversations/AGENTS.md`:
- Around line 18-34: Update the conversation binding documentation to state that
the live external identity is (space_id, conversation_id, topic_id). Clarify
that thread_id refers to canonical ironclaw_host_api::ids::ThreadId, with the
sole compatibility exception being the stored_refs field spelling used for
rollback-safe storage.

In `@docs/reborn/target-architecture/CHECKLIST.md`:
- Around line 260-261: Update the recorded defects in the checklist amendment to
include follow-up issue IDs for the stranded-exemption failure mode, the WS2
entry-count mismatch, and the stale workflow comment. Replace the existing
review reference to `#7018` with the corresponding issue reference, and ensure
each unresolved defect has an explicit issue link before marking the audit
complete.
- Line 17: The WS7 checklist entry overclaims that every gate uses
crate-inventory discovery and positive/negative fixtures while later
acknowledging roughly 20 named-path gates still need repointing. Narrow that
guarantee to only the gates fixed by `#6946` and `#6996`, or remove the claim, while
preserving the accurate details about the remaining WS10 work.

In `@docs/reborn/target-architecture/families/domains.md`:
- Around line 63-64: Update the family-level exhaustive dependency summaries to
include ironclaw_attachments → ironclaw_threads and ironclaw_product_contracts
wherever the chartered same-family edges and contracts allowlist are listed.
Revise the stated edge count from three to four and ensure the attachments and
contracts crate-level “Depends on” records match these summaries.
- Around line 103-110: Update the “Identity and binding value types” ownership
entry in the target-architecture documentation to remove external actor and
conversation reference types from ironclaw_conversations ownership. Retain only
this crate’s ownership of the durable stored_refs on-disk grammar, while
identifying ironclaw_extension_contracts::external as the sole home for those
reference types.

In `@docs/reborn/target-architecture/families/product.md`:
- Line 75: Update the secret-access statement on line 54 to reflect that
ironclaw_operator currently has a direct ironclaw_secrets dependency, or
explicitly label the port-only access guarantee as target state. Keep the
dependency inventory and its existing distinction between current and intended
architecture consistent.
- Around line 42-44: Update the live dependency guidance in this document to use
the current crate identifiers ironclaw_process_sandbox and
ironclaw_reborn_openai_compat, including the amended architecture text and any
other non-historical references. Search the Markdown guidance for stale
ironclaw_sandbox and ironclaw_openai_compat matches, and explicitly mark any
retained historical or target-state names.

In `@docs/reborn/target-architecture/PROPOSAL.md`:
- Around line 797-801: Correct the quantitative claim in the Wave 2 truth-audit
amendment so the same-layer category counts and stated total agree: either
change “72” to the sum of the listed categories, or add the missing category
with its verified count. Update the surrounding claim consistently without
altering the edge examples or conclusions.
- Line 640: Clarify the dependency statement in the 6.9.4 ironclaw_webui entry
by marking the ironclaw_product → product_contracts change as a target or
conditional outcome, not an applied change. Keep the later statement that the
dependency does not flip in this row and that placement remains an open
§6.1.3-vs-§6.9.4 decision consistent throughout the entry.
- Line 1098: Run mint dev and mint broken-links from the docs directory, then
record both completed checks in the documentation change; if mint is
unavailable, explicitly note the missing dependency instead.

In `@docs/reborn/target-architecture/README.md`:
- Line 11: Rewrite the paragraph beginning “Three program-level facts” to
distinguish the recorded causes for each surviving product edge: concrete
assembly in channel_host.rs for extension_host, DTO/capability and port residue
for extension_manager, and frozen product constants for webui and openai_compat.
Preserve the ironclaw_operator removal and Wave 2 exception-count statements,
and state the corresponding owner decisions without attributing all four edges
to route handlers.
🪄 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: aeae7778-b1d6-47f1-8d8b-92730ac7adcd

📥 Commits

Reviewing files that changed from the base of the PR and between 3be5f05 and 3a8a220.

📒 Files selected for processing (13)
  • crates/AGENTS.md
  • crates/ironclaw_conversations/AGENTS.md
  • crates/ironclaw_operator/AGENTS.md
  • crates/ironclaw_operator/CLAUDE.md
  • crates/ironclaw_reborn_openai_compat/CLAUDE.md
  • crates/ironclaw_webui/CLAUDE.md
  • docs/reborn/target-architecture/CHECKLIST.md
  • docs/reborn/target-architecture/PLAN.md
  • docs/reborn/target-architecture/PROPOSAL.md
  • docs/reborn/target-architecture/README.md
  • docs/reborn/target-architecture/families/domains.md
  • docs/reborn/target-architecture/families/extensions.md
  • docs/reborn/target-architecture/families/product.md

Comment thread crates/AGENTS.md
| `ironclaw_loop_contracts` | `ironclaw_loop_contracts/CLAUDE.md`, `docs/reborn/target-architecture/families/contracts.md` | The loop-tier contract: the eleven `Loop*Port` traits + `AgentLoopDriverHost`, `AgentLoopDriver`, run-profile vocabulary, prompt/model/skill/instruction/milestone contract types, the `LoopExit` claim DTOs, the redacted checkpoint payload. | Any implementation of a port declared here, the turn coordinator/state store/exit applier, a dependency on `ironclaw_turns` (the direction inverts), any framework or driver crate. |
| `ironclaw_threads` | `ironclaw_threads/AGENTS.md`, `ironclaw_threads/CLAUDE.md` | Canonical session thread/transcript service contracts, identifiers, tool-result references, db/in-memory stores. | Product delivery policy or model/provider behavior. |
| `ironclaw_conversations` | `ironclaw_conversations/AGENTS.md`, `ironclaw_conversations/CLAUDE.md` | Conversation binding, session thread contracts, inbound/state store, libSQL/Postgres conversation persistence. | Capability runtime internals or UI transport. |
| `ironclaw_conversations` | `ironclaw_conversations/AGENTS.md`, `ironclaw_conversations/CLAUDE.md` | Conversation binding, the **inbound conversation** service contracts, inbound/state store, libSQL/Postgres conversation persistence, and the **durable ref grammar** (`stored_refs`) that keeps the released on-disk field spelling so a rename survives a rollback. ✎ *Corrected 2026-08-02: this read "session thread contracts", which is exactly the naming trap WS5 removed — `SessionThreadService` is `InboundConversationService` and `ThreadMessageRecord` is `ConversationMessageRecord`; five names collided with `ironclaw_threads` and all five were renamed.* | Capability runtime internals or UI transport. **The external actor/conversation ref types** — WS5 unified those onto `ironclaw_extension_contracts::external`; this crate owns the durable *grammar* for them, never a second declaration (`reborn_conversations_threads_attachments.rs` fails on one). |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n --hidden \
  --glob '.claude/**' \
  --glob '**/AGENTS.md' \
  --glob '**/CLAUDE.md' \
  --glob 'crates/AGENTS.md' \
  --glob 'docs/reborn/contracts/**' \
  --glob '**/*.md' \
  -P '(?<![A-Za-z0-9_])(SessionThreadService|ThreadMessageRecord|llm_config|SseManager|AppEvent|OperatorPublicRouteMount|OperatorProtectedRouteMount)(?![A-Za-z0-9_])'

Repository: nearai/ironclaw

Length of output: 153


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
import re

names = re.compile(
    r"(?<![A-Za-z0-9_])"
    r"(SessionThreadService|ThreadMessageRecord|llm_config|SseManager|AppEvent|"
    r"OperatorPublicRouteMount|OperatorProtectedRouteMount)"
    r"(?![A-Za-z0-9_])"
)

roots = [Path(".claude"), Path("docs/reborn/contracts")]
files = set()
for root in roots:
    if root.exists():
        files.update(p for p in root.rglob("*") if p.is_file())
files.update(Path(".").rglob("AGENTS.md"))
files.update(Path(".").rglob("CLAUDE.md"))
files.update(p for p in Path(".").rglob("*.md") if p.is_file())

matches = []
for path in sorted(files):
    text = path.read_text(encoding="utf-8", errors="replace")
    found = sorted(set(names.findall(text)))
    if found:
        matches.append((str(path), found))

print(f"scanned_files={len(files)}")
print(f"stale_reference_files={len(matches)}")
for path, found in matches:
    print(f"{path}: {', '.join(found)}")
PY

Repository: nearai/ironclaw

Length of output: 2410


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
import re

pattern = re.compile(
    r"(?<![A-Za-z0-9_])"
    r"(SessionThreadService|ThreadMessageRecord|llm_config|SseManager|AppEvent|"
    r"OperatorPublicRouteMount|OperatorProtectedRouteMount)"
    r"(?![A-Za-z0-9_])"
)

files = set()
for root in (Path(".claude"), Path("docs/reborn/contracts")):
    if root.exists():
        files.update(p for p in root.rglob("*") if p.is_file())
files.update(Path(".").rglob("AGENTS.md"))
files.update(Path(".").rglob("CLAUDE.md"))
files.update(p for p in Path(".").rglob("*.md") if p.is_file())

for path in sorted(files):
    lines = path.read_text(encoding="utf-8", errors="replace").splitlines()
    for number, line in enumerate(lines, 1):
        if pattern.search(line):
            before = lines[number - 2].strip() if number > 1 else ""
            after = lines[number].strip() if number < len(lines) else ""
            print(f"{path}:{number}")
            print(f"  {before}")
            print(f"  {line.strip()}")
            print(f"  {after}")
PY

Repository: nearai/ironclaw

Length of output: 50373


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' 'Current Rust declarations and references:'
rg -n --glob '*.rs' \
  'trait (SessionThreadService|InboundConversationService)|struct (ThreadMessageRecord|ConversationMessageRecord)|\b(SessionThreadService|InboundConversationService|ThreadMessageRecord|ConversationMessageRecord)\b' crates | head -120

printf '%s\n' 'Relevant guidance and contract references:'
rg -n \
  'SessionThreadService|InboundConversationService|ThreadMessageRecord|ConversationMessageRecord|SseManager|EventStreamManager|AppEvent|OperatorPublicRouteMount|OperatorProtectedRouteMount|PublicRouteMount|ProtectedRouteMount|llm_config|operator_llm' \
  .claude/commands/trace.md \
  .claude/skills/ironclaw-reborn-orientation/SKILL.md \
  AGENTS.md \
  crates/AGENTS.md \
  crates/Architecture.md \
  crates/ironclaw_conversations/CLAUDE.md \
  crates/ironclaw_product/AGENTS.md \
  crates/ironclaw_product/CLAUDE.md \
  crates/ironclaw_reborn_openai_compat/CLAUDE.md \
  docs/reborn/contracts/openai-compatible-api.md \
  docs/reborn/contracts/storage-placement.md \
  docs/reborn/contracts/settings-config.md \
  2>/dev/null

Repository: nearai/ironclaw

Length of output: 21858


🏁 Script executed:

#!/bin/bash
set -euo pipefail

for spec in \
  'crates/ironclaw_product/CLAUDE.md:48:86' \
  'crates/ironclaw_product/CLAUDE.md:168:194' \
  'crates/ironclaw_operator/CLAUDE.md:28:72' \
  'docs/reborn/contracts/openai-compatible-api.md:104:120' \
  'docs/reborn/contracts/openai-compatible-api.md:246:260' \
  'docs/reborn/contracts/storage-placement.md:66:108' \
  'docs/reborn/contracts/settings-config.md:128:142'
do
  file=${spec%%:*}
  rest=${spec#*:}
  start=${rest%%:*}
  end=${rest##*:}
  printf '\n--- %s:%s-%s ---\n' "$file" "$start" "$end"
  sed -n "${start},${end}p" "$file"
done

printf '\n--- conversation service declarations ---\n'
rg -n --glob '*.rs' \
  'pub trait (InboundConversationService|SessionThreadService)|pub struct (ConversationMessageRecord|ThreadMessageRecord)' \
  crates/ironclaw_conversations crates/ironclaw_threads

Repository: nearai/ironclaw

Length of output: 11408


Replace the stale llm_config module reference. In crates/ironclaw_product/CLAUDE.md, use operator_llm::{LlmConfigService, ActiveModelReader, ...}. Keep llm_config when it denotes the public ProductSurface view or historical text.

🤖 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 `@crates/AGENTS.md` at line 127, Update the stale module reference in
crates/ironclaw_product/CLAUDE.md to use operator_llm::{LlmConfigService,
ActiveModelReader, ...} for the service implementation. Preserve llm_config only
where it refers to the public ProductSurface view or historical text.

Source: Path instructions

Comment on lines 18 to +34
- Adapter-safe conversation binding and inbound-turn service contracts.
- External actor/conversation refs, source/reply binding refs, participant checks, message acceptance refs, and idempotency semantics.
- Source/reply binding refs, participant checks, message acceptance refs, and
idempotency semantics — plus the **durable grammar** for external refs
(`stored_refs`): write the released spelling
`{space_id, conversation_id, thread_id, message_id}`, read either, so the
WS5 rename is invisible to storage in both directions and a rollback stays
safe.
> Corrected 2026-08-02 (Wave 2 docs-truth audit): this read "External
> actor/conversation refs, source/reply binding refs, …". The ref **types**
> are no longer owned here — WS5 unified them onto
> `ironclaw_extension_contracts::external` after finding the two copies were
> field-divergent *and* compared differently (this crate's derived `PartialEq`
> included the per-event message id; the canonical type excludes the
> reply-target hint by hand), so two refs for one route could be equal or
> unequal depending on which copy the caller held. Declaring them again here
> fails `reborn_conversations_threads_attachments.rs`. What this crate owns is
> the record grammar, above.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

State the live external identity separately from the storage spelling.

The guide documents the legacy stored_refs.thread_id field but does not state the live external binding identity. Add that identity as (space_id, conversation_id, topic_id). Reserve thread_id for canonical ironclaw_host_api::ids::ThreadId, except for the rollback-compatible stored_refs field spelling. This prevents callers from using the storage key as the runtime route identity.

Based on learnings: the stable external conversation binding identity is (space_id, conversation_id, topic_id), while thread_id has the documented compatibility-only exception.

Suggested clarification
   - Source/reply binding refs, participant checks, message acceptance refs, and
     idempotency semantics — plus the durable grammar for external refs
     (`stored_refs`): write the released spelling
     `{space_id, conversation_id, thread_id, message_id}`, read either, so the
     WS5 rename is invisible to storage in both directions and a rollback stays
     safe.
+  - Live external conversation identity is `(space_id, conversation_id,
+    topic_id)`. Use `thread_id` only for canonical `ThreadId` values and the
+    rollback-compatible `stored_refs` field spelling.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- Adapter-safe conversation binding and inbound-turn service contracts.
- External actor/conversation refs, source/reply binding refs, participant checks, message acceptance refs, and idempotency semantics.
- Source/reply binding refs, participant checks, message acceptance refs, and
idempotency semantics — plus the **durable grammar** for external refs
(`stored_refs`): write the released spelling
`{space_id, conversation_id, thread_id, message_id}`, read either, so the
WS5 rename is invisible to storage in both directions and a rollback stays
safe.
> Corrected 2026-08-02 (Wave 2 docs-truth audit): this read "External
> actor/conversation refs, source/reply binding refs, …". The ref **types**
> are no longer owned here — WS5 unified them onto
> `ironclaw_extension_contracts::external` after finding the two copies were
> field-divergent *and* compared differently (this crate's derived `PartialEq`
> included the per-event message id; the canonical type excludes the
> reply-target hint by hand), so two refs for one route could be equal or
> unequal depending on which copy the caller held. Declaring them again here
> fails `reborn_conversations_threads_attachments.rs`. What this crate owns is
> the record grammar, above.
- Adapter-safe conversation binding and inbound-turn service contracts.
- Source/reply binding refs, participant checks, message acceptance refs, and
idempotency semantics — plus the **durable grammar** for external refs
(`stored_refs`): write the released spelling
`{space_id, conversation_id, thread_id, message_id}`, read either, so the
WS5 rename is invisible to storage in both directions and a rollback stays
safe.
- Live external conversation identity is `(space_id, conversation_id,
topic_id)`. Use `thread_id` only for canonical `ThreadId` values and the
rollback-compatible `stored_refs` field spelling.
> Corrected 2026-08-02 (Wave 2 docs-truth audit): this read "External
> actor/conversation refs, source/reply binding refs, …". The ref **types**
> are no longer owned here — WS5 unified them onto
> `ironclaw_extension_contracts::external` after finding the two copies were
> field-divergent *and* compared differently (this crate's derived `PartialEq`
> included the per-event message id; the canonical type excludes the
> reply-target hint by hand), so two refs for one route could be equal or
> unequal depending on which copy the caller held. Declaring them again here
> fails `reborn_conversations_threads_attachments.rs`. What this crate owns is
> the record grammar, above.
🤖 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 `@crates/ironclaw_conversations/AGENTS.md` around lines 18 - 34, Update the
conversation binding documentation to state that the live external identity is
(space_id, conversation_id, topic_id). Clarify that thread_id refers to
canonical ironclaw_host_api::ids::ThreadId, with the sole compatibility
exception being the stored_refs field spelling used for rollback-safe storage.

Source: Learnings

- [x] Record baselines for the ratchets that must not regress during the restructure: composition mass, production-struct dead-code, integration coverage floor, `LAYER_MATRIX_EXCEPTIONS` count (=20), extension-specificity allowlist size. **Landed with #6936**, every number measured from `origin/main` @ `ae0989c37` rather than copied from these docs: `LAYER_MATRIX_EXCEPTIONS` **20** (the recount matched the documented 20), extension-specificity allowlist **130** pairs, production-struct dead-code **82 frozen paths / 283 members**, composition mass **43,936 / 667,978 production LOC = 6.58% (658 bp)** with **827** governed `Arc<dyn>` sites, integration-coverage floor **85.54%** (a counting mechanism already existed — `tests/integration/coverage-floor.toml` + `scripts/ci/reborn-coverage-ratchet.sh` — so none was invented). The three list-shaped baselines sit beside the lists they measure (`reborn_dependency_boundaries.rs`, `reborn_extension_specificity.rs`, `reborn_struct_test_support_ratchet.rs`), each now shrink-only; the two enforced by shell gates are recorded in `reborn_restructure_baselines.rs`, which also pins that both gates stay armed.
- [x] Confirm the team decision on Strategy B (family dirs + focused crates). Rename scope is fully decided (PROPOSAL §12.10; naming rule §5.1). **[decision]** — **Confirmed 2026-07-31 (owner): north star shared with the team, epic #3773 cut from this checklist, and Waves 0–1 executing it — decision recorded retroactively; it was made in practice at program start.**
- [x] ⚠ Blocking prerequisite for WS7: the WS10 path-keyed-gate rewrites land before the first family `git mv` (they fail silently under nested dirs). **Landed in two PRs — #6946 (the five gates the WS10 row names) and #6996, which closed #6963: the six further silent gates, the two loud-but-flat-keyed repoints, and the two members later comments added.** Every gate now discovers through the crate inventory (`scripts/ci/lib/crate_tree.py` — the outermost owner of each `crates/**/Cargo.toml`), asserts it measured something, and carries positive + negative fixtures; behavior on the flat tree is proven unchanged per gate (trigger sets over all 4203 tracked files for the three workflow filters, byte-identical stdout and `--json` for the script gates, an identical 1249-file scanned set for the registration boundary). *Fixed by #6996:* `code_style.yml`'s `has_reborn_cli` regex, `platform-and-compat.yml`'s `has_direct_wasm_abi_risk` regex and `ironclaw-stress.yml`'s `paths:` filter — all three now keyed to crate **name at any depth** and pinned by `scripts/ci/ws12_workflow_contracts.py` against the real inventory, so a renamed, moved or deleted crate fails loudly in Code Style instead of quietly unhooking a lane — plus `scripts/ci/regression-test-check.py`'s `HIGH_RISK_PATTERNS`, `scripts/build-wasm-extensions.sh`'s assets glob, `scripts/ci/reborn_changed_coverage.py`'s pathspec and `PRODUCTION_PATH`, `scripts/ci/critical_mutation_gate.py`, `scripts/ci/check-composition-budget.sh`, and `crates/ironclaw_architecture/tests/reborn_registration_pipeline_boundary.rs`. **Two stale terms removed, each matching nothing today** — `ironclaw_wasm_product_adapters` (crate deleted) and `ironclaw_run_state` (deleted with #6696) — so the staleness the previous version of this row recorded is now historical. **Two corrections to #6963's inventory, both established empirically rather than by reading:** `build-wasm-extensions.sh` did *not* build nothing and exit 0 — `build_manifest_set` already carried an empty-set guard, so it needed discovery only (its bash-3.2 `unbound variable` death before reaching that guard was the real sub-defect); and `check-composition-budget.sh` is not purely loud — the all-crates move is loud, but the *partial* move, which is the realistic WS7 batch shape, was **silently green** at `0.00% (0 bp)` with a "lower the ceiling" nudge. A fourth pin on the dist-build regex turned up only because it failed: `crates/ironclaw_reborn_cli/tests/smoke.rs` greps that workflow line for the flat literal, and it is the reason a one-sided edit could not land silently. *Residue, none of it blocking:* #6996 also fixed the shared `ratchet_support::workspace_root()` fixed-depth idiom that 23 of the 24 `ironclaw_architecture` gates shared, the two that went silently green under it (`reborn_authorized_seal_ratchet` — worst under a *partial* move, 1309 → 45 files scanned with no error — and `reborn_retired_taxonomy`, 1492 → 0), and two vacuous `assert!(!path.exists())` checks; the other 20 gates' *named-path* keying still needs repointing at the `git mv` and is tracked on the WS10 loud-inventory row below. #6947 (classifier arm-inventory rot) and #6999 (the server-lifecycle rule's WebChat v2 gap, found by this sweep) stay open and neither blocks WS7.
- [x] ⚠ Blocking prerequisite for WS7: the WS10 path-keyed-gate rewrites land before the first family `git mv` (they fail silently under nested dirs). **Landed in two PRs — #6946 (the five gates the WS10 row names) and #6996, which closed #6963: the six further silent gates, the two loud-but-flat-keyed repoints, and the two members later comments added.** Every gate now discovers through the crate inventory (`scripts/ci/lib/crate_tree.py` — the outermost owner of each `crates/**/Cargo.toml`), asserts it measured something, and carries positive + negative fixtures; behavior on the flat tree is proven unchanged per gate (trigger sets over all 4203 tracked files for the three workflow filters, byte-identical stdout and `--json` for the script gates, an identical 1249-file scanned set for the registration boundary). *Fixed by #6996:* `code_style.yml`'s `has_reborn_cli` regex, `platform-and-compat.yml`'s `has_direct_wasm_abi_risk` regex and `ironclaw-stress.yml`'s `paths:` filter — all three now keyed to crate **name at any depth** and pinned by `scripts/ci/ws12_workflow_contracts.py` against the real inventory, so a renamed, moved or deleted crate fails loudly in Code Style instead of quietly unhooking a lane — plus `scripts/ci/regression-test-check.py`'s `HIGH_RISK_PATTERNS`, `scripts/build-wasm-extensions.sh`'s assets glob, `scripts/ci/reborn_changed_coverage.py`'s pathspec and `PRODUCTION_PATH` ✎ *(the constant is `CRATE_PRODUCTION_SOURCE` on `main` — #6996 renamed it when it stopped being a whole-path regex and became a crate-relative one applied to inventory-discovered crates; the substance of this clause is unchanged)*, `scripts/ci/critical_mutation_gate.py`, `scripts/ci/check-composition-budget.sh`, and `crates/ironclaw_architecture/tests/reborn_registration_pipeline_boundary.rs`. **Two stale terms removed, each matching nothing today** — `ironclaw_wasm_product_adapters` (crate deleted) and `ironclaw_run_state` (deleted with #6696) — so the staleness the previous version of this row recorded is now historical. **Two corrections to #6963's inventory, both established empirically rather than by reading:** `build-wasm-extensions.sh` did *not* build nothing and exit 0 — `build_manifest_set` already carried an empty-set guard, so it needed discovery only (its bash-3.2 `unbound variable` death before reaching that guard was the real sub-defect); and `check-composition-budget.sh` is not purely loud — the all-crates move is loud, but the *partial* move, which is the realistic WS7 batch shape, was **silently green** at `0.00% (0 bp)` with a "lower the ceiling" nudge. A fourth pin on the dist-build regex turned up only because it failed: `crates/ironclaw_reborn_cli/tests/smoke.rs` greps that workflow line for the flat literal, and it is the reason a one-sided edit could not land silently. *Residue, none of it blocking:* #6996 also fixed the shared `ratchet_support::workspace_root()` fixed-depth idiom that 23 of the 24 `ironclaw_architecture` gates shared, the two that went silently green under it (`reborn_authorized_seal_ratchet` — worst under a *partial* move, 1309 → 45 files scanned with no error — and `reborn_retired_taxonomy`, 1492 → 0), and two vacuous `assert!(!path.exists())` checks; the other 20 gates' *named-path* keying still needs repointing at the `git mv` and is tracked on the WS10 loud-inventory row below. #6947 (classifier arm-inventory rot) and #6999 (the server-lifecycle rule's WebChat v2 gap, found by this sweep) stay open and neither blocks WS7.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Narrow the completed-gate claim.

Line 17 says every gate now uses crate-inventory discovery and positive and negative fixtures. Later text still lists about 20 named-path gates that require repointing. Scope this sentence to the gates fixed by #6946 and #6996, or remove the completion claim.

As per coding guidelines, documentation promising guardrail guarantees must match the enforcing code and tests.

🤖 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 `@docs/reborn/target-architecture/CHECKLIST.md` at line 17, The WS7 checklist
entry overclaims that every gate uses crate-inventory discovery and
positive/negative fixtures while later acknowledging roughly 20 named-path gates
still need repointing. Narrow that guarantee to only the gates fixed by `#6946`
and `#6996`, or remove the claim, while preserving the accurate details about the
remaining WS10 work.

Source: Coding guidelines

Comment on lines +260 to +261
- **⚠ A stranded-exemption failure mode this wave created, recorded because nothing detects it.** `load_manifest` is aggressively fail-closed about *staleness* — a path that is not a live production `.rs` aborts the whole gate before any coverage is read, a line past EOF fails, a non-`nearai/ironclaw` issue URL fails, and an **expired `review_after` reds the gate**. It has no notion of an exemption that is simply never *used*. The pre-existing-uncovered exclusion (WS2's coverage note above) now removes lines automatically that the WS2 consolidation had already hand-exempted as *"PRE-EXISTING AND BEHAVIOURALLY UNTOUCHED … its pre-image scored zero in the BASE commit's merged tracefile"* — the two mechanisms overlap by construction, so some of the 79 entries can be permanently inert while still reading as live carve-outs. **Wanted (WS10-shaped, one assertion):** report exemptions that matched no excluded line in a run where base coverage *was* applied, so an obsolete carve-out expires by evidence instead of by the `review_after` calendar. Sibling defect in the same file, found the same way: the WS2 consolidation block's header says *"Thirteen lines across six files"* while its six entries list **fifteen** (1+2+5+2+1+4) — flagged in review on #7018, not applied before merge. Both are code-file fixes, out of scope for a docs-only PR.
- **Live figures for the floor ratchet**, since this row's numbers are quoted downstream: `[global]` `enforce = true`, `floor_percent = 85.11`, `tolerance_percent = 0.5` (effective **84.61%**), captured 2026-07-30. WS0's recorded **85.54%** (the row at the top of this file) is the WS0 capture and is now history, not the live floor. One stale in-repo comment worth fixing alongside: `.github/workflows/reborn-tests.yml:782-784` still says *"While `[global].enforce = false` … this always exits 0 (dry-run soak period)"* — the ratchet has been enforcing since the recapture.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Link follow-up issues for the recorded defects.

This amendment records the stranded-exemption defect and stale workflow comment without follow-up issue references. It also points to a review on #7018 for the count mismatch, but that is not a follow-up issue. Add issue IDs for each unresolved defect before marking the audit complete.

As per coding guidelines, discovered problems need follow-up issues.

🤖 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 `@docs/reborn/target-architecture/CHECKLIST.md` around lines 260 - 261, Update
the recorded defects in the checklist amendment to include follow-up issue IDs
for the stranded-exemption failure mode, the WS2 entry-count mismatch, and the
stale workflow comment. Replace the existing review reference to `#7018` with the
corresponding issue reference, and ensure each unresolved defect has an explicit
issue link before marking the audit complete.

Source: Coding guidelines

Comment on lines +63 to +64
> ✎ **Corrected 2026-08-02 (Wave 2 truth audit) — there is a fourth edge, and Wave 2 created it.** Prior text, quoted: *"No other crate in the family depends on a sibling — the family's internal graph is a shallow forest, not a mesh."* `ironclaw_attachments` now depends on `ironclaw_threads` (`attachments/src/ports.rs:23`, `src/project_scoped.rs:24`, for `ThreadScope`), acquired with the WS5 attachments widening. It is a legal downward-within-layer edge and the forest is still a forest — four edges, no cycles — but the sentence claimed an exhaustive list and is now short by one. The `attachments` entry's own **Depends on** line below carries the same omission plus a second one, and is corrected there.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Update every exhaustive dependency summary.

Line 63 records ironclaw_attachments → ironclaw_threads, but Line 57 still says there are only three chartered same-family edges and Line 61 still lists only three. Line 200 also adds ironclaw_product_contracts, which is absent from the contracts allowlist in Line 57. Update the family-level summaries so they match the crate-level dependency records.

Suggested documentation fix
- contracts/ — host_api, common, prompt_envelope · plus the three chartered same-family edges only: conversations→triggers, attachments→extractors, trace_commons→llm
+ contracts/ — host_api, common, prompt_envelope, product_contracts · plus the four chartered same-family edges only: conversations→triggers, attachments→extractors, attachments→threads, trace_commons→llm

Also applies to: 200-202

🤖 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 `@docs/reborn/target-architecture/families/domains.md` around lines 63 - 64,
Update the family-level exhaustive dependency summaries to include
ironclaw_attachments → ironclaw_threads and ironclaw_product_contracts wherever
the chartered same-family edges and contracts allowlist are listed. Revise the
stated edge count from three to four and ensure the attachments and contracts
crate-level “Depends on” records match these summaries.

- **Never contains:** conversation or channel behavior of any kind; extension lifecycle; route-handling logic beyond mounting a carrier supplied by the ingress vocabulary.
- **Public surface:** implementations of the operator-service ports — LLM configuration, active-model reading, log service, service-lifecycle service, and status service — each defined in `ironclaw_product_contracts`.
- **Depends on:** `ironclaw_product_contracts` for the ports it implements, `ironclaw_llm` for provider mechanics, and `ironclaw_host_ingress` for its route carriers; boot-time values it needs arrive as construction input from whoever assembles the deployment, never as a direct dependency on the boot-configuration crate.
- **Depends on:** `ironclaw_product_contracts` for the ports it implements, `ironclaw_llm` for provider mechanics, and `ironclaw_host_ingress` for its route carriers; boot-time values it needs arrive as construction input from whoever assembles the deployment, never as a direct dependency on the boot-configuration crate. ✎ **Corrected 2026-08-02 (Wave 2 truth audit): the last clause is the family's target and is false today.** `ironclaw_operator` names `ironclaw_reborn_config` in its manifest and uses it in `operator_service_lifecycle.rs` at five sites, and its `BoundaryRule` — new with WS5 — does **not** forbid the edge. Also absent from this list and present in the manifest: `ironclaw_secrets` (a *known* debt, called out in the crate's own `AGENTS.md` and in the gate's comment, and the "product/operator lose direct `secrets`" tightening PROPOSAL §6.2.2 owns), plus `ironclaw_safety`, `ironclaw_common`, `ironclaw_filesystem`, `ironclaw_host_api`. **What WS5 did close is the headline edge:** `ironclaw_product` is gone from the manifest with a residue of zero, proven through `cargo metadata` rather than a path literal. The rest of this line is still ahead of the code.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Correct the secret-access guarantee.

Line 54 says ironclaw_operator reaches secret storage only through a port. Line 75 records a current direct ironclaw_secrets dependency. Mark Line 54 as target state or rewrite it to the current state. Otherwise the documentation claims a security boundary that the current manifest does not enforce.

🤖 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 `@docs/reborn/target-architecture/families/product.md` at line 75, Update the
secret-access statement on line 54 to reflect that ironclaw_operator currently
has a direct ironclaw_secrets dependency, or explicitly label the port-only
access guarantee as target state. Keep the dependency inventory and its existing
distinction between current and intended architecture consistent.

✎ **Landed 2026-08-01 (WS5 operator row), with two corrections to this entry's wording.** (1) *"Its Axum route fragments move behind `host_ingress` carriers wired by composition (it stops owning routers)"* — the carriers already existed and operator had **duplicated** them: `OperatorPublicRouteMount`/`OperatorProtectedRouteMount` were field-identical copies of `ironclaw_host_ingress::{PublicRouteMount, ProtectedRouteMount}`, and the duplicate forced a composition-side shim whose whole body converted one into the other. The clause was satisfied by *deleting* both the local carriers and the shim, not by moving a route; the protected copy had no consumer at all. Operator still owns the one route it has (the public NEAR AI login callback) and hands it back as a host-owned mount — which is what "stops owning routers" should say: it never mounts, it never nests, it hands back a carrier. (2) *"Gets: guidance files + a boundary rule (today it has neither)"* — done, and the absence turned out to be causal rather than cosmetic. `ironclaw_operator` and `ironclaw_product` are both `products`-layer, so `products → products` is legal by the matrix and **invisible to every existing gate**; with no `BoundaryRule` and no crate guidance, nothing in the workspace could have reported the edge. It now has `AGENTS.md`, `CLAUDE.md`, a `BoundaryRule`, and a purpose-built gate (`reborn_operator_port_inversion.rs`) that proves the manifest edge gone through `cargo metadata` rather than a literal path, so WS10's move of this crate into `product/` fails loudly instead of silently scanning nothing.
- **6.9.3 `ironclaw_openai_compat`** — retain, rename (drop `reborn_`). The OpenAI-shaped ingress adapter: route descriptors, wire DTOs, sanitized error envelope, ref/idempotency store, workflows over `BoundProductSurface`. Change: depends on `product_contracts` (+`extension_contracts` where channel DTOs are shared) instead of `ironclaw_product`; stale feature-gating guidance corrected. ✎ *2026-08-01: both edges landed with the WS5 transport inversion — 23 → 3 product symbols, the three survivors being the same frozen command constants that keep webui's edge alive. The `extension_contracts` edge carries exactly one type, `ProductTriggerReason`.* Open modeling question (adapter-as-extension?) stays §12.10 — not forced. Why a crate: a protocol surface with its own wire-stability contract and the tightest honored guardrails in the audit.
- **6.9.4 `ironclaw_webui`** — retain. Route surface + descriptor table (✎ **92** routes, contract-locked — re-counted 2026-07-31 at `2e6522580`: `rg -c 'pub const WEBUI_V2_ROUTE_' crates/ironclaw_webui/src/webui_v2/descriptors.rs` → 92, was 91; #6930 added `WEBUI_V2_ROUTE_REGISTER_HOSTED_MCP_EXTENSION` with its frozen-table row and updated the crate's own `CLAUDE.md` route table in the same PR — the contract lock working as intended), gateway middleware order, serve loop, host authentication (Env/Session/OIDC/composite + `/auth/*` login), product-auth HTTP routes, embedded SPA. Changes: `ironclaw_product` dep → `product_contracts` (the one non-DTO import, the bearer-evidence mint, moves to `host_api`'s sealed evidence home, deleting the `host-auth-mint` feature plumbing) ✎ **Corrected 2026-08-01 (WS5 transport inversion): "the one non-DTO import" is wrong by 91.** Beyond the mint (which left with WS1.5), webui names **91 concrete command/view/capability constants** — the frozen inventory §6.1.3 keeps in product — plus 11 wire DTOs whose fields name `ironclaw_attachments`/`threads`/`auth`/`common`/`loop_contracts`. Measured at `f4819bb50`: 228 product symbols before the inversion, 102 after. **The dep therefore does not flip in this row**; whether the inventory follows the descriptor types into contracts is the open §6.1.3-vs-§6.9.4 decision recorded on the CHECKLIST row; gains the pairing routes from `extension_host`; its second OAuth stack (host login) stays by charter (documented, distinct concern) — §12.10 records the consolidation question. Why a crate: the transport/presentation artifact (axum + SPA cone) with a comprehensive boundary rule.
- **6.9.4 `ironclaw_webui`** — retain. Route surface + descriptor table (✎ **92** routes, contract-locked — re-counted 2026-07-31 at `2e6522580`: `rg -c 'pub const WEBUI_V2_ROUTE_' crates/ironclaw_webui/src/webui_v2/descriptors.rs` → 92, was 91; #6930 added `WEBUI_V2_ROUTE_REGISTER_HOSTED_MCP_EXTENSION` with its frozen-table row and updated the crate's own `CLAUDE.md` route table in the same PR — the contract lock working as intended), gateway middleware order, serve loop, host authentication (Env/Session/OIDC/composite + `/auth/*` login), product-auth HTTP routes, embedded SPA. Changes: `ironclaw_product` dep → `product_contracts` (the one non-DTO import, the bearer-evidence mint, moves to `host_api`'s sealed evidence home, deleting the `host-auth-mint` feature plumbing) ✎ **Corrected 2026-08-01 (WS5 transport inversion): "the one non-DTO import" is wrong by 91.** Beyond the mint (which left with WS1.5), webui names **91 concrete command/view/capability constants** — the frozen inventory §6.1.3 keeps in product — plus 11 wire DTOs whose fields name `ironclaw_attachments`/`threads`/`auth`/`common`/`loop_contracts`. Measured at `f4819bb50`: 228 product symbols before the inversion, 102 after. ✎ *Corrected 2026-08-02 (Wave 2 truth audit): **9** DTOs and **100** symbols at merged `main`. The row predicted its own invalidation and nobody applied it — the WS5 `attachments widened` slice in the very same PR moved `ProductAttachmentCapabilities`/`product_attachment_capabilities` into `ironclaw_attachments` (they are `AttachmentCapabilities`/`attachment_capabilities()` now), which the transport gate's own comment records: "102 when the WS5 transport inversion landed; **100** after the WS5 `attachments widened` row". The pin is `WEBUI_PRODUCT_SYMBOL_BASELINE: usize = 100` (`reborn_transport_product_boundary.rs:212`) over a 100-entry exact-match list. **91 constants is unchanged and exact**, as is "92 routes". The stale pair propagated to three other places — CHECKLIST WS5's `webui` row, its "eleven survivors" sub-finding, and `crates/ironclaw_webui/CLAUDE.md` — all corrected in this audit.* **The dep therefore does not flip in this row**; whether the inventory follows the descriptor types into contracts is the open §6.1.3-vs-§6.9.4 decision recorded on the CHECKLIST row; gains the pairing routes from `extension_host`; its second OAuth stack (host login) stays by charter (documented, distinct concern) — §12.10 records the consolidation question. Why a crate: the transport/presentation artifact (axum + SPA cone) with a comprehensive boundary rule.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Disambiguate the WebUI dependency status.

The entry first states that ironclaw_webui changes from ironclaw_product to product_contracts. The amendment later says the dependency does not flip in this row and leaves placement open. Mark the first statement as target-only or conditional. Otherwise, readers can treat an unresolved decision as landed.

🤖 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 `@docs/reborn/target-architecture/PROPOSAL.md` at line 640, Clarify the
dependency statement in the 6.9.4 ironclaw_webui entry by marking the
ironclaw_product → product_contracts change as a target or conditional outcome,
not an applied change. Keep the later statement that the dependency does not
flip in this row and that placement remains an open §6.1.3-vs-§6.9.4 decision
consistent throughout the entry.

Comment on lines +797 to +801
> ✎ **Amended 2026-08-02 (Wave 2 truth audit) — "each layer may use itself" is the whole of Wave 2's blind spot, and this rule states it as a permission without stating its cost.** `layer_allows_dependency` is **reflexive at every layer** (`reborn_dependency_boundaries.rs:4294`, and for products at `:4307-4310`), and the caller only consults the exception register *inside* the `if !layer_allows_dependency(...)` branch (`:196`). So a same-layer edge never reaches the violation branch and **no `LAYER_MATRIX_EXCEPTION` can ever exist for one**. On `main` that leaves **72 same-layer edges entirely outside the matrix** — 34 substrates→substrates, 18 kernel→kernel, **10 products→products**, 5 contracts→contracts, 4 loops→loops.
>
> **Why this matters more than it reads.** Every edge Wave 2 exists to kill is in that unpoliced plane: `extension_host → product`, `webui → product`, `openai_compat → product`, `operator → product`, `extension_manager → product`. All five crates declare `layer = "products"`. That is why Wave 2's milestones could never have moved the exception count, why each removal needed a **purpose-built** gate instead (§11.1's amendment lists them), and why `ironclaw_operator` carried an inverted dependency for months with, in that PR's words, *"nothing watching"* — no `BoundaryRule`, no guidance, and a matrix structurally incapable of reporting it. **The exception register is not a progress metric for any wave whose work is intra-layer.** Read the per-edge residue baselines in §11.1's scan list instead.
>
> Four `products → products` edges are policed by nothing at all today — `extension_host → host_ingress`, `webui → host_ingress`, `operator → host_ingress`, and `webui → openai_compat` (plus `telegram_extension → telegram_v2_adapter`, which §6.8.4 dissolves by merging the crates). The first four are sanctioned by §8.2's `product/` "siblings" cell and are genuinely fine; they are listed so the next audit does not rediscover them as findings.

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 | 🟡 Minor | ⚡ Quick win

Fix the same-layer edge count.

The listed categories total 71 edges, not 72. Add the omitted category or correct the total. Keep the quantitative claim consistent with the evidence.

🤖 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 `@docs/reborn/target-architecture/PROPOSAL.md` around lines 797 - 801, Correct
the quantitative claim in the Wave 2 truth-audit amendment so the same-layer
category counts and stated total agree: either change “72” to the sum of the
listed categories, or add the missing category with its verified count. Update
the surrounding claim consistently without altering the edge examples or
conclusions.

## 13. Final validation checklist

- ☑ **Every current workspace crate accounted for:** §9 rows 1–3, 7–52, and 54–68 cover all 64 `crates/` packages; 69–70 the tools/root packages; 71–74 excluded packages; 4–6, 53 the new crates. (66 workspace + 4 excluded classes; ✎ **re-verified 2026-07-30 at `457088c8f`** — every `cargo metadata` package name appears exactly once, with `ironclaw_libsql_runtime` added at row 12 and `ironclaw_run_state` retired; `first_party_extension_ports`' implicit membership is still called out. ✎ **2026-08-01 (Wave 1 truth audit): the criterion still holds at `a50ad0638`, where the live figure is 67, not 66** — §9's rows 4–6 are the three Wave 1 contracts crates, entered at authoring time as **new** and now built, and the two WS0 deletions are `ironclaw_dispatcher` and `ironclaw_embeddings`. The 66/64 figures on this line and in §9's header are that table's 2026-07-30 measurement and are deliberately not re-derived here; §2.1 carries the current count and its arithmetic.)
- ☑ **Every current workspace crate accounted for:** §9 rows 1–3, 7–52, and 54–68 cover all 64 `crates/` packages; 69–70 the tools/root packages; 71–74 excluded packages; 4–6, 53 the new crates. (66 workspace + 4 excluded classes; ✎ **re-verified 2026-07-30 at `457088c8f`** — every `cargo metadata` package name appears exactly once, with `ironclaw_libsql_runtime` added at row 12 and `ironclaw_run_state` retired; `first_party_extension_ports`' implicit membership is still called out. ✎ **2026-08-02 (Wave 2 truth audit): the criterion still holds at `3be5f056e`, where the live figure is 68** — row 53's `ironclaw_extension_manager` is built, so four of §9's five "new" rows are now real crates and only `sandbox` is still a target. ✎ **2026-08-01 (Wave 1 truth audit): the criterion still holds at `a50ad0638`, where the live figure is 67, not 66** — §9's rows 4–6 are the three Wave 1 contracts crates, entered at authoring time as **new** and now built, and the two WS0 deletions are `ironclaw_dispatcher` and `ironclaw_embeddings`. The 66/64 figures on this line and in §9's header are that table's 2026-07-30 measurement and are deliberately not re-derived here; §2.1 carries the current count and its arithmetic.)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
cd docs
mint dev
mint broken-links

Repository: nearai/ironclaw

Length of output: 195


🏁 Script executed:

#!/bin/bash
set -euo pipefail
cd docs
mint dev
mint broken-links

Repository: nearai/ironclaw

Length of output: 195


🏁 Script executed:

#!/bin/bash
set -euo pipefail
cd docs
mint dev
mint broken-links

Repository: nearai/ironclaw

Length of output: 195


🏁 Script executed:

#!/bin/bash
set -euo pipefail
cd docs
mint dev
mint broken-links

Repository: nearai/ironclaw

Length of output: 195


🏁 Script executed:

#!/bin/bash
set -euo pipefail
cd docs
mint dev
mint broken-links

Repository: nearai/ironclaw

Length of output: 195


🏁 Script executed:

#!/bin/bash
set -euo pipefail
cd docs
mint dev
mint broken-links

Repository: nearai/ironclaw

Length of output: 195


🏁 Script executed:

#!/bin/bash
set -euo pipefail
cd docs
mint dev
mint broken-links

Repository: nearai/ironclaw

Length of output: 195


🏁 Script executed:

#!/bin/bash
set -euo pipefail
cd docs
mint dev
mint broken-links

Repository: nearai/ironclaw

Length of output: 195


🏁 Script executed:

#!/bin/bash
set -euo pipefail
cd docs
mint dev
mint broken-links

Repository: nearai/ironclaw

Length of output: 195


🏁 Script executed:

#!/bin/bash
set -euo pipefail
cd docs
mint dev
mint broken-links

Repository: nearai/ironclaw

Length of output: 195


Run mint dev and mint broken-links from docs/.

This Markdown change is under docs/**/*, so the repo check for documented enforcement requires both results before merge. Include both completed checks here or note any missing mint dependency.

🤖 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 `@docs/reborn/target-architecture/PROPOSAL.md` at line 1098, Run mint dev and
mint broken-links from the docs directory, then record both completed checks in
the documentation change; if mint is unavailable, explicitly note the missing
dependency instead.

Source: Coding guidelines


> ✎ **Landed marker — Wave 2's port-inversion half is on `main` (2026-08-02, audited at `3be5f056e`).** Four PRs: **#6998** (WS2.1, `extension_host`'s product-facing ports inverted onto `product_contracts`), **#7002** (WS5, `webui` + `openai_compat`), **#7018** (the consolidated stack: WS2.2's `ProductSurfaceFailure` linchpin, WS2.4's `ironclaw_extension_manager` split, WS5's operator inversion and the conversations/threads naming trap + attachments widening), plus **#6996** (the WS0 path-keyed-gate closeout, #6963). **`ironclaw_extension_manager` now exists**, so the `NEW` tag on it in the map below — like the three contracts crates' — describes the target rather than a gap; four of the five planned new crates are built and only `sandbox` remains. Workspace packages: **68** (PROPOSAL §2.1); the steady-state target of 64 is unchanged.
>
> **Three program-level facts came out of the wave and are recorded rather than smoothed over.** (1) **`ironclaw_operator`'s product dependency is gone from the manifest — the first of §8.2's three named product edges to actually close**, with a residue of zero, which no earlier inversion achieved. (2) The other four edges (`extension_host`, `extension_manager`, `webui`, `openai_compat` → `product`) **survive by construction, not by shortfall**: a route handler must name product's frozen command/view/capability *constants* to call the surface, and §6.1.3 deliberately withholds those from contracts — so those flips need an owner decision, not more work (CHECKLIST WS5's `webui` row). (3) **Wave 2 moved the `LAYER_MATRIX_EXCEPTIONS` count by zero and could not have moved it at all** — every edge it removed is `products → products`, a class the layer matrix is structurally blind to, which is why each removal needed its own purpose-built shrink-only gate (PROPOSAL §8.1 reading rule 1 and §11.1, both amended). **Read exception count as a Wave 3 metric, not a Wave 2 one.**

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Separate the four surviving product-edge causes.

Line 11 attributes all four edges to route handlers naming frozen product constants. The audit records different blockers: concrete assembly in channel_host.rs for extension_host, DTO/capability and port residue for extension_manager, and frozen constants for WebUI/OpenAI compatibility. Rewrite this paragraph with the per-crate causes and owner decisions.

As per coding guidelines, documentation claims must match the recorded architecture evidence.

🤖 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 `@docs/reborn/target-architecture/README.md` at line 11, Rewrite the paragraph
beginning “Three program-level facts” to distinguish the recorded causes for
each surviving product edge: concrete assembly in channel_host.rs for
extension_host, DTO/capability and port residue for extension_manager, and
frozen product constants for webui and openai_compat. Preserve the
ironclaw_operator removal and Wave 2 exception-count statements, and state the
corresponding owner decisions without attributing all four edges to route
handlers.

Source: Coding guidelines

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Coverage ratchet

Ratchet mode: ENFORCING

RATCHET PASS: global
  observed: 86.17% (328043 / 380706 lines)
  floor:    85.11% (tolerance 0.5pp -> effective floor 84.61%)
  denominator: 380706 lines now vs 375097 at floor capture (+5609 lines, +1.5%) — not a material change

RATCHET PASS: ironclaw_runner
  observed: 85.93% (14917 / 17359 lines)
  floor:    85.55% (tolerance 0.5pp -> effective floor 85.05%)
  floor_covered_lines: 14658 (tolerance 20 lines -> effective floor 14638)
  denominator: 17359 lines now vs 17133 at floor capture (+226 lines, +1.32%) — not a material change

RATCHET PASS: ironclaw_processes
  observed: 88.76% (5889 / 6635 lines)
  floor:    88.07% (tolerance 0.5pp -> effective floor 87.57%)
  floor_covered_lines: 5839 (tolerance 20 lines -> effective floor 5819)
  denominator: 6635 lines now vs 6630 at floor capture (+5 lines, +0.08%) — not a material change

RATCHET PASS: ironclaw_turns
  observed: 88.46% (3709 / 4193 lines)
  floor:    85.11% (tolerance 0.5pp -> effective floor 84.61%)

RATCHET PASS: ironclaw_authorization
  observed: 86.59% (723 / 835 lines)
  floor:    62.51% (tolerance 0.5pp -> effective floor 62.01%)
  floor_covered_lines: 612 (tolerance 20 lines -> effective floor 592)
  denominator: 835 lines now vs 979 at floor capture (-144 lines, -14.71%) — material change (>5%)

RATCHET PASS: ironclaw_approvals
  observed: 91.05% (1820 / 1999 lines)
  floor:    85.86% (tolerance 0.5pp -> effective floor 85.36%)
  floor_covered_lines: 1822 (tolerance 20 lines -> effective floor 1802)
  denominator: 1999 lines now vs 2122 at floor capture (-123 lines, -5.8%) — material change (>5%)

RATCHET PASS: ironclaw_secrets
  observed: 85.81% (2896 / 3375 lines)
  floor:    84.01% (tolerance 0.5pp -> effective floor 83.51%)
  floor_covered_lines: 2795 (tolerance 20 lines -> effective floor 2775)
  denominator: 3375 lines now vs 3327 at floor capture (+48 lines, +1.44%) — not a material change

RATCHET PASS: ironclaw_filesystem
  observed: 77.09% (5915 / 7673 lines)
  floor:    75.93% (tolerance 0.5pp -> effective floor 75.43%)
  floor_covered_lines: 5826 (tolerance 20 lines -> effective floor 5806)
  denominator: 7673 lines now vs 7673 at floor capture (+0 lines, +0%) — not a material change

RATCHET PASS: ironclaw_llm
  observed: 79.22% (20885 / 26364 lines)
  floor:    79.22% (tolerance 0.5pp -> effective floor 78.72%)
  floor_covered_lines: 20885 (tolerance 20 lines -> effective floor 20865)
  denominator: 26364 lines now vs 26364 at floor capture (+0 lines, +0%) — not a material change

RATCHET PASS: ironclaw_triggers
  observed: 94.68% (3134 / 3310 lines)
  floor:    86.04% (tolerance 0.5pp -> effective floor 85.54%)
  floor_covered_lines: 2804 (tolerance 20 lines -> effective floor 2784)
  denominator: 3310 lines now vs 3259 at floor capture (+51 lines, +1.56%) — not a material change

RATCHET PASS: ironclaw_product
  observed: 87.97% (22219 / 25258 lines)
  floor:    86.94% (tolerance 0.5pp -> effective floor 86.44%)
  floor_covered_lines: 21367 (tolerance 20 lines -> effective floor 21347)
  denominator: 25258 lines now vs 24576 at floor capture (+682 lines, +2.78%) — not a material change

RATCHET PASS: ironclaw_outbound
  observed: 94.68% (4271 / 4511 lines)
  floor:    93.49% (tolerance 0.5pp -> effective floor 92.99%)
  floor_covered_lines: 4105 (tolerance 20 lines -> effective floor 4085)
  denominator: 4511 lines now vs 4391 at floor capture (+120 lines, +2.73%) — not a material change

RATCHET PASS: ironclaw_extension_host
  observed: 85.82% (20590 / 23991 lines)
  floor:    84.83% (tolerance 0.5pp -> effective floor 84.33%)
  floor_covered_lines: 19907 (tolerance 20 lines -> effective floor 19887)
  denominator: 23991 lines now vs 23467 at floor capture (+524 lines, +2.23%) — not a material change

RATCHET PASS: ironclaw_extension_manager
  observed: 88.93% (6027 / 6777 lines)
  floor:    84.6% (tolerance 0.5pp -> effective floor 84.1%)
  floor_covered_lines: 4602 (tolerance 20 lines -> effective floor 4582)
  denominator: 6777 lines now vs 5440 at floor capture (+1337 lines, +24.58%) — material change (>5%)

RATCHET PASS: ironclaw_events
  observed: 80.55% (1197 / 1486 lines)
  floor:    80.55% (tolerance 0.5pp -> effective floor 80.05%)
  floor_covered_lines: 1197 (tolerance 20 lines -> effective floor 1177)
  denominator: 1486 lines now vs 1486 at floor capture (+0 lines, +0%) — not a material change

RATCHET PASS: ironclaw_safety
  observed: 92.75% (4468 / 4817 lines)
  floor:    92.44% (tolerance 0.5pp -> effective floor 91.94%)
  floor_covered_lines: 3973 (tolerance 20 lines -> effective floor 3953)
  denominator: 4817 lines now vs 4298 at floor capture (+519 lines, +12.08%) — material change (>5%)

RATCHET PASS: ironclaw_host_runtime
  observed: 88.41% (21338 / 24135 lines)
  floor:    88.23% (tolerance 0.5pp -> effective floor 87.73%)
  floor_covered_lines: 20538 (tolerance 20 lines -> effective floor 20518)
  denominator: 24135 lines now vs 23277 at floor capture (+858 lines, +3.69%) — not a material change

Reborn integration-tier coverage

Line coverage (Reborn crates): 86.17% — 328043 / 380706 lines

Per-crate breakdown (64 crates, lowest-covered first)
Crate Line % Covered / Total
ironclaw_host_ingress 42.5% 17 / 40
ironclaw_memory 53.48% 630 / 1178
ironclaw_projects 72.36% 233 / 322
ironclaw_capabilities 74.59% 2876 / 3856
ironclaw_trust 75.79% 748 / 987
ironclaw_extractors 75.88% 538 / 709
ironclaw_reborn_cli 76.1% 11084 / 14566
ironclaw_observability 76.19% 32 / 42
ironclaw_filesystem 77.09% 5915 / 7673
ironclaw_wasm 78.84% 704 / 893
ironclaw_llm 79.22% 20885 / 26364
ironclaw_events 80.55% 1197 / 1486
ironclaw_loop_contracts 82.4% 5637 / 6841
ironclaw_first_party_extensions 82.57% 6784 / 8216
ironclaw_memory_native 82.85% 2850 / 3440
ironclaw_libsql_runtime 83.3% 384 / 461
ironclaw_auth 83.95% 6699 / 7980
ironclaw_operator 84.54% 5303 / 6273
ironclaw_hooks 84.57% 9896 / 11702
ironclaw_event_projections 84.81% 854 / 1007
ironclaw_reborn_event_store 84.93% 1206 / 1420
ironclaw_reborn_config 85.29% 2110 / 2474
ironclaw_network 85.31% 894 / 1048
ironclaw_product_contracts 85.59% 4111 / 4803
ironclaw_secrets 85.81% 2896 / 3375
ironclaw_extension_contracts 85.81% 2558 / 2981
ironclaw_reborn_composition 85.82% 22051 / 25695
ironclaw_extension_host 85.82% 20590 / 23991
ironclaw_runner 85.93% 14917 / 17359
ironclaw_host_api 86.05% 6367 / 7399
ironclaw_authorization 86.59% 723 / 835
ironclaw_webui 86.95% 11937 / 13729
ironclaw_wasm_limiter 87.06% 74 / 85
ironclaw_common 87.07% 1152 / 1323
ironclaw_reborn_traces 87.61% 11720 / 13377
ironclaw_scripts 87.87% 420 / 478
ironclaw_product 87.97% 22219 / 25258
ironclaw_threads 88.14% 5189 / 5887
ironclaw_host_runtime 88.41% 21338 / 24135
ironclaw_turns 88.46% 3709 / 4193
ironclaw_telegram_extension 88.55% 588 / 664
ironclaw_skills 88.58% 2784 / 3143
ironclaw_process_sandbox 88.64% 281 / 317
ironclaw_processes 88.76% 5889 / 6635
ironclaw_extension_manager 88.93% 6027 / 6777
ironclaw_reborn_openai_compat 89.4% 3644 / 4076
ironclaw_telegram_v2_adapter 89.47% 1580 / 1766
ironclaw_extensions 89.55% 6249 / 6978
ironclaw_loop_host 90.47% 18043 / 19944
ironclaw_resources 90.76% 4084 / 4500
ironclaw_approvals 91.05% 1820 / 1999
ironclaw_reborn_identity 91.3% 451 / 494
ironclaw_mcp 92% 1426 / 1550
ironclaw_event_streams 92.5% 1048 / 1133
ironclaw_safety 92.75% 4468 / 4817
ironclaw_conversations 93.22% 2503 / 2685
ironclaw_agent_loop 93.52% 10430 / 11153
ironclaw_slack_extension 93.95% 3697 / 3935
ironclaw_first_party_extension_ports 94.66% 3758 / 3970
ironclaw_outbound 94.68% 4271 / 4511
ironclaw_triggers 94.68% 3134 / 3310
ironclaw_prompt_envelope 97.46% 192 / 197
ironclaw_runtime_policy 97.6% 855 / 876
ironclaw_attachments 98.49% 1374 / 1395

This table itself is informational and never gates the PR on its own — not the percentage, not the per-crate holes, not the 0-coverage callout. A separate coverage ratchet (dry-run until enforce=true; see tests/integration/coverage-floor.toml) can fail the build on specific configured floors.

Exemptions (18 entry/entries excluded from the accounting above)
Module / Crate Reason Issue
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_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
crates/ironclaw_attachments/src/lib.rs Declarative crate facade: module declarations, constants, and re-exports only; executable attachment modules remain covered. #6524
crates/ironclaw_extension_host/src/ingress/mod.rs Declarative ingress module facade and documentation only; executable router modules remain covered. #6524
crates/ironclaw_host_api/src/lib.rs Declarative crate facade: module declarations and re-exports only; executable host API modules remain covered. #6524
crates/ironclaw_host_api/src/product_adapter/mod.rs Declarative product-adapter facade: module declarations and re-exports only; executable adapter modules remain covered. #6524
crates/ironclaw_llm/src/rig_adapter/tests/finish_reason_tests.rs Test-only module stored under src/ for private adapter access; cargo-llvm-cov omits test harness source from production LCOV while the exercised rig_adapter.rs production lines remain coverage-gated. #6284
crates/ironclaw_loop_contracts/src/lib.rs Declaration-only public facade with no executable Rust statements; rustc emits no LCOV source record. Executable loop-contract behavior remains covered in the owned implementation modules. #6524
crates/ironclaw_outbound/src/error.rs Declarative error vocabulary only; variants have no LLVM-instrumentable production statements. #6524
crates/ironclaw_outbound/src/lib.rs Declarative crate facade: module declarations and re-exports only; executable outbound modules remain covered. #6524
crates/ironclaw_product/src/lib.rs Declaration-only public facade with no executable Rust statements; rustc emits no LCOV source record. Executable product behavior remains covered in the owned implementation modules. #6524
crates/ironclaw_product/src/lib.rs Declarative crate facade: module declarations and re-exports only; executable product modules remain covered. #6524
crates/ironclaw_product/src/scoped_fs/mod.rs Declarative scoped-filesystem facade and documentation only; executable scoped filesystem modules remain covered. #6524
crates/ironclaw_reborn_composition/src/support/fs/mod.rs Declarative composition support facade: module declarations and re-exports only; executable filesystem adapters remain covered. #6524
crates/ironclaw_slack_extension/src/lib.rs Declarative Slack crate facade: module declarations and re-exports only; executable Slack modules remain covered. #6524
crates/ironclaw_telegram_extension/src/lib.rs Declarative Telegram crate facade: module declarations and re-exports only; executable Telegram modules remain covered. #6524
crates/ironclaw_threads/src/lib.rs Declaration-only public facade with no executable Rust statements; rustc emits no LCOV source record. Executable thread behavior remains covered in the owned implementation modules. #6524
crates/ironclaw_webui/src/webui_v2/mod.rs Declaration-only WebUI v2 facade with no executable Rust statements; rustc emits no LCOV source record. Executable route behavior remains covered in the owned implementation modules. #6524

@BenKurrek
BenKurrek enabled auto-merge August 3, 2026 12:40
@BenKurrek
BenKurrek added this pull request to the merge queue Aug 3, 2026
Merged via the queue into main with commit 9ad5709 Aug 3, 2026
68 checks passed
@BenKurrek
BenKurrek deleted the docs/wave2-truth-audit branch August 3, 2026 13:02
BenKurrek added a commit that referenced this pull request Aug 3, 2026
Reconciles the Wave 2 decision-log entries with #7037 (package
colocation) and #7032 (docs audit). Both sides' additions are unioned:
every dated amendment from the audit and every decision entry survives.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
BenKurrek added a commit that referenced this pull request Aug 3, 2026
Reconciles the WS2 strays/follow-ups with #7037 (package colocation) and
#7032 (docs audit). No file this branch touches was moved by the
colocation, so the only conflicts were the two decision-record docs;
both sides' rows are unioned.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
l3ocifer pushed a commit to l3ocifer/frick-ironclaw that referenced this pull request Sep 3, 2026
…ve-2 main (nearai#7032)

Audits docs/reborn/target-architecture/ (plus crates/AGENTS.md and the
crate guides Wave 2 touched) against merged main at 3be5f05, after
nearai#6996, nearai#6998, nearai#7002 and nearai#7018.

Docs-only: 13 .md files, no code, no tests. House style throughout —
dated amendments, prior text quoted verbatim wherever a clause is
corrected, nothing rewritten silently and no decision record deleted.

The two structural findings the wave produced and nobody had written
down: same-layer edges are invisible to the layer matrix by
construction, so the exception count could never have moved in Wave 2
and each removal needed its own purpose-built shrink-only gate
(PROPOSAL §8.1, §8.2, §11.1); and the changed-line coverage policy —
90% lines, branch coverage ungated since nearai#7013 — was recorded in no
document at all, alongside a stranded-exemption failure mode the new
pre-existing-uncovered exclusion creates (CHECKLIST WS10).

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

This branch was successfully deployed

No deployments
ironclaw-ci-preview / ironclaw-pr-7032 — 3a8a2208 Deployed Aug 3, 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: low Changes to docs, tests, or low-risk modules scope: docs Documentation size: XS < 10 changed lines (excluding docs)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants