Skip to content

docs(reborn): target crate architecture — the north star (overview, family specs, checklist, plan, explorer) - #6918

Merged
BenKurrek merged 40 commits into
mainfrom
proposal/target-crate-architecture
Jul 30, 2026
Merged

BenKurrek merged 40 commits into
mainfrom
proposal/target-crate-architecture

Conversation

@BenKurrek

@BenKurrek BenKurrek commented Jul 30, 2026 •

Copy link
Copy Markdown
Collaborator

What this is

The north star for the Reborn architecture cleanup: a concrete crate/folder map with explicit security and authority boundaries, so agents and humans can answer "where does this go?" without archaeology — and so the refactor train has a fixed destination instead of a direction.

Docs-only. Everything lives under docs/reborn/target-architecture/:

File Role
README.md Executive overview — start here (family map, why-ten, reviewer decisions)
PROPOSAL.md Full evidence-backed spec: target tree, §5.1 naming rule, per-crate contracts, dependency matrix, 74-row current→target mapping, risks & open decisions
families/ One forward-looking spec per family: boundaries, belongs/never, per-crate contracts, AGENTS.md requirements
CHECKLIST.md Definition of done (WS0–WS12) — every box checked = target reached
PLAN.md Execution waves, gates, load-bearing ordering constraints
explorer.html Interactive map — self-contained, opens offline; per-crate panels with interface sketches + load-bearing type inventories (rendered preview)

The shape

Ten families over the existing (CI-enforced) 7-layer ladder — contracts/ substrates/ events/ domains/ kernel/ lanes/ loop/ extensions/ product/ app/ — with three new contracts crates, four god-crate narrowings, a verified dead-code deletion list, and per-extension package colocation. All 20 standing LAYER_MATRIX_EXCEPTIONS eliminated structurally; 66 → 63 workspace packages; ≈25k dead LOC deleted, ≈95k+ re-homed (both measured, not estimated).

Decisions already taken on this branch (each recorded in PROPOSAL §12.10 with rationale)

  • Renames: events→event_log, extensions→extension_registry, product→assistant (family/crate stutters); architecture→architecture_tests, first_party_extensions→extension_support, runner→turn_runner, reborn_traces→trace_commons (naming audit); the full reborn_ batch upgraded to decided. Reborn* type names retire with their crate renames (RebornServices→AssistantServices, RebornHostBindings→HostBindings, …).
  • Memory providers are extension packages (extensions/packages/memory-native/, mem0/) declaring [memory] manifest surfaces; the provider-neutral contract stays in domains/.
  • §5.1 naming rule written down and mechanically assertable (subject names, no family prefixes, role-class suffixes, dir==package-name, non-crate-dir convention).
  • Consolidation audit executed (three adversarial passes, ~45 forced merge attacks): one clear merge decided — projects → identity (module) — everything gray kept per owner rule; the prompt_envelope⊕safety question closed (keep separate; denylist unifies via safety→prompt_envelope); two prose-held splits get convert-to-mechanical enforcement tests; the sandbox merge gains its two load-bearing details.

How to review

  1. Skim README, then PROPOSAL §1–§5 (argument) and §8.3 (exception-elimination proof).
  2. Deep-dive your family via families/ — each is a pure forward-looking spec.
  3. Challenge CHECKLIST.md — it is the definition of done; anything missing goes there.
  4. Argue sequencing in PLAN.md — only the ⚠ ordering constraints are load-bearing.

Status & relationships

🤖 Generated with Claude Code

BenKurrek and others added 30 commits July 29, 2026 13:21
Executive overview, full evidence-backed proposal (validated against
dde662d), completion checklist (WS0-WS12), execution plan (waves 0-6),
and per-family deep dives (7 of 10; lanes/extensions/app follow).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
All ten family files now present; 65 crate/subsection specs total.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The compact hybrid (box-drawing connectors on family rows, floating
crate rows in the gutter, ragged description columns) rendered badly;
one crate per line with real connectors and aligned annotations.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The family files now describe the architecture as designed — present
tense, no line counts, no file:line citations, no dispositions or
migration deltas, no current-vs-target tables. Everything about the
present codebase and the path from it stays in PROPOSAL/CHECKLIST/PLAN,
which each family file points to once.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The map lists only the ten families; crate rosters live in each
family's spec, now linked (with crate counts) from the roles table.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
One short paragraph per family (linked, crate count): what it is, what
it owns, what it must never contain — instead of a four-column grid of
fragment lists.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Each families/*.md now opens with its directory tree (crates plus
one-line roles) before the prose — visualize first, read second.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The ten-families section is high-level: name, what it is, its rule —
crate rosters belong to the family specs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
'The one-paragraph decision' was a compressed insider changelog. The
opening now explains the proposal in plain language: the problem, the
ten-family/one-direction idea, what actually changes (mostly moves),
and that the security model is untouched. 'Why this shape' de-jargoned.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds 'Three that sound alike': what the system knows / what the agent
decides / how an approved action runs, plus the one-request flow line.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Full target tree with one-line roles per crate; packages/ abbreviated
to its shape (first_party, slack, telegram, …) rather than the roster.

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

Family map: crate names without the ironclaw_ prefix, blank gutter rows
between families. Extensions layout amended (marked in PROPOSAL): every
package gets its own packages/<ext>/ directory uniformly; the shared
inventory/executors crate moves beside the host as extensions/first_party
— it is support code serving many packages, not a package itself.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e extension packages

Owner review 2026-07-29, three decisions:
- Rename ironclaw_events -> ironclaw_event_log, ironclaw_extensions ->
  ironclaw_extension_registry, ironclaw_product -> ironclaw_assistant:
  the family directories made each old name collapse into a
  family/family stutter (events/events, extensions/extensions,
  product/product), and each new name states what the crate is.
- Both memory providers move out of domains/ and ship as extension
  packages at the same level: extensions/packages/memory-native/ and
  extensions/packages/mem0/, each declaring a [memory] manifest
  surface, linked only by the binary; native installed by default.
  ironclaw_memory (contract + conformance suite) stays in domains/.
- Package-to-crate rule gains the provider-surface clause.

Applied across README map, family specs (domains/extensions/product/
events + cross-refs), PROPOSAL (tree, crate entries, dependency model,
mapping rows 12/19-21/51/59, decided-renames note) and CHECKLIST
(WS2 provider-package item, decided-renames item).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Six parallel audit agents (naming, seams/boundaries, checklist/plan
completeness, sponsor-vision alignment, register purity, rendering)
reviewed the whole package; this applies every confirmed finding.

Blockers fixed:
- substrate access rule was over-generalized from lanes to four
  families, contradicting six charter-sanctioned dep lists; now
  lane-scoped with charter-governed access for everyone else
- composition no longer described as seeing provider implementations;
  the binary links memory providers, composition receives the handle
- runner no longer claims loop-exit validation; the turn kernel owns
  it and the runner submits claims
- CHECKLIST gains the enforcement re-point that the memory-provider
  move requires (mem0-naming arch test, memory-mem0 cargo feature,
  allowlists, binary-only linkage list)

Also: rename propagation completed through PROPOSAL SS6-SS10 prose and
both mermaid diagrams; PLAN updated for the decided renames + memory
move with exception arithmetic corrected; README security sentence
de-overclaimed, ladder-vs-families rule stated precisely, splits
enumerated, PR #6253 supersession noted, and a new 'Why ten families'
section naming the two debatable groupings; family specs get uniform
verified-inbound vocabulary, corrected dep lists (hooks+wasm_limiter,
loop_host+turns, triggers+filesystem, event_store+common), sealed-mint
mechanism stated coherently, and complete AGENTS.md requirement
sections; prompt_envelope fork resolved (dropped); gate-prompt port
committed to host_api; first_party gets its own SS8.2 matrix row.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Single self-contained HTML (no CDN, no network, theme-aware, opens
offline) following the PR #6253 explorer pattern: clickable family
map with per-crate inspector, and a dependency-graph view — 222
target-state edges compiled from the family specs, per-crate fan-in/
fan-out, review lenses (load-bearing, wide-reach, thin/pass-through
candidates, dependency inversions, all edges).

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

One surface for the whole ladder instead of ten stacked cards; family
name + role in a readable left column; crates as compact fixed-width
tags that never stretch; per-crate blurbs move to hover/inspector;
kernel row highlighted as the perimeter with its stages in pipeline
order; contracts rails and bindings strip removed (the dependency
graph below tells that story better).

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

'in flight' on nearly every crate read as work-in-progress; the dots
actually encode how much a crate changes between today's tree and the
target. Relabel: already in shape / reshaped by the proposal / new
crate — wave and demolition pills keep execution language (landed /
in flight / not started) via a separate label map.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Answers 'where does gsuite / notion go': every bundled extension gets
its own packages/<ext>/ directory uniformly — four crate-bearing
(slack, telegram, memory-native, mem0) and the data-only directories
github, gmail, google-* (one per extension, shared google credential
authority), web-access, notion-mcp, nearai-mcp — with the rule for
where each one's code executes (declared lane; native executors as
first_party modules).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Clicking a crate now opens a full-width modal instead of the cramped
sidebar: what-it-does prose, a doc-grounded interface sketch for every
crate, owns as a bulleted list, clickable depends-on / used-by chips
wired from the dependency data, and changes-when / security-role /
why-its-own-crate. Adds the six data-only packages (github, gmail,
google-*, web-access, notion-mcp, nearai-mcp) as clickable entries in
the extensions row so 'where does X go' has an in-map answer.

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

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The interface sketch's pre whitespace + grid min-width:auto blew the
right column open and crushed the owns list to one word per line.
Sections now stack full-width (about, sketch + key types, owns as a
two-column list, deps/used-by, footer); sketches pre-wrap inside a
bounded box; grid children get min-width:0; comment alignment runs
normalized.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Remove the migration-status layer from the map and crate panels (no
disposition strips, no PR numbers, no dots/legend); kernel row loses
its special highlight and pipeline arrows — uniform family rows; the
standalone dependency-graph section is removed (each crate's panel
keeps its depends-on / used-by chips).

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

~55 fixes across the 68 entries and 10 family lines, all audit-verified
against the family specs (and sig names against live code):
- boundary clarity: one-sentence differentiators wherever two entries
  shared a noun without stating the layering (assistant/conversations
  binding+dedup, llm/operator key custody, turns/assistant idempotency,
  extension egress path, pairing chain, lease minting, identity minting)
- accuracy: first_party no longer claims per-package assets; the
  domains family line stops saying 'no authority' beside three narrow
  authorities; conversations consumes rather than seals the trusted
  binding; four invented sig type names replaced with the real ones
  (build_runtime, openai_compat_routes, NativeMemoryService,
  Mem0MemoryService); common's wire-compat exception re-pinned to the
  identity newtypes
- readability: cryptic owns fragments expanded ('the tick', 'the
  caps', 'ratchets'), semicolon-shattered parentheticals rewritten,
  redundant notes replaced with facts that add something

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

Naming rule written down as PROPOSAL SS5.1 (head-final subject names,
global ironclaw_ prefix, role-class suffixes, provider idiom, host-*
moratorium, dir==package-name + non-crate-dir conventions, family-dir
number rule) with SS11.2.11 assertions and CHECKLIST/AGENTS items.

Renames decided 2026-07-30 (naming audit), applied across README,
family specs, PROPOSAL tree/entries/rows, CHECKLIST, PLAN, explorer:
- ironclaw_architecture -> ironclaw_architecture_tests (tests-only
  crate says so; zero importers)
- ironclaw_reborn_traces target -> ironclaw_trace_commons (the crate
  is the Trace Commons client; unresolvable beside observability)
- ironclaw_first_party_extensions -> ironclaw_extension_support at
  extensions/ironclaw_extension_support/ (old name named a set its
  sibling packages belong to; completes the extension_* line)
- ironclaw_runner -> ironclaw_turn_runner (turns-admits/runner-
  executes split legible from the crate list)
- reborn_ batch upgraded severable -> decided (+ root package
  ironclaw_integration_tests); substrate/ -> substrates/
- wit/ moves inside crates/lanes/ironclaw_wasm/

Plus the migration-mechanics findings as WS10 items: five path-keyed
gates that fail silently under family dirs (coverage merge, panic
scanner, e2e filters, scope classifier, metrics globs) rewritten
before the first git mv, and the loud path-pattern inventory.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… one roadmap strip

The two document-length sections duplicated PLAN.md and the deletion
inventory. One quiet strip now carries the feasibility signal: the
headline numbers (20->0 exceptions, 66->64 crates, ~18k deleted /
~21k relocated), the seven waves in one line, and links to PLAN.md
and CHECKLIST.md for the real sequencing and definition of done.

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

Ten 'packages/' prefixes collapse into one group label; package tags
use short extension ids; data-only packages draw dashed vs the
crate-bearing four; the family row now mirrors the family's actual
two-level shape. Also fixes the stale first_party mention in the
extensions role line.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Drop the dashed group container, floating label, and hint text; the
packages line is now a plain second row led by a faint 'packages/'
tree glyph, tags uniform (crate-vs-data-only stays in the panel).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…pe, not total

'≈21k relocated' was the demolition ledger's whole-unit moves only
(telegram_v2 + sandbox trio + first_party_tools + ports crate); as a
restructure total it undercounted ~3-4x by omitting the god-crate
narrowings. Recomputed from PROPOSAL §2's own figures: ≈75k+ re-homed
(extension_host ~24k, composition ~20-54k, turns run_profile 13.9k,
host_api ~9.8k, runner ~10k, host_runtime ~10k, whole-unit ~13k);
deletions restated ≈19k itemized.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
wc -l against the live tree at baseline: named dead surface sums to
25,382 LOC (dispatcher 1.2k, embeddings 1.8k, llm::reasoning 4.7k,
dead skills 4.0k, run_state 3.2k, runner subagent 7.7k + scheduler
1.0k + production_readiness 0.8k, loopback/trust_boundary/fuzz);
named relocation paths sum to 71,004 LOC measured (run_profile 14.3k,
host_api product vocab 10.6k, first_party_tools 10.4k, sandbox trio
9.0k, runner sheds 7.0k, composition local_dev 11.7k, telegram_v2
2.6k, ports crate 5.4k) — plus the audit-stated ~24k extension_host
product wiring and ~10k further named composition behavior => ≈95k+.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ly packages get manifest sketches

Self-contained tokenizer (keywords, types, strings, TOML section
headers, comments — string-aware so URLs survive) colors every
interface sketch from the page palette. The six data-only packages
now carry their real interface: manifest.toml sketches grounded in
the shipped reborn.extension_manifest.v3 files (github's wasm+tools
+credential injection, gmail/google-* shared auth authority, mcp
server blocks for notion/nearai, web-access first_party runtime).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
rdisandro added a commit that referenced this pull request Aug 5, 2026
…n phasing

Add a #6918-style proposal package under docs/design/oobe/ (README / PROPOSAL /
PLAN / CHECKLIST) for phasing the OOBE prototype into production:

- Foundational (near-term, ships on current main) then Vision (north-star),
  matching the mockup's two versions; every Vision piece a superset of a
  Foundational one, so nothing is redone.
- Scopes Foundational as shipped-vs-net-new: the connect CTA, busy states,
  agent-mode semantics, and manage-result surface all REUSE code on main
  (extension-auth path, NearProcessIndicator, resolve_gate/global_auto_approve,
  pages/automations); the net-new surface is the card family, the
  AutomationTask events+projection+routes+facade, and the first-run suggestion
  producer.
- Inventories dependencies D-F1..F6 (Foundational) and D-V1..V5 (Vision), each
  with an implementation approach, and maps the work onto the five-layer WebUI
  flow and the #6918 target families.
- Applies the APDD governance kit (docs-first workflow, Feedback & Decisions
  anchor, Critical Bug Fix Log, design track, CUJ baseline).

Companion human-review artifact (schematics/diagrams):
https://claude.ai/code/artifact/734b1b6a-e35d-4736-9ac2-952dcdf84ab4

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
rdisandro added a commit that referenced this pull request Aug 5, 2026
Brings the branch up to date with main (64 commits), including the #6918
family-folder reorg. Resolution is relocation-only (behavior-free): main
renamed crates/ironclaw_webui/ -> crates/product/ironclaw_webui/, so the
prototype's net-new files (automation cards, action bar, mode selector, data
seam, design-preview harness, AUTOMATION-TASKS-CONTRACT.md) move to the new
path alongside main's rename; modified files (empty-state, chat-input, app,
en.ts, design-system) auto-merged onto the new path with the branch's edits
preserved. Doc/name reconciliation follows in a separate commit.
rdisandro added a commit that referenced this pull request Aug 5, 2026
… names

The #6918 family-folder reorg has landed on main; update the proposal package
and the wiring contract to current crate names/paths and fix a stale claim:

- crates now under crates/{contracts,events,domains,product,app}/; renames
  ironclaw_events -> ironclaw_event_log, add ironclaw_event_store (both under
  events/), ironclaw_reborn_composition -> ironclaw_composition, and the webui
  frontend paths move to crates/product/ironclaw_webui/frontend/.
- correct the facade identity: it is RebornServicesApi in
  crates/product/ironclaw_assistant (NOT "ProductSurface" — that is the typed
  capability contract/DTOs in ironclaw_product_contracts).
- reframe "#6918 target families" as the family folders now on main.
- note the triggers-hosted suggester option (D-F2) can reuse the existing
  composition automation wiring (trigger_poller + trusted_submit).
- retire the removed .claude/rules/tool-evidence.md reference -> gateway-events
  / lifecycle; product adapters -> the ProductAdapter surface in ironclaw_host_api.
- mark the F0 merge-to-main + contract-reconciliation boxes done.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
BenKurrek added a commit that referenced this pull request Aug 6, 2026
… family laws

kernel.md: ironclaw_authorization's 'Security & authority role' bullet has been
textually corrupted since #6918 — an approvals sentence was spliced into it
mid-clause, orphaning its continuation line. Reconstructed, with the spliced
sentence restored to the approvals entry where it is true.

lanes.md: 'a lane never depends on a substrate' is false as a family-wide law
(ironclaw_sandbox holds network/safety/secrets normal deps, which its own entry
licenses); the accurate law is the layer ladder, and the narrow claim holds for
ironclaw_wasm alone.

lanes.md + events.md: the 'every crate ships both an AGENTS.md and a CLAUDE.md'
requirement is superseded by docs/reborn/guidance-conventions.md — two files
restating one rule is the drift the guidance program removes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ogarciarevett pushed a commit to ogarciarevett/ironclaw that referenced this pull request Aug 6, 2026
…2 100% gate (nearai#7263)

* docs(target-arch): resolve the await-edge design question by measurement (D-S) and re-walk the WS9 verify row

Appends §12.13 D-S under delegated authority at owner direction, flagged
for post-hoc review by Illia Polosukhin (nearai#6696's author): the await-edge
store is measured to be a pure projection over ProcessDependencyPort
(that half of the shed happened inside nearai#6696 itself), and the resolver
is a genuine loop-tier responsibility journal edges cannot express
(owner recovery, sanitized transcript result materialization, batch-gate
resume-once drain, BlockedDependentRunGate resume policy). §6.7.3 is
amended (scheduler DONE / store DONE / resolver KEEP) instead of the
shed being executed; the 2.9k figure is corrected to 1,459 production +
1,448 cfg(test) lines. The §12.10 bullet, §2 divergence flag, §9 row 49,
§13 validation row, CHECKLIST header/WS4 pointer, README and PLAN all
carry the dated resolution.

WS9 verify row ticked with evidence: one lifecycle authority (the
process journal; TurnRunState/TurnRunRecord are projections via
AgentTurnProcessRuntime, ProcessRecord is a capability-invocation view,
no bare RunRecord exists) and §7 T4 re-walked clause-by-clause against
merged code — matches, including the checkpoint-gated no-auto-retry
mechanism (BeforeModel precedes ModelStage; requeue only when
checkpoint-free under the 3-claim cap).

Docs-only; no code, no tests, no gates touched.

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

* docs(ws12): rows 1-2 — package-set tick (64==64/1/0, gate+selftest+independent rederivation) and the 74-row §9 mapping audit (45 L / 15 L-A / 14 OBD / 0 NOT-LANDED; 3 findings recorded)

Row 1: check-target-tree.py reports 64 workspace members == 64 documented
packages, 1 documented exclusion (tools/ironclaw_silk_decoder), 0 owned
exceptions (EXCEPTIONS table empty — §5 steady state); self-test 17/17;
cargo-metadata name set diffed empty against an independent §5 parse.

Row 2: docs/reborn/target-architecture/ws12-mapping-audit.md is the audit
record — per-row executed-evidence, delete-clauses read against WS8's
execution notes, all 14 open rows cite their owning CHECKLIST/PROPOSAL
row or issue. Findings (recorded, not fixed): F1 prompt_envelope
manifest-description fix has no owner row; F2 WS6:429's 'nearai#5618 residue
deleted' overstates vs the live adopt_migrated_identity + open WS8:523;
F3 stale-docs cluster where the tree is ahead of the prose (trace
re-export drop, TurnRunTransitionPort, processes->resources).

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

* fold(7154): squash-port fix/red-main-7119 onto family-world main — defect train nearai#7146/nearai#7115/nearai#7104/nearai#7103/nearai#7144 (+nearai#7119 CI lane), 34-hunk contribution.rs port into the split modules, planner entrypoint classification, D-R loopback exception on the widened HTTPS credential guard

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

* test(extractors): issue-number + assertion-rationale doc refinement (rescued 844964f from rescue/7154-parked-guard)

Ports only the doc/assertion refinement commit; the guard-parking commit
e8f5a31 on that branch is deliberately NOT taken — superseded by the
D-R loopback ruling.

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

* docs(target-arch): record D-R — the loopback credential-guard ruling, wiring choice, and regression pins (PROPOSAL §12.13, 2026-08-05)

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

* review(7154): CodeRabbit round-1 triage — fail-closed tracing-target scan traversal (+node_modules), bounded sidecar output draining (capped capture + discard drain), deadlock regression asserts successful redaction (no seq), XLSX/DOCX empty-classification via extract_document, raise_for_status annotations

Threads already addressed by the fold: latency.rs caller-contract wording
(merged doc scopes the requirement to latency-trace callers), BodyJsonPointer
coverage (the plaintext-refusal test drives all four injection shapes).
Deliberately not taken: un-xfailing the four Slack-catalog projections —
the xfail is a documented tripwire (unexpected-pass goes red) and clearing
them is the nearai#6520 projection-modeling follow-on its comment specs.

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

* fix(assistant): re-point the one field-form tracing target the nearai#7146 gate caught — main's relocated triggered_run_delivery_services carried the drift the PR fixed at its old channel_host address

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

* closure fixups: execute the mapping-audit findings — prompt_envelope manifest description (F1), dated ✎ corrections for the nearai#5618 overstatement (F2) and the stale-prose cluster (F3)

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

* docs(ws12): second-reviewer security spot-audit + extension-journey re-verification (rows 5-6)

Adversarial second-reviewer pass over PROPOSAL §12.1a/b/c and the batch's own
§12.13 D-R loopback carve-out, plus a re-run of the five extension journeys.
Attacks were executed rather than argued: two sabotage files and a 38-shape
hostile-URL probe were planted, run, and reverted.

Verdicts — mint consolidation HOLDS-WITH-RESIDUAL, secrets tightening
HOLDS-WITH-RESIDUAL, host/verifier colocation HOLDS, D-R HOLDS. No HOLE.

Four findings recorded rather than fixed (report-not-repair):
- F1 test_verified/_for_tenant are ungranted mint constructors gated only by
  the `test-support` feature, in no mint-name table, with nothing pinning the
  feature to [dev-dependencies]; the shipped binary is measured feature-free.
- F2 §12.1b's products-layer residue undercounts by one (ironclaw_assistant).
- F3 journey coverage hole: gsuite-with-credential-injection is proven in two
  halves that no committed test joins.
- F4 both recorded census evasions and both fail-open reads are CLOSED on this
  tree, so §11.2.5/§12.1a/CHECKLIST:552/:597 now understate the seal.

Rows 5-6 ticked; only lines 631-632 of CHECKLIST touched so the concurrent
rows 3-4 edit folds cleanly.

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

* ratchet(closure): lock the budget gate at the program's end state

Dispatch ceiling 1122 -> 814 (today's observed, nudge taken; WS0 record 827
stays within effective 829). Mass-share ceiling 2398 -> 658 bp (the WS0
baseline floor — the arch-test assert refuses lower, and observed 578 bp sits
inside the nudge window). Absolute LOC re-equalized at 40423: nearai#6831 added 4
governed LOC through the queue's tolerance window; ceiling, observed, and
COMPOSITION_ABSOLUTE_SRC_LOC move together here. Both tightenings
sabotage-verified red (dispatch 9-over at 790; abs 73-over at 40200).

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

* docs(ws12): gauntlet report — row 3 ticked (full gauntlet green, 0 REAL in scope), row 4 verified-but-open on two pre-existing Postgres-leg test-isolation defects

WS12 rows 3-4 verification on the assembled batch tip 0c6c0cf:

Row 3 (ticked): fmt, clippy default/all-features/--lib --bins, workspace
tests (495 targets, 15,203 passed, 0 failed; the smoke.rs:3132
CPU-saturation flake passed first try), arch suite 285/0, the
integration-feature lane 1,665/0, recorded-fixture QA (61 fixtures clean,
41/0), frontend (typecheck 1,588 files; vitest 1,088/0; build + bundle
budgets), e2e smoke = the CI browser lane under the hermetic wrapper
(50 + 21 + 5 passed), and all 41 scripts/ci self-tests (two mapfile/bash-3.2
casualties green under bash 5, the CI shape).

Row 4 (stays open, dated note added): both-backend parity proven with
legs demonstrably executed for the fabric (57 pg + 81 libsql), triggers
(ADR 0003, REQUIRE_POSTGRES), hooks (ADR 0004, all three backends),
composition, processes journal, extension-registry, host-runtime libSQL
restart, and the backend matrix; fabric-delegated domains enumerated.
Two REAL blockers (one class): the Postgres legs of the event-store and
assistant-ledger contract suites assert against shared-database state and
cannot pass as-written (each failing test passes alone on a virgin
database; files byte-identical to origin/main; no CI lane sets their env
vars). Full evidence: docs/reborn/target-architecture/ws12-gauntlet-report.md.

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

* fix(tests): per-test isolated Postgres databases for the two WS12 parity-blocking contract suites

The WS12 gauntlet (ws12-gauntlet-report.md §P6/§P8) measured the Postgres
legs of ironclaw_event_store's durable_event_store_contract and
ironclaw_assistant's durable_ledger_contract as test-isolation-defective:
absolute database-global asserts (event cursors; settled-entry prune
bookkeeping) run against the single external database named by their
IRONCLAW_*_POSTGRES_URL env vars. Every failing test passes alone on a
virgin database - store semantics correct, suites not self-isolating
(PROPOSAL §12.13 D-T).

Fix: each affected test provisions a private database on the configured
server - the fabric contract's IsolatedDatabase pattern
(db_root_filesystem_contract.rs) ported locally into each suite: CREATE
DATABASE per test, store/pool + migrations against it, courtesy
DROP ... WITH (FORCE), and a once-per-binary stale-name sweep. Every
assertion preserved byte-identical; libsql/jsonl twins untouched. In the
ledger suite only the two retention tests move - the other six Postgres
tests keep their proven fingerprint-suffix isolation.

Regression pins are the fixed tests themselves:
- postgres_replay_advances_next_cursor_past_trailing_filtered_records
- postgres_runtime_and_audit_logs_survive_rebuild_with_filtered_cursor_semantics
- postgres_settled_entry_limit_prunes_oldest_when_configured
- postgres_settled_prune_interval_defers_until_interval_when_configured
Green proven on a shared dirty database twice in a row (parallel default
threading) and serially on a virgin database; red-first reproduction
captured before the fix.

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

* docs(reborn): record §12.13 D-T (parity-suite isolation ruling) and close CHECKLIST WS12 row 4

D-T (after D-S): the WS12 gauntlet's two REAL findings were one defect
class — absolute database-global asserts against the single shared
env-var Postgres database — in two suites (event store cursor contract,
assistant settled-ledger retention). Ruling executed in commit 864d93e:
per-test isolated databases via the fabric contract's IsolatedDatabase
pattern, assertions preserved; alternatives (baseline-relative asserts,
serial-only, leave-open) recorded with why they lost; regression pin =
the four fixed tests themselves.

CHECKLIST WS12 backend-parity row ticks [x] with a dated addendum: red-first
reproduction, the three green isolation runs (dirty shared DB twice in
parallel; failing pairs serial on virgin), parity now green 10/10.

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

* docs(target-arch): three measured corrections surfaced by the guidance program

memory packages are substrates-layer, not products (families/extensions.md);
memory_native declares no extension_contracts dep (PROPOSAL §6.8.4); wasm's
extension_contracts edge is dev-only and the wasm 'never depends on' bullet is
lane-scoped, not family-wide (families/lanes.md).

Three further reported defects were checked and NOT corrected — they were
misreads: the sandbox 'never above the runtime tier' rule holds (substrates sit
below it), and PROPOSAL's safety consumer count already reads 17, matching the
tree.

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

* docs(target-arch): repair the corrupted kernel bullet and correct two family laws

kernel.md: ironclaw_authorization's 'Security & authority role' bullet has been
textually corrupted since nearai#6918 — an approvals sentence was spliced into it
mid-clause, orphaning its continuation line. Reconstructed, with the spliced
sentence restored to the approvals entry where it is true.

lanes.md: 'a lane never depends on a substrate' is false as a family-wide law
(ironclaw_sandbox holds network/safety/secrets normal deps, which its own entry
licenses); the accurate law is the layer ladder, and the narrow claim holds for
ironclaw_wasm alone.

lanes.md + events.md: the 'every crate ships both an AGENTS.md and a CLAUDE.md'
requirement is superseded by docs/reborn/guidance-conventions.md — two files
restating one rule is the drift the guidance program removes.

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

* test(arch): govern the ProtocolAuthEvidence test seam — WS12 audit F1

Two new gates in reborn_sealed_evidence_mint_ratchet (closed paths nearai#12/nearai#13),
per the audit's remedy spec:
(a) TEST_SEAM_MINT_FNS governs test_verified/test_verified_for_tenant — any
    production-text call site outside ironclaw_host_api is an offender
    (comments/strings stripped, #[cfg(test)] blocks stripped, tests.rs /
    *_tests.rs and cfg-test-only files excluded via the shared census);
(b) test-support may appear in no normal dependency table workspace-wide
    (dependencies / build-dependencies / target.* variants /
    workspace.dependencies), and no [features] key other than test-support
    may forward to it — the laundering shape that would evade (b) by one
    rename. [dev-dependencies] enablement stays legal (cargo-features.md
    bar 4, the sanctioned dev seam).

Measured zero offenders on this tree in both directions before pinning;
sabotage-proven red->green both ways (planted production call named with
file:line-text; [dependencies] enablement named with its table path).
Self-tests drive the same pipelines the gates run (zero-match principle);
the definition-location and partition tests now cover the new table.

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

* test(integration): join the gsuite credential-injection journey — WS12 audit F3

WS12 row 5 leg 3 was verified in two halves no committed test joined: gsuite
handler -> staged credential (crate tier) and staged obligation -> wire
(GitHub/Slack only). Scenario 5 already drives gmail.list_messages through
production dispatch on a Google-OAuth-configured group; it now also asserts
the JOIN: the seeded google account's token (itest-google-token) lands on
the recorded outbound gmail.googleapis.com request as
'authorization: Bearer ...', injected at the host egress chokepoint
(apply_credential_injection) per the gmail manifest's declared recipe —
store -> dispatch-time staging -> chokepoint -> wire, through the caller.

Sabotage-proven: disabling the Header injection arm reds exactly this
scenario with 'no network egress request matching url gmail.googleapis.com
has header authorization' while the request itself still reaches the wire
(headers seen: content-type only) — the injection reason, not a setup
error; restore -> green.

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

* docs(target-arch): correct five measured dependency claims in families/domains.md

conversations does not depend on safety (its BoundaryRule now forbids it);
triggers depends on libsql_runtime + safety and NOT filesystem, so its
'filesystem-routed persistence path alongside SQL' is one path, not two;
memory's live set is host_api alone (prompt_envelope is allowlisted, unused);
auth was short by extension_contracts + product_contracts.

Each verified against the manifest before editing.

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

* docs(target-arch): record the closed scan evasions (F4) and the secrets-consumer correction (F2)

The sealed-mint census weaknesses PROPOSAL §11.2.5/§12.1a and CHECKLIST recorded
as live and owed to WS10 are all closed on this tree, verified by re-attacking
the seam with both evasions at once; the docs understated the seal. Ratchet is
23 tests. One residual replaces them: the test_verified test-seam constructors,
now pinned by two gates.

§12.1b's 'only products-layer crate with the edge' is false by one —
ironclaw_assistant carries ironclaw_secrets as port-declaration vocabulary with
no expose_secret call. Not a value-reach bypass; joins nearai#7095's inventory.

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

* docs(target-arch): correct the app-family layer, config's consumer set, and the webui route count

ironclaw_config declares layer=substrates while living in crates/app/;
its consumers include operator, extension_manager and extension_host, not just
the assembly crate and the binary; webui is 93 contract-locked routes, not 92
(nearai#6780 landed after the last recount).

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

* docs(ws12): tick row 7 — the fresh-agent placement probe passed on the final tree

All three placements correct with high confidence, each naming the trait, the
tests, and the tempting wrong place it rejected. The probe doubled as a docs
audit and independently hit four defects, three of which the stacked guidance
PR fixes — it succeeded despite them.

WS12 is now 7/7. The restructure is complete.

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

* docs(target-arch): the product→loop_host recount was wrong on the day it was written

Eight importing files across four seams, not seven across three — the fourth
being a skill-activation-observer seam (projection.rs, projection/live_progress.rs)
this bullet never named, which §6.4.7's own same-day note already implied.
Surfaced by the plan-conformance audit.

The recount history is 3→5→6→7→8, wrong at four of five attempts. That retires
the prose count as a method: the sever slice should land an inventory ratchet
before or with the move, not another number.

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

* review(7263): CodeRabbit round-1 triage — 4 code fixes (2 sabotage-proven, 2 red-first) + 6 doc-truth corrections

Code, each verified red-first or by sabotage matrix:
- sealed-mint ratchet: per-name sighting floor for TEST_SEAM_MINT_FNS
  (closed path nearai#12). Proven: renaming test_verified_for_tenant away plus one
  extra legitimate sibling mention passed the old aggregate floor (silent
  disarm) and fails the new per-name floor naming the constructor; suite
  23/23 after revert. (CodeRabbit's claimed baseline ">2 mentions today" is
  wrong — each name has exactly one kept sighting — but the doc/enforcement
  mismatch and at-threshold fragility were real.)
- trace credit: non-finite novelty_score/duplicate_score are treated as
  absent before clamping (clamp preserves NaN, which poisoned online_score
  and credit_points_estimate); NaN cases added to the nearai#7144 regression test,
  red first.
- trace submission: a 2xx whose body stream dies mid-read now maps through
  request_failed (network telemetry kind, true I/O cause) instead of
  collapsing to an empty body that the nearai#7144 strict parse misreported as
  response_invalid/Submission; truncated-body regression test, red first.
- Postgres contract suites (event store + assistant ledger): isolated-DB
  names now carry a creation epoch and the once-per-binary sweep is
  age-gated (1h), closing the cross-process window where a sibling's fresh
  zero-backend database (between CREATE DATABASE and first connection) was
  sweepable; legacy pid-scheme leftovers still collect immediately. Proven
  on live Postgres 16: planted stale name swept, planted fresh name
  survives, 13/13 x2 and 20/20 x2 with zero leftovers.

Docs (target-architecture truth pass):
- PROPOSAL section 9: the WS6 rename sweep (nearai#7152) had rewritten the source
  column of the 12 renamed rows to their post-rename names, turning their
  rename dispositions into no-ops (rows 13/14/28/30/49/51/59/61/64/66/67/70);
  pre-restructure names restored with a dated footnote.
- PROPOSAL:69: removed the superseded 3->5->6->7 recount sentence (the
  corrected 3->5->6->7->8 passage subsumes it).
- PROPOSAL row 34: ToolPermissionOverrideStorePort deletion marked landed
  (2026-08-05 WS8, matching section 6.5.3; zero workspace hits).
- CHECKLIST:631: dated note recording that the WS12 F3 gsuite join landed in
  this batch (scenario_uninstalled_tool_call_denied_until_active.rs asserts
  the seeded google token on the gmail.googleapis.com wire; suite run green).
- CHECKLIST:632: dated note spending F4 (the audit's 19 was correct at its
  SHA; the ratchet file now holds 23 tests, re-counted at lines 552/597).
- ws12-gauntlet-report P6 heading: first of TWO real failures (one class),
  matching P8 and the report's own summary.
- ws12-mapping-audit rows 49/137: dated D-S closure notes (await-edge store
  half = journal projection already; resolver retained loop-tier; no shed
  owed) so the backlog register no longer lists it as in-flight.

Not fixed, with evidence: the span-helper macros gate suggestion
(info_span!(target = ...) is a hard compile error, E0425 — no silent trap),
the webui tracing-subscriber workspace-dep suggestion (no
[workspace.dependencies] entry exists; suggestion would not build; 8
siblings use the identical direct shape), and the mapping-audit
regeneration (the audit is accurate at its pinned SHA; the in-batch F1 fix
is recorded in its dated coordinator note).

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

* review(7263): CodeRabbit round-2 — rejection-body read keeps its cause; 200 {} is not a submission acknowledgement; lanes.md family dep rule matches measured Cargo.tomls

- submission.rs non-2xx path: a failed rejection-body read no longer collapses
  to an empty detail via .unwrap_or_default() (banned by
  .claude/rules/error-handling.md); the read error folds into the
  http_rejection detail so the received status keeps driving the 401/403
  auth-retry and the Credential/HttpRejection telemetry split.
  Regression: submit_preserves_rejection_body_read_failure_cause_with_status.

- TraceSubmissionReceipt.status: serde default removed — it fabricated
  status "submitted" from a proxy's 200 {} (the nearai#7144 synthesis, resurfacing
  through the wire type's defaults), after which the flush caller recorded
  Submitted and deleted the only retryable queued copy. The acknowledgement is
  the server naming what happened to the submission — every workspace fixture
  sends status and callers persist it unconditionally as server_status — so a
  status-less 2xx body now fails the strict receipt parse as response_invalid.
  Regression: submit_rejects_success_response_without_explicit_server_status
  (covers 200 {} and a status-less non-empty object).

- docs(lanes.md): the family Dependency-direction rule no longer claims every
  lane takes the extension-surface vocabulary crate — measured across
  crates/lanes/*/Cargo.toml: mcp + sandbox hold ironclaw_extension_contracts
  under [dependencies], wasm only under [dev-dependencies]; dated ✎
  cross-references the ironclaw_wasm entry's 2026-08-05 correction.

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

* review(7263): CodeRabbit round-3 — shared Postgres test provisioner (the "new dep edge" premise measured false), entrypoint self-test armed (sabotage-proven), six doc self-contradictions reconciled

Code:
- ironclaw_filesystem gains a `postgres_isolation` test-support module — the
  single home of the per-test isolated-database scaffolding (once-per-binary
  age-gated stale sweep, epoch-in-name convention, DROP WITH (FORCE) cleanup),
  parameterised by suite/env-var/prefix/unreachable-policy. Zero new
  production edges: event_store already normal-deps filesystem, filesystem
  already owns tokio-postgres, and the dev-dep+feature pattern is the one 17
  crates already use. The event-store and product-workflow-ledger suites
  migrate onto it; both Postgres legs proven live against postgres:16 (12
  tests, zero leftover databases). The fabric original keeps its older
  variant with the differences documented at its IsolatedDatabase.
- ironclaw_event_store drops the duplicate tokio-postgres dev-dep (the normal
  dep already reaches tests).
- test-reborn-docker-entrypoint.sh: the missing-argv check now exits the
  command-substitution subshell instead of incrementing a counter the parent
  never sees — red-proven (a migrate-but-never-exec entrypoint passed with 7
  FAIL lines printed), green after the fix both sabotaged and restored.
- trace_commons submission test additionally pins !auth_rejection() for the
  503 rejection (the structural assert the API affords; the prescribed
  payload asserts are refuted — status is private and source is None by
  design, with the message derived from the structured status in the same
  constructor).

Docs (each reconciled to one canonical statement, measured):
- kernel.md: lease ownership decided from code — authorization stores,
  matches, and expires leases (CapabilityLeaseStore + port + expiry all live
  there); approvals constructs and issues into that store. The round-1
  re-homing of the spliced sentence into approvals was wrong and is corrected
  in the dated repair note.
- app.md: "nothing depends on app" scoped to the three app-layer crates;
  ironclaw_config's consumers restated by dependency kind (normal:
  composition, cli, operator, extension_host; dev-only: extension_manager,
  root integration-tests package).
- lanes.md: the mediated-services sentence now states the family law as
  layer-ladder + injected authority; the no-secrets/network/filesystem-dep
  claim is scoped to ironclaw_wasm, matching the file's own corrections.
- CHECKLIST 429/430: the one open traces clause is named (ScopedFilesystem
  adoption); the stale "other two" count corrected against the F3a strike.
- PROPOSAL:69 + CHECKLIST:72: the project-create route repointed —
  first_party_extension_ports dissolved into loop_host::skill_activation
  (WS8, §9 row 55) — still unattempted.
- PROPOSAL §9 rows 57/62 synced to §6.8.4 (telegram: dependency-set equality
  with Slack's four contract-tier crates) and §6.9.4 (webui -> assistant is a
  charter-permanent edge, §12.11 D-B).
- PLAN top summary records Wave 6's design question as resolved (D-S,
  2026-08-05).
- deploy-reborn-cli-docker.md: the two migration paragraphs unified on the
  entrypoint's actual behavior — only enabled = false beside
  signing_secret_env/bot_token_env is migrated; every other retired-key shape
  fails startup with the migration pointer.
- composition-budget.toml: the stale "2398 bp, a true ratchet" header
  replaced with the WS0-floor truth the baselines test asserts.

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

* docs: move the guidance convention into this PR so its citations resolve

families/lanes.md and families/events.md cite docs/reborn/guidance-conventions.md
when superseding their 'every crate ships both an AGENTS.md and a CLAUDE.md'
requirement, but the file was only on the stacked guidance branch — a forward
reference that dangles if this PR merges alone. The convention is the rule those
notes invoke, so it belongs with them.

Caught by the CodeRabbit round-3 pass.

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

* fix(ci): give the hoisted postgres provisioner its safety rationales

The round-3 hoist moved test provisioning into a production src/ path, so
check_no_panics flagged its four panic/expect sites and reddened Code Style via
fast-checks. The gate is right to flag them: it deliberately does NOT exempt
#[cfg(feature = "test-support")] modules, because a cargo feature is not a
privilege boundary in this workspace (PROPOSAL 12.1a proved exactly that) —
so a test-support module still compiles into a build where any sibling enables
the feature.

Suppressed with the gate's documented inline rationale, which must trail the
statement rather than precede it. The panics themselves stay: a configured but
unusable Postgres must fail the suite loudly rather than skip it, which is the
inert-guard rule the isolation fix exists to serve.

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
pull Bot pushed a commit to bryanwills/ironclaw that referenced this pull request Aug 6, 2026
…ry crate, and a repo-wide stale sweep (nearai#7264)

* docs(target-arch): resolve the await-edge design question by measurement (D-S) and re-walk the WS9 verify row

Appends §12.13 D-S under delegated authority at owner direction, flagged
for post-hoc review by Illia Polosukhin (nearai#6696's author): the await-edge
store is measured to be a pure projection over ProcessDependencyPort
(that half of the shed happened inside nearai#6696 itself), and the resolver
is a genuine loop-tier responsibility journal edges cannot express
(owner recovery, sanitized transcript result materialization, batch-gate
resume-once drain, BlockedDependentRunGate resume policy). §6.7.3 is
amended (scheduler DONE / store DONE / resolver KEEP) instead of the
shed being executed; the 2.9k figure is corrected to 1,459 production +
1,448 cfg(test) lines. The §12.10 bullet, §2 divergence flag, §9 row 49,
§13 validation row, CHECKLIST header/WS4 pointer, README and PLAN all
carry the dated resolution.

WS9 verify row ticked with evidence: one lifecycle authority (the
process journal; TurnRunState/TurnRunRecord are projections via
AgentTurnProcessRuntime, ProcessRecord is a capability-invocation view,
no bare RunRecord exists) and §7 T4 re-walked clause-by-clause against
merged code — matches, including the checkpoint-gated no-auto-retry
mechanism (BeforeModel precedes ModelStage; requeue only when
checkpoint-free under the 3-claim cap).

Docs-only; no code, no tests, no gates touched.

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

* docs(ws12): rows 1-2 — package-set tick (64==64/1/0, gate+selftest+independent rederivation) and the 74-row §9 mapping audit (45 L / 15 L-A / 14 OBD / 0 NOT-LANDED; 3 findings recorded)

Row 1: check-target-tree.py reports 64 workspace members == 64 documented
packages, 1 documented exclusion (tools/ironclaw_silk_decoder), 0 owned
exceptions (EXCEPTIONS table empty — §5 steady state); self-test 17/17;
cargo-metadata name set diffed empty against an independent §5 parse.

Row 2: docs/reborn/target-architecture/ws12-mapping-audit.md is the audit
record — per-row executed-evidence, delete-clauses read against WS8's
execution notes, all 14 open rows cite their owning CHECKLIST/PROPOSAL
row or issue. Findings (recorded, not fixed): F1 prompt_envelope
manifest-description fix has no owner row; F2 WS6:429's 'nearai#5618 residue
deleted' overstates vs the live adopt_migrated_identity + open WS8:523;
F3 stale-docs cluster where the tree is ahead of the prose (trace
re-export drop, TurnRunTransitionPort, processes->resources).

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

* fold(7154): squash-port fix/red-main-7119 onto family-world main — defect train nearai#7146/nearai#7115/nearai#7104/nearai#7103/nearai#7144 (+nearai#7119 CI lane), 34-hunk contribution.rs port into the split modules, planner entrypoint classification, D-R loopback exception on the widened HTTPS credential guard

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

* test(extractors): issue-number + assertion-rationale doc refinement (rescued 844964f from rescue/7154-parked-guard)

Ports only the doc/assertion refinement commit; the guard-parking commit
e8f5a31 on that branch is deliberately NOT taken — superseded by the
D-R loopback ruling.

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

* docs(target-arch): record D-R — the loopback credential-guard ruling, wiring choice, and regression pins (PROPOSAL §12.13, 2026-08-05)

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

* review(7154): CodeRabbit round-1 triage — fail-closed tracing-target scan traversal (+node_modules), bounded sidecar output draining (capped capture + discard drain), deadlock regression asserts successful redaction (no seq), XLSX/DOCX empty-classification via extract_document, raise_for_status annotations

Threads already addressed by the fold: latency.rs caller-contract wording
(merged doc scopes the requirement to latency-trace callers), BodyJsonPointer
coverage (the plaintext-refusal test drives all four injection shapes).
Deliberately not taken: un-xfailing the four Slack-catalog projections —
the xfail is a documented tripwire (unexpected-pass goes red) and clearing
them is the nearai#6520 projection-modeling follow-on its comment specs.

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

* fix(assistant): re-point the one field-form tracing target the nearai#7146 gate caught — main's relocated triggered_run_delivery_services carried the drift the PR fixed at its old channel_host address

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

* closure fixups: execute the mapping-audit findings — prompt_envelope manifest description (F1), dated ✎ corrections for the nearai#5618 overstatement (F2) and the stale-prose cluster (F3)

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

* docs(ws12): second-reviewer security spot-audit + extension-journey re-verification (rows 5-6)

Adversarial second-reviewer pass over PROPOSAL §12.1a/b/c and the batch's own
§12.13 D-R loopback carve-out, plus a re-run of the five extension journeys.
Attacks were executed rather than argued: two sabotage files and a 38-shape
hostile-URL probe were planted, run, and reverted.

Verdicts — mint consolidation HOLDS-WITH-RESIDUAL, secrets tightening
HOLDS-WITH-RESIDUAL, host/verifier colocation HOLDS, D-R HOLDS. No HOLE.

Four findings recorded rather than fixed (report-not-repair):
- F1 test_verified/_for_tenant are ungranted mint constructors gated only by
  the `test-support` feature, in no mint-name table, with nothing pinning the
  feature to [dev-dependencies]; the shipped binary is measured feature-free.
- F2 §12.1b's products-layer residue undercounts by one (ironclaw_assistant).
- F3 journey coverage hole: gsuite-with-credential-injection is proven in two
  halves that no committed test joins.
- F4 both recorded census evasions and both fail-open reads are CLOSED on this
  tree, so §11.2.5/§12.1a/CHECKLIST:552/:597 now understate the seal.

Rows 5-6 ticked; only lines 631-632 of CHECKLIST touched so the concurrent
rows 3-4 edit folds cleanly.

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

* ratchet(closure): lock the budget gate at the program's end state

Dispatch ceiling 1122 -> 814 (today's observed, nudge taken; WS0 record 827
stays within effective 829). Mass-share ceiling 2398 -> 658 bp (the WS0
baseline floor — the arch-test assert refuses lower, and observed 578 bp sits
inside the nudge window). Absolute LOC re-equalized at 40423: nearai#6831 added 4
governed LOC through the queue's tolerance window; ceiling, observed, and
COMPOSITION_ABSOLUTE_SRC_LOC move together here. Both tightenings
sabotage-verified red (dispatch 9-over at 790; abs 73-over at 40200).

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

* docs(ws12): gauntlet report — row 3 ticked (full gauntlet green, 0 REAL in scope), row 4 verified-but-open on two pre-existing Postgres-leg test-isolation defects

WS12 rows 3-4 verification on the assembled batch tip 0c6c0cf:

Row 3 (ticked): fmt, clippy default/all-features/--lib --bins, workspace
tests (495 targets, 15,203 passed, 0 failed; the smoke.rs:3132
CPU-saturation flake passed first try), arch suite 285/0, the
integration-feature lane 1,665/0, recorded-fixture QA (61 fixtures clean,
41/0), frontend (typecheck 1,588 files; vitest 1,088/0; build + bundle
budgets), e2e smoke = the CI browser lane under the hermetic wrapper
(50 + 21 + 5 passed), and all 41 scripts/ci self-tests (two mapfile/bash-3.2
casualties green under bash 5, the CI shape).

Row 4 (stays open, dated note added): both-backend parity proven with
legs demonstrably executed for the fabric (57 pg + 81 libsql), triggers
(ADR 0003, REQUIRE_POSTGRES), hooks (ADR 0004, all three backends),
composition, processes journal, extension-registry, host-runtime libSQL
restart, and the backend matrix; fabric-delegated domains enumerated.
Two REAL blockers (one class): the Postgres legs of the event-store and
assistant-ledger contract suites assert against shared-database state and
cannot pass as-written (each failing test passes alone on a virgin
database; files byte-identical to origin/main; no CI lane sets their env
vars). Full evidence: docs/reborn/target-architecture/ws12-gauntlet-report.md.

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

* docs(guidance): set the crate/family guidance convention

The base commit for the family-guidance program: one canonical home per fact,
measured-not-aspirational claims, boundaries stated as exclusions, and the note
that guidance files can be gate-pinned. Every family/crate document written on
top of this branch follows this shape.

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

* fix(tests): per-test isolated Postgres databases for the two WS12 parity-blocking contract suites

The WS12 gauntlet (ws12-gauntlet-report.md §P6/§P8) measured the Postgres
legs of ironclaw_event_store's durable_event_store_contract and
ironclaw_assistant's durable_ledger_contract as test-isolation-defective:
absolute database-global asserts (event cursors; settled-entry prune
bookkeeping) run against the single external database named by their
IRONCLAW_*_POSTGRES_URL env vars. Every failing test passes alone on a
virgin database - store semantics correct, suites not self-isolating
(PROPOSAL §12.13 D-T).

Fix: each affected test provisions a private database on the configured
server - the fabric contract's IsolatedDatabase pattern
(db_root_filesystem_contract.rs) ported locally into each suite: CREATE
DATABASE per test, store/pool + migrations against it, courtesy
DROP ... WITH (FORCE), and a once-per-binary stale-name sweep. Every
assertion preserved byte-identical; libsql/jsonl twins untouched. In the
ledger suite only the two retention tests move - the other six Postgres
tests keep their proven fingerprint-suffix isolation.

Regression pins are the fixed tests themselves:
- postgres_replay_advances_next_cursor_past_trailing_filtered_records
- postgres_runtime_and_audit_logs_survive_rebuild_with_filtered_cursor_semantics
- postgres_settled_entry_limit_prunes_oldest_when_configured
- postgres_settled_prune_interval_defers_until_interval_when_configured
Green proven on a shared dirty database twice in a row (parallel default
threading) and serially on a virgin database; red-first reproduction
captured before the fix.

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

* docs(reborn): record §12.13 D-T (parity-suite isolation ruling) and close CHECKLIST WS12 row 4

D-T (after D-S): the WS12 gauntlet's two REAL findings were one defect
class — absolute database-global asserts against the single shared
env-var Postgres database — in two suites (event store cursor contract,
assistant settled-ledger retention). Ruling executed in commit 864d93e:
per-test isolated databases via the fabric contract's IsolatedDatabase
pattern, assertions preserved; alternatives (baseline-relative asserts,
serial-only, leave-open) recorded with why they lost; regression pin =
the four fixed tests themselves.

CHECKLIST WS12 backend-parity row ticks [x] with a dated addendum: red-first
reproduction, the three green isolation runs (dirty shared DB twice in
parallel; failing pairs serial on virgin), parity now green 10/10.

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

* docs(extensions): family guidance layer — AGENTS.md rewrite to the guidance-conventions shape, READMEs for all 4 family crates and 14 packages, duplicate-guidance consolidation

The family AGENTS.md now teaches the unified extension model (extension =
the only product object; channel/tool/auth are manifest surfaces; runtime
is loading, never taxonomy; ExtensionId vs VendorId; retired vocabulary
pinned by reborn_retired_taxonomy.rs), carries the self-containment and
package-to-crate rules from families/extensions.md, the four-responsibility
lookup, the measured package catalog, the exclusion list, and the armed
gates by test name.

Every crate and package gains a README.md (ironclaw_extension_host had no
guidance of any kind). ironclaw_extension_registry and memory-native each
had both an AGENTS.md and a CLAUDE.md saying overlapping things: AGENTS.md
is now canonical, CLAUDE.md a pointer, and memory-native's stale v1
references (src/workspace, src/db/libsql) are dropped in the merge. The
slack/telegram agent maps get package framing and a contracts-tier pointer
in place of the stale ironclaw_assistant one. Every path literal verified
to resolve on disk; all figures (tool counts, dep sets, consumers, layer
declarations) measured from the tree at 8d13454.

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

* docs(guidance): substrates + lanes family guidance per guidance-conventions.md

Family AGENTS.md rewritten to the spec shape for crates/substrates/ and
crates/lanes/: boundary, crate table, exclusion lists (mechanism-not-authority
for substrates; kernel-decides-lane-executes for lanes), armed gates by test
name, and measured deviations stated as deviations (sandbox's three substrate
deps, script.rs direct spawn). The lanes wit/-is-load-bearing note is kept.

A README.md for every crate in both families (10 new), measured against
cargo metadata 2026-08-05: public surface, workspace edges, consumer counts,
and enforced invariants each citing their gate. ironclaw_libsql_runtime and
ironclaw_wasm_limiter previously had no guidance of any kind; their READMEs
carry the sole-pool-home rule (ADDITIONAL_DRIVER_ALLOWLISTS: deadpool =
{filesystem, libsql_runtime}) and the outbound-only limiter gate
(wasm_sandbox_core_module_stays_domain_free_v1_parity_kernel; no BoundaryRule
names the limiter).

Duplicate guidance consolidated per rule 1: for the six crates holding both
AGENTS.md and CLAUDE.md (filesystem, network, secrets, mcp, sandbox, wasm),
CLAUDE.md stays canonical (module spec for filesystem; gate-pinned wording for
mcp and wasm) and AGENTS.md becomes a short pointer. No gate-pinned file was
edited. Stale reference removed: safety AGENTS.md pointed at
src/NETWORK_SECURITY.md, which exists nowhere in the tree.

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

* docs(crates-map): rewrite the three top-level maps family-first after the restructure

crates/AGENTS.md (264 -> 175 lines): routing map only — the ten families,
the read order (family AGENTS.md -> crate README.md -> working rules/module
spec -> docs/reborn/contracts/), the enforced seven-layer matrix with the
family/layer divergences, measured workspace facts (64 packages, 1 documented
exclusion, 0 owned exceptions per scripts/ci/check-target-tree.py), and a
verified command block. The 40-row per-crate map is gone: family AGENTS.md
files own crate routing per docs/reborn/guidance-conventions.md.

crates/README.md (141 -> 119 lines): human map — mental model in family
vocabulary, the ten families with measured crate counts, the 14 extension
packages (4 crates + 10 data-only), and the two workspace members outside
crates/.

crates/Architecture.md (1019 -> 1059 lines): audited against the live tree;
every named symbol/path re-verified 2026-08-05. Corrected: retired
ProductAdapter vocabulary (zero residue in code), the stale pre-rename
dependency ladder that still cited the deleted gateway/TUI crates, run-state
store mentions, lane-table crate anchors (sandbox/extension_support),
declared-in vs minted-by owners in the core data model, and the subagent
deny-filter status note (re-verified). Marked the pre-restructure
'partial or evolving' list as unmeasured rather than asserting it.

Also documents that scripts/check-boundaries.sh fails on a clean tree
(check-5 grep false positives) and greps the deleted v1 src/ in 4 of 6
checks — boundary enforcement for crates/ is the architecture suite.

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

* docs(crates-map): package directories carry their own README.md (coordinator sync with extensions-family agent)

Every extensions package dir — the 10 data-only ones included — now ships a
README.md, so both maps extend the read order to package level. The sibling
branch also confirmed what this map already derived per-crate: packages/ is
not uniformly products-layer (memory-native and mem0 declare substrates).
The other two coordinator corrections targeted rows of the old per-crate
map, which this rewrite deleted wholesale; nothing here cites
memory-native's CLAUDE.md or claims ironclaw_extension_host lacks guidance.

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

* docs(guidance): contracts + events family guidance layer per docs/reborn/guidance-conventions.md

- crates/contracts/AGENTS.md and crates/events/AGENTS.md rewritten to the
  family shape: exclusion lists with destinations, armed gates by test name,
  layer-matrix rows, crossing guide, measured header counts.
- README.md added for all 10 crates (ironclaw_prompt_envelope previously had
  no guidance of any kind — the CHECKLIST WS11 gap).
- One canonical guidance file per crate, other file a pointer:
  A+C merges for ironclaw_host_api, ironclaw_event_log,
  ironclaw_event_projections, ironclaw_event_streams; CLAUDE-only content
  moved to AGENTS.md for ironclaw_loop_contracts,
  ironclaw_extension_contracts, ironclaw_product_contracts (none of these are
  root module-spec crates, so AGENTS.md is the working-rules home).
- Stale guidance fixed against the live tree:
  * loop_contracts dep list contradicted the enforced allowlist (manifest is
    host_api + extension_contracts; common/prompt_envelope are permitted,
    unused).
  * event_log still documented the deleted jsonl parse/replay helpers.
  * event_projections still claimed EventStreamManager,
    DurableMemoryAuditSink, MemoryAuditProjectionMetadata, and
    PendingGateProjection — all deleted per PROPOSAL 6.3.3.
  * product_contracts still carried the pre-D-E open vendor decision under
    the nonexistent module name llm_config, and a Deferred section
    contradicting its own operator_llm/operator_service rows.
  * extension_contracts module table was missing the WS3 runtime module
    while counting 18.
  * common's llm_costs note carried the ModelCostTable seam claim refuted by
    PROPOSAL 12.11 D-F; now cites the pricer-port ruling and the vendor
    census residue.
- Deleted crates/events/ironclaw_event_projections/PENDING_GATE_PROJECTION.md:
  every claim in it referenced deleted symbols or the removed v1 src/ tree,
  and its only inbound reference was the crate's own CLAUDE.md.

Verified: all consumer counts reproduce via the printed grep commands; 147
path literals across the 28 touched files resolve on disk; no architecture
test reads any of these files by name; conflict-marker scan clean.

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

* docs(target-arch): three measured corrections surfaced by the guidance program

memory packages are substrates-layer, not products (families/extensions.md);
memory_native declares no extension_contracts dep (PROPOSAL §6.8.4); wasm's
extension_contracts edge is dev-only and the wasm 'never depends on' bullet is
lane-scoped, not family-wide (families/lanes.md).

Three further reported defects were checked and NOT corrected — they were
misreads: the sandbox 'never above the runtime tier' rule holds (substrates sit
below it), and PROPOSAL's safety consumer count already reads 17, matching the
tree.

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

* docs(kernel): family guidance layer — perimeter AGENTS.md, nine crate READMEs, AGENTS/CLAUDE consolidation

Family-guidance program, kernel family (guidance-conventions.md shape):

- crates/kernel/AGENTS.md rewritten to the family shape: the nine-stage
  effect pipeline with stage ownership, the sealed-mint table (witness /
  trust ceiling / approval lease / verified-inbound evidence, each with its
  mint site and its seal mechanism), the per-stage fail-closed table with
  file:line or test citations, the sharp exclusion list, and the armed
  gates by test name (authorized-seal ratchet, sealed-evidence mint
  ratchet, BoundaryRules, same-layer edge inventory at 21 kernel edges,
  empty LAYER_MATRIX_EXCEPTIONS register, driver boundary, process storage
  scan, origin-gate matrix ratchet).
- A README.md for each of the nine crates, per the crate shape: measured
  workspace deps and consumer counts (cargo metadata), public surface with
  verified citations, enforced invariants naming their gates.
  ironclaw_processes states the single-lifecycle-authority direction of
  truth (journal = store; TurnRunState/ProcessRecord/await-edge =
  projections; PROPOSAL §12.13 D-S); ironclaw_host_runtime documents the
  D-R literal-loopback carve-out and names its two regression tests.
- Duplicate guidance reconciled in all nine crates: AGENTS.md is canonical
  (guardrails absorbed), CLAUDE.md reduced to a pointer; ironclaw_trust's
  CONTRACT.md untouched as the co-located cross-crate contract.
- Stale references fixed inside owned paths: the deleted capability-profile
  conformance module (evaluate_profile_conformance — zero hits
  workspace-wide) removed from ironclaw_capabilities guidance; trust's
  'staging branch' / 'PR3' phrasing updated; capabilities' 'later
  obligation slices' updated to the landed host_runtime obligations split;
  cross-crate path mentions fully qualified. Every path literal in all 29
  kernel .md files verified to resolve on disk; every named symbol swept
  against crate sources.

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

* docs(domains): family guidance layer — AGENTS.md boundary doc, 12 crate READMEs, duplicate-guidance consolidation, stale-path fixes

Family guidance for crates/domains/ per docs/reborn/guidance-conventions.md:

- crates/domains/AGENTS.md rewritten to the family shape: charter table with
  go-here-when routing, the exclusion list, every armed gate named by test
  (BoundaryRules + identity/memory allowlists, the 5-entry in-family edge
  inventory, the naming gates, trusted-trigger ownership, the memory-provider
  residue ledger, persistence-driver boundary, the two module-charter gates).
- A measured README.md for each of the 12 crates: charter, use-when /
  don't-use-when routing, public surface, measured normal deps + named
  consumers, enforced invariants with their gates, exact test commands.
  ironclaw_attachments and ironclaw_identity had no guidance of any kind;
  identity's README points at CONTRACT.md (the module spec), llm's at its
  CLAUDE.md module spec.
- Duplicate guidance consolidated to one canonical file + pointer per crate:
  threads/conversations/memory/outbound rules now live in AGENTS.md (CLAUDE.md
  is a pointer); auth/llm keep CLAUDE.md canonical because their
  tests/module_charter.rs gates read it (AGENTS.md is the pointer). One
  misstatement fixed in the conversations merge: transcript content belongs to
  ironclaw_threads' SessionThreadService, not InboundConversationService.
- Staleness fixed inside the family: identity CONTRACT.md two-edge allowlist
  claim reconciled with D-Q's three entries; trace_commons CLAUDE.md gains the
  capture module row and strikes its two discharged Known Gaps (recording/paths
  shims deleted, rename done); llm CLAUDE.md reasoning.rs caller corrected to
  crates/loop/ironclaw_loop_host; triggers lib.rs 'feature-gated' repo doc
  comments corrected; pre-family path literals in comments repointed
  (kernel/approvals+processes, loop/hooks, app/architecture_tests,
  domains/auth) and the deleted-v1-engine references in skills marked
  historical.

Verified: cargo test -p ironclaw_llm --no-fail-fast (922 passed, exit 0 —
CLAUDE.md is gate-pinned); cargo check --all-targets on all six crates with
source edits; every cited path literal resolves on disk; conflict-marker scan
clean.

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

* docs(target-arch): repair the corrupted kernel bullet and correct two family laws

kernel.md: ironclaw_authorization's 'Security & authority role' bullet has been
textually corrupted since nearai#6918 — an approvals sentence was spliced into it
mid-clause, orphaning its continuation line. Reconstructed, with the spliced
sentence restored to the approvals entry where it is true.

lanes.md: 'a lane never depends on a substrate' is false as a family-wide law
(ironclaw_sandbox holds network/safety/secrets normal deps, which its own entry
licenses); the accurate law is the layer ladder, and the narrow claim holds for
ironclaw_wasm alone.

lanes.md + events.md: the 'every crate ships both an AGENTS.md and a CLAUDE.md'
requirement is superseded by docs/reborn/guidance-conventions.md — two files
restating one rule is the drift the guidance program removes.

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

* test(arch): govern the ProtocolAuthEvidence test seam — WS12 audit F1

Two new gates in reborn_sealed_evidence_mint_ratchet (closed paths #12/#13),
per the audit's remedy spec:
(a) TEST_SEAM_MINT_FNS governs test_verified/test_verified_for_tenant — any
    production-text call site outside ironclaw_host_api is an offender
    (comments/strings stripped, #[cfg(test)] blocks stripped, tests.rs /
    *_tests.rs and cfg-test-only files excluded via the shared census);
(b) test-support may appear in no normal dependency table workspace-wide
    (dependencies / build-dependencies / target.* variants /
    workspace.dependencies), and no [features] key other than test-support
    may forward to it — the laundering shape that would evade (b) by one
    rename. [dev-dependencies] enablement stays legal (cargo-features.md
    bar 4, the sanctioned dev seam).

Measured zero offenders on this tree in both directions before pinning;
sabotage-proven red->green both ways (planted production call named with
file:line-text; [dependencies] enablement named with its table path).
Self-tests drive the same pipelines the gates run (zero-match principle);
the definition-location and partition tests now cover the new table.

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

* test(integration): join the gsuite credential-injection journey — WS12 audit F3

WS12 row 5 leg 3 was verified in two halves no committed test joined: gsuite
handler -> staged credential (crate tier) and staged obligation -> wire
(GitHub/Slack only). Scenario 5 already drives gmail.list_messages through
production dispatch on a Google-OAuth-configured group; it now also asserts
the JOIN: the seeded google account's token (itest-google-token) lands on
the recorded outbound gmail.googleapis.com request as
'authorization: Bearer ...', injected at the host egress chokepoint
(apply_credential_injection) per the gmail manifest's declared recipe —
store -> dispatch-time staging -> chokepoint -> wire, through the caller.

Sabotage-proven: disabling the Header injection arm reds exactly this
scenario with 'no network egress request matching url gmail.googleapis.com
has header authorization' while the request itself still reaches the wire
(headers seen: content-type only) — the injection reason, not a setup
error; restore -> green.

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

* docs(target-arch): correct five measured dependency claims in families/domains.md

conversations does not depend on safety (its BoundaryRule now forbids it);
triggers depends on libsql_runtime + safety and NOT filesystem, so its
'filesystem-routed persistence path alongside SQL' is one path, not two;
memory's live set is host_api alone (prompt_envelope is allowlisted, unused);
auth was short by extension_contracts + product_contracts.

Each verified against the manifest before editing.

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

* docs(guidance): family AGENTS.md + crate READMEs + guidance consolidation for loop/product/app

Family-guidance program, families 8-10 (the top of the stack), per
docs/reborn/guidance-conventions.md:

- Rewrite crates/{loop,product,app}/AGENTS.md from routing stubs to the
  spec's family shape: exclusion lists, armed gates by test name, layer
  rows, crossing guides. Loop carries the trust story + the declared
  Loop*Port decorator chain; product carries the frozen-surface rule,
  the transports-consume-contracts rule (with the D-B frozen-constant
  qualification), the evidence-mint prohibition, and the two vendor
  exceptions; app carries the wires-owners-never-becomes-one charter,
  the binary-names-packages rule, config's zero-dep guarantee, and the
  composition mass ratchet (loc 40423 / Arc<dyn> 814).
- Add a README.md to all 13 crates (12 new; webui's rewritten to the
  spec shape) with measured public surface, deps, and consumer counts.
- Consolidate duplicate AGENTS.md/CLAUDE.md per spec rule 1: AGENTS.md
  is canonical and CLAUDE.md a pointer for agent_loop, loop_host,
  turn_runner, hooks, host_ingress, openai_compat, operator, and
  architecture_tests; CLAUDE.md stays canonical (module spec /
  gate-pinned) for webui, composition, and assistant, with
  composition's AGENTS.md reduced to the pointer.
- Fix stale references in owned paths: hooks' dependency diagram and
  AgentLoopDriver home (ironclaw_loop_contracts, not ironclaw_turns),
  loop_host/agent_loop port-home claims, turn_runner's pre-nearai#6696
  scheduler description, webui's ProductSurface path
  (product_contracts, not host_api), route count (93, measured), and
  webui's allowed-dependency list (7 of 10 were listed), the D-S
  await-edge ruling reflected in turn_runner guidance, composition's
  llm_admin residue (nearai_login_serve left for operator).

Verified: cargo test -p ironclaw_architecture_tests --no-fail-fast
(39 binaries, 0 failures — covers the CLI AGENTS.md phrase pin and the
composition guidance-markdown scan), scripts/ci/check-target-tree.py,
path-literal resolution over all 37 changed files, conflict-marker scan.

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

* docs(target-arch): record the closed scan evasions (F4) and the secrets-consumer correction (F2)

The sealed-mint census weaknesses PROPOSAL §11.2.5/§12.1a and CHECKLIST recorded
as live and owed to WS10 are all closed on this tree, verified by re-attacking
the seam with both evasions at once; the docs understated the seal. Ratchet is
23 tests. One residual replaces them: the test_verified test-seam constructors,
now pinned by two gates.

§12.1b's 'only products-layer crate with the edge' is false by one —
ironclaw_assistant carries ironclaw_secrets as port-declaration vocabulary with
no expose_secret call. Not a value-reach bypass; joins nearai#7095's inventory.

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

* docs(target-arch): correct the app-family layer, config's consumer set, and the webui route count

ironclaw_config declares layer=substrates while living in crates/app/;
its consumers include operator, extension_manager and extension_host, not just
the assembly crate and the binary; webui is 93 contract-locked routes, not 92
(nearai#6780 landed after the last recount).

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

* docs(stale-sweep): fix agent guidance outside crates/ for the family restructure

Audit-and-fix pass over every stale document outside crates/ (PR 2 of the
family-guidance program). Live guidance verified against the tree; records
kept with dated notes instead of rewrites.

Guidance fixes (verified against HEAD before writing):
- .claude/commands/trace.md: MCP tool prefix codebase-memory -> codebase-memory-mcp
  (allowed-tools never matched the real server), ProductSurface home ->
  ironclaw_product_contracts, capabilities host.rs -> host/ module split,
  scripts lane -> script-sandbox; deleted the redundant v1-anchors section.
- .claude/commands/add-sse-event.md: deleted the banner-quarantined v1 scaffold
  steps (every path deleted with the monolith); now an honest redirect to the
  Reborn projection/SSE path. Frontmatter no longer advertises a working scaffold.
- .claude/commands/deslop-reborn.md: three dead crates/*/Cargo.toml globs (family
  layout added a level), ls crates/ -> family-aware listing, v1-only consumer
  logic retired, per-crate --features integration phrasing.
- .claude/rules/type-placement.md: crates/*/src globs matched nothing; recipes
  re-pointed and numbers re-measured 2026-08 (3,495 structs/enums, 385 traits,
  fan-in host_api 53 / common 20 / turns 12).
- .claude/rules/skills.md: paths trigger pointed at a nonexistent
  bundled_skills.rs (rule never fired); SKILLS_REGEX_ACTIVATION_ENABLED /
  SKILLS_MAX_TOKENS env vars are read by nothing -> documented the real
  config-file setting and DEFAULT_MAX_SKILL_CONTEXT_TOKENS.
- .claude/rules/testing.md, ironclaw-reborn-testing skill, CONTRIBUTING.md,
  .github/pull_request_template.md, testing-playbook, deslop: the workspace-root
  `integration` feature is empty with zero consumers - all "cargo test
  --features integration" guidance re-pointed to crate-level suites.
- .claude/skills/reborn-extension-surfaces: four pre-colocation assets/ paths,
  CapabilitySurfaceKind home, conformance-suite move to
  ironclaw_extension_contracts, ingestion test move to the registry crate,
  gate-banned migration exemplar replaced with the live behavioral pin, [mcp]
  instead-of claim softened (nearai-mcp pins a static [[tools]]).
- .claude/skills/ironclaw-reborn-orientation: turn_runner labels, prompt-crate
  list re-derived (turns/first_party_extension_ports out; host_api,
  loop_contracts, assistant in), consumer-grep glob fixed.
- .claude/skills/reborn-feature + docs/reborn/how-to-port-channel-to-reborn.md:
  ProductSurface/ProductView/descriptors/caller types live in
  ironclaw_product_contracts; recipes re-pointed.
- CLAUDE.md: dead root --features integration line replaced; project tree
  redrawn with the ten families; trait homes corrected; ProviderId -> VendorId;
  CapabilitySurfaceKind + ChannelAdapter homes; [channel.config] ->
  [channel.connection]/[admin_configuration]; v1 Job State Machine section
  deleted (no such machine in Reborn); prompt-crates recipe fixed; MCP server
  name; LLM backend list re-derived from LlmBackendKind.
- docs/extensions/building-a-tool.md: product-adapter crates row -> channel
  surface model; package registration -> PACKAGES collector in
  ironclaw_extension_support (available_extensions.rs is being dissolved);
  hosted-MCP policy home -> ironclaw_extension_host/src/mcp.rs; dead v1 bullets
  dropped.
- docs/internal/mutation-audit.md: runnable command blocks re-pointed (family
  paths; ironclaw_dispatcher example replaced - crate deleted in WS0).
- docs/reborn/harness/e2e.md: dispatcher row -> the capabilities dispatch
  contract suites. docs/reborn/contracts/host-api.md: three ironclaw_dispatcher
  mentions -> capabilities dispatch module. standard-operations.md: renamed
  crate + arch-test package name.
- scripts: mutation-audit.sh usage header, check-hermetic-env.sh env_helpers
  pointer, check-generic-without-concrete.sh mirror pointer,
  telegram_smoke/README regression step (target deleted with v1 in nearai#6375).
- .env.example: dead SKILLS_REGEX_ACTIVATION_ENABLED entry -> config-file doc.
- docs/qa/telegram-coverage-map.md: nine not-automated reasons re-worded to the
  crate-level integration tier.

Records (dated notes, no rewrites): ADR 0003/0004 path notes (evidence pinned
to their measured SHA), FEATURE_PARITY state-migration paragraph marked
historical with a git-show recovery pointer, engine-v2 parity record's
"coexist on main" claim corrected with a historical note, subagent-spawn
legacy scope re-tensed.

Pre-family path reproduction count: 73 -> 70 files; every remaining file is a
dated record (docs/plans, docs/superpowers, ADRs, audits, CHANGELOG history,
historical-marked train docs) or a deliberate past-tense mention.

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

* docs(ws12): tick row 7 — the fresh-agent placement probe passed on the final tree

All three placements correct with high confidence, each naming the trait, the
tests, and the tempting wrong place it rejected. The probe doubled as a docs
audit and independently hit four defects, three of which the stacked guidance
PR fixes — it succeeded despite them.

WS12 is now 7/7. The restructure is complete.

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

* docs(target-arch): the product→loop_host recount was wrong on the day it was written

Eight importing files across four seams, not seven across three — the fourth
being a skill-activation-observer seam (projection.rs, projection/live_progress.rs)
this bullet never named, which §6.4.7's own same-day note already implied.
Surfaced by the plan-conformance audit.

The recount history is 3→5→6→7→8, wrong at four of five attempts. That retires
the prose count as a method: the sever slice should land an inventory ratchet
before or with the move, not another number.

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

* review(7263): CodeRabbit round-1 triage — 4 code fixes (2 sabotage-proven, 2 red-first) + 6 doc-truth corrections

Code, each verified red-first or by sabotage matrix:
- sealed-mint ratchet: per-name sighting floor for TEST_SEAM_MINT_FNS
  (closed path #12). Proven: renaming test_verified_for_tenant away plus one
  extra legitimate sibling mention passed the old aggregate floor (silent
  disarm) and fails the new per-name floor naming the constructor; suite
  23/23 after revert. (CodeRabbit's claimed baseline ">2 mentions today" is
  wrong — each name has exactly one kept sighting — but the doc/enforcement
  mismatch and at-threshold fragility were real.)
- trace credit: non-finite novelty_score/duplicate_score are treated as
  absent before clamping (clamp preserves NaN, which poisoned online_score
  and credit_points_estimate); NaN cases added to the nearai#7144 regression test,
  red first.
- trace submission: a 2xx whose body stream dies mid-read now maps through
  request_failed (network telemetry kind, true I/O cause) instead of
  collapsing to an empty body that the nearai#7144 strict parse misreported as
  response_invalid/Submission; truncated-body regression test, red first.
- Postgres contract suites (event store + assistant ledger): isolated-DB
  names now carry a creation epoch and the once-per-binary sweep is
  age-gated (1h), closing the cross-process window where a sibling's fresh
  zero-backend database (between CREATE DATABASE and first connection) was
  sweepable; legacy pid-scheme leftovers still collect immediately. Proven
  on live Postgres 16: planted stale name swept, planted fresh name
  survives, 13/13 x2 and 20/20 x2 with zero leftovers.

Docs (target-architecture truth pass):
- PROPOSAL section 9: the WS6 rename sweep (nearai#7152) had rewritten the source
  column of the 12 renamed rows to their post-rename names, turning their
  rename dispositions into no-ops (rows 13/14/28/30/49/51/59/61/64/66/67/70);
  pre-restructure names restored with a dated footnote.
- PROPOSAL:69: removed the superseded 3->5->6->7 recount sentence (the
  corrected 3->5->6->7->8 passage subsumes it).
- PROPOSAL row 34: ToolPermissionOverrideStorePort deletion marked landed
  (2026-08-05 WS8, matching section 6.5.3; zero workspace hits).
- CHECKLIST:631: dated note recording that the WS12 F3 gsuite join landed in
  this batch (scenario_uninstalled_tool_call_denied_until_active.rs asserts
  the seeded google token on the gmail.googleapis.com wire; suite run green).
- CHECKLIST:632: dated note spending F4 (the audit's 19 was correct at its
  SHA; the ratchet file now holds 23 tests, re-counted at lines 552/597).
- ws12-gauntlet-report P6 heading: first of TWO real failures (one class),
  matching P8 and the report's own summary.
- ws12-mapping-audit rows 49/137: dated D-S closure notes (await-edge store
  half = journal projection already; resolver retained loop-tier; no shed
  owed) so the backlog register no longer lists it as in-flight.

Not fixed, with evidence: the span-helper macros gate suggestion
(info_span!(target = ...) is a hard compile error, E0425 — no silent trap),
the webui tracing-subscriber workspace-dep suggestion (no
[workspace.dependencies] entry exists; suggestion would not build; 8
siblings use the identical direct shape), and the mapping-audit
regeneration (the audit is accurate at its pinned SHA; the in-batch F1 fix
is recorded in its dated coordinator note).

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

* review(7263): CodeRabbit round-2 — rejection-body read keeps its cause; 200 {} is not a submission acknowledgement; lanes.md family dep rule matches measured Cargo.tomls

- submission.rs non-2xx path: a failed rejection-body read no longer collapses
  to an empty detail via .unwrap_or_default() (banned by
  .claude/rules/error-handling.md); the read error folds into the
  http_rejection detail so the received status keeps driving the 401/403
  auth-retry and the Credential/HttpRejection telemetry split.
  Regression: submit_preserves_rejection_body_read_failure_cause_with_status.

- TraceSubmissionReceipt.status: serde default removed — it fabricated
  status "submitted" from a proxy's 200 {} (the nearai#7144 synthesis, resurfacing
  through the wire type's defaults), after which the flush caller recorded
  Submitted and deleted the only retryable queued copy. The acknowledgement is
  the server naming what happened to the submission — every workspace fixture
  sends status and callers persist it unconditionally as server_status — so a
  status-less 2xx body now fails the strict receipt parse as response_invalid.
  Regression: submit_rejects_success_response_without_explicit_server_status
  (covers 200 {} and a status-less non-empty object).

- docs(lanes.md): the family Dependency-direction rule no longer claims every
  lane takes the extension-surface vocabulary crate — measured across
  crates/lanes/*/Cargo.toml: mcp + sandbox hold ironclaw_extension_contracts
  under [dependencies], wasm only under [dev-dependencies]; dated ✎
  cross-references the ironclaw_wasm entry's 2026-08-05 correction.

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

* review(7263): CodeRabbit round-3 — shared Postgres test provisioner (the "new dep edge" premise measured false), entrypoint self-test armed (sabotage-proven), six doc self-contradictions reconciled

Code:
- ironclaw_filesystem gains a `postgres_isolation` test-support module — the
  single home of the per-test isolated-database scaffolding (once-per-binary
  age-gated stale sweep, epoch-in-name convention, DROP WITH (FORCE) cleanup),
  parameterised by suite/env-var/prefix/unreachable-policy. Zero new
  production edges: event_store already normal-deps filesystem, filesystem
  already owns tokio-postgres, and the dev-dep+feature pattern is the one 17
  crates already use. The event-store and product-workflow-ledger suites
  migrate onto it; both Postgres legs proven live against postgres:16 (12
  tests, zero leftover databases). The fabric original keeps its older
  variant with the differences documented at its IsolatedDatabase.
- ironclaw_event_store drops the duplicate tokio-postgres dev-dep (the normal
  dep already reaches tests).
- test-reborn-docker-entrypoint.sh: the missing-argv check now exits the
  command-substitution subshell instead of incrementing a counter the parent
  never sees — red-proven (a migrate-but-never-exec entrypoint passed with 7
  FAIL lines printed), green after the fix both sabotaged and restored.
- trace_commons submission test additionally pins !auth_rejection() for the
  503 rejection (the structural assert the API affords; the prescribed
  payload asserts are refuted — status is private and source is None by
  design, with the message derived from the structured status in the same
  constructor).

Docs (each reconciled to one canonical statement, measured):
- kernel.md: lease ownership decided from code — authorization stores,
  matches, and expires leases (CapabilityLeaseStore + port + expiry all live
  there); approvals constructs and issues into that store. The round-1
  re-homing of the spliced sentence into approvals was wrong and is corrected
  in the dated repair note.
- app.md: "nothing depends on app" scoped to the three app-layer crates;
  ironclaw_config's consumers restated by dependency kind (normal:
  composition, cli, operator, extension_host; dev-only: extension_manager,
  root integration-tests package).
- lanes.md: the mediated-services sentence now states the family law as
  layer-ladder + injected authority; the no-secrets/network/filesystem-dep
  claim is scoped to ironclaw_wasm, matching the file's own corrections.
- CHECKLIST 429/430: the one open traces clause is named (ScopedFilesystem
  adoption); the stale "other two" count corrected against the F3a strike.
- PROPOSAL:69 + CHECKLIST:72: the project-create route repointed —
  first_party_extension_ports dissolved into loop_host::skill_activation
  (WS8, §9 row 55) — still unattempted.
- PROPOSAL §9 rows 57/62 synced to §6.8.4 (telegram: dependency-set equality
  with Slack's four contract-tier crates) and §6.9.4 (webui -> assistant is a
  charter-permanent edge, §12.11 D-B).
- PLAN top summary records Wave 6's design question as resolved (D-S,
  2026-08-05).
- deploy-reborn-cli-docker.md: the two migration paragraphs unified on the
  entrypoint's actual behavior — only enabled = false beside
  signing_secret_env/bot_token_env is migrated; every other retired-key shape
  fails startup with the migration pointer.
- composition-budget.toml: the stale "2398 bp, a true ratchet" header
  replaced with the WS0-floor truth the baselines test asserts.

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

* docs: move the guidance convention into this PR so its citations resolve

families/lanes.md and families/events.md cite docs/reborn/guidance-conventions.md
when superseding their 'every crate ships both an AGENTS.md and a CLAUDE.md'
requirement, but the file was only on the stacked guidance branch — a forward
reference that dangles if this PR merges alone. The convention is the rule those
notes invoke, so it belongs with them.

Caught by the CodeRabbit round-3 pass.

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

* fix(ci): give the hoisted postgres provisioner its safety rationales

The round-3 hoist moved test provisioning into a production src/ path, so
check_no_panics flagged its four panic/expect sites and reddened Code Style via
fast-checks. The gate is right to flag them: it deliberately does NOT exempt
#[cfg(feature = "test-support")] modules, because a cargo feature is not a
privilege boundary in this workspace (PROPOSAL 12.1a proved exactly that) —
so a test-support module still compiles into a build where any sibling enables
the feature.

Suppressed with the gate's documented inline rationale, which must trail the
statement rather than precede it. The panics themselves stay: a configured but
unusable Postgres must fail the suite loudly rather than skip it, which is the
inert-guard rule the isolation fix exists to serve.

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

* fix(ci): classify the three planner-unknown paths this PR touches

The Reborn PR test planner fails closed on any unclassified path and
raises on the FIRST failure in sorted order, so CI only ever showed
.github/pull_request_template.md. Classifying that unmasked two more
paths in this PR's own diff: scripts/mutation-audit.sh and
scripts/telegram_smoke/README.md. All three are classified; the
fail-closed arm is untouched:

* .github/pull_request_template.md -> IGNORED_PREFIXES, beside its
  exact sibling .github/ISSUE_TEMPLATE/ (both GitHub UI templates;
  classify-test-scope.sh already pairs them in its docs-only arm).
* scripts/mutation-audit.sh -> PR_STATIC_CONTROL_PATHS, beside its
  self-test scripts/test-mutation-audit.sh; both run only in
  nightly-deep-ci.yml's mutation-frontier job.
* scripts/telegram_smoke/ -> QA_HARNESS_PREFIXES; a live, by-hand
  release smoke harness referenced by no workflow, same class as
  scripts/reborn_qa_matrix/.

Each entry is pinned red-first in test_reborn_pr_test_plan.py (entry
commented out, new assertion fails with the exact production error,
entry restored, green): a new PR-template test with paired
accept-AND-select-nothing assertions plus unknown-.github/-sibling
refusal probes, and the two existing class tests extended. Planner
self-test: 65 tests OK. The planner CLI over this PR's full 209-path
diff now exits 0.

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
personal-upstream-sync Bot pushed a commit to theredspoon/ironclaw that referenced this pull request Aug 20, 2026
…, agent-mode pill (nearai#6994)

* feat(webui): OOBE automation-tasks prototype — carousel, inline cards, agent-mode pill

First-time-user OOBE concepts for the WebChat v2 landing view, built as a
UI-only prototype on mock data (backend intentionally not wired yet). Recovered
and rebased from the Jul design session (was the stale design/oobe-chat-automations
WIP); the streaming NearProcessIndicator busy-states are re-applied on top of #6901.

Adds to the chat view:
- Completed-automations carousel above the composer (automation-carousel,
  automation-task-card) — validates auto-run tasks, deep-links into the 3rd-party app.
- Inline calendar-reschedule rich-preview (calendar-reschedule-card) and a Plan-mode
  batch card (plan-card), sharing one decision model via task-action-bar
  (suggested → Approve/Modify/Cancel; automated → Modify/Revert).
- Agent-mode composer pill (mode-selector + lib/agent-mode) — Suggest/Plan/Auto/Bypass,
  persisted to scoped localStorage in the prototype.
- Typed mock domain + endpoint-shaped seam (lib/automation-tasks*, useAutomationTasks)
  so wiring the backend is a mock→fetch body swap with no component changes.
- DEV-only /design-preview harness (design-preview-page) to view the concepts, gated by import.meta.env.DEV.
- Busy states render the branded NearProcessIndicator (from #6901) — shared design language.

The backend (durable events, projection, transport frame, HTTP routes, facade+effect,
agent-mode persistence) is NOT implemented; AUTOMATION-TASKS-CONTRACT.md is the
reviewable wiring spec, tracked as a follow-up.

NOTE (why this is a draft): the landing carousel reads listAutomationTasks(), which
returns MOCK data for all users and is not DEV-gated. Must be backend-wired or gated
before this can leave draft / merge.

Frontend gate green: conventions + typecheck clean, 1032 tests pass.

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

* docs(design): add OOBE first-run onboarding mockup + brief

Standalone design exploration for the two first-run moments the PR #6994
prototype skips: the cold-start landing (zero automations, nothing connected)
and the first "Done for you" card appearing. House style matches
docs/design/agent-activity-streaming.

- docs/design/oobe.md — brief: goal, the two moments, the Invite vs Coach
  direction fork, what ships (#6994) vs needs backend (#6993), open questions.
- docs/design/oobe/mockup.html — interactive: plays cold-start → connect →
  anticipatory (NEAR indicator + skeleton tiles) → first-card reveal →
  populated, with a seg toggle for Invite (minimal) vs Coach (anticipatory
  ghost cards). Real --v2-* tokens; light+dark; reduced-motion honored.

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

* docs(design): OOBE mockup — add Thread + Plan scenes

Fold the two in-thread concepts into the standalone mockup so one shared
Artifact covers the whole OOBE arc. Adds a Scene selector (First run /
Thread / Plan):
- Thread — the inline CalendarRescheduleCard rich-preview (live: Approve →
  "Rescheduling…" → Automated; Modify time cycles the proposed slot; Skip →
  dismissed), plus an already-automated example with Modify/Revert.
- Plan — the batched PlanCard (Approve all → "Running your plan…" → all done;
  per-item skip), faithful to plan-card.tsx.
Same --v2-* tokens, NearProcessIndicator busy states, light+dark, flags.

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

* docs(design): OOBE mockup — flag taxonomy + connect-pill redesign

Flags reframed around what's on main: Shipped (already on main), Redesign
(design update to existing main UI), New Feature (net-new, needs new
events/functionality), New UX (new design not on main); New Feature + New UX
combine. Applied: connect row = Shipped (reuses AuthRequired); composer =
Redesign (mode pill added); Coach ghost = New UX; carousel, both calendar
cards, and the plan card = New UX + New Feature.

Connect pills redesigned: per-tool checkbox state (no "connect" text), a
"Connect all" action, and — once connected — the pills condense into an
overlapping icon stack ("N connected", tap to re-expand).

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

* docs(design): OOBE mockup — Connect all as a lightweight link

Restyle the "Connect all" action from a filled primary button to a
lightweight accent text link (underline on hover) so it doesn't compete with
the connect pills. Kept as a <button> for keyboard/focus + the click handler.

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

* docs(design): OOBE mockup — avatar-style condensed connect stack

Restyle the condensed connected-tools stack after the stacked-avatars
reference: circular app icons with a white ring (theme surface) + soft drop
shadow, heavier overlap, and a trailing "+" circle to add another tool. The
count moves to the header subtitle ("3 connected — tap to manage"); the whole
stack re-expands on tap. Light + dark, reduced-motion honored.

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

* docs(design): OOBE mockup — refine condensed connect stack

Per feedback on the stacked-tools chip: opaque icon fills (drop the
transparent tint so overlaps don't bleed), rounded-square shape to match the
expanded pills (was circular), a ">" chevron instead of "+" on the trailing
chip, and "add more later" → "add more anytime" in the header subtitle.

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

* docs(design): OOBE mockup — relocate live indicator to carousel + collapse action

Contextual placement: the branded NEAR process indicator now leads the carousel
header (animated while working with a live elapsed, settling to a solid mark +
"worked for Ns" when done) instead of floating above the composer — it sits
where the agent's output is forming. Header is now a two-line block (mark +
title/elapsed over subtitle) so it stays clear of the annotation flags.

Connect pills: add a collapse control (left-chevron chip) to the right of the
expanded pills, mirroring the stack's expand affordance, to re-condense.

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

* docs(design): OOBE mockup — agent mode drives task-card state

Rename the "Automated" badge to "Completed", and make the agent-mode pill a
live control: Suggest / Plan render the carousel cards as suggested (Approve /
Modify / Cancel, "Suggested" badge, "Suggested for you" header + hero); Auto /
Bypass render them completed ("Completed" badge, Modify / Revert, "Done for
you"). Per-card Approve flips a single card to completed, Cancel → dismissed,
Revert → reverted — so the suggested→completed flow is real, not just a label.

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

* docs(design): OOBE mockup — single-line carousel header

Put the secondary description back on the same line as the indicator's activity
string (title + elapsed). To keep it single-line and clear of the annotation
flag, drop the redundant working-state subtitle (title + live elapsed is enough)
and tighten the done-state subtitle to "Review or undo anytime".

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

* docs(design): OOBE mockup — remove the cold-start Invite/Coach switcher

Drop the Invite/Coach direction toggle and its JS; first run now uses the
minimal ("Invite") cold start. Cleaned up the lede + footnote copy that
referenced the toggle and the Coach ghost strip.

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

* docs(design): OOBE — dismissible connect panel + composer pill; archive stack

Connect-tools panel:
- add a close (X) to dismiss the panel; when dismissed it collapses to a small
  "Connect your tools" pill in the composer action row (left of the agent-mode
  picker) with its own X. Pill body re-opens the panel; pill X removes it.
- remove the collapse/expand overlapping-stack control entirely.

Archive: docs/design/oobe/archive/connect-tools-stack.html — a self-contained,
theme-aware record of the retired collapse/expand states (expanded pills +
collapsed avatar stack) for the design archive.

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

* docs(design): OOBE mockup — move connect pill right of the mode selector

Place the dismissed-state "Connect your tools" pill after the agent-mode picker
in the composer action row (was to its left).

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

* docs(design): OOBE mockup — connect panel button + reflow

- Move the connect action out of the header into a bottom-right button (was a
  link); its label is "Connect all" with nothing selected, "Connect" once any
  tool is picked, hidden when all are connected.
- Pin the dismiss (X) far-right in the header (margin-left:auto) so it no longer
  relocates when the button hides.
- Add more tools (Notion, Drive, GitHub) so the pills reflow to a second row
  past four.

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

* docs(design): OOBE mockup — connect button rides the pill row (drop empty footer)

The connect action now flows at the end of the pills (right-aligned via
margin-left:auto) instead of a dedicated full-width footer row, removing the
wasted empty space to the button's left.

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

* docs(design): OOBE mockup — Gemini ai-spark border on the first-card reveal

Replace the static accent glow ring on the first "aha" card with a Gemini-style
ai-spark: a blue→purple→pink conic gradient masked to the card border that
chases around once (1.35s) and then dissipates, with a soft purple/coral glow.
Uses @property --ai-angle for the sweep; hidden under prefers-reduced-motion.

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

* docs(design): OOBE mockup — make the ai-spark actually chase the border

The conic-gradient + @property --ai-angle version interpolated the angle but
Chromium didn't repaint the gradient, so the spark never moved. Rebuild it as
an SVG rect stroke with an animated stroke-dashoffset (a Gemini blue→purple→pink
gradient dash that travels the border once, then dissipates) — stroke-dashoffset
repaints reliably every frame. Hidden under prefers-reduced-motion.

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

* docs(design): OOBE ai-spark — faster, tapered comet tail, theme-aware colors

- Speed: 1.5s → 0.7s lap.
- Tail: uniform round-cap dash → a solid head fading into progressively
  sparser dashes; the drop-shadow glow blurs it into a smooth tapered comet
  (restores the taper the conic version had).
- Colors: per-theme tokens (--ais-1/2/3 + --ais-glow) — deeper/saturated blue
  →purple→magenta on light so it reads on white, brighter on dark.

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

* docs(design): OOBE first card is conjured — spell-cast reveal

Make the first automation card feel summoned rather than placed:

- Faster spark: 0.7s -> 0.5s lap.
- Conjure: the card no longer pops in fully-formed — it materializes
  (opacity 0->1, scale .84->1 with a slight overshoot, blur 7px->0) in sync
  with the spark tracing its border.
- Spell-land: a brief glow pulse (--ais-glow) blooms around the card as the
  spark completes its loop.
- prefers-reduced-motion disables conjure + spell-land alongside the spark.

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

* docs(design): OOBE — soften the conjure/spark effect

Dial the spell-cast reveal back to a subtle shimmer:
- Thinner spark stroke (2.6 -> 2.1) with a softer drop-shadow (3/8px -> 2/5px).
- Lower glow alpha (dark .85 -> .62, light .5 -> .4).
- Gentler spell-land pulse (24px/.85 -> 14px/.4).
- Calmer conjure: less blur (7 -> 4px), smaller scale-up (.84 -> .92) and
  near-zero overshoot.

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

* docs(design): OOBE spark — smooth continuous tapered comet

Replace the segmented SVG dash with one intact line:
- Technique: a conic-gradient comet masked to the border ring and rotated
  (transform repaints reliably, unlike an animated conic angle) — gives a
  single continuous line with a smooth head-to-tail taper.
- Transparency: color-mix bakes translucency into the color line
  (head ~86%, fading to fully transparent at the tail).
- Faster: 0.5s -> 0.4s lap.

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

* docs(design): OOBE — clean up the task card layout & styling

Restyle the automation cards after the "Your availability" reference pattern:
- Hierarchy: the task title now leads the header (icon + bold title, status
  badge top-right); the app name drops to a muted "From Gmail · 2m ago"
  provenance line above the actions.
- Buttons: filled primary + text secondaries (Approve / Modify / Dismiss)
  instead of three bordered buttons; Cancel -> Dismiss.
- Surface: larger radius (13 -> 16px), more padding, a soft floating shadow,
  a middot-separated metric line, and bottom-aligned action rows so equal-
  height cards line up. Spark/conjure ring radii follow the new corner.

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

* docs(design): OOBE cards — real brand logos, drop the tag, condense

- Real product logos (Gmail, Google Calendar, Docs, Drive, Slack full-colour;
  Notion + GitHub monochrome via currentColor so they follow the theme) replace
  the placeholder line icons — on the task cards, connect pills, Thread card,
  and Plan list. Icon chips become tile-less logo holders (no tint/border).
- Remove the status tag/badge from the task-card header (state still reads from
  the action row).
- Condense card height (padding 14->12, tighter header/prov gaps; single-line
  titles now that the badge is gone) and scale the button row down
  (height 32->28, smaller padding/font).

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

* docs(design): OOBE — consistent card buttons, real Notion mark, task drawer

1. Link buttons carry icons in both modes: suggested-mode Modify/Dismiss now
   get the edit / close icons, matching the completed-mode Modify/Revert.
2. Notion logo swapped to the real Notion mark (notebook + N, monochrome via
   currentColor so it follows the theme) instead of the plain geometric N.
3. Task drawer: typing in the composer collapses the full task cards into a
   condensed, scrollable pill row (brand logo + title) above the composer;
   clearing the field — or tapping a pill — re-expands. Same control can seed
   suggested tasks for a returning user / new thread.

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

* docs(design): OOBE — Vision/Foundational versions + attached task drawer

Add a Version switch (toolbar) with two design tracks:

Vision (north-star): the task cards now sit in a bordered "drawer" frame that
docks onto the composer and extends up from it, cards inset within the frame.
The drawer header carries collapse/expand (cards <-> pills) and a dismiss (X)
that hides it behind a "Show suggestions" restore bar. Typing still collapses
to pills. Keeps the connect flow, named greeting, and full mode set.

Foundational (near-term, v2-faithful): scoped for a multi-tenant enterprise
deploy — tools are admin-preconfigured so there's no connect step; no username
unless derivable (nameless greeting + blank account chip); agent modes scoped to
Suggest / Plan / Auto Approve, default Suggest. Uses main's composer and the
plain pills-collapse from the prior commit (no bordered drawer).

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

* docs(design): OOBE — Foundational cards at first step, Vision status line above drawer

1. Foundational first run is now a single populated state: because enterprise
   tools are admin-preconnected, the suggested task cards appear at the first
   step (no empty cold start, no beat scrubber).
2. The branded progress indicator + agent activity string move ABOVE the drawer
   (a relocated status line); the drawer header now carries the subtitle
   top-left ("Approve to run, or tweak first") beside the collapse/dismiss
   controls. Applies across both versions; the frame remains Vision-only.
3. Auto Approve description clarified: auto-approves task types already approved
   plus any task the user requests.
4. Rewrote docs/design/oobe.md to document the Vision/Foundational split,
   Foundational enterprise scoping, the reusable task drawer, and phasing.

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

* docs(design): OOBE — corner-X dismiss, empty-state fallback, drawer title = agent string

- Per-item dismiss: the "× Dismiss" link is gone; each task card gets an X in
  its top-right corner and each collapsed pill gets an X on the right. Dismissed
  items are removed from the strip/pills.
- Empty state: when every suggestion is dismissed, a dashed fallback appears —
  Vision "Coming up with new suggestions" (pulsing), Foundational "Find new
  suggestions" (tap to repopulate).
- Removed the drawer-level dismiss X and the restore bar (dismissal is per-item
  now); the drawer header keeps only the collapse/expand toggle.
- Removed the branded NEAR progress indicator on both versions; the agent
  activity string ("Looking for things to suggest" / "Suggested for you") is now
  the drawer title (upper-left) with the subtitle beneath it. Hidden when collapsed.
- Toggle is pinned top-right and floats above the pills (bg fade + padding) so it
  no longer covers an overflowing pill.
- Foundational is steppable again (scrubber restored) with suggested cards from
  the first step; revert now returns a card to suggested.

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

* docs(design): OOBE — keep drawer title + subtitle on one line

Revert the drawer header to a row layout so the agent string and its subtitle
("Suggested for you  Approve to run, or tweak first") stay inline on a single
line instead of the subtitle reflowing to a second line.

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

* docs(design): OOBE — Foundational approve→automate→complete journey, Modify modal, attachment collapse

1. Foundational now steps through a real flow: beat 0 suggested → approve →
   beat 1 "Automating…" (spinner) → beat 2 completed, repeating for the next
   task, ending all-done. Adds a `running` card state; clicking Approve (either
   version) animates suggested → Automating… → completed (~1s). Drawer title
   tracks the state (Suggested for you / Automating… / Done for you).
2. Attachment collapse: adding an attachment (the composer + button, with a
   removable chip) now collapses the drawer to pills too — alongside typing.
3. Modify opens a modification modal (both versions): title = task name, an
   "adjust before it runs" field, Cancel / Save changes; backdrop over the app.

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

* docs(design): OOBE — state-aware card copy, tighter composer gap, pill tap expands

1. Cards/pills now carry both a suggested (proposal) and completed (result)
   phrasing and switch on state: e.g. "Triage your inbox · 40 unread · 12 need
   replies · From Gmail" while suggested, "Triaged your inbox · 12 replied · 40
   archived · From Gmail · 2m ago" once done. Fixes suggested cards reading as
   already-completed (both versions).
2. Halved the gap between the cards/pills and the composer (Foundational).
3. Tapping a collapsed pill now expands it back to the full task cards (both
   versions); typing/attaching re-collapses (suppression flag so a tap-to-expand
   isn't immediately re-collapsed by lingering composer text).

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

* docs(design): OOBE — 3rd-party auth flows (queued OAuth modal)

Add a reusable modal "browser" OAuth dialog (chrome bar + provider domain,
sign-in account chooser, consent/scopes, Allow) wired into both tracks:

- Vision: the connect panel now *selects* tools; the Connect button opens the
  dialog queued across the selection (sign in once, approve scopes per tool)
  until all are authorized, then advances.
- Foundational: tools are admin-whitelisted but user-authorized — each task card
  starts unconnected with a "Connect <Tool>" CTA; connecting runs the dialog and
  the card becomes an actionable suggestion. Beat journey now walks
  unconnected → connected(suggested) → automating → completed.

Brief updated to match (Foundational connect model + Vision OAuth queue).

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

* docs(design): OOBE — refresh the 5 suggested/automated tasks

Replace the 3 sample cards with the intended task set (both versions):
1. Email triage — archive marketing to "IronClaw Archive", flag urgent (Gmail)
2. Calendar — accept free invites, propose times for conflicts
3. Build your profile — read activity across Gmail/Slack/Telegram (multi-tool)
4. Catch-you-up 24h digest — org summary, flag replies, propose priorities
   (Drive/Notion, multi-tool)
5. Suggest 5 automations — agent drafts its top-5 to approve (no external tool)

Cards now carry a short description line (suggested proposal vs completed
result) instead of the number pairs, custom glyphs for the agent/meta tasks,
and a per-card `conn` tool list so the connect CTA queues the right OAuth
dialogs ("Connect 3 tools" → Gmail→Slack→Telegram). Added a Telegram brand
logo + auth metadata; Foundational beat table + greeting updated for 5 cards.

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

* docs(design): OOBE — match collapsed-pill bottom gap to the task-card gap

The pill row carried 6px bottom padding vs the card strip's 2px, so the pills
sat ~4px farther from the composer. Reduce the task-drawer bottom padding to
match the strip (4px base, 2px Foundational) — pill and card bottoms now sit the
same distance above the composer.

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

* docs(design): OOBE Vision — connect banner confirms then dismisses after auth

After the user authorizes their selected tools through the OAuth queue, the
"Connect your tools" banner flips to a confirmation state — green check icon,
"Tools connected · N authorized", the connected tools shown green, close-X
hidden — then dismisses (~1.3s) as the flow advances to the working/anticipatory
beat. Beat 1 is now that confirmation moment (also reachable via the scrubber).

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

* docs(design): OOBE Foundational — section-level dismiss X for cards + pills

Add a drawer-level close (X) pinned top-right of the suggestions section,
visible in both the expanded task-card state and the collapsed pill row
(Foundational only — Vision keeps its collapse toggle there). Dismissing hides
the whole drawer and drops a "Show suggestions N" restore bar above the
composer; restoring brings it back. Per-item × on each card/pill is unchanged.

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

* docs(design): OOBE Foundational — align the section dismiss X in both states

Center the drawer dismiss X on the "Suggested for you" header (expanded) and on
the pill row (collapsed) via a state-specific top, and move it flush to the
right edge of the card/pill container + composer (right 11px -> 2px). Verified
dy=0 in both states.

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

* docs(design): OOBE — dismiss-X container masks against the real background

The dismiss X used --v2-surface (white) for its fill + left fade, but the pills
sit on --v2-canvas, so pills bled through the gradient. Switch the X container
fill and its left-fade shadow to --v2-canvas so it matches the background behind
the pills — overflowing pills now fade cleanly into the bg (masking effect),
gradient retained. Verified fill == scene bg in light and dark.

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

* docs(design): OOBE Foundational — collapsed dismiss becomes a full-height gutter mask

In the collapsed pill state the dismiss control is no longer a small rounded
square: it fills the drawer height, pins flush to the right edge, and carries a
transparent->canvas gradient so pills fade out and aren't visible past it. The X
sits centred in the gutter. Expanded (cards) keeps the header-aligned X.

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

* docs(design): OOBE Foundational — move "Show suggestions" restore into the composer

Replace the restore bar above the composer with a pill inside the composer, to
the right of the agent-mode selector (reusing the connect-pill style). Tapping
the pill body restores the dismissed suggestions drawer; the pill's X fully
dismisses it (new 'gone' state — drawer and pill both hidden). Removed the dead
restore-bar markup + CSS.

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

* docs(design): OOBE integration proposal & plan — Foundational + Vision phasing

Add a #6918-style proposal package under docs/design/oobe/ (README / PROPOSAL /
PLAN / CHECKLIST) for phasing the OOBE prototype into production:

- Foundational (near-term, ships on current main) then Vision (north-star),
  matching the mockup's two versions; every Vision piece a superset of a
  Foundational one, so nothing is redone.
- Scopes Foundational as shipped-vs-net-new: the connect CTA, busy states,
  agent-mode semantics, and manage-result surface all REUSE code on main
  (extension-auth path, NearProcessIndicator, resolve_gate/global_auto_approve,
  pages/automations); the net-new surface is the card family, the
  AutomationTask events+projection+routes+facade, and the first-run suggestion
  producer.
- Inventories dependencies D-F1..F6 (Foundational) and D-V1..V5 (Vision), each
  with an implementation approach, and maps the work onto the five-layer WebUI
  flow and the #6918 target families.
- Applies the APDD governance kit (docs-first workflow, Feedback & Decisions
  anchor, Critical Bug Fix Log, design track, CUJ baseline).

Companion human-review artifact (schematics/diagrams):
https://claude.ai/code/artifact/734b1b6a-e35d-4736-9ac2-952dcdf84ab4

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

* docs(design): reconcile OOBE proposal + contract to post-#6918 family names

The #6918 family-folder reorg has landed on main; update the proposal package
and the wiring contract to current crate names/paths and fix a stale claim:

- crates now under crates/{contracts,events,domains,product,app}/; renames
  ironclaw_events -> ironclaw_event_log, add ironclaw_event_store (both under
  events/), ironclaw_reborn_composition -> ironclaw_composition, and the webui
  frontend paths move to crates/product/ironclaw_webui/frontend/.
- correct the facade identity: it is RebornServicesApi in
  crates/product/ironclaw_assistant (NOT "ProductSurface" — that is the typed
  capability contract/DTOs in ironclaw_product_contracts).
- reframe "#6918 target families" as the family folders now on main.
- note the triggers-hosted suggester option (D-F2) can reuse the existing
  composition automation wiring (trigger_poller + trusted_submit).
- retire the removed .claude/rules/tool-evidence.md reference -> gateway-events
  / lifecycle; product adapters -> the ProductAdapter surface in ironclaw_host_api.
- mark the F0 merge-to-main + contract-reconciliation boxes done.

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

* Roll back the OOBE prototype code; reposition PR as design artifacts + plan

Per review (IronLoop/CodeRabbit flagged mock automations shown to real users and
an autonomy selector execution ignored), drop the prototype source and make this
branch code-free: crates/ is now identical to main.

- Revert the edits to shipped files (app.tsx, chat-input, empty-state, en.ts,
  button/icons + their tests) and delete the added prototype files (automation
  cards, action bar, mode selector, data seam, hooks, design-preview harness).
- Move AUTOMATION-TASKS-CONTRACT.md out of the code tree into docs/design/oobe/
  (kept as the design reference / proposed wiring).
- Plan of record is now the artifacts + the written plan: add
  docs/design/oobe/integration-review.html (the "IronClaw OOBE — Integration
  Review" page) in-branch, and repoint the former claude.ai artifact links to it
  (rendered via html-preview.github.io).
- Reconcile the package (README/PROPOSAL/PLAN/CHECKLIST/brief + contract): a
  code-free banner, fix links to rolled-back files, and reframe "the prototype
  ships here / mock->fetch swap" as "prototyped earlier + demonstrated in the
  mockup; the first implementation builds fresh." D-F5/D-F4 gating moves to the
  implementation PRs.

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

* docs(design): OOBE mockup — align the Foundational version to shipped v2

The mockup's design tokens already match crates/product/ironclaw_webui/src/styles/app.css
verbatim; this aligns the Foundational version's *treatment* to the shipped
WebChat v2 landing:

- hero switches from the serif exploration face to Geist sans, heavier and larger
  (matching empty-state.tsx's text-4xl/6xl font-semibold hero);
- suggestions become full-width divider rows with a round leading icon (matching
  the shipped grid-cols-[auto_1fr_auto] row treatment) instead of pill chips;
- composer picks up the shipped 20px radius + card-bg + round icon buttons.

All scoped to .v-foundational so the Vision (north-star) version keeps its
distinctive treatment. CSS validated (balanced); in-app browser CDP was wedged,
so verify visually via html-preview.

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

* docs(design): OOBE mockup composer — match main (remove mic, round send, larger, full-width suggestions)

Correct the composer to the shipped chat-input.tsx:
- remove the microphone/dictate button (main has none);
- send button becomes a round primary icon button (paper-plane), replacing the
  labeled "Send ⌘↵" pill, matching Button variant="primary" size="icon-sm" rounded-full;
- enlarge the Foundational composer (min-height 120, 15px field, roomier padding)
  to match main's min-h-[120px] hero composer;
- the suggestion rows below the composer now span the full composer width
  (width:100% on .v-foundational .suggs — they were shrink-to-fit + centered).

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

* docs(design): OOBE mockup — apply composer button treatment to Vision too

The mic-removal and round send-button were already global; the round attach
icon button was still Foundational-scoped, leaving Vision's composer with a
square attach. Make the icon-button treatment global (round, 36px) so the
Vision flow's composer reflects the same Send / attach / no-mic design as
Foundational and main. (Composer *sizing* stays Foundational-scoped — Vision
docks its composer onto the drawer.)

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

* docs(design): OOBE CHECKLIST — adopt epic #7044 success criteria

Additive only: add the epic's Phase-1 success criteria (time-to-first-automation,
first-session activation, suggestion quality) to the Foundational exit gate. No
other plan content changes — the proposal package stays the plan of record; the
epic↔proposal scope conflicts are reconciled in #7044, not here.

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

* docs(design): OOBE Phase-1 (v1) UX update — 6 changes wired to shipped backend seams

Mockup (Foundational-scoped; Vision mock unchanged):
- remove the agent-mode selector (kept in Vision) [1]
- disable the other cards while one job runs [3]
- replace Revert with "+ Automation" (creates a scheduled automation) [4]
- v1 = connect + approve UI, no background jobs [5]
- drop Modify; show completed / error-incomplete status on the card [6]

PROPOSAL: new §2A "Phase 1 (v1) implementation update" specifying how each change
wires to EXISTING backend seams (verified on main) — no new AutomationTask
events/projection needed for v1:
- approve -> POST /threads/{id}/messages (submit_turn -> TurnCoordinator), run in thread [2]
- status/activity -> existing WebChatV2Event stream (running/capability_activity/final_reply/failed)
- one-active-run -> submit_turn DeferredBusy/RejectedBusy
- connect -> extension setup/OAuth + AuthRequired frame
- "+ Automation" -> prompt injection -> builtin.trigger_create -> automations dashboard
- gates -> resolve_gate

Also: fix doc link depth after main renamed docs/design -> docs/internal/design.

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

* docs(design): OOBE Foundational v1 — implementation plan grounded in current main

Add IMPLEMENTATION.md: a concrete build plan for the Phase-1 v1 UX (PROPOSAL §2A),
proving every card action wires to seams already enabled on main and enumerating
the frontend components, the feature-flag gating (the D-F5 merge-safety fix), the
vertical PR slices, and the tests.

Verified-enabled on main: submit_turn via lib/api.ts sendMessage; status via
useChatEvents (folds WebChatV2Event frames → running/final_reply/failed); connect
via extension-pairing-api + AuthRequired; resolve_gate; automations dashboard +
useAutomations; builtin.trigger_create; session feature flags (app/auth.ts
features?.). The one net-new backend piece is the first-run suggestion producer
(D-F2) — slices 1–5 ship frontend-only behind an off-by-default flag; the flag
flips on only when the producer lands. No new AutomationTask events/projection.

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

* feat(webui): OOBE Foundational v1 slice 1 — feature-gated SuggestedTaskCard

First implementation slice of the OOBE Foundational v1 (docs/internal/design/oobe
PROPOSAL §2A / IMPLEMENTATION.md). Presentational + gated only — no backend
wiring, no mock data reachable by real users.

- SuggestedTaskCard: one action row per state per §2A — unconnected→Connect,
  suggested→Approve (no Modify), running→NearProcessIndicator, completed→Completed
  chip + "+ Automation" (no Revert/Modify), failed→"Couldn't complete" + Try again;
  `locked` disables the card (item 3). Pure/presentational (callbacks are props).
- SuggestedTaskSurface: reads the `oobe_suggestions` deployment flag via a shared
  ["session"] query and renders null when off (landing unchanged for real users);
  renders a static demo list only when on. Mounted in empty-state above composer.
- auth.ts: `oobeSuggestionsEnabled` + downstream `useOobeSuggestionsEnabled()`
  (no extra session fetch), off by default.
- i18n: 15 chat.oobe.* keys across all 11 locales (parity).
- Tests: per-state card tests + surface gating tests. Frontend gate green
  (pnpm lint clean; pnpm test 1252 passing).

Later slices wire Approve→submit_turn, Connect→extension setup, +Automation→
trigger_create, and the real suggestion feed; the flag stays off in prod until then.

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

* docs(design): reconcile OOBE package — implementation restarted behind a flag

Slice 1 landed real (gated) code on this branch, so the "code-free" framing is
retired: README status + banner, PROPOSAL banner, CHECKLIST F0, and PLAN now say
implementation is underway behind the off-by-default `oobe_suggestions` flag
(slice 1 gate-green). Add IMPLEMENTATION.md to the README doc index.

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

* feat(webui): OOBE v1 slice 2 — Approve a suggested card runs a foreground turn

Wire the card's Approve to the existing send path (PROPOSAL §2A change 2):
approving submits the task's `approvePrompt` through chat.tsx `handleSend`
(display content = the card title), so it runs as a real foreground agent turn
and the thread streams the activity by reuse — no new event/backend code. The
approved card flips to `running` optimistically; its live completed/failed
status arrives via the thread in a later slice (persistent drawer).

- SuggestedTask: add required `approvePrompt`.
- SuggestedTaskSurface: `onApproveTask` prop + `runningId` state (hook before the
  flag early-return); each card wires approve → setRunningId + onApproveTask.
- empty-state/chat.tsx: thread `onApproveTask` down; chat.tsx adds only
  `handleApproveTask` over the existing `handleSend` (gates/nav untouched).
- Tests: approve reports the task + flips it to running; empty-state forwards the
  prop. Still gated off by default. Gate green (pnpm lint clean; 1254 tests).

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

* docs(design): OOBE IMPLEMENTATION — mark slices 1–2 landed; split 2b (live card status)

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

* feat(webui): OOBE v1 slice 4 — "+ Automation" schedules via prompt injection

PROPOSAL §2A change 4. On a completed suggested card, "+ Automation" submits the
task's `automationPrompt` through the existing `handleSend` (display content
"Set up automation — <title>"), so the agent creates a scheduled automation via
`builtin.trigger_create` (prompt injection — no REST create). The card flips to
an "Automation scheduled" chip optimistically. Mirrors the slice-2 approve wiring.

- SuggestedTask: add required `automationPrompt`.
- card: `scheduled?` prop → completed shows a scheduled chip instead of the button.
- surface: `onAutomationTask` prop + `scheduledId` state; +Automation → set + submit.
- empty-state/chat.tsx: thread `onAutomationTask` down; chat.tsx adds only
  `handleAutomationTask` over the existing `handleSend`.
- i18n: `chat.oobe.status.scheduled` across all 11 locales.
- Tests for the scheduled chip + the +Automation wiring. Gated off by default.
  Gate green (pnpm lint clean; 1257 tests).

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

* docs(design): OOBE IMPLEMENTATION — slice 4 landed; slice 3 (Connect) deferred w/ reason

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

* feat(webui): add oobe_suggestions server feature flag so deployments can enable the OOBE cards

Mirror of the reborn_projects flag: GET /session now emits
features.oobe_suggestions, read from the IRONCLAW_OOBE_SUGGESTIONS env var
(default off). The frontend already reads session.features.oobe_suggestions
(slices 1/2/4), so setting IRONCLAW_OOBE_SUGGESTIONS=1 on a deployment (e.g. the
Railway PR preview) turns the first-run suggestion cards on; unset everywhere
else they stay hidden.

- webui_serve.rs: oobe_suggestions_enabled() env read + builder wiring.
- webui_v2/router.rs: WebUiV2State field + with_/getter.
- webui_v2/handlers.rs: WebUiV2Features.oobe_suggestions + get_session literal.
- test: get_session_reports_oobe_suggestions_feature_from_state_flag (drives the
  real router, asserts features.oobe_suggestions mirrors the state flag).

Note: no Rust toolchain in this environment — cargo check/clippy/test not run
locally; CI + the Railway build compile it. Change is a mechanical mirror of an
existing, passing flag.

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

* fix(webui): OOBE — close the /chat bundle-budget CI failure

The "Initial /chat JavaScript (gzip)" budget (check-bundle-budgets.ts,
219.0 KB) failed at 220.6 KB after slices 1/2/4 landed, because
suggested-task-surface.tsx (+ its card + demo data) was imported eagerly from
empty-state.tsx. Not caught by pnpm lint/test — it's a separate CI job
(WebUI v2 JS lint) this PR's frontend gate never ran locally.

Three-part fix, in order of diminishing-but-real savings:

1. Lazy-load the surface: `React.lazy(() => import("./suggested-task-surface"))`
   + `<Suspense fallback={null}>` in empty-state.tsx, mirroring the existing
   CommandResult/AttachmentPreviewModal pattern in message-bubble.tsx.
   (220.6 -> 220.0 KB — smaller gain than expected, see #2.)
2. Hoist the `useOobeSuggestionsEnabled()` flag check OUT of the lazy module
   into empty-state.tsx (already-eager): the hook's own import (app/auth.ts ->
   api.ts/auth-scope.ts) was already eager-reachable elsewhere, so calling it
   from inside the lazy chunk too forced the bundler to extract those modules
   into their own less-efficient standalone chunks. suggested-task-surface.tsx
   is now purely presentational; empty-state.tsx decides whether to even mount
   the lazy import. (220.0 -> 219.3 KB.)
3. Same fix for NearProcessIndicator: suggested-task-card.tsx no longer imports
   it directly (also already-eager via typing-indicator.tsx); empty-state.tsx
   passes a `renderRunningIndicator` render-prop down through the surface to
   the card instead. (219.3 -> 219.2 KB.)

The remaining 0.2 KB is irreducible: gating the lazy-import decision and the
flag-read hook must live in the eager /chat closure. check-bundle-budgets.ts's
own history shows this is the established path for a legitimate net-new
eager cost — CHAT_GZIP_BUDGET raised 219.0 -> 220.0 KB with the same
documented-rationale-comment convention as every prior increase in that file.

Verified: pnpm build clean; check-bundle-budgets.ts passes (login 134.3 KB/
45.7 KB headroom; /chat 219.2 KB/0.8 KB headroom; largest chunk 435.4 KB raw/
64.6 KB headroom); pnpm lint clean; pnpm test 141 files / 1260 tests, all green.

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

* feat(webui): OOBE v1 slice 5 (partial) — lock other cards while one job runs

PROPOSAL §2A change 3: only one suggested job may run at a time. The card
already supported a `locked` prop (slice 1, disables connect/approve/automation
+ dims the card); the surface just wasn't computing it. Now every card other
than the one actively running gets `locked={runningId !== null && runningId
!== task.id}` — the acting card itself stays interactive so its own
running/completed state remains visible.

Test generically discovers whichever card the vm-harness surfaces (its
componentProps helper collapses a mapped list to the last instance's props, so
the test asserts relative to a discovered task id rather than a hardcoded demo
id) and checks all three states: idle (unlocked), a different card running
(locked), the card itself running (unlocked).

The other half of slice 5 — a live `failed`-frame error/incomplete status —
depends on slice 2b's useChatEvents wiring (not yet landed) and stays open.

Gate green: pnpm lint clean; pnpm test 141 files / 1261 tests; pnpm build +
check-bundle-budgets.ts still pass (219.2 KB / 0.8 KB headroom, unchanged —
logic-only change, no new eager weight).

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

* docs(design): OOBE IMPLEMENTATION — slice 5 half-landed (lock done; failed-status blocked on 2b)

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

* docs(design): OOBE IMPLEMENTATION — retire slice 2b, mark 5 done

2b assumed the surface needed to persist into the thread view for live status.
Traced chat.tsx: EmptyState/MessageList are mutually exclusive (showLanding
ternary) — EmptyState fully unmounts on navigation into a thread, so a
persistent drawer would duplicate the thread's own event/message rendering and
import Vision's docked-drawer architecture into Foundational. The correct
model (already delivered by slices 1/2/5): the card gives instant local
feedback pre-navigation; the thread owns live status once the user is in it.
Card-persistent status for a *returning* user needs a durable record, which is
slice 6's scope, not a new frontend slice.

Also: mark slice 5 fully landed for what's achievable (the lock); the
failed-status half is resolved by the 2b finding, not blocked.

Slice 3 (Connect): recorded the useExtensions() investigation — page-level
hook, no isolated connect primitive; recommend extracting one first.

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

* feat(webui): OOBE v1 slice 3 — Connect reuses the real setup/OAuth modal

An unconnected suggested card's Connect now resolves its `app` to a real
catalog extension and opens the EXISTING extensions setup/OAuth modal
(configure-modal.tsx), rather than cloning the connect flow:

- New pure resolver `pages/chat/lib/connect-extension.ts` maps a card's `app`
  id -> a real `useExtensions()` catalog entry, returning the `configurePayload`
  shape ConfigureModal expects (packageRef + displayName). Tolerant matching
  (normalized, containment) bridges static demo ids and live package refs;
  prefers installed over registry; returns null (no modal) when nothing matches.
- `suggested-task-surface.tsx` calls `useExtensions()`, tracks the connecting
  task + connected ids, and React.lazy-loads ConfigureModal so its OAuth
  watcher/state-machine weight lands in a lazy chunk (eager /chat unchanged at
  219.3 KB, 0.7 KB headroom). Successful save flips unconnected -> suggested;
  an unresolvable app shows a plain notice instead of a dead button.
- New i18n key `chat.oobe.connectUnavailable` across all 11 locales.

Why reuse, not reimplement: useOauthSetup is a ~250-line page-level state
machine keyed on a real packageRef + secret descriptor, not an extractable
helper — cloning its popup/polling/error-mapping would duplicate it and risk
bugs. Driving the one real path keeps OOBE connect and the extensions page in
lockstep.

Tests: connect-extension.test.ts (6, pure) + 4 new surface vm-tests. Full gate
green: pnpm lint, 1271 tests, build + bundle budgets. The live OAuth popup
round-trip is the only uncovered part (needs a real third-party consent grant)
— to be walked in browser QA.

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

* docs(design): OOBE mockup — reconcile provenance note with shipped Foundational v1

The mockup's Foundational flow already matches the shipped SuggestedTaskCard
(found-gated Connect / Approve-only / "Working — activity in the thread" /
Completed + "+ Automation" / "Couldn't complete", single-active lock, no
Modify/Revert, no agent-mode selector). Only the footer provenance note was
stale — it described the retired prototype (AutomationCarousel,
AutomationTaskCard, TaskActionBar Approve/Modify/Cancel · Modify/Revert, agent-
mode pill) as "built".

Updated the note to the actual branch state: SuggestedTaskCard +
SuggestedTaskSurface behind the off-by-default oobe_suggestions flag; the
server flag (IRONCLAW_OOBE_SUGGESTIONS -> /session features.oobe_suggestions);
Approve/+Automation via the existing chat send path; Connect resolving to a
real catalog extension and opening the existing ConfigureModal (no cloned OAuth);
NearProcessIndicator reuse. Carousel/TaskActionBar/agent-mode/Calendar/Plan are
now correctly labeled Vision-only (not built). Backend suggestion producer
(#6993, slice 6) called out as the remaining net-new piece + prod gate.

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

* refactor(webui): retarget OOBE to Vision on the durable suggestions contract (#7694)

Foundational is cut. PR #7694 shipped the durable backend suggestions contract
— the agent-driven producer this package had classified as Vision-tier — so
#6994 becomes its frontend consumer and the static demo model is replaced by
real data.

Docs:
- New VISION-RECONCILIATION.md (governs): what #7694 grants (V2 reveal, V3
  anticipatory states, live card status), the connect-model conflict and its
  resolution, superseded sections, and the keep/change/delete refactor map.
- Marked superseded: PROPOSAL §2/§3.1 P3/§3.2 N3-N5/§4 V1/§2A.3,
  AUTOMATION-TASKS-CONTRACT §§1-3 (events/projection -> typed ScopedFilesystem
  store), IMPLEMENTATION (historical), README (scope retargeted).

Frontend:
- suggestions-api.ts: typed client over the four routes (list/generate/start/
  dismiss) mirroring RebornSuggestion; pollDelayMs clamps the backend retry
  hint so a missing/hostile value can't hot-loop or stall.
- useSuggestions.ts: react-query owner. Polls only while status=generating, at
  the backend's cadence. Generation is never automatic — it costs a model run,
  so `empty` renders a CTA.
- Surface consumes real state: empty -> CTA, generating -> anticipatory
  indicator (V3), ready -> cards, failed -> retry. An existing set survives
  regeneration rather than blanking.
- Approve now calls POST /suggestions/{id}/start; the backend creates the
  thread/run and returns the binding, and the browser navigates to it. No more
  prompt injection through the composer.
- Cards are tool-agnostic: the backend schema carries no app identity and its
  generator is instructed not to assume capability availability, so the
  connect card-state, resolveConnectExtension, and ConfigureModal wiring are
  removed. Connect re-homes to its own catalog-driven surface (V1).
- A started card keeps its durable thread binding and offers "View in thread".
- i18n reduced to the 9 keys actually used, parity across all 11 locales.

Deferred with the contract: "+ Automation" (no backend field/route) and live
run-derived card status (its own slice, now buildable via the bound run_id).

Gate: pnpm lint clean, 1265 tests / 142 files pass, build + bundle budgets pass
(/chat 219.1 KB, down from 219.3).

Cannot QA against a preview yet: #7694 targets native-structured-output, not
main, so the routes are not deployed. Built against the frozen DTOs.

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

* docs(design): Vision-only — parallel cards, remove +Automation, excise Foundational

Per the retarget decisions:
- Cards run in parallel: the single-active lock is gone (each suggestion starts
  its own thread — no backend constraint to reflect). VISION-RECONCILIATION §4.1
  is now a decision, not an open question.
- "+ Automation" removed (no field/route in the shipped contract) — dropped from
  the card, not deferred. §4.2 decided.
- VISION-RECONCILIATION open questions trimmed to the three still open
  (AuthRequired verification, agent modes, replacement UX).

Docs swept for stale references: PROPOSAL/IMPLEMENTATION banners now enumerate
the reversed decisions and mark the bodies historical; README status +
"what this proposes" rewritten to Vision (connect is a separate surface;
approve → start-thread → navigate); oobe.md brief retargeted.

mockup.html: removed the Foundational/Vision toggle and all Foundational scope
— version pinned to Vision, isVision/found branches collapsed to the Vision
path, FOUND_BEATS/FOUND_CAP/HERO_FOUND/CAP_FOUND/MODES.foundational deleted,
.v-foundational CSS + is-locked + item-N comments removed, footer rewritten to
describe the #7694 contract (icon + source_ids, parallel cards). Script
re-verified with `node --check`.

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

* feat(webui): brand icons for suggestion cards (icon + source_ids)

The #7694 author is adding `icon` (brand-icon enum) and `source_ids` (related
extension ids) to the card schema. Build the frontend mapping ahead of it:

- brand-icons.tsx: BrandIconId enum (mirrors the extension-package namespace),
  iconIdForSource() (source-id → icon), resolveIconId() (prefer explicit icon,
  else derive from source_ids[0], else `generic`), and <BrandIcon>. Colored
  marks reuse the license-clean inline SVGs already committed in the OOBE
  mockup; sheets/slides/web/memory/generic are neutral in-house glyphs. Lives in
  the lazy surface chunk — /chat stays 219.1 KB.
- Suggestion type gains optional icon + source_ids; the card renders the
  resolved brand mark. All optional, everything degrades to `generic`, so the
  card is correct before the backend field lands.
- SUGGESTION-ICONS.md: the enum, JSON-schema block, suggested Rust
  SuggestionIconId, and the icon↔source_ids derivation note for the #7694
  author. Records that icon/source_ids reverse the connect-conflict premise;
  connect stays decoupled but per-card connect is reopened as a review question.

No web scraping: assets are in-repo or in-house; brand marks are nominative-use.

Tests: brand-icons.test.ts (13) + a card BrandIcon test. Full gate green:
lint, 1273 tests, build + bundle budgets.

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

* fix(webui): reconcile OOBE frontend to the shipped #7694 contract

#7694 (durable backend suggestions) + #7693 (native structured output) landed
on main and are now merged into this branch — the /api/webchat/v2/suggestions
routes and the RebornSuggestion contract are present here. Reconcile the
frontend to the shipped shape:

- Field is `sources` (1-5 human-readable tool names, for display), not
  `source_ids`. Rename on the Suggestion type.
- `icon` is REQUIRED and enum-constrained, and its values are byte-identical to
  the enum this branch proposed (gmail..generic). It is the authoritative icon
  source. `resolveIconId` now trusts `icon` directly (→ generic fallback) and no
  longer derives from sources (those are free-form display names, not ids) —
  which also removes any icon↔sources drift. Dropped the obsolete
  iconIdForSource/SOURCE_TO_ICON extension-id mapping.
- Docs updated to shipped reality: SUGGESTION-ICONS.md (proposal → shipped
  reference), VISION-RECONCILIATION §3/§5.2/§6.4 (sequencing resolved; source_ids
  → sources; icon authoritative).

Everything else already matched the shipped contract exactly: routes, the
status enum (empty/generating/ready/failed), and the generate/start/dismiss
DTOs.

Gate green on the merged tree: lint, 1362 tests / 162 files, build + bundle
budgets (/chat 221.5 KB under the 222 budget — OOBE stays lazy).

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

* feat(webui): OOBE suggestion surface — Vision polish (drawer, skeleton, reveal, provenance)

Closes the visual gap against the Vision mockup for the affordances that need
no new backend; tracks the rest as follow-ups (VISION-RECONCILIATION §5.1).

- V4 docked drawer frame: the surface now renders as a bordered drawer with a
  "Suggested for you · approve to run, or tweak first" header, docked close to
  the composer (empty/failed CTA states stay frameless). Composer gap tightened
  only when the flag is on, so the non-OOBE landing is byte-unchanged.
- V3 anticipatory beat: the generating state shows the branded NEAR indicator
  over static `.v2-skeleton` tiles instead of a lone line of text.
- V2 reveal: cards get a restrained `.oobe-card-reveal` entrance — reuses the
  sanctioned `v2-page-in` keyframe with a class-selector + !important exception
  and prefers-reduced-motion suppression, per the app.css motion policy (NOT the
  mockup's ad-hoc conic ai-spark sweep, which would bypass the policy).
- Card provenance: renders the suggestion's `sources` as a "From <tools>" line
  (formatSources joins the human-readable names). Modify stays dropped.
- i18n: chat.oobe.subtitle + chat.oobe.from across all 11 locales.

Deferred/tracked follow-ups (not built): live card status (slice 7), V1 connect
panel (slice 8), agent-mode selector, pills-collapse-on-typing, and the named
greeting + client username call-out in the header (V5, per review).

Gate green: pnpm lint, 1366 tests / 162 files, build + bundle budgets (/chat
221.5 KB — all new UI is in the lazy surface chunk, eager route unchanged).

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

* feat(webui): OOBE drawer — close/restore, horizontal strip, subtitle

Interaction polish to match the Vision mockup:

- Subtitle "Approve to run, or tweak first" -> "Approve to run" (11 locales).
- Horizontal scrollable card strip (fixed-width cards, overflow-x with hidden
  scrollbar via .oobe-strip) instead of the reflowing grid — matches the mockup.
- Section close: a × in the drawer header dismisses the whole drawer (distinct
  from per-card dismiss). Drawer-visibility state (open/dismissed/gone) lifted
  to empty-state, wired to the surface via `hidden`/`onClose`.
- Restore pill: a "Show suggestions" pill inside the composer appears once the
  drawer is dismissed; the label reopens it, its × dismisses fully. Lazy-loaded
  (oobe-restore-pill.tsx) so its markup stays out of eager /chat.

Merged latest main (0 behind) first.

Bundle: the close/restore gate + two new eager en.ts keys add ~0.5 KB to the
eager /chat closure (the pill markup and the surface stay lazy); budget bumped
222.0 -> 223.0 KB with documented rationale. /chat measured 222.5 KB.

Tests: +oobe-restore-pill.test.ts, +surface hidden/close tests, +empty-state
drawer/pill tests. Gate green: lint, 1394 tests / 164 files, build + budgets.

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

* fix: keep suggestion icons provider-neutral

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Henry Park <henrypark133@gmail.com>
personal-upstream-sync Bot pushed a commit to theredspoon/ironclaw that referenced this pull request Aug 25, 2026
…system (Epic nearai#7038) (nearai#7257)

* docs(design-system): proposal, plan & checklist for the WebUI design system (Epic nearai#7038)

Benchmarked on the APDD governance kit and the target-crate-architecture package
(PR nearai#6918): a north-star README + RFC PROPOSAL + phased PLAN + CHECKLIST for the
Storybook + design-system catalog initiative under docs/reborn/design-system/.

Captures the five predefined phases (1-2 landed via nearai#7039, nearai#7043; 3-5 planned),
the Native-M3X-not-Material-Web decision, and — per the request — every Phase 3-5
dependency with a proposed implementation (dark palette, contrast, fonts,
animation, CI/Chromium, MSW). Mermaid schematics render on GitHub; an interactive
review artifact accompanies the package.

Docs-only; references the open Phase-1/2 PRs.

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

* docs(design-system): add self-contained explorer.html review page + link it

Rich, self-contained HTML review aid (the claude.ai artifact converted to a
branch file): HTML/CSS schematics — layer map, five-phase flow, dependency
graph — theme-aware with a standalone toggle, no external/runtime deps so it
renders from the branch (or via html-preview) without a build. Linked from the
package README.

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

* docs(design-system): re-home proposal package to docs/internal/reborn/

main relocated docs/reborn -> docs/internal/reborn (nearai#7206-era restructure); move the
design-system proposal package to match and fix the path/depth references (apdd-kit,
target-architecture, explorer html-preview link).

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

* docs(design-system): track the three-Epic split and refresh phase/PR state

Epic nearai#7038 was split into three tracking issues — nearai#7038 (Phases 1-2),
nearai#7781 (Phase 3), nearai#7782 (Phases 4-5). Record that ownership across the
package and correct the phase/PR state it asserted:

- Epic-ownership table in README / PLAN / CHECKLIST; per-phase and per-WS
  Epic attribution; "Tracks:" headers name all three.
- Phase 1/2 are in review, not landed: nearai#7039 and nearai#7043 were closed after
  the stack became unmergeable; Phase 1 is now nearai#7750 (non-stacked off
  main) and the Phase-2 changeset is preserved on nearai#7042. §7.6 merge order
  and the WS1/WS2 boxes updated to match.
- Frontend path refreshed to crates/product/ironclaw_webui/frontend.
- explorer.html: phase pills, chips, eyebrow and footer follow the same.

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

* docs(design-system): re-home Phase 2 under Epic nearai#7781; nearai#7038 is Phase 1 only

Epic ownership changed again: nearai#7038 narrows to Phase 1 (Storybook catalog,
PR nearai#7750), Phase 2 folds in with Phase 3 under nearai#7781, and the older
Phases 2-3 Epic nearai#7733 is closed as superseded by nearai#7781.

- Ownership tables, "Tracks:" headers, PLAN subgraphs, per-phase and
  per-WS attribution all follow the new mapping.
- PLAN Phase 3 gains the ⚠ "Phase 2 lands before Phase 3" constraint now
  that both sit in one Epic; §7.6 re-labelled as the Phase 1→2 gate.
- explorer.html eyebrow, phase pills, and footer updated; nearai#7733 recorded
  as superseded.

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

* docs(design-system): resolve the approach audit — one governance owner, honest state, named owners

Addresses all five findings on PR nearai#7257's approach audit (e11332d).

SP2 — competing governance records. PROPOSAL §9 (new) makes this package
the single canonical owner of `DESIGN.md`, the `--v2-*` token architecture,
the Storybook catalog/test-harness/MCP, and `.claude/rules/design-system.md`,
and states the alternative call explicitly if a reviewer would rather OOBE
own it. The OOBE package now points here instead of proposing the same work:
D-F6 keeps only its pilot role (the card family is catalogued *through* this
system) across its PROPOSAL §5.6/§8.3/§10.5/§11, README, PLAN F5 and
CHECKLIST F5.

ST3 — unresolvable references. The APDD kit is external and not vendored;
it is described as such rather than linked at `../../../../apdd-kit`. Its
in-repo evaluation is `docs/internal/apdd-governance-kit/` (PR nearai#7255, open),
not `docs/plans/apdd-governance-kit/` — corrected here and in the OOBE
package. PROPOSAL §11 is restructured into resolves-on-`main` / not-in-repo /
proposed-but-unmerged, and `src/design-system/README.md` is given its full
path and marked a Phase-2 deliverable. Every relative link in both packages
resolves.

ST6 — `LANDED` claims. §2.3 becomes "Foundations in flight (not yet on
`main`)": Phase 1 is `IN REVIEW` (nearai#7750), Phase 2 is `PREPARED` with no open
PR (nearai#7042), and each bullet says what `main` actually contains today. §2.4,
§6, the README lede and the explorer masthead carry the same correction.

SD6 — repeated ownership mapping. The Epic table is now a real, canonical
section in README; PLAN, CHECKLIST and explorer.html carry a pointer to it
plus their own per-phase/per-WS attribution, so ownership changes are one
edit.

EI1 — dependencies without owners. PROPOSAL §7 gains an accountability rule
and an owner table: the owner is the Epic carrying the gating phase, made
individual by a dependency sub-issue that must be cut and assigned before
that phase's first PR opens; each [decision] needs a named caller on its
Epic. Owners are repeated per-dependency in §7.1–§7.6, on the README
at-a-glance list and on the explorer's dependency cards, and CHECKLIST WS6
gains the naming gate.

Also merges current `main` (the branch was 26 commits behind, and the OOBE
package the audit cites lives there).

Verified: `scripts/ci/docs_publication_boundary.py` and
`scripts/ci/check-guidance.py` both pass; explorer.html parses with balanced
tags and renders correctly in light and dark.

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

* docs(design-system): address the automated review round — WCAG AA, honest gates, safeguards

Explorer accessibility (CodeRabbit 3724702856). Real, and worse than
reported: `.pill.good` in light was also failing at 3.78:1, which the finding
missed. Adds `--on-spark` and `--accent-strong` tokens and retunes the light
palette — spark `#e21f7e`→`#c9146d`, good `#0f8a5f`→`#0a6e4b`, plan
`#7a7488`→`#5d5869`; dark spark badges flip to dark-on-pink. Every text/background
pair on the page now clears 4.5:1 in both themes (measured: worst is 4.82).
A page proposing a WCAG AA invariant should not fail it.

Epic ownership single-source (3832432430). Declaring the README table canonical
wasn't enough while PLAN/CHECKLIST/explorer restated the mapping. Every
`Epic #NNNN` label is now a *link into* that table (5 in PLAN, 5 in CHECKLIST,
5 explorer pills), and the two prose restatements are gone.

Dependency owners (3832432423). Correct that role placeholders made the gate
non-verifiable. Rather than invent names, the table now records what is actually
assigned — `Sub-issue: not yet cut`, `Assignee: — none`, `Gate: 🔒 closed` on
every row — with a callout stating plainly that no dependency has a named
individual yet and no Phase 3–5 work may open while a row reads `— none`.

Operational safeguards (3722756794, raised three times). A genuine gap: new
§7.0 defines isolation / fallback / rollback / compatibility as exit criteria,
and §7.1–§7.5 each state theirs — MSW proven absent from the production bundle
by an asserted check, fonts with a tested system-fallback stack and
`font-display: swap`, motion degrading to the static baseline on both
reduced-motion and library-load failure, the `app.css` policy line as an
independent kill switch. Mirrored into PLAN phase exit criteria and CHECKLIST
WS3/WS4/WS6.

AGENTS.md as canonical contract (3815505058). The explorer named only
`.claude/rules/design-system.md`; it now names `DESIGN.md` as the tool-neutral
constitution reachable from `AGENTS.md`, with the Claude rule as the adapter.

Smaller corrections: CHECKLIST's WCAG item cited `§7.4/§8-a11y`, neither of
which is the contrast section — now invariant §3.4 / §7.3 (3722756785); PLAN
cited `§7.3–§7.5` for Phase 3 when §7.5 is Phase-4 motion (3832432399);
§2.3 said each path is created by "the PR named beside it" when Phase 2 has an
issue, not a PR (3832432413).

OOBE D-F6 migration completed (3832432393). The prior commit missed the F0
surfaces: PLAN's "(Optional) D-F6 seed" step and decision-round item 5, and
CHECKLIST's "first-draft DESIGN.md seeded" box both still directed a local
seed. Both now point at the owning program, and the retained §5.6 Needs/Approach
text is marked historical.

Verified: docs_publication_boundary.py and check-guidance.py pass; zero broken
relative links across both packages; explorer.html parses with balanced tags and
its computed styles were checked in both themes.

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

* docs(design-system): fix the MSW public/ trap, the motion kill switch, and two stale facts

Four findings from the latest review round; two were verified against live
code and both were real defects in what the previous commit asserted.

MSW would have shipped to production (CodeRabbit 3836710726). §7.2 said to
"generate the worker into `public/`" while its own safeguard claimed `msw` was
provably absent from the production build — a contradiction I introduced.
`frontend/vite.config.ts` sets `publicDir: "public"`, so `public/` is copied
into `dist/`; `crates/product/ironclaw_webui/build.rs` then walks `dist/`
recursively via `collect()` (skipping only `.vite`) and embeds every file into
the shipping binary. A worker in `public/` would be compiled into production
and served by the real WebUI regardless of being a `devDependency`. §7.2 now
carries a ⚠ block explaining the mechanism and directs the worker into a
Storybook-only static dir, with the assertion widened to cover
`mockServiceWorker.js` as well as `msw` chunks, asserted against `dist/`
before build.rs embeds it.

The motion kill switch was not enforceable (3836710728). `app.css`'s
`* { animation: none !important }` stops CSS animation and transitions but
cannot stop a JS spring's RAF loop or its inline transform writes, so calling
that line the kill switch was a guardrail promise the code would not keep.
§7.5 now specifies the mechanism once: one shared disabled-motion signal
behind both `prefers-reduced-motion` and the app switch, read by CSS and every
JS caller; a running spring cancels its RAF loop and writes the static
end-state; a rejected dynamic motion chunk renders the static baseline while a
failed static import stays a build failure; asserted by caller-level tests.
PLAN and CHECKLIST reference it rather than restating it.

§2.1 was factually wrong about the same policy. It claimed `.v2-spin` is the
sole animation exception; `app.css` has five — `v2-marquee-scroll`, `v2-spin`,
`near-pulse`, `near-chase`, and `v2-page-in` on `.oobe-card-reveal`. The
correction also makes the better point: each is `!important` to outrank the
universal rule and each is individually re-suppressed under
`prefers-reduced-motion`, which is the discipline Phase 4 extends rather than
replaces.

AGENTS.md precedence (3836710722). PLAN Phase 2 and CHECKLIST WS2/WS6 listed
`.claude/rules/design-system.md` and the `CLAUDE.md` pointer as governance
deliverables without stating that `AGENTS.md` is the canonical tool-neutral
contract they supplement. All three sites now state the precedence, and WS6
requires later updates to preserve it.

OOBE Epic precision (3836710714). The ownership notes wrote "Phase 2 = nearai#7042",
conflating the tracking issue with the owning Epic. Phases 2–3 sit under Epic
nearai#7781; nearai#7042 tracks the Phase-2 DESIGN.md work specifically. Corrected across
the OOBE PROPOSAL, PLAN and CHECKLIST.

Verified: docs_publication_boundary.py and check-guidance.py pass; zero broken
relative links; the corrected app.css and build.rs claims were each read from
live code rather than taken from the review.

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

* docs(design-system): make the Epic ownership table genuinely single-source

Follow-up to the partial fix in 772fc8c. Linking the phase and workstream
headings was not enough — the phase-to-Epic mapping was still written out in
full in six more places, any of which could drift from the canonical table.

Removed, in favour of a link to README's canonical table:

- PLAN's mermaid subgraphs, which grouped the five phases into three labelled
  Epic boxes. The diagram keeps the phase sequence — its actual job — with a
  caption saying ownership is deliberately not redrawn here. Last round I
  argued removing the grouping would gut the diagram; re-reading it, the
  sequencing carries the meaning and the Epic boxes were pure duplication.
- The `**Tracks:** Epics …` status header in PLAN, CHECKLIST and PROPOSAL
  (README's header now points down to its own table on the same page).
- PROPOSAL §1's per-phase Epic sentence and §11's `Tracking:` line.
- PLAN's coordination note restating the nearai#7733 supersession.
- explorer.html's masthead eyebrow and footer, both of which spelled out the
  full three-Epic mapping; the footer now links the canonical table.

What remains outside the table is per-phase and per-workstream attribution
that already links into it — the form the canonical section explicitly allows —
plus per-dependency owner lines in §7, which name an Epic per dependency
rather than restating the phase mapping.

Verified: docs_publication_boundary.py and check-guidance.py pass; zero broken
relative links; the canonical anchor resolves; explorer.html parses with
balanced tags.

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

* docs(design-system): give every frontend path an explicit base

The taxonomy table, layer map, explorer ladder, and the Phase 5 / WS5 path
lists used bare paths (`design-system/`, `pages/`, `app/routes.ts`) without
stating what they were relative to, while §2.1 documents the source root as
`crates/product/ironclaw_webui/frontend`.

Each surface now states its base once — PROPOSAL §5's taxonomy table, the
README layer map, and the explorer ladder are labelled relative to
`crates/product/ironclaw_webui/frontend/src/` — and the two short Phase 5 /
WS5 lists carry explicit `src/` prefixes instead, since spelling them out
there is shorter than a note.

Every cited path was checked against the live tree; `gateway-layout` is also
corrected to its real filename, `src/layout/gateway-layout.tsx`.

Verified: docs_publication_boundary.py and check-guidance.py pass;
explorer.html parses with balanced tags.

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

* docs(design-system): remove the last phase→Epic copies, including one in README itself

CodeRabbit was right that the finding was still open. The worst copy was in
the file that owns the canonical table: README's "The five phases" table had
its own `Epic` column, a full second mapping sitting a few lines below the
canonical one.

- README's five-phases table drops the `Epic` column and says in a lead-in
  that it covers scope and delivery state only, pointing at the table above.
  The Epic ownership table is now the only place the mapping is written down.
- PROPOSAL §2.3's two bullets drop their `Epic #NNNN` parentheticals — what
  matters there is the PR or issue that lands the artifact.
- §7.6's gate label loses `(Epic nearai#7038 → nearai#7781)`; it reads `Phase 1→2 landing`.
- PLAN's ⚠ Phase-3 ordering note and the "Merge nearai#7750" next-PR step no longer
  name the Epics to make a sequencing point.

What deliberately stays is the per-dependency owner attribution in §7, on the
README dependency list, and on the explorer cards: those assign an owner to a
*dependency*, which is a different axis from the phase mapping. The README
list now says so explicitly — the Epic on each line is derived from the
gating phase via the canonical table, not a second copy of it.

Verified: one `| Epic |` table remains in the package; the reshaped
five-phases table is column-consistent; both CI scripts pass; zero broken
relative links.

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

* docs(design-system): stop asserting a token invariant the tree does not meet

Two findings, both defects in my own recent commits.

The token invariant was stated as fact and is not one. §3 listed "no hardcoded
hex/px in components" among "non-negotiable invariants" in the present tense,
while naming the OOBE card family as the governance pilot. Measured against
`origin/main` under `frontend/src/`, the tree has 347 arbitrary pixel classes
across 93 files — 9 of them inside `design-system/` itself, the layer the
invariant most directly governs — plus 4 `.tsx` files with hardcoded hexes.
The cited pilot, `pages/chat/components/suggested-task-card.tsx`, is among
them. CodeRabbit named one file; the sweep found the real scope.

§3 now says plainly that the invariants are the target state and the bar for
new and touched code, not a description of the tree, and marks which hold
today (1 and 5) and which does not (2). New §3.1 carries the measured gap as
a table, and records a nuance worth keeping: the pilot card is already
*colour*-conformant — every colour on it is a `var(--v2-*)` reference — so the
gap is dimensional, which is why Phase 3's type/space/radius scales are what
close it. The pilot is now described as the pilot *subject*, demonstrating the
governance loop, not as a conformant exemplar. Migration is routed to PLAN
Phase 3 and CHECKLIST WS3, with a gate to stop the count regrowing.

The layer-map path base was wrong for two of its nodes. 2917534 claimed
"every node below is relative to `frontend/src/`", which is false for the
governance node: `DESIGN.md` lands at `…/frontend/DESIGN.md` and
`.claude/rules/design-system.md` at the repository root, while the Storybook
node names catalog sections rather than a directory. Corrected in the README
layer map and the explorer ladder caption.

Every number published here was measured twice, before and after the edit.

Verified: docs_publication_boundary.py and check-guidance.py pass; zero broken
relative links; the new §3.1 table is column-consistent; explorer.html parses
with balanced tags.

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

* docs(design-system): state the invariant-2 backlog in consistent, re-measured units

Two precision findings on yesterday's §3.1, both correct.

The hex row mixed units. "4 hardcoded hexes" in PLAN and CHECKLIST read as
four occurrences, but the measurement was four *files*. Rather than just
relabel, re-measured both axes and split them properly — and scoped the count
to what the invariant actually governs. The invariant is about components, so
`*.test.*` is now excluded, and §3.1 gives files and occurrences per row:

  arbitrary px          91 files / 345 occurrences
  …inside design-system/ 8 files /  38 occurrences
  hardcoded 6-digit hex   3 files /  10 occurrences

The test-inclusive totals (93/347 and 4/13, the figures published yesterday)
are kept in a parenthetical so the earlier numbers remain traceable rather
than silently changed. The pilot card's count is now stated as 5 classes and
enumerated, instead of listing four of the five.

The explorer abbreviated a path. Its ladder caption wrote `…/frontend/DESIGN.md`
where the README gives the full repository-relative path; readers should not
have to reconstruct it. Now `crates/product/ironclaw_webui/frontend/DESIGN.md`.

Every one of the nine figures in this commit was measured directly and
re-verified after the edit.

Verified: docs_publication_boundary.py and check-guidance.py pass; zero broken
relative links; the §3.1 table is column-consistent at 3 columns;
explorer.html parses with balanced tags.

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

* docs(design-system): match PLAN/CHECKLIST wording to the canonical §7.3 and §3.1

Two consistency findings, one of which was a real self-contradiction.

PLAN listed three Phase-3 dependencies while §7 says there are two. §7's
table states outright that "WCAG AA contrast validation is not a seventh
line: it is a standing invariant (§3.4) enforced inside 7.3", yet PLAN's
Phase-3 bullet named it as a peer of dark-palette derivation and
fonts/licensing. The bullet now says there are two, not three, and groups
contrast inside the palette dependency where §7.3 owns it. CHECKLIST WS3's
contrast box carries the same framing.

The backlog figures drifted in units again. PLAN and CHECKLIST said "91
production components" where §3.1 measures "91 files", and dropped
"six-digit" from the hex description. Both now use §3.1's exact wording —
345 occurrences across 91 files, 10 hardcoded six-digit hex values in 3
`.tsx` files — and §3.1 still carries the scope note (`*.test.*` excluded)
that both documents reference, so the shorter phrasing stays unambiguous.
No figure changed; only the words around them.

Left alone deliberately: the README dependency list and the explorer card
still show contrast as its own line, but both already qualify it as "carried
inside/by the palette work", so neither contradicts §7.3 — they give it
visibility without claiming separate ownership.

Verified: the two backlog phrasings now appear identically in both files;
both CI scripts pass; zero broken relative links.

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

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
l3ocifer pushed a commit to l3ocifer/frick-ironclaw that referenced this pull request Sep 3, 2026
…amily specs, checklist, plan, explorer) (nearai#6918)

* docs(reborn): add target crate architecture proposal package

Executive overview, full evidence-backed proposal (validated against
dde662d), completion checklist (WS0-WS12), execution plan (waves 0-6),
and per-family deep dives (7 of 10; lanes/extensions/app follow).

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

* docs(reborn): complete family deep dives (lanes, extensions, app)

All ten family files now present; 65 crate/subsection specs total.

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

* docs(reborn): redraw README family map as a proper tree

The compact hybrid (box-drawing connectors on family rows, floating
crate rows in the gutter, ragged description columns) rendered badly;
one crate per line with real connectors and aligned annotations.

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

* docs(reborn): rewrite family specs as forward-looking documents

The family files now describe the architecture as designed — present
tense, no line counts, no file:line citations, no dispositions or
migration deltas, no current-vs-target tables. Everything about the
present codebase and the path from it stays in PROPOSAL/CHECKLIST/PLAN,
which each family file points to once.

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

* docs(reborn): keep the README family map at family altitude

The map lists only the ten families; crate rosters live in each
family's spec, now linked (with crate counts) from the roles table.

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

* docs(reborn): replace the family roles table with prose blurbs

One short paragraph per family (linked, crate count): what it is, what
it owns, what it must never contain — instead of a four-column grid of
fragment lists.

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

* docs(reborn): add a folder-structure tree atop each family spec

Each families/*.md now opens with its directory tree (crates plus
one-line roles) before the prose — visualize first, read second.

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

* docs(reborn): drop per-family crate counts from the overview

The ten-families section is high-level: name, what it is, its rule —
crate rosters belong to the family specs.

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

* docs(reborn): rewrite the overview opening as an actual explanation

'The one-paragraph decision' was a compressed insider changelog. The
opening now explains the proposal in plain language: the problem, the
ten-family/one-direction idea, what actually changes (mostly moves),
and that the security model is untouched. 'Why this shape' de-jargoned.

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

* docs(reborn): disambiguate domains vs loop vs lanes in the overview

Adds 'Three that sound alike': what the system knows / what the agent
decides / how an approved action runs, plus the one-request flow line.

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

* docs(reborn): expand the family map to show each family's crates

Full target tree with one-line roles per crate; packages/ abbreviated
to its shape (first_party, slack, telegram, …) rather than the roster.

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

* docs(reborn): drop prefixes + add spacing in the map; fix the first_party asymmetry

Family map: crate names without the ironclaw_ prefix, blank gutter rows
between families. Extensions layout amended (marked in PROPOSAL): every
package gets its own packages/<ext>/ directory uniformly; the shared
inventory/executors crate moves beside the host as extensions/first_party
— it is support code serving many packages, not a package itself.

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

* docs(target-arch): kill family/crate stutters; memory providers become extension packages

Owner review 2026-07-29, three decisions:
- Rename ironclaw_events -> ironclaw_event_log, ironclaw_extensions ->
  ironclaw_extension_registry, ironclaw_product -> ironclaw_assistant:
  the family directories made each old name collapse into a
  family/family stutter (events/events, extensions/extensions,
  product/product), and each new name states what the crate is.
- Both memory providers move out of domains/ and ship as extension
  packages at the same level: extensions/packages/memory-native/ and
  extensions/packages/mem0/, each declaring a [memory] manifest
  surface, linked only by the binary; native installed by default.
  ironclaw_memory (contract + conformance suite) stays in domains/.
- Package-to-crate rule gains the provider-surface clause.

Applied across README map, family specs (domains/extensions/product/
events + cross-refs), PROPOSAL (tree, crate entries, dependency model,
mapping rows 12/19-21/51/59, decided-renames note) and CHECKLIST
(WS2 provider-package item, decided-renames item).

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

* docs(target-arch): apply six-audit hardening pass before team review

Six parallel audit agents (naming, seams/boundaries, checklist/plan
completeness, sponsor-vision alignment, register purity, rendering)
reviewed the whole package; this applies every confirmed finding.

Blockers fixed:
- substrate access rule was over-generalized from lanes to four
  families, contradicting six charter-sanctioned dep lists; now
  lane-scoped with charter-governed access for everyone else
- composition no longer described as seeing provider implementations;
  the binary links memory providers, composition receives the handle
- runner no longer claims loop-exit validation; the turn kernel owns
  it and the runner submits claims
- CHECKLIST gains the enforcement re-point that the memory-provider
  move requires (mem0-naming arch test, memory-mem0 cargo feature,
  allowlists, binary-only linkage list)

Also: rename propagation completed through PROPOSAL SS6-SS10 prose and
both mermaid diagrams; PLAN updated for the decided renames + memory
move with exception arithmetic corrected; README security sentence
de-overclaimed, ladder-vs-families rule stated precisely, splits
enumerated, PR nearai#6253 supersession noted, and a new 'Why ten families'
section naming the two debatable groupings; family specs get uniform
verified-inbound vocabulary, corrected dep lists (hooks+wasm_limiter,
loop_host+turns, triggers+filesystem, event_store+common), sealed-mint
mechanism stated coherently, and complete AGENTS.md requirement
sections; prompt_envelope fork resolved (dropped); gate-prompt port
committed to host_api; first_party gets its own SS8.2 matrix row.

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

* docs(target-arch): add interactive explorer with dependency graph

Single self-contained HTML (no CDN, no network, theme-aware, opens
offline) following the PR nearai#6253 explorer pattern: clickable family
map with per-crate inspector, and a dependency-graph view — 222
target-state edges compiled from the family specs, per-crate fan-in/
fan-out, review lenses (load-bearing, wide-reach, thin/pass-through
candidates, dependency inversions, all edges).

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

* docs(target-arch): calm the explorer map — families first, crates as tags

One surface for the whole ladder instead of ten stacked cards; family
name + role in a readable left column; crates as compact fixed-width
tags that never stretch; per-crate blurbs move to hover/inspector;
kernel row highlighted as the perimeter with its stages in pipeline
order; contracts rails and bindings strip removed (the dependency
graph below tells that story better).

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

* docs(target-arch): explorer dots say delta-vs-today, not execution status

'in flight' on nearly every crate read as work-in-progress; the dots
actually encode how much a crate changes between today's tree and the
target. Relabel: already in shape / reshaped by the proposal / new
crate — wave and demolition pills keep execution language (landed /
in flight / not started) via a separate label map.

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

* docs(target-arch): enumerate the bundled package set concretely

Answers 'where does gsuite / notion go': every bundled extension gets
its own packages/<ext>/ directory uniformly — four crate-bearing
(slack, telegram, memory-native, mem0) and the data-only directories
github, gmail, google-* (one per extension, shared google credential
authority), web-access, notion-mcp, nearai-mcp — with the rule for
where each one's code executes (declared lane; native executors as
first_party modules).

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

* docs(target-arch): explorer crate detail becomes a full panel

Clicking a crate now opens a full-width modal instead of the cramped
sidebar: what-it-does prose, a doc-grounded interface sketch for every
crate, owns as a bulleted list, clickable depends-on / used-by chips
wired from the dependency data, and changes-when / security-role /
why-its-own-crate. Adds the six data-only packages (github, gmail,
google-*, web-access, notion-mcp, nearai-mcp) as clickable entries in
the extensions row so 'where does X go' has an in-map answer.

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

* docs(target-arch): fix modal visible on load — [hidden] lost to display:flex

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

* docs(target-arch): fix modal layout — stacked sections, bounded overflow

The interface sketch's pre whitespace + grid min-width:auto blew the
right column open and crushed the owns list to one word per line.
Sections now stack full-width (about, sketch + key types, owns as a
two-column list, deps/used-by, footer); sketches pre-wrap inside a
bounded box; grid children get min-width:0; comment alignment runs
normalized.

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

* docs(target-arch): explorer becomes a pure high-level overview

Remove the migration-status layer from the map and crate panels (no
disposition strips, no PR numbers, no dots/legend); kernel row loses
its special highlight and pipeline arrows — uniform family rows; the
standalone dependency-graph section is removed (each crate's panel
keeps its depends-on / used-by chips).

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

* docs(target-arch): apply four-agent content audit to explorer descriptions

~55 fixes across the 68 entries and 10 family lines, all audit-verified
against the family specs (and sig names against live code):
- boundary clarity: one-sentence differentiators wherever two entries
  shared a noun without stating the layering (assistant/conversations
  binding+dedup, llm/operator key custody, turns/assistant idempotency,
  extension egress path, pairing chain, lease minting, identity minting)
- accuracy: first_party no longer claims per-package assets; the
  domains family line stops saying 'no authority' beside three narrow
  authorities; conversations consumes rather than seals the trusted
  binding; four invented sig type names replaced with the real ones
  (build_runtime, openai_compat_routes, NativeMemoryService,
  Mem0MemoryService); common's wire-compat exception re-pinned to the
  identity newtypes
- readability: cryptic owns fragments expanded ('the tick', 'the
  caps', 'ratchets'), semicolon-shattered parentheticals rewritten,
  redundant notes replaced with facts that add something

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

* docs(target-arch): adopt the naming audit — rule, four renames, structure fixes

Naming rule written down as PROPOSAL SS5.1 (head-final subject names,
global ironclaw_ prefix, role-class suffixes, provider idiom, host-*
moratorium, dir==package-name + non-crate-dir conventions, family-dir
number rule) with SS11.2.11 assertions and CHECKLIST/AGENTS items.

Renames decided 2026-07-30 (naming audit), applied across README,
family specs, PROPOSAL tree/entries/rows, CHECKLIST, PLAN, explorer:
- ironclaw_architecture -> ironclaw_architecture_tests (tests-only
  crate says so; zero importers)
- ironclaw_reborn_traces target -> ironclaw_trace_commons (the crate
  is the Trace Commons client; unresolvable beside observability)
- ironclaw_first_party_extensions -> ironclaw_extension_support at
  extensions/ironclaw_extension_support/ (old name named a set its
  sibling packages belong to; completes the extension_* line)
- ironclaw_runner -> ironclaw_turn_runner (turns-admits/runner-
  executes split legible from the crate list)
- reborn_ batch upgraded severable -> decided (+ root package
  ironclaw_integration_tests); substrate/ -> substrates/
- wit/ moves inside crates/lanes/ironclaw_wasm/

Plus the migration-mechanics findings as WS10 items: five path-keyed
gates that fail silently under family dirs (coverage merge, panic
scanner, e2e filters, scope classifier, metrics globs) rewritten
before the first git mv, and the loud path-pattern inventory.

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

* docs(target-arch): explorer replaces waves + demolition sections with one roadmap strip

The two document-length sections duplicated PLAN.md and the deletion
inventory. One quiet strip now carries the feasibility signal: the
headline numbers (20->0 exceptions, 66->64 crates, ~18k deleted /
~21k relocated), the seven waves in one line, and links to PLAN.md
and CHECKLIST.md for the real sequencing and definition of done.

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

* docs(target-arch): explorer nests packages/ as a labeled group in the extensions row

Ten 'packages/' prefixes collapse into one group label; package tags
use short extension ids; data-only packages draw dashed vs the
crate-bearing four; the family row now mirrors the family's actual
two-level shape. Also fixes the stale first_party mention in the
extensions role line.

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

* docs(target-arch): packages sub-row as a quiet tree branch, not a box

Drop the dashed group container, floating label, and hint text; the
packages line is now a plain second row led by a faint 'packages/'
tree glyph, tags uniform (crate-vs-data-only stays in the panel).

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

* docs(target-arch): correct the roadmap relocation figure — ledger scope, not total

'≈21k relocated' was the demolition ledger's whole-unit moves only
(telegram_v2 + sandbox trio + first_party_tools + ports crate); as a
restructure total it undercounted ~3-4x by omitting the god-crate
narrowings. Recomputed from PROPOSAL §2's own figures: ≈75k+ re-homed
(extension_host ~24k, composition ~20-54k, turns run_profile 13.9k,
host_api ~9.8k, runner ~10k, host_runtime ~10k, whole-unit ~13k);
deletions restated ≈19k itemized.

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

* docs(target-arch): roadmap figures now measured, not estimated

wc -l against the live tree at baseline: named dead surface sums to
25,382 LOC (dispatcher 1.2k, embeddings 1.8k, llm::reasoning 4.7k,
dead skills 4.0k, run_state 3.2k, runner subagent 7.7k + scheduler
1.0k + production_readiness 0.8k, loopback/trust_boundary/fuzz);
named relocation paths sum to 71,004 LOC measured (run_profile 14.3k,
host_api product vocab 10.6k, first_party_tools 10.4k, sandbox trio
9.0k, runner sheds 7.0k, composition local_dev 11.7k, telegram_v2
2.6k, ports crate 5.4k) — plus the audit-stated ~24k extension_host
product wiring and ~10k further named composition behavior => ≈95k+.

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

* docs(target-arch): explorer sketches get syntax highlighting; data-only packages get manifest sketches

Self-contained tokenizer (keywords, types, strings, TOML section
headers, comments — string-aware so URLs survive) colors every
interface sketch from the page palette. The six data-only packages
now carry their real interface: manifest.toml sketches grounded in
the shipped reborn.extension_manifest.v3 files (github's wasm+tools
+credential injection, gmail/google-* shared auth authority, mcp
server blocks for notion/nearai, web-access first_party runtime).

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

* docs(target-arch): explorer completeness — the three workspace stragglers

Audit vs the canonical inventory: all 62 family crates present, six
data-only packages intended extras; genuinely absent were run_state
(transitional), tools/ironclaw_stress (excluded diagnostic), and the
workspace-root integration_tests package. They join as a subdued
final '…workspace' row with full panels and honest paths, so the map
accounts for every workspace member without polluting the ladder.

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

* docs(target-arch): type-level audit — 459 types verified, panels get load-bearing inventories

Three agents audited every significant public type against live code
and the boundary specs (459 types, 89 findings). The owner's smell
was right: RebornServices is real (the ProductSurface impl aggregate,
2.3k-line module) -> AssistantServices; IdempotencyLedger is a real
trait (its Reborn* impls carry the residue); DeliveryCoordinator is
correctly named and homed. §5.1 gains the type-name clause with the
full Reborn-retirement inventory; CHECKLIST gains the audit items
(CapabilityLease actually sealed, event_streams port narrowed,
composition record shapes to owners, ExtensionActivationMode dedupe,
lifecycle Workflow rename, webui error-name collision).

Explorer: every crate panel now carries 'inside the crate — the
load-bearing types': kind-badged rows in target names with one-liners,
'today: X' notes on renames, NEW badges on spec-proposed types; sigs
and key-type chips swept to target names (ExitEvidencePort corrected
to the real LoopExitEvidencePort).

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

* docs(target-arch): consolidation-audit corrections — seals, keep-reasons, sandbox port home

Three adversarial merge audits over all 62 crates. Accuracy fixes
applied: triggers' trust mint is ratchet-pinned, not constructor-
sealed (outbound's seal is real); extractors has three consumers, not
one; openai_compat's keep-reason restated as the webui-free mount +
SPA/listener cone fact; runtime_policy's void keep-reason replaced;
authorization's lease-mint line states the public-port reality; mcp/
observability/event_streams keep-reasons now cite their actual pins;
extension_host's vestigial loop_host dep dropped; sandbox merge gains
its two load-bearing details (capability id and transport port move
to host_api). §12.10 records the audit outcomes: prompt_envelope/
safety CLOSED (keep separate, unify denylist via safety→envelope);
projects→identity recommended pending owner; observability→host_api
free-but-not-recommended; ten WEAK-KEEPs recorded with the two
convert-to-KEEP enforcement tests added to the CHECKLIST.

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

* docs(target-arch): event_streams keep-reason cites the three-contract invariant

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

* docs(target-arch): family-specific crate panels — real manifests, pipeline strips, trust banners

Clicking a crate now renders what its family calls for, per the panel
designer's spec: extension packages show curated excerpts of their
REAL manifest.toml files (all ten verified byte-for-byte against
source, including the memory providers' v3 manifests found in
host_runtime/assets — ids ironclaw.memory and mem0.local.memory)
with derived surface chips (real tool counts, read/write split, auth
provider, runtime kind); kernel crates get the nine-stage effect-
pipeline strip (admission/lifecycle bracket + seven-stage fold, all
clickable); events crates the record→persist→derive→deliver strip;
extension infra the four-responsibilities strip; contracts crates a
consumer-first 'who speaks this vocabulary' grouped by family; loop
crates trust banners + the eleven Loop*Port chips; lanes receives→
returns contracts; domains the record·service split with mint
badges; substrates promoted invariants + who-may-hold-directly;
app wires-vs-may-never-contain; sealed types tagged. Strict
fallbacks: missing data renders the universal template.

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

* docs(target-arch): execute the one clear merge — projects into identity

Owner rule applied (2026-07-30): gray areas keep their crates; only
clear cases merge. The consolidation audit produced exactly one clear
verdict — ironclaw_projects → ironclaw_identity (842 lines, one
wiring consumer, dep set byte-identical to identity's pinned
allowlist, no distinguishing rule). Executed across family specs,
README map, PROPOSAL (§6.4.11 overturns the W2 retain with the dated
rationale; row 26; counts 66→63 steady-state), CHECKLIST (migration
item: allowlist widens verbatim, gating adapter moves in, port stays
in product_contracts, never-cached ACL becomes a module test), and
the explorer (node folded, identity widened, deps recomputed).
observability→host_api and all ten WEAK-KEEPs stay split per the
same rule.

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

* docs(target-arch): families are clickable — full family panels

Clicking a family name opens its own panel: what-this-family-is in
plain language (distilled faithfully from families/*.md), a clickable
ten-family ladder strip, where-the-line-sits rows against each
neighbor the spec itself contrasts, belongs/never columns, the member
crates with role lines (click-through), the dependency-direction rule,
the security posture, and a link to the full spec on the branch.
Family/crate/family cross-navigation shares one wiring.

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

* docs(target-arch): fix family headers not clickable — builder patch had silently no-opped

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

* docs(target-arch): family names read as buttons — pill + chevron affordance

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

* docs(target-arch): apply CodeRabbit review fixes

Docs: lanes tree drops the moved wit/ dir and the last 'kernel
vocabulary' phrasing for the sandbox transport port; domains states
its three chartered same-family edges in the allowed cell; events
carves the composition factory exception; memory-native's exclusion
scoped to production backends (in-memory = test support); the turns/
assistant idempotency layering and the sanctioned-lease-minter
wording ported into the family specs themselves; §8.2 first_party
row renamed extension_support; projects-merge allowlist wording
uncontradicted; kernel band notes nine + transitional; wit row 42
unstaled; §11.2.11 encodes the naming-rule exceptions, deletes the
vestigial legacy layer variant, and requires regression fixtures +
run-on-self-change for every guardrail; consolidation-audit
denominator scoped; WS0 gains the blocking pre-WS7 path-gate
prerequisite; move-order-sensitive verifies now resolve manifests
via cargo metadata.

Explorer: dead+stale INVERSIONS const deleted; esc() escapes quotes
(attribute-safe) with the highlighter updated to match; modal gains
focus trap + focus restore; the committed copy ships a standards-
mode shell (doctype/charset/viewport) while the artifact copy stays
shell-free per its publish pipeline.

Declined with reasons (posted to the PR): mint dev/broken-links (no
Mintlify config exists in this repo); re-adding a dependency-graph
view (removed deliberately by owner request — chips in the panels
carry the data).

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
l3ocifer pushed a commit to l3ocifer/frick-ironclaw that referenced this pull request Sep 3, 2026
…2 100% gate (nearai#7263)

* docs(target-arch): resolve the await-edge design question by measurement (D-S) and re-walk the WS9 verify row

Appends §12.13 D-S under delegated authority at owner direction, flagged
for post-hoc review by Illia Polosukhin (nearai#6696's author): the await-edge
store is measured to be a pure projection over ProcessDependencyPort
(that half of the shed happened inside nearai#6696 itself), and the resolver
is a genuine loop-tier responsibility journal edges cannot express
(owner recovery, sanitized transcript result materialization, batch-gate
resume-once drain, BlockedDependentRunGate resume policy). §6.7.3 is
amended (scheduler DONE / store DONE / resolver KEEP) instead of the
shed being executed; the 2.9k figure is corrected to 1,459 production +
1,448 cfg(test) lines. The §12.10 bullet, §2 divergence flag, §9 row 49,
§13 validation row, CHECKLIST header/WS4 pointer, README and PLAN all
carry the dated resolution.

WS9 verify row ticked with evidence: one lifecycle authority (the
process journal; TurnRunState/TurnRunRecord are projections via
AgentTurnProcessRuntime, ProcessRecord is a capability-invocation view,
no bare RunRecord exists) and §7 T4 re-walked clause-by-clause against
merged code — matches, including the checkpoint-gated no-auto-retry
mechanism (BeforeModel precedes ModelStage; requeue only when
checkpoint-free under the 3-claim cap).

Docs-only; no code, no tests, no gates touched.

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

* docs(ws12): rows 1-2 — package-set tick (64==64/1/0, gate+selftest+independent rederivation) and the 74-row §9 mapping audit (45 L / 15 L-A / 14 OBD / 0 NOT-LANDED; 3 findings recorded)

Row 1: check-target-tree.py reports 64 workspace members == 64 documented
packages, 1 documented exclusion (tools/ironclaw_silk_decoder), 0 owned
exceptions (EXCEPTIONS table empty — §5 steady state); self-test 17/17;
cargo-metadata name set diffed empty against an independent §5 parse.

Row 2: docs/reborn/target-architecture/ws12-mapping-audit.md is the audit
record — per-row executed-evidence, delete-clauses read against WS8's
execution notes, all 14 open rows cite their owning CHECKLIST/PROPOSAL
row or issue. Findings (recorded, not fixed): F1 prompt_envelope
manifest-description fix has no owner row; F2 WS6:429's 'nearai#5618 residue
deleted' overstates vs the live adopt_migrated_identity + open WS8:523;
F3 stale-docs cluster where the tree is ahead of the prose (trace
re-export drop, TurnRunTransitionPort, processes->resources).

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

* fold(7154): squash-port fix/red-main-7119 onto family-world main — defect train nearai#7146/nearai#7115/nearai#7104/nearai#7103/nearai#7144 (+nearai#7119 CI lane), 34-hunk contribution.rs port into the split modules, planner entrypoint classification, D-R loopback exception on the widened HTTPS credential guard

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

* test(extractors): issue-number + assertion-rationale doc refinement (rescued 844964f from rescue/7154-parked-guard)

Ports only the doc/assertion refinement commit; the guard-parking commit
e8f5a31 on that branch is deliberately NOT taken — superseded by the
D-R loopback ruling.

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

* docs(target-arch): record D-R — the loopback credential-guard ruling, wiring choice, and regression pins (PROPOSAL §12.13, 2026-08-05)

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

* review(7154): CodeRabbit round-1 triage — fail-closed tracing-target scan traversal (+node_modules), bounded sidecar output draining (capped capture + discard drain), deadlock regression asserts successful redaction (no seq), XLSX/DOCX empty-classification via extract_document, raise_for_status annotations

Threads already addressed by the fold: latency.rs caller-contract wording
(merged doc scopes the requirement to latency-trace callers), BodyJsonPointer
coverage (the plaintext-refusal test drives all four injection shapes).
Deliberately not taken: un-xfailing the four Slack-catalog projections —
the xfail is a documented tripwire (unexpected-pass goes red) and clearing
them is the nearai#6520 projection-modeling follow-on its comment specs.

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

* fix(assistant): re-point the one field-form tracing target the nearai#7146 gate caught — main's relocated triggered_run_delivery_services carried the drift the PR fixed at its old channel_host address

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

* closure fixups: execute the mapping-audit findings — prompt_envelope manifest description (F1), dated ✎ corrections for the nearai#5618 overstatement (F2) and the stale-prose cluster (F3)

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

* docs(ws12): second-reviewer security spot-audit + extension-journey re-verification (rows 5-6)

Adversarial second-reviewer pass over PROPOSAL §12.1a/b/c and the batch's own
§12.13 D-R loopback carve-out, plus a re-run of the five extension journeys.
Attacks were executed rather than argued: two sabotage files and a 38-shape
hostile-URL probe were planted, run, and reverted.

Verdicts — mint consolidation HOLDS-WITH-RESIDUAL, secrets tightening
HOLDS-WITH-RESIDUAL, host/verifier colocation HOLDS, D-R HOLDS. No HOLE.

Four findings recorded rather than fixed (report-not-repair):
- F1 test_verified/_for_tenant are ungranted mint constructors gated only by
  the `test-support` feature, in no mint-name table, with nothing pinning the
  feature to [dev-dependencies]; the shipped binary is measured feature-free.
- F2 §12.1b's products-layer residue undercounts by one (ironclaw_assistant).
- F3 journey coverage hole: gsuite-with-credential-injection is proven in two
  halves that no committed test joins.
- F4 both recorded census evasions and both fail-open reads are CLOSED on this
  tree, so §11.2.5/§12.1a/CHECKLIST:552/:597 now understate the seal.

Rows 5-6 ticked; only lines 631-632 of CHECKLIST touched so the concurrent
rows 3-4 edit folds cleanly.

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

* ratchet(closure): lock the budget gate at the program's end state

Dispatch ceiling 1122 -> 814 (today's observed, nudge taken; WS0 record 827
stays within effective 829). Mass-share ceiling 2398 -> 658 bp (the WS0
baseline floor — the arch-test assert refuses lower, and observed 578 bp sits
inside the nudge window). Absolute LOC re-equalized at 40423: nearai#6831 added 4
governed LOC through the queue's tolerance window; ceiling, observed, and
COMPOSITION_ABSOLUTE_SRC_LOC move together here. Both tightenings
sabotage-verified red (dispatch 9-over at 790; abs 73-over at 40200).

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

* docs(ws12): gauntlet report — row 3 ticked (full gauntlet green, 0 REAL in scope), row 4 verified-but-open on two pre-existing Postgres-leg test-isolation defects

WS12 rows 3-4 verification on the assembled batch tip 0c6c0cf:

Row 3 (ticked): fmt, clippy default/all-features/--lib --bins, workspace
tests (495 targets, 15,203 passed, 0 failed; the smoke.rs:3132
CPU-saturation flake passed first try), arch suite 285/0, the
integration-feature lane 1,665/0, recorded-fixture QA (61 fixtures clean,
41/0), frontend (typecheck 1,588 files; vitest 1,088/0; build + bundle
budgets), e2e smoke = the CI browser lane under the hermetic wrapper
(50 + 21 + 5 passed), and all 41 scripts/ci self-tests (two mapfile/bash-3.2
casualties green under bash 5, the CI shape).

Row 4 (stays open, dated note added): both-backend parity proven with
legs demonstrably executed for the fabric (57 pg + 81 libsql), triggers
(ADR 0003, REQUIRE_POSTGRES), hooks (ADR 0004, all three backends),
composition, processes journal, extension-registry, host-runtime libSQL
restart, and the backend matrix; fabric-delegated domains enumerated.
Two REAL blockers (one class): the Postgres legs of the event-store and
assistant-ledger contract suites assert against shared-database state and
cannot pass as-written (each failing test passes alone on a virgin
database; files byte-identical to origin/main; no CI lane sets their env
vars). Full evidence: docs/reborn/target-architecture/ws12-gauntlet-report.md.

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

* fix(tests): per-test isolated Postgres databases for the two WS12 parity-blocking contract suites

The WS12 gauntlet (ws12-gauntlet-report.md §P6/§P8) measured the Postgres
legs of ironclaw_event_store's durable_event_store_contract and
ironclaw_assistant's durable_ledger_contract as test-isolation-defective:
absolute database-global asserts (event cursors; settled-entry prune
bookkeeping) run against the single external database named by their
IRONCLAW_*_POSTGRES_URL env vars. Every failing test passes alone on a
virgin database - store semantics correct, suites not self-isolating
(PROPOSAL §12.13 D-T).

Fix: each affected test provisions a private database on the configured
server - the fabric contract's IsolatedDatabase pattern
(db_root_filesystem_contract.rs) ported locally into each suite: CREATE
DATABASE per test, store/pool + migrations against it, courtesy
DROP ... WITH (FORCE), and a once-per-binary stale-name sweep. Every
assertion preserved byte-identical; libsql/jsonl twins untouched. In the
ledger suite only the two retention tests move - the other six Postgres
tests keep their proven fingerprint-suffix isolation.

Regression pins are the fixed tests themselves:
- postgres_replay_advances_next_cursor_past_trailing_filtered_records
- postgres_runtime_and_audit_logs_survive_rebuild_with_filtered_cursor_semantics
- postgres_settled_entry_limit_prunes_oldest_when_configured
- postgres_settled_prune_interval_defers_until_interval_when_configured
Green proven on a shared dirty database twice in a row (parallel default
threading) and serially on a virgin database; red-first reproduction
captured before the fix.

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

* docs(reborn): record §12.13 D-T (parity-suite isolation ruling) and close CHECKLIST WS12 row 4

D-T (after D-S): the WS12 gauntlet's two REAL findings were one defect
class — absolute database-global asserts against the single shared
env-var Postgres database — in two suites (event store cursor contract,
assistant settled-ledger retention). Ruling executed in commit 864d93e:
per-test isolated databases via the fabric contract's IsolatedDatabase
pattern, assertions preserved; alternatives (baseline-relative asserts,
serial-only, leave-open) recorded with why they lost; regression pin =
the four fixed tests themselves.

CHECKLIST WS12 backend-parity row ticks [x] with a dated addendum: red-first
reproduction, the three green isolation runs (dirty shared DB twice in
parallel; failing pairs serial on virgin), parity now green 10/10.

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

* docs(target-arch): three measured corrections surfaced by the guidance program

memory packages are substrates-layer, not products (families/extensions.md);
memory_native declares no extension_contracts dep (PROPOSAL §6.8.4); wasm's
extension_contracts edge is dev-only and the wasm 'never depends on' bullet is
lane-scoped, not family-wide (families/lanes.md).

Three further reported defects were checked and NOT corrected — they were
misreads: the sandbox 'never above the runtime tier' rule holds (substrates sit
below it), and PROPOSAL's safety consumer count already reads 17, matching the
tree.

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

* docs(target-arch): repair the corrupted kernel bullet and correct two family laws

kernel.md: ironclaw_authorization's 'Security & authority role' bullet has been
textually corrupted since nearai#6918 — an approvals sentence was spliced into it
mid-clause, orphaning its continuation line. Reconstructed, with the spliced
sentence restored to the approvals entry where it is true.

lanes.md: 'a lane never depends on a substrate' is false as a family-wide law
(ironclaw_sandbox holds network/safety/secrets normal deps, which its own entry
licenses); the accurate law is the layer ladder, and the narrow claim holds for
ironclaw_wasm alone.

lanes.md + events.md: the 'every crate ships both an AGENTS.md and a CLAUDE.md'
requirement is superseded by docs/reborn/guidance-conventions.md — two files
restating one rule is the drift the guidance program removes.

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

* test(arch): govern the ProtocolAuthEvidence test seam — WS12 audit F1

Two new gates in reborn_sealed_evidence_mint_ratchet (closed paths #12/#13),
per the audit's remedy spec:
(a) TEST_SEAM_MINT_FNS governs test_verified/test_verified_for_tenant — any
    production-text call site outside ironclaw_host_api is an offender
    (comments/strings stripped, #[cfg(test)] blocks stripped, tests.rs /
    *_tests.rs and cfg-test-only files excluded via the shared census);
(b) test-support may appear in no normal dependency table workspace-wide
    (dependencies / build-dependencies / target.* variants /
    workspace.dependencies), and no [features] key other than test-support
    may forward to it — the laundering shape that would evade (b) by one
    rename. [dev-dependencies] enablement stays legal (cargo-features.md
    bar 4, the sanctioned dev seam).

Measured zero offenders on this tree in both directions before pinning;
sabotage-proven red->green both ways (planted production call named with
file:line-text; [dependencies] enablement named with its table path).
Self-tests drive the same pipelines the gates run (zero-match principle);
the definition-location and partition tests now cover the new table.

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

* test(integration): join the gsuite credential-injection journey — WS12 audit F3

WS12 row 5 leg 3 was verified in two halves no committed test joined: gsuite
handler -> staged credential (crate tier) and staged obligation -> wire
(GitHub/Slack only). Scenario 5 already drives gmail.list_messages through
production dispatch on a Google-OAuth-configured group; it now also asserts
the JOIN: the seeded google account's token (itest-google-token) lands on
the recorded outbound gmail.googleapis.com request as
'authorization: Bearer ...', injected at the host egress chokepoint
(apply_credential_injection) per the gmail manifest's declared recipe —
store -> dispatch-time staging -> chokepoint -> wire, through the caller.

Sabotage-proven: disabling the Header injection arm reds exactly this
scenario with 'no network egress request matching url gmail.googleapis.com
has header authorization' while the request itself still reaches the wire
(headers seen: content-type only) — the injection reason, not a setup
error; restore -> green.

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

* docs(target-arch): correct five measured dependency claims in families/domains.md

conversations does not depend on safety (its BoundaryRule now forbids it);
triggers depends on libsql_runtime + safety and NOT filesystem, so its
'filesystem-routed persistence path alongside SQL' is one path, not two;
memory's live set is host_api alone (prompt_envelope is allowlisted, unused);
auth was short by extension_contracts + product_contracts.

Each verified against the manifest before editing.

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

* docs(target-arch): record the closed scan evasions (F4) and the secrets-consumer correction (F2)

The sealed-mint census weaknesses PROPOSAL §11.2.5/§12.1a and CHECKLIST recorded
as live and owed to WS10 are all closed on this tree, verified by re-attacking
the seam with both evasions at once; the docs understated the seal. Ratchet is
23 tests. One residual replaces them: the test_verified test-seam constructors,
now pinned by two gates.

§12.1b's 'only products-layer crate with the edge' is false by one —
ironclaw_assistant carries ironclaw_secrets as port-declaration vocabulary with
no expose_secret call. Not a value-reach bypass; joins nearai#7095's inventory.

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

* docs(target-arch): correct the app-family layer, config's consumer set, and the webui route count

ironclaw_config declares layer=substrates while living in crates/app/;
its consumers include operator, extension_manager and extension_host, not just
the assembly crate and the binary; webui is 93 contract-locked routes, not 92
(nearai#6780 landed after the last recount).

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

* docs(ws12): tick row 7 — the fresh-agent placement probe passed on the final tree

All three placements correct with high confidence, each naming the trait, the
tests, and the tempting wrong place it rejected. The probe doubled as a docs
audit and independently hit four defects, three of which the stacked guidance
PR fixes — it succeeded despite them.

WS12 is now 7/7. The restructure is complete.

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

* docs(target-arch): the product→loop_host recount was wrong on the day it was written

Eight importing files across four seams, not seven across three — the fourth
being a skill-activation-observer seam (projection.rs, projection/live_progress.rs)
this bullet never named, which §6.4.7's own same-day note already implied.
Surfaced by the plan-conformance audit.

The recount history is 3→5→6→7→8, wrong at four of five attempts. That retires
the prose count as a method: the sever slice should land an inventory ratchet
before or with the move, not another number.

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

* review(7263): CodeRabbit round-1 triage — 4 code fixes (2 sabotage-proven, 2 red-first) + 6 doc-truth corrections

Code, each verified red-first or by sabotage matrix:
- sealed-mint ratchet: per-name sighting floor for TEST_SEAM_MINT_FNS
  (closed path #12). Proven: renaming test_verified_for_tenant away plus one
  extra legitimate sibling mention passed the old aggregate floor (silent
  disarm) and fails the new per-name floor naming the constructor; suite
  23/23 after revert. (CodeRabbit's claimed baseline ">2 mentions today" is
  wrong — each name has exactly one kept sighting — but the doc/enforcement
  mismatch and at-threshold fragility were real.)
- trace credit: non-finite novelty_score/duplicate_score are treated as
  absent before clamping (clamp preserves NaN, which poisoned online_score
  and credit_points_estimate); NaN cases added to the nearai#7144 regression test,
  red first.
- trace submission: a 2xx whose body stream dies mid-read now maps through
  request_failed (network telemetry kind, true I/O cause) instead of
  collapsing to an empty body that the nearai#7144 strict parse misreported as
  response_invalid/Submission; truncated-body regression test, red first.
- Postgres contract suites (event store + assistant ledger): isolated-DB
  names now carry a creation epoch and the once-per-binary sweep is
  age-gated (1h), closing the cross-process window where a sibling's fresh
  zero-backend database (between CREATE DATABASE and first connection) was
  sweepable; legacy pid-scheme leftovers still collect immediately. Proven
  on live Postgres 16: planted stale name swept, planted fresh name
  survives, 13/13 x2 and 20/20 x2 with zero leftovers.

Docs (target-architecture truth pass):
- PROPOSAL section 9: the WS6 rename sweep (nearai#7152) had rewritten the source
  column of the 12 renamed rows to their post-rename names, turning their
  rename dispositions into no-ops (rows 13/14/28/30/49/51/59/61/64/66/67/70);
  pre-restructure names restored with a dated footnote.
- PROPOSAL:69: removed the superseded 3->5->6->7 recount sentence (the
  corrected 3->5->6->7->8 passage subsumes it).
- PROPOSAL row 34: ToolPermissionOverrideStorePort deletion marked landed
  (2026-08-05 WS8, matching section 6.5.3; zero workspace hits).
- CHECKLIST:631: dated note recording that the WS12 F3 gsuite join landed in
  this batch (scenario_uninstalled_tool_call_denied_until_active.rs asserts
  the seeded google token on the gmail.googleapis.com wire; suite run green).
- CHECKLIST:632: dated note spending F4 (the audit's 19 was correct at its
  SHA; the ratchet file now holds 23 tests, re-counted at lines 552/597).
- ws12-gauntlet-report P6 heading: first of TWO real failures (one class),
  matching P8 and the report's own summary.
- ws12-mapping-audit rows 49/137: dated D-S closure notes (await-edge store
  half = journal projection already; resolver retained loop-tier; no shed
  owed) so the backlog register no longer lists it as in-flight.

Not fixed, with evidence: the span-helper macros gate suggestion
(info_span!(target = ...) is a hard compile error, E0425 — no silent trap),
the webui tracing-subscriber workspace-dep suggestion (no
[workspace.dependencies] entry exists; suggestion would not build; 8
siblings use the identical direct shape), and the mapping-audit
regeneration (the audit is accurate at its pinned SHA; the in-batch F1 fix
is recorded in its dated coordinator note).

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

* review(7263): CodeRabbit round-2 — rejection-body read keeps its cause; 200 {} is not a submission acknowledgement; lanes.md family dep rule matches measured Cargo.tomls

- submission.rs non-2xx path: a failed rejection-body read no longer collapses
  to an empty detail via .unwrap_or_default() (banned by
  .claude/rules/error-handling.md); the read error folds into the
  http_rejection detail so the received status keeps driving the 401/403
  auth-retry and the Credential/HttpRejection telemetry split.
  Regression: submit_preserves_rejection_body_read_failure_cause_with_status.

- TraceSubmissionReceipt.status: serde default removed — it fabricated
  status "submitted" from a proxy's 200 {} (the nearai#7144 synthesis, resurfacing
  through the wire type's defaults), after which the flush caller recorded
  Submitted and deleted the only retryable queued copy. The acknowledgement is
  the server naming what happened to the submission — every workspace fixture
  sends status and callers persist it unconditionally as server_status — so a
  status-less 2xx body now fails the strict receipt parse as response_invalid.
  Regression: submit_rejects_success_response_without_explicit_server_status
  (covers 200 {} and a status-less non-empty object).

- docs(lanes.md): the family Dependency-direction rule no longer claims every
  lane takes the extension-surface vocabulary crate — measured across
  crates/lanes/*/Cargo.toml: mcp + sandbox hold ironclaw_extension_contracts
  under [dependencies], wasm only under [dev-dependencies]; dated ✎
  cross-references the ironclaw_wasm entry's 2026-08-05 correction.

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

* review(7263): CodeRabbit round-3 — shared Postgres test provisioner (the "new dep edge" premise measured false), entrypoint self-test armed (sabotage-proven), six doc self-contradictions reconciled

Code:
- ironclaw_filesystem gains a `postgres_isolation` test-support module — the
  single home of the per-test isolated-database scaffolding (once-per-binary
  age-gated stale sweep, epoch-in-name convention, DROP WITH (FORCE) cleanup),
  parameterised by suite/env-var/prefix/unreachable-policy. Zero new
  production edges: event_store already normal-deps filesystem, filesystem
  already owns tokio-postgres, and the dev-dep+feature pattern is the one 17
  crates already use. The event-store and product-workflow-ledger suites
  migrate onto it; both Postgres legs proven live against postgres:16 (12
  tests, zero leftover databases). The fabric original keeps its older
  variant with the differences documented at its IsolatedDatabase.
- ironclaw_event_store drops the duplicate tokio-postgres dev-dep (the normal
  dep already reaches tests).
- test-reborn-docker-entrypoint.sh: the missing-argv check now exits the
  command-substitution subshell instead of incrementing a counter the parent
  never sees — red-proven (a migrate-but-never-exec entrypoint passed with 7
  FAIL lines printed), green after the fix both sabotaged and restored.
- trace_commons submission test additionally pins !auth_rejection() for the
  503 rejection (the structural assert the API affords; the prescribed
  payload asserts are refuted — status is private and source is None by
  design, with the message derived from the structured status in the same
  constructor).

Docs (each reconciled to one canonical statement, measured):
- kernel.md: lease ownership decided from code — authorization stores,
  matches, and expires leases (CapabilityLeaseStore + port + expiry all live
  there); approvals constructs and issues into that store. The round-1
  re-homing of the spliced sentence into approvals was wrong and is corrected
  in the dated repair note.
- app.md: "nothing depends on app" scoped to the three app-layer crates;
  ironclaw_config's consumers restated by dependency kind (normal:
  composition, cli, operator, extension_host; dev-only: extension_manager,
  root integration-tests package).
- lanes.md: the mediated-services sentence now states the family law as
  layer-ladder + injected authority; the no-secrets/network/filesystem-dep
  claim is scoped to ironclaw_wasm, matching the file's own corrections.
- CHECKLIST 429/430: the one open traces clause is named (ScopedFilesystem
  adoption); the stale "other two" count corrected against the F3a strike.
- PROPOSAL:69 + CHECKLIST:72: the project-create route repointed —
  first_party_extension_ports dissolved into loop_host::skill_activation
  (WS8, §9 row 55) — still unattempted.
- PROPOSAL §9 rows 57/62 synced to §6.8.4 (telegram: dependency-set equality
  with Slack's four contract-tier crates) and §6.9.4 (webui -> assistant is a
  charter-permanent edge, §12.11 D-B).
- PLAN top summary records Wave 6's design question as resolved (D-S,
  2026-08-05).
- deploy-reborn-cli-docker.md: the two migration paragraphs unified on the
  entrypoint's actual behavior — only enabled = false beside
  signing_secret_env/bot_token_env is migrated; every other retired-key shape
  fails startup with the migration pointer.
- composition-budget.toml: the stale "2398 bp, a true ratchet" header
  replaced with the WS0-floor truth the baselines test asserts.

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

* docs: move the guidance convention into this PR so its citations resolve

families/lanes.md and families/events.md cite docs/reborn/guidance-conventions.md
when superseding their 'every crate ships both an AGENTS.md and a CLAUDE.md'
requirement, but the file was only on the stacked guidance branch — a forward
reference that dangles if this PR merges alone. The convention is the rule those
notes invoke, so it belongs with them.

Caught by the CodeRabbit round-3 pass.

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

* fix(ci): give the hoisted postgres provisioner its safety rationales

The round-3 hoist moved test provisioning into a production src/ path, so
check_no_panics flagged its four panic/expect sites and reddened Code Style via
fast-checks. The gate is right to flag them: it deliberately does NOT exempt
#[cfg(feature = "test-support")] modules, because a cargo feature is not a
privilege boundary in this workspace (PROPOSAL 12.1a proved exactly that) —
so a test-support module still compiles into a build where any sibling enables
the feature.

Suppressed with the gate's documented inline rationale, which must trail the
statement rather than precede it. The panics themselves stay: a configured but
unusable Postgres must fail the suite loudly rather than skip it, which is the
inert-guard rule the isolation fix exists to serve.

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
l3ocifer pushed a commit to l3ocifer/frick-ironclaw that referenced this pull request Sep 3, 2026
…ry crate, and a repo-wide stale sweep (nearai#7264)

* docs(target-arch): resolve the await-edge design question by measurement (D-S) and re-walk the WS9 verify row

Appends §12.13 D-S under delegated authority at owner direction, flagged
for post-hoc review by Illia Polosukhin (nearai#6696's author): the await-edge
store is measured to be a pure projection over ProcessDependencyPort
(that half of the shed happened inside nearai#6696 itself), and the resolver
is a genuine loop-tier responsibility journal edges cannot express
(owner recovery, sanitized transcript result materialization, batch-gate
resume-once drain, BlockedDependentRunGate resume policy). §6.7.3 is
amended (scheduler DONE / store DONE / resolver KEEP) instead of the
shed being executed; the 2.9k figure is corrected to 1,459 production +
1,448 cfg(test) lines. The §12.10 bullet, §2 divergence flag, §9 row 49,
§13 validation row, CHECKLIST header/WS4 pointer, README and PLAN all
carry the dated resolution.

WS9 verify row ticked with evidence: one lifecycle authority (the
process journal; TurnRunState/TurnRunRecord are projections via
AgentTurnProcessRuntime, ProcessRecord is a capability-invocation view,
no bare RunRecord exists) and §7 T4 re-walked clause-by-clause against
merged code — matches, including the checkpoint-gated no-auto-retry
mechanism (BeforeModel precedes ModelStage; requeue only when
checkpoint-free under the 3-claim cap).

Docs-only; no code, no tests, no gates touched.

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

* docs(ws12): rows 1-2 — package-set tick (64==64/1/0, gate+selftest+independent rederivation) and the 74-row §9 mapping audit (45 L / 15 L-A / 14 OBD / 0 NOT-LANDED; 3 findings recorded)

Row 1: check-target-tree.py reports 64 workspace members == 64 documented
packages, 1 documented exclusion (tools/ironclaw_silk_decoder), 0 owned
exceptions (EXCEPTIONS table empty — §5 steady state); self-test 17/17;
cargo-metadata name set diffed empty against an independent §5 parse.

Row 2: docs/reborn/target-architecture/ws12-mapping-audit.md is the audit
record — per-row executed-evidence, delete-clauses read against WS8's
execution notes, all 14 open rows cite their owning CHECKLIST/PROPOSAL
row or issue. Findings (recorded, not fixed): F1 prompt_envelope
manifest-description fix has no owner row; F2 WS6:429's 'nearai#5618 residue
deleted' overstates vs the live adopt_migrated_identity + open WS8:523;
F3 stale-docs cluster where the tree is ahead of the prose (trace
re-export drop, TurnRunTransitionPort, processes->resources).

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

* fold(7154): squash-port fix/red-main-7119 onto family-world main — defect train nearai#7146/nearai#7115/nearai#7104/nearai#7103/nearai#7144 (+nearai#7119 CI lane), 34-hunk contribution.rs port into the split modules, planner entrypoint classification, D-R loopback exception on the widened HTTPS credential guard

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

* test(extractors): issue-number + assertion-rationale doc refinement (rescued 844964f from rescue/7154-parked-guard)

Ports only the doc/assertion refinement commit; the guard-parking commit
e8f5a31 on that branch is deliberately NOT taken — superseded by the
D-R loopback ruling.

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

* docs(target-arch): record D-R — the loopback credential-guard ruling, wiring choice, and regression pins (PROPOSAL §12.13, 2026-08-05)

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

* review(7154): CodeRabbit round-1 triage — fail-closed tracing-target scan traversal (+node_modules), bounded sidecar output draining (capped capture + discard drain), deadlock regression asserts successful redaction (no seq), XLSX/DOCX empty-classification via extract_document, raise_for_status annotations

Threads already addressed by the fold: latency.rs caller-contract wording
(merged doc scopes the requirement to latency-trace callers), BodyJsonPointer
coverage (the plaintext-refusal test drives all four injection shapes).
Deliberately not taken: un-xfailing the four Slack-catalog projections —
the xfail is a documented tripwire (unexpected-pass goes red) and clearing
them is the nearai#6520 projection-modeling follow-on its comment specs.

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

* fix(assistant): re-point the one field-form tracing target the nearai#7146 gate caught — main's relocated triggered_run_delivery_services carried the drift the PR fixed at its old channel_host address

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

* closure fixups: execute the mapping-audit findings — prompt_envelope manifest description (F1), dated ✎ corrections for the nearai#5618 overstatement (F2) and the stale-prose cluster (F3)

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

* docs(ws12): second-reviewer security spot-audit + extension-journey re-verification (rows 5-6)

Adversarial second-reviewer pass over PROPOSAL §12.1a/b/c and the batch's own
§12.13 D-R loopback carve-out, plus a re-run of the five extension journeys.
Attacks were executed rather than argued: two sabotage files and a 38-shape
hostile-URL probe were planted, run, and reverted.

Verdicts — mint consolidation HOLDS-WITH-RESIDUAL, secrets tightening
HOLDS-WITH-RESIDUAL, host/verifier colocation HOLDS, D-R HOLDS. No HOLE.

Four findings recorded rather than fixed (report-not-repair):
- F1 test_verified/_for_tenant are ungranted mint constructors gated only by
  the `test-support` feature, in no mint-name table, with nothing pinning the
  feature to [dev-dependencies]; the shipped binary is measured feature-free.
- F2 §12.1b's products-layer residue undercounts by one (ironclaw_assistant).
- F3 journey coverage hole: gsuite-with-credential-injection is proven in two
  halves that no committed test joins.
- F4 both recorded census evasions and both fail-open reads are CLOSED on this
  tree, so §11.2.5/§12.1a/CHECKLIST:552/:597 now understate the seal.

Rows 5-6 ticked; only lines 631-632 of CHECKLIST touched so the concurrent
rows 3-4 edit folds cleanly.

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

* ratchet(closure): lock the budget gate at the program's end state

Dispatch ceiling 1122 -> 814 (today's observed, nudge taken; WS0 record 827
stays within effective 829). Mass-share ceiling 2398 -> 658 bp (the WS0
baseline floor — the arch-test assert refuses lower, and observed 578 bp sits
inside the nudge window). Absolute LOC re-equalized at 40423: nearai#6831 added 4
governed LOC through the queue's tolerance window; ceiling, observed, and
COMPOSITION_ABSOLUTE_SRC_LOC move together here. Both tightenings
sabotage-verified red (dispatch 9-over at 790; abs 73-over at 40200).

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

* docs(ws12): gauntlet report — row 3 ticked (full gauntlet green, 0 REAL in scope), row 4 verified-but-open on two pre-existing Postgres-leg test-isolation defects

WS12 rows 3-4 verification on the assembled batch tip 0c6c0cf:

Row 3 (ticked): fmt, clippy default/all-features/--lib --bins, workspace
tests (495 targets, 15,203 passed, 0 failed; the smoke.rs:3132
CPU-saturation flake passed first try), arch suite 285/0, the
integration-feature lane 1,665/0, recorded-fixture QA (61 fixtures clean,
41/0), frontend (typecheck 1,588 files; vitest 1,088/0; build + bundle
budgets), e2e smoke = the CI browser lane under the hermetic wrapper
(50 + 21 + 5 passed), and all 41 scripts/ci self-tests (two mapfile/bash-3.2
casualties green under bash 5, the CI shape).

Row 4 (stays open, dated note added): both-backend parity proven with
legs demonstrably executed for the fabric (57 pg + 81 libsql), triggers
(ADR 0003, REQUIRE_POSTGRES), hooks (ADR 0004, all three backends),
composition, processes journal, extension-registry, host-runtime libSQL
restart, and the backend matrix; fabric-delegated domains enumerated.
Two REAL blockers (one class): the Postgres legs of the event-store and
assistant-ledger contract suites assert against shared-database state and
cannot pass as-written (each failing test passes alone on a virgin
database; files byte-identical to origin/main; no CI lane sets their env
vars). Full evidence: docs/reborn/target-architecture/ws12-gauntlet-report.md.

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

* docs(guidance): set the crate/family guidance convention

The base commit for the family-guidance program: one canonical home per fact,
measured-not-aspirational claims, boundaries stated as exclusions, and the note
that guidance files can be gate-pinned. Every family/crate document written on
top of this branch follows this shape.

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

* fix(tests): per-test isolated Postgres databases for the two WS12 parity-blocking contract suites

The WS12 gauntlet (ws12-gauntlet-report.md §P6/§P8) measured the Postgres
legs of ironclaw_event_store's durable_event_store_contract and
ironclaw_assistant's durable_ledger_contract as test-isolation-defective:
absolute database-global asserts (event cursors; settled-entry prune
bookkeeping) run against the single external database named by their
IRONCLAW_*_POSTGRES_URL env vars. Every failing test passes alone on a
virgin database - store semantics correct, suites not self-isolating
(PROPOSAL §12.13 D-T).

Fix: each affected test provisions a private database on the configured
server - the fabric contract's IsolatedDatabase pattern
(db_root_filesystem_contract.rs) ported locally into each suite: CREATE
DATABASE per test, store/pool + migrations against it, courtesy
DROP ... WITH (FORCE), and a once-per-binary stale-name sweep. Every
assertion preserved byte-identical; libsql/jsonl twins untouched. In the
ledger suite only the two retention tests move - the other six Postgres
tests keep their proven fingerprint-suffix isolation.

Regression pins are the fixed tests themselves:
- postgres_replay_advances_next_cursor_past_trailing_filtered_records
- postgres_runtime_and_audit_logs_survive_rebuild_with_filtered_cursor_semantics
- postgres_settled_entry_limit_prunes_oldest_when_configured
- postgres_settled_prune_interval_defers_until_interval_when_configured
Green proven on a shared dirty database twice in a row (parallel default
threading) and serially on a virgin database; red-first reproduction
captured before the fix.

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

* docs(reborn): record §12.13 D-T (parity-suite isolation ruling) and close CHECKLIST WS12 row 4

D-T (after D-S): the WS12 gauntlet's two REAL findings were one defect
class — absolute database-global asserts against the single shared
env-var Postgres database — in two suites (event store cursor contract,
assistant settled-ledger retention). Ruling executed in commit 864d93e:
per-test isolated databases via the fabric contract's IsolatedDatabase
pattern, assertions preserved; alternatives (baseline-relative asserts,
serial-only, leave-open) recorded with why they lost; regression pin =
the four fixed tests themselves.

CHECKLIST WS12 backend-parity row ticks [x] with a dated addendum: red-first
reproduction, the three green isolation runs (dirty shared DB twice in
parallel; failing pairs serial on virgin), parity now green 10/10.

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

* docs(extensions): family guidance layer — AGENTS.md rewrite to the guidance-conventions shape, READMEs for all 4 family crates and 14 packages, duplicate-guidance consolidation

The family AGENTS.md now teaches the unified extension model (extension =
the only product object; channel/tool/auth are manifest surfaces; runtime
is loading, never taxonomy; ExtensionId vs VendorId; retired vocabulary
pinned by reborn_retired_taxonomy.rs), carries the self-containment and
package-to-crate rules from families/extensions.md, the four-responsibility
lookup, the measured package catalog, the exclusion list, and the armed
gates by test name.

Every crate and package gains a README.md (ironclaw_extension_host had no
guidance of any kind). ironclaw_extension_registry and memory-native each
had both an AGENTS.md and a CLAUDE.md saying overlapping things: AGENTS.md
is now canonical, CLAUDE.md a pointer, and memory-native's stale v1
references (src/workspace, src/db/libsql) are dropped in the merge. The
slack/telegram agent maps get package framing and a contracts-tier pointer
in place of the stale ironclaw_assistant one. Every path literal verified
to resolve on disk; all figures (tool counts, dep sets, consumers, layer
declarations) measured from the tree at 8d13454.

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

* docs(guidance): substrates + lanes family guidance per guidance-conventions.md

Family AGENTS.md rewritten to the spec shape for crates/substrates/ and
crates/lanes/: boundary, crate table, exclusion lists (mechanism-not-authority
for substrates; kernel-decides-lane-executes for lanes), armed gates by test
name, and measured deviations stated as deviations (sandbox's three substrate
deps, script.rs direct spawn). The lanes wit/-is-load-bearing note is kept.

A README.md for every crate in both families (10 new), measured against
cargo metadata 2026-08-05: public surface, workspace edges, consumer counts,
and enforced invariants each citing their gate. ironclaw_libsql_runtime and
ironclaw_wasm_limiter previously had no guidance of any kind; their READMEs
carry the sole-pool-home rule (ADDITIONAL_DRIVER_ALLOWLISTS: deadpool =
{filesystem, libsql_runtime}) and the outbound-only limiter gate
(wasm_sandbox_core_module_stays_domain_free_v1_parity_kernel; no BoundaryRule
names the limiter).

Duplicate guidance consolidated per rule 1: for the six crates holding both
AGENTS.md and CLAUDE.md (filesystem, network, secrets, mcp, sandbox, wasm),
CLAUDE.md stays canonical (module spec for filesystem; gate-pinned wording for
mcp and wasm) and AGENTS.md becomes a short pointer. No gate-pinned file was
edited. Stale reference removed: safety AGENTS.md pointed at
src/NETWORK_SECURITY.md, which exists nowhere in the tree.

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

* docs(crates-map): rewrite the three top-level maps family-first after the restructure

crates/AGENTS.md (264 -> 175 lines): routing map only — the ten families,
the read order (family AGENTS.md -> crate README.md -> working rules/module
spec -> docs/reborn/contracts/), the enforced seven-layer matrix with the
family/layer divergences, measured workspace facts (64 packages, 1 documented
exclusion, 0 owned exceptions per scripts/ci/check-target-tree.py), and a
verified command block. The 40-row per-crate map is gone: family AGENTS.md
files own crate routing per docs/reborn/guidance-conventions.md.

crates/README.md (141 -> 119 lines): human map — mental model in family
vocabulary, the ten families with measured crate counts, the 14 extension
packages (4 crates + 10 data-only), and the two workspace members outside
crates/.

crates/Architecture.md (1019 -> 1059 lines): audited against the live tree;
every named symbol/path re-verified 2026-08-05. Corrected: retired
ProductAdapter vocabulary (zero residue in code), the stale pre-rename
dependency ladder that still cited the deleted gateway/TUI crates, run-state
store mentions, lane-table crate anchors (sandbox/extension_support),
declared-in vs minted-by owners in the core data model, and the subagent
deny-filter status note (re-verified). Marked the pre-restructure
'partial or evolving' list as unmeasured rather than asserting it.

Also documents that scripts/check-boundaries.sh fails on a clean tree
(check-5 grep false positives) and greps the deleted v1 src/ in 4 of 6
checks — boundary enforcement for crates/ is the architecture suite.

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

* docs(crates-map): package directories carry their own README.md (coordinator sync with extensions-family agent)

Every extensions package dir — the 10 data-only ones included — now ships a
README.md, so both maps extend the read order to package level. The sibling
branch also confirmed what this map already derived per-crate: packages/ is
not uniformly products-layer (memory-native and mem0 declare substrates).
The other two coordinator corrections targeted rows of the old per-crate
map, which this rewrite deleted wholesale; nothing here cites
memory-native's CLAUDE.md or claims ironclaw_extension_host lacks guidance.

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

* docs(guidance): contracts + events family guidance layer per docs/reborn/guidance-conventions.md

- crates/contracts/AGENTS.md and crates/events/AGENTS.md rewritten to the
  family shape: exclusion lists with destinations, armed gates by test name,
  layer-matrix rows, crossing guide, measured header counts.
- README.md added for all 10 crates (ironclaw_prompt_envelope previously had
  no guidance of any kind — the CHECKLIST WS11 gap).
- One canonical guidance file per crate, other file a pointer:
  A+C merges for ironclaw_host_api, ironclaw_event_log,
  ironclaw_event_projections, ironclaw_event_streams; CLAUDE-only content
  moved to AGENTS.md for ironclaw_loop_contracts,
  ironclaw_extension_contracts, ironclaw_product_contracts (none of these are
  root module-spec crates, so AGENTS.md is the working-rules home).
- Stale guidance fixed against the live tree:
  * loop_contracts dep list contradicted the enforced allowlist (manifest is
    host_api + extension_contracts; common/prompt_envelope are permitted,
    unused).
  * event_log still documented the deleted jsonl parse/replay helpers.
  * event_projections still claimed EventStreamManager,
    DurableMemoryAuditSink, MemoryAuditProjectionMetadata, and
    PendingGateProjection — all deleted per PROPOSAL 6.3.3.
  * product_contracts still carried the pre-D-E open vendor decision under
    the nonexistent module name llm_config, and a Deferred section
    contradicting its own operator_llm/operator_service rows.
  * extension_contracts module table was missing the WS3 runtime module
    while counting 18.
  * common's llm_costs note carried the ModelCostTable seam claim refuted by
    PROPOSAL 12.11 D-F; now cites the pricer-port ruling and the vendor
    census residue.
- Deleted crates/events/ironclaw_event_projections/PENDING_GATE_PROJECTION.md:
  every claim in it referenced deleted symbols or the removed v1 src/ tree,
  and its only inbound reference was the crate's own CLAUDE.md.

Verified: all consumer counts reproduce via the printed grep commands; 147
path literals across the 28 touched files resolve on disk; no architecture
test reads any of these files by name; conflict-marker scan clean.

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

* docs(target-arch): three measured corrections surfaced by the guidance program

memory packages are substrates-layer, not products (families/extensions.md);
memory_native declares no extension_contracts dep (PROPOSAL §6.8.4); wasm's
extension_contracts edge is dev-only and the wasm 'never depends on' bullet is
lane-scoped, not family-wide (families/lanes.md).

Three further reported defects were checked and NOT corrected — they were
misreads: the sandbox 'never above the runtime tier' rule holds (substrates sit
below it), and PROPOSAL's safety consumer count already reads 17, matching the
tree.

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

* docs(kernel): family guidance layer — perimeter AGENTS.md, nine crate READMEs, AGENTS/CLAUDE consolidation

Family-guidance program, kernel family (guidance-conventions.md shape):

- crates/kernel/AGENTS.md rewritten to the family shape: the nine-stage
  effect pipeline with stage ownership, the sealed-mint table (witness /
  trust ceiling / approval lease / verified-inbound evidence, each with its
  mint site and its seal mechanism), the per-stage fail-closed table with
  file:line or test citations, the sharp exclusion list, and the armed
  gates by test name (authorized-seal ratchet, sealed-evidence mint
  ratchet, BoundaryRules, same-layer edge inventory at 21 kernel edges,
  empty LAYER_MATRIX_EXCEPTIONS register, driver boundary, process storage
  scan, origin-gate matrix ratchet).
- A README.md for each of the nine crates, per the crate shape: measured
  workspace deps and consumer counts (cargo metadata), public surface with
  verified citations, enforced invariants naming their gates.
  ironclaw_processes states the single-lifecycle-authority direction of
  truth (journal = store; TurnRunState/ProcessRecord/await-edge =
  projections; PROPOSAL §12.13 D-S); ironclaw_host_runtime documents the
  D-R literal-loopback carve-out and names its two regression tests.
- Duplicate guidance reconciled in all nine crates: AGENTS.md is canonical
  (guardrails absorbed), CLAUDE.md reduced to a pointer; ironclaw_trust's
  CONTRACT.md untouched as the co-located cross-crate contract.
- Stale references fixed inside owned paths: the deleted capability-profile
  conformance module (evaluate_profile_conformance — zero hits
  workspace-wide) removed from ironclaw_capabilities guidance; trust's
  'staging branch' / 'PR3' phrasing updated; capabilities' 'later
  obligation slices' updated to the landed host_runtime obligations split;
  cross-crate path mentions fully qualified. Every path literal in all 29
  kernel .md files verified to resolve on disk; every named symbol swept
  against crate sources.

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

* docs(domains): family guidance layer — AGENTS.md boundary doc, 12 crate READMEs, duplicate-guidance consolidation, stale-path fixes

Family guidance for crates/domains/ per docs/reborn/guidance-conventions.md:

- crates/domains/AGENTS.md rewritten to the family shape: charter table with
  go-here-when routing, the exclusion list, every armed gate named by test
  (BoundaryRules + identity/memory allowlists, the 5-entry in-family edge
  inventory, the naming gates, trusted-trigger ownership, the memory-provider
  residue ledger, persistence-driver boundary, the two module-charter gates).
- A measured README.md for each of the 12 crates: charter, use-when /
  don't-use-when routing, public surface, measured normal deps + named
  consumers, enforced invariants with their gates, exact test commands.
  ironclaw_attachments and ironclaw_identity had no guidance of any kind;
  identity's README points at CONTRACT.md (the module spec), llm's at its
  CLAUDE.md module spec.
- Duplicate guidance consolidated to one canonical file + pointer per crate:
  threads/conversations/memory/outbound rules now live in AGENTS.md (CLAUDE.md
  is a pointer); auth/llm keep CLAUDE.md canonical because their
  tests/module_charter.rs gates read it (AGENTS.md is the pointer). One
  misstatement fixed in the conversations merge: transcript content belongs to
  ironclaw_threads' SessionThreadService, not InboundConversationService.
- Staleness fixed inside the family: identity CONTRACT.md two-edge allowlist
  claim reconciled with D-Q's three entries; trace_commons CLAUDE.md gains the
  capture module row and strikes its two discharged Known Gaps (recording/paths
  shims deleted, rename done); llm CLAUDE.md reasoning.rs caller corrected to
  crates/loop/ironclaw_loop_host; triggers lib.rs 'feature-gated' repo doc
  comments corrected; pre-family path literals in comments repointed
  (kernel/approvals+processes, loop/hooks, app/architecture_tests,
  domains/auth) and the deleted-v1-engine references in skills marked
  historical.

Verified: cargo test -p ironclaw_llm --no-fail-fast (922 passed, exit 0 —
CLAUDE.md is gate-pinned); cargo check --all-targets on all six crates with
source edits; every cited path literal resolves on disk; conflict-marker scan
clean.

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

* docs(target-arch): repair the corrupted kernel bullet and correct two family laws

kernel.md: ironclaw_authorization's 'Security & authority role' bullet has been
textually corrupted since nearai#6918 — an approvals sentence was spliced into it
mid-clause, orphaning its continuation line. Reconstructed, with the spliced
sentence restored to the approvals entry where it is true.

lanes.md: 'a lane never depends on a substrate' is false as a family-wide law
(ironclaw_sandbox holds network/safety/secrets normal deps, which its own entry
licenses); the accurate law is the layer ladder, and the narrow claim holds for
ironclaw_wasm alone.

lanes.md + events.md: the 'every crate ships both an AGENTS.md and a CLAUDE.md'
requirement is superseded by docs/reborn/guidance-conventions.md — two files
restating one rule is the drift the guidance program removes.

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

* test(arch): govern the ProtocolAuthEvidence test seam — WS12 audit F1

Two new gates in reborn_sealed_evidence_mint_ratchet (closed paths #12/#13),
per the audit's remedy spec:
(a) TEST_SEAM_MINT_FNS governs test_verified/test_verified_for_tenant — any
    production-text call site outside ironclaw_host_api is an offender
    (comments/strings stripped, #[cfg(test)] blocks stripped, tests.rs /
    *_tests.rs and cfg-test-only files excluded via the shared census);
(b) test-support may appear in no normal dependency table workspace-wide
    (dependencies / build-dependencies / target.* variants /
    workspace.dependencies), and no [features] key other than test-support
    may forward to it — the laundering shape that would evade (b) by one
    rename. [dev-dependencies] enablement stays legal (cargo-features.md
    bar 4, the sanctioned dev seam).

Measured zero offenders on this tree in both directions before pinning;
sabotage-proven red->green both ways (planted production call named with
file:line-text; [dependencies] enablement named with its table path).
Self-tests drive the same pipelines the gates run (zero-match principle);
the definition-location and partition tests now cover the new table.

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

* test(integration): join the gsuite credential-injection journey — WS12 audit F3

WS12 row 5 leg 3 was verified in two halves no committed test joined: gsuite
handler -> staged credential (crate tier) and staged obligation -> wire
(GitHub/Slack only). Scenario 5 already drives gmail.list_messages through
production dispatch on a Google-OAuth-configured group; it now also asserts
the JOIN: the seeded google account's token (itest-google-token) lands on
the recorded outbound gmail.googleapis.com request as
'authorization: Bearer ...', injected at the host egress chokepoint
(apply_credential_injection) per the gmail manifest's declared recipe —
store -> dispatch-time staging -> chokepoint -> wire, through the caller.

Sabotage-proven: disabling the Header injection arm reds exactly this
scenario with 'no network egress request matching url gmail.googleapis.com
has header authorization' while the request itself still reaches the wire
(headers seen: content-type only) — the injection reason, not a setup
error; restore -> green.

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

* docs(target-arch): correct five measured dependency claims in families/domains.md

conversations does not depend on safety (its BoundaryRule now forbids it);
triggers depends on libsql_runtime + safety and NOT filesystem, so its
'filesystem-routed persistence path alongside SQL' is one path, not two;
memory's live set is host_api alone (prompt_envelope is allowlisted, unused);
auth was short by extension_contracts + product_contracts.

Each verified against the manifest before editing.

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

* docs(guidance): family AGENTS.md + crate READMEs + guidance consolidation for loop/product/app

Family-guidance program, families 8-10 (the top of the stack), per
docs/reborn/guidance-conventions.md:

- Rewrite crates/{loop,product,app}/AGENTS.md from routing stubs to the
  spec's family shape: exclusion lists, armed gates by test name, layer
  rows, crossing guides. Loop carries the trust story + the declared
  Loop*Port decorator chain; product carries the frozen-surface rule,
  the transports-consume-contracts rule (with the D-B frozen-constant
  qualification), the evidence-mint prohibition, and the two vendor
  exceptions; app carries the wires-owners-never-becomes-one charter,
  the binary-names-packages rule, config's zero-dep guarantee, and the
  composition mass ratchet (loc 40423 / Arc<dyn> 814).
- Add a README.md to all 13 crates (12 new; webui's rewritten to the
  spec shape) with measured public surface, deps, and consumer counts.
- Consolidate duplicate AGENTS.md/CLAUDE.md per spec rule 1: AGENTS.md
  is canonical and CLAUDE.md a pointer for agent_loop, loop_host,
  turn_runner, hooks, host_ingress, openai_compat, operator, and
  architecture_tests; CLAUDE.md stays canonical (module spec /
  gate-pinned) for webui, composition, and assistant, with
  composition's AGENTS.md reduced to the pointer.
- Fix stale references in owned paths: hooks' dependency diagram and
  AgentLoopDriver home (ironclaw_loop_contracts, not ironclaw_turns),
  loop_host/agent_loop port-home claims, turn_runner's pre-nearai#6696
  scheduler description, webui's ProductSurface path
  (product_contracts, not host_api), route count (93, measured), and
  webui's allowed-dependency list (7 of 10 were listed), the D-S
  await-edge ruling reflected in turn_runner guidance, composition's
  llm_admin residue (nearai_login_serve left for operator).

Verified: cargo test -p ironclaw_architecture_tests --no-fail-fast
(39 binaries, 0 failures — covers the CLI AGENTS.md phrase pin and the
composition guidance-markdown scan), scripts/ci/check-target-tree.py,
path-literal resolution over all 37 changed files, conflict-marker scan.

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

* docs(target-arch): record the closed scan evasions (F4) and the secrets-consumer correction (F2)

The sealed-mint census weaknesses PROPOSAL §11.2.5/§12.1a and CHECKLIST recorded
as live and owed to WS10 are all closed on this tree, verified by re-attacking
the seam with both evasions at once; the docs understated the seal. Ratchet is
23 tests. One residual replaces them: the test_verified test-seam constructors,
now pinned by two gates.

§12.1b's 'only products-layer crate with the edge' is false by one —
ironclaw_assistant carries ironclaw_secrets as port-declaration vocabulary with
no expose_secret call. Not a value-reach bypass; joins nearai#7095's inventory.

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

* docs(target-arch): correct the app-family layer, config's consumer set, and the webui route count

ironclaw_config declares layer=substrates while living in crates/app/;
its consumers include operator, extension_manager and extension_host, not just
the assembly crate and the binary; webui is 93 contract-locked routes, not 92
(nearai#6780 landed after the last recount).

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

* docs(stale-sweep): fix agent guidance outside crates/ for the family restructure

Audit-and-fix pass over every stale document outside crates/ (PR 2 of the
family-guidance program). Live guidance verified against the tree; records
kept with dated notes instead of rewrites.

Guidance fixes (verified against HEAD before writing):
- .claude/commands/trace.md: MCP tool prefix codebase-memory -> codebase-memory-mcp
  (allowed-tools never matched the real server), ProductSurface home ->
  ironclaw_product_contracts, capabilities host.rs -> host/ module split,
  scripts lane -> script-sandbox; deleted the redundant v1-anchors section.
- .claude/commands/add-sse-event.md: deleted the banner-quarantined v1 scaffold
  steps (every path deleted with the monolith); now an honest redirect to the
  Reborn projection/SSE path. Frontmatter no longer advertises a working scaffold.
- .claude/commands/deslop-reborn.md: three dead crates/*/Cargo.toml globs (family
  layout added a level), ls crates/ -> family-aware listing, v1-only consumer
  logic retired, per-crate --features integration phrasing.
- .claude/rules/type-placement.md: crates/*/src globs matched nothing; recipes
  re-pointed and numbers re-measured 2026-08 (3,495 structs/enums, 385 traits,
  fan-in host_api 53 / common 20 / turns 12).
- .claude/rules/skills.md: paths trigger pointed at a nonexistent
  bundled_skills.rs (rule never fired); SKILLS_REGEX_ACTIVATION_ENABLED /
  SKILLS_MAX_TOKENS env vars are read by nothing -> documented the real
  config-file setting and DEFAULT_MAX_SKILL_CONTEXT_TOKENS.
- .claude/rules/testing.md, ironclaw-reborn-testing skill, CONTRIBUTING.md,
  .github/pull_request_template.md, testing-playbook, deslop: the workspace-root
  `integration` feature is empty with zero consumers - all "cargo test
  --features integration" guidance re-pointed to crate-level suites.
- .claude/skills/reborn-extension-surfaces: four pre-colocation assets/ paths,
  CapabilitySurfaceKind home, conformance-suite move to
  ironclaw_extension_contracts, ingestion test move to the registry crate,
  gate-banned migration exemplar replaced with the live behavioral pin, [mcp]
  instead-of claim softened (nearai-mcp pins a static [[tools]]).
- .claude/skills/ironclaw-reborn-orientation: turn_runner labels, prompt-crate
  list re-derived (turns/first_party_extension_ports out; host_api,
  loop_contracts, assistant in), consumer-grep glob fixed.
- .claude/skills/reborn-feature + docs/reborn/how-to-port-channel-to-reborn.md:
  ProductSurface/ProductView/descriptors/caller types live in
  ironclaw_product_contracts; recipes re-pointed.
- CLAUDE.md: dead root --features integration line replaced; project tree
  redrawn with the ten families; trait homes corrected; ProviderId -> VendorId;
  CapabilitySurfaceKind + ChannelAdapter homes; [channel.config] ->
  [channel.connection]/[admin_configuration]; v1 Job State Machine section
  deleted (no such machine in Reborn); prompt-crates recipe fixed; MCP server
  name; LLM backend list re-derived from LlmBackendKind.
- docs/extensions/building-a-tool.md: product-adapter crates row -> channel
  surface model; package registration -> PACKAGES collector in
  ironclaw_extension_support (available_extensions.rs is being dissolved);
  hosted-MCP policy home -> ironclaw_extension_host/src/mcp.rs; dead v1 bullets
  dropped.
- docs/internal/mutation-audit.md: runnable command blocks re-pointed (family
  paths; ironclaw_dispatcher example replaced - crate deleted in WS0).
- docs/reborn/harness/e2e.md: dispatcher row -> the capabilities dispatch
  contract suites. docs/reborn/contracts/host-api.md: three ironclaw_dispatcher
  mentions -> capabilities dispatch module. standard-operations.md: renamed
  crate + arch-test package name.
- scripts: mutation-audit.sh usage header, check-hermetic-env.sh env_helpers
  pointer, check-generic-without-concrete.sh mirror pointer,
  telegram_smoke/README regression step (target deleted with v1 in nearai#6375).
- .env.example: dead SKILLS_REGEX_ACTIVATION_ENABLED entry -> config-file doc.
- docs/qa/telegram-coverage-map.md: nine not-automated reasons re-worded to the
  crate-level integration tier.

Records (dated notes, no rewrites): ADR 0003/0004 path notes (evidence pinned
to their measured SHA), FEATURE_PARITY state-migration paragraph marked
historical with a git-show recovery pointer, engine-v2 parity record's
"coexist on main" claim corrected with a historical note, subagent-spawn
legacy scope re-tensed.

Pre-family path reproduction count: 73 -> 70 files; every remaining file is a
dated record (docs/plans, docs/superpowers, ADRs, audits, CHANGELOG history,
historical-marked train docs) or a deliberate past-tense mention.

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

* docs(ws12): tick row 7 — the fresh-agent placement probe passed on the final tree

All three placements correct with high confidence, each naming the trait, the
tests, and the tempting wrong place it rejected. The probe doubled as a docs
audit and independently hit four defects, three of which the stacked guidance
PR fixes — it succeeded despite them.

WS12 is now 7/7. The restructure is complete.

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

* docs(target-arch): the product→loop_host recount was wrong on the day it was written

Eight importing files across four seams, not seven across three — the fourth
being a skill-activation-observer seam (projection.rs, projection/live_progress.rs)
this bullet never named, which §6.4.7's own same-day note already implied.
Surfaced by the plan-conformance audit.

The recount history is 3→5→6→7→8, wrong at four of five attempts. That retires
the prose count as a method: the sever slice should land an inventory ratchet
before or with the move, not another number.

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

* review(7263): CodeRabbit round-1 triage — 4 code fixes (2 sabotage-proven, 2 red-first) + 6 doc-truth corrections

Code, each verified red-first or by sabotage matrix:
- sealed-mint ratchet: per-name sighting floor for TEST_SEAM_MINT_FNS
  (closed path #12). Proven: renaming test_verified_for_tenant away plus one
  extra legitimate sibling mention passed the old aggregate floor (silent
  disarm) and fails the new per-name floor naming the constructor; suite
  23/23 after revert. (CodeRabbit's claimed baseline ">2 mentions today" is
  wrong — each name has exactly one kept sighting — but the doc/enforcement
  mismatch and at-threshold fragility were real.)
- trace credit: non-finite novelty_score/duplicate_score are treated as
  absent before clamping (clamp preserves NaN, which poisoned online_score
  and credit_points_estimate); NaN cases added to the nearai#7144 regression test,
  red first.
- trace submission: a 2xx whose body stream dies mid-read now maps through
  request_failed (network telemetry kind, true I/O cause) instead of
  collapsing to an empty body that the nearai#7144 strict parse misreported as
  response_invalid/Submission; truncated-body regression test, red first.
- Postgres contract suites (event store + assistant ledger): isolated-DB
  names now carry a creation epoch and the once-per-binary sweep is
  age-gated (1h), closing the cross-process window where a sibling's fresh
  zero-backend database (between CREATE DATABASE and first connection) was
  sweepable; legacy pid-scheme leftovers still collect immediately. Proven
  on live Postgres 16: planted stale name swept, planted fresh name
  survives, 13/13 x2 and 20/20 x2 with zero leftovers.

Docs (target-architecture truth pass):
- PROPOSAL section 9: the WS6 rename sweep (nearai#7152) had rewritten the source
  column of the 12 renamed rows to their post-rename names, turning their
  rename dispositions into no-ops (rows 13/14/28/30/49/51/59/61/64/66/67/70);
  pre-restructure names restored with a dated footnote.
- PROPOSAL:69: removed the superseded 3->5->6->7 recount sentence (the
  corrected 3->5->6->7->8 passage subsumes it).
- PROPOSAL row 34: ToolPermissionOverrideStorePort deletion marked landed
  (2026-08-05 WS8, matching section 6.5.3; zero workspace hits).
- CHECKLIST:631: dated note recording that the WS12 F3 gsuite join landed in
  this batch (scenario_uninstalled_tool_call_denied_until_active.rs asserts
  the seeded google token on the gmail.googleapis.com wire; suite run green).
- CHECKLIST:632: dated note spending F4 (the audit's 19 was correct at its
  SHA; the ratchet file now holds 23 tests, re-counted at lines 552/597).
- ws12-gauntlet-report P6 heading: first of TWO real failures (one class),
  matching P8 and the report's own summary.
- ws12-mapping-audit rows 49/137: dated D-S closure notes (await-edge store
  half = journal projection already; resolver retained loop-tier; no shed
  owed) so the backlog register no longer lists it as in-flight.

Not fixed, with evidence: the span-helper macros gate suggestion
(info_span!(target = ...) is a hard compile error, E0425 — no silent trap),
the webui tracing-subscriber workspace-dep suggestion (no
[workspace.dependencies] entry exists; suggestion would not build; 8
siblings use the identical direct shape), and the mapping-audit
regeneration (the audit is accurate at its pinned SHA; the in-batch F1 fix
is recorded in its dated coordinator note).

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

* review(7263): CodeRabbit round-2 — rejection-body read keeps its cause; 200 {} is not a submission acknowledgement; lanes.md family dep rule matches measured Cargo.tomls

- submission.rs non-2xx path: a failed rejection-body read no longer collapses
  to an empty detail via .unwrap_or_default() (banned by
  .claude/rules/error-handling.md); the read error folds into the
  http_rejection detail so the received status keeps driving the 401/403
  auth-retry and the Credential/HttpRejection telemetry split.
  Regression: submit_preserves_rejection_body_read_failure_cause_with_status.

- TraceSubmissionReceipt.status: serde default removed — it fabricated
  status "submitted" from a proxy's 200 {} (the nearai#7144 synthesis, resurfacing
  through the wire type's defaults), after which the flush caller recorded
  Submitted and deleted the only retryable queued copy. The acknowledgement is
  the server naming what happened to the submission — every workspace fixture
  sends status and callers persist it unconditionally as server_status — so a
  status-less 2xx body now fails the strict receipt parse as response_invalid.
  Regression: submit_rejects_success_response_without_explicit_server_status
  (covers 200 {} and a status-less non-empty object).

- docs(lanes.md): the family Dependency-direction rule no longer claims every
  lane takes the extension-surface vocabulary crate — measured across
  crates/lanes/*/Cargo.toml: mcp + sandbox hold ironclaw_extension_contracts
  under [dependencies], wasm only under [dev-dependencies]; dated ✎
  cross-references the ironclaw_wasm entry's 2026-08-05 correction.

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

* review(7263): CodeRabbit round-3 — shared Postgres test provisioner (the "new dep edge" premise measured false), entrypoint self-test armed (sabotage-proven), six doc self-contradictions reconciled

Code:
- ironclaw_filesystem gains a `postgres_isolation` test-support module — the
  single home of the per-test isolated-database scaffolding (once-per-binary
  age-gated stale sweep, epoch-in-name convention, DROP WITH (FORCE) cleanup),
  parameterised by suite/env-var/prefix/unreachable-policy. Zero new
  production edges: event_store already normal-deps filesystem, filesystem
  already owns tokio-postgres, and the dev-dep+feature pattern is the one 17
  crates already use. The event-store and product-workflow-ledger suites
  migrate onto it; both Postgres legs proven live against postgres:16 (12
  tests, zero leftover databases). The fabric original keeps its older
  variant with the differences documented at its IsolatedDatabase.
- ironclaw_event_store drops the duplicate tokio-postgres dev-dep (the normal
  dep already reaches tests).
- test-reborn-docker-entrypoint.sh: the missing-argv check now exits the
  command-substitution subshell instead of incrementing a counter the parent
  never sees — red-proven (a migrate-but-never-exec entrypoint passed with 7
  FAIL lines printed), green after the fix both sabotaged and restored.
- trace_commons submission test additionally pins !auth_rejection() for the
  503 rejection (the structural assert the API affords; the prescribed
  payload asserts are refuted — status is private and source is None by
  design, with the message derived from the structured status in the same
  constructor).

Docs (each reconciled to one canonical statement, measured):
- kernel.md: lease ownership decided from code — authorization stores,
  matches, and expires leases (CapabilityLeaseStore + port + expiry all live
  there); approvals constructs and issues into that store. The round-1
  re-homing of the spliced sentence into approvals was wrong and is corrected
  in the dated repair note.
- app.md: "nothing depends on app" scoped to the three app-layer crates;
  ironclaw_config's consumers restated by dependency kind (normal:
  composition, cli, operator, extension_host; dev-only: extension_manager,
  root integration-tests package).
- lanes.md: the mediated-services sentence now states the family law as
  layer-ladder + injected authority; the no-secrets/network/filesystem-dep
  claim is scoped to ironclaw_wasm, matching the file's own corrections.
- CHECKLIST 429/430: the one open traces clause is named (ScopedFilesystem
  adoption); the stale "other two" count corrected against the F3a strike.
- PROPOSAL:69 + CHECKLIST:72: the project-create route repointed —
  first_party_extension_ports dissolved into loop_host::skill_activation
  (WS8, §9 row 55) — still unattempted.
- PROPOSAL §9 rows 57/62 synced to §6.8.4 (telegram: dependency-set equality
  with Slack's four contract-tier crates) and §6.9.4 (webui -> assistant is a
  charter-permanent edge, §12.11 D-B).
- PLAN top summary records Wave 6's design question as resolved (D-S,
  2026-08-05).
- deploy-reborn-cli-docker.md: the two migration paragraphs unified on the
  entrypoint's actual behavior — only enabled = false beside
  signing_secret_env/bot_token_env is migrated; every other retired-key shape
  fails startup with the migration pointer.
- composition-budget.toml: the stale "2398 bp, a true ratchet" header
  replaced with the WS0-floor truth the baselines test asserts.

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

* docs: move the guidance convention into this PR so its citations resolve

families/lanes.md and families/events.md cite docs/reborn/guidance-conventions.md
when superseding their 'every crate ships both an AGENTS.md and a CLAUDE.md'
requirement, but the file was only on the stacked guidance branch — a forward
reference that dangles if this PR merges alone. The convention is the rule those
notes invoke, so it belongs with them.

Caught by the CodeRabbit round-3 pass.

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

* fix(ci): give the hoisted postgres provisioner its safety rationales

The round-3 hoist moved test provisioning into a production src/ path, so
check_no_panics flagged its four panic/expect sites and reddened Code Style via
fast-checks. The gate is right to flag them: it deliberately does NOT exempt
#[cfg(feature = "test-support")] modules, because a cargo feature is not a
privilege boundary in this workspace (PROPOSAL 12.1a proved exactly that) —
so a test-support module still compiles into a build where any sibling enables
the feature.

Suppressed with the gate's documented inline rationale, which must trail the
statement rather than precede it. The panics themselves stay: a configured but
unusable Postgres must fail the suite loudly rather than skip it, which is the
inert-guard rule the isolation fix exists to serve.

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

* fix(ci): classify the three planner-unknown paths this PR touches

The Reborn PR test planner fails closed on any unclassified path and
raises on the FIRST failure in sorted order, so CI only ever showed
.github/pull_request_template.md. Classifying that unmasked two more
paths in this PR's own diff: scripts/mutation-audit.sh and
scripts/telegram_smoke/README.md. All three are classified; the
fail-closed arm is untouched:

* .github/pull_request_template.md -> IGNORED_PREFIXES, beside its
  exact sibling .github/ISSUE_TEMPLATE/ (both GitHub UI templates;
  classify-test-scope.sh already pairs them in its docs-only arm).
* scripts/mutation-audit.sh -> PR_STATIC_CONTROL_PATHS, beside its
  self-test scripts/test-mutation-audit.sh; both run only in
  nightly-deep-ci.yml's mutation-frontier job.
* scripts/telegram_smoke/ -> QA_HARNESS_PREFIXES; a live, by-hand
  release smoke harness referenced by no workflow, same class as
  scripts/reborn_qa_matrix/.

Each entry is pinned red-first in test_reborn_pr_test_plan.py (entry
commented out, new assertion fails with the exact production error,
entry restored, green): a new PR-template test with paired
accept-AND-select-nothing assertions plus unknown-.github/-sibling
refusal probes, and the two existing class tests extended. Planner
self-test: 65 tests OK. The planner CLI over this PR's full 209-path
diff now exits 0.

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
l3ocifer pushed a commit to l3ocifer/frick-ironclaw that referenced this pull request Sep 3, 2026
…, agent-mode pill (nearai#6994)

* feat(webui): OOBE automation-tasks prototype — carousel, inline cards, agent-mode pill

First-time-user OOBE concepts for the WebChat v2 landing view, built as a
UI-only prototype on mock data (backend intentionally not wired yet). Recovered
and rebased from the Jul design session (was the stale design/oobe-chat-automations
WIP); the streaming NearProcessIndicator busy-states are re-applied on top of #6901.

Adds to the chat view:
- Completed-automations carousel above the composer (automation-carousel,
  automation-task-card) — validates auto-run tasks, deep-links into the 3rd-party app.
- Inline calendar-reschedule rich-preview (calendar-reschedule-card) and a Plan-mode
  batch card (plan-card), sharing one decision model via task-action-bar
  (suggested → Approve/Modify/Cancel; automated → Modify/Revert).
- Agent-mode composer pill (mode-selector + lib/agent-mode) — Suggest/Plan/Auto/Bypass,
  persisted to scoped localStorage in the prototype.
- Typed mock domain + endpoint-shaped seam (lib/automation-tasks*, useAutomationTasks)
  so wiring the backend is a mock→fetch body swap with no component changes.
- DEV-only /design-preview harness (design-preview-page) to view the concepts, gated by import.meta.env.DEV.
- Busy states render the branded NearProcessIndicator (from #6901) — shared design language.

The backend (durable events, projection, transport frame, HTTP routes, facade+effect,
agent-mode persistence) is NOT implemented; AUTOMATION-TASKS-CONTRACT.md is the
reviewable wiring spec, tracked as a follow-up.

NOTE (why this is a draft): the landing carousel reads listAutomationTasks(), which
returns MOCK data for all users and is not DEV-gated. Must be backend-wired or gated
before this can leave draft / merge.

Frontend gate green: conventions + typecheck clean, 1032 tests pass.

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

* docs(design): add OOBE first-run onboarding mockup + brief

Standalone design exploration for the two first-run moments the PR #6994
prototype skips: the cold-start landing (zero automations, nothing connected)
and the first "Done for you" card appearing. House style matches
docs/design/agent-activity-streaming.

- docs/design/oobe.md — brief: goal, the two moments, the Invite vs Coach
  direction fork, what ships (#6994) vs needs backend (#6993), open questions.
- docs/design/oobe/mockup.html — interactive: plays cold-start → connect →
  anticipatory (NEAR indicator + skeleton tiles) → first-card reveal →
  populated, with a seg toggle for Invite (minimal) vs Coach (anticipatory
  ghost cards). Real --v2-* tokens; light+dark; reduced-motion honored.

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

* docs(design): OOBE mockup — add Thread + Plan scenes

Fold the two in-thread concepts into the standalone mockup so one shared
Artifact covers the whole OOBE arc. Adds a Scene selector (First run /
Thread / Plan):
- Thread — the inline CalendarRescheduleCard rich-preview (live: Approve →
  "Rescheduling…" → Automated; Modify time cycles the proposed slot; Skip →
  dismissed), plus an already-automated example with Modify/Revert.
- Plan — the batched PlanCard (Approve all → "Running your plan…" → all done;
  per-item skip), faithful to plan-card.tsx.
Same --v2-* tokens, NearProcessIndicator busy states, light+dark, flags.

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

* docs(design): OOBE mockup — flag taxonomy + connect-pill redesign

Flags reframed around what's on main: Shipped (already on main), Redesign
(design update to existing main UI), New Feature (net-new, needs new
events/functionality), New UX (new design not on main); New Feature + New UX
combine. Applied: connect row = Shipped (reuses AuthRequired); composer =
Redesign (mode pill added); Coach ghost = New UX; carousel, both calendar
cards, and the plan card = New UX + New Feature.

Connect pills redesigned: per-tool checkbox state (no "connect" text), a
"Connect all" action, and — once connected — the pills condense into an
overlapping icon stack ("N connected", tap to re-expand).

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

* docs(design): OOBE mockup — Connect all as a lightweight link

Restyle the "Connect all" action from a filled primary button to a
lightweight accent text link (underline on hover) so it doesn't compete with
the connect pills. Kept as a <button> for keyboard/focus + the click handler.

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

* docs(design): OOBE mockup — avatar-style condensed connect stack

Restyle the condensed connected-tools stack after the stacked-avatars
reference: circular app icons with a white ring (theme surface) + soft drop
shadow, heavier overlap, and a trailing "+" circle to add another tool. The
count moves to the header subtitle ("3 connected — tap to manage"); the whole
stack re-expands on tap. Light + dark, reduced-motion honored.

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

* docs(design): OOBE mockup — refine condensed connect stack

Per feedback on the stacked-tools chip: opaque icon fills (drop the
transparent tint so overlaps don't bleed), rounded-square shape to match the
expanded pills (was circular), a ">" chevron instead of "+" on the trailing
chip, and "add more later" → "add more anytime" in the header subtitle.

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

* docs(design): OOBE mockup — relocate live indicator to carousel + collapse action

Contextual placement: the branded NEAR process indicator now leads the carousel
header (animated while working with a live elapsed, settling to a solid mark +
"worked for Ns" when done) instead of floating above the composer — it sits
where the agent's output is forming. Header is now a two-line block (mark +
title/elapsed over subtitle) so it stays clear of the annotation flags.

Connect pills: add a collapse control (left-chevron chip) to the right of the
expanded pills, mirroring the stack's expand affordance, to re-condense.

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

* docs(design): OOBE mockup — agent mode drives task-card state

Rename the "Automated" badge to "Completed", and make the agent-mode pill a
live control: Suggest / Plan render the carousel cards as suggested (Approve /
Modify / Cancel, "Suggested" badge, "Suggested for you" header + hero); Auto /
Bypass render them completed ("Completed" badge, Modify / Revert, "Done for
you"). Per-card Approve flips a single card to completed, Cancel → dismissed,
Revert → reverted — so the suggested→completed flow is real, not just a label.

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

* docs(design): OOBE mockup — single-line carousel header

Put the secondary description back on the same line as the indicator's activity
string (title + elapsed). To keep it single-line and clear of the annotation
flag, drop the redundant working-state subtitle (title + live elapsed is enough)
and tighten the done-state subtitle to "Review or undo anytime".

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

* docs(design): OOBE mockup — remove the cold-start Invite/Coach switcher

Drop the Invite/Coach direction toggle and its JS; first run now uses the
minimal ("Invite") cold start. Cleaned up the lede + footnote copy that
referenced the toggle and the Coach ghost strip.

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

* docs(design): OOBE — dismissible connect panel + composer pill; archive stack

Connect-tools panel:
- add a close (X) to dismiss the panel; when dismissed it collapses to a small
  "Connect your tools" pill in the composer action row (left of the agent-mode
  picker) with its own X. Pill body re-opens the panel; pill X removes it.
- remove the collapse/expand overlapping-stack control entirely.

Archive: docs/design/oobe/archive/connect-tools-stack.html — a self-contained,
theme-aware record of the retired collapse/expand states (expanded pills +
collapsed avatar stack) for the design archive.

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

* docs(design): OOBE mockup — move connect pill right of the mode selector

Place the dismissed-state "Connect your tools" pill after the agent-mode picker
in the composer action row (was to its left).

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

* docs(design): OOBE mockup — connect panel button + reflow

- Move the connect action out of the header into a bottom-right button (was a
  link); its label is "Connect all" with nothing selected, "Connect" once any
  tool is picked, hidden when all are connected.
- Pin the dismiss (X) far-right in the header (margin-left:auto) so it no longer
  relocates when the button hides.
- Add more tools (Notion, Drive, GitHub) so the pills reflow to a second row
  past four.

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

* docs(design): OOBE mockup — connect button rides the pill row (drop empty footer)

The connect action now flows at the end of the pills (right-aligned via
margin-left:auto) instead of a dedicated full-width footer row, removing the
wasted empty space to the button's left.

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

* docs(design): OOBE mockup — Gemini ai-spark border on the first-card reveal

Replace the static accent glow ring on the first "aha" card with a Gemini-style
ai-spark: a blue→purple→pink conic gradient masked to the card border that
chases around once (1.35s) and then dissipates, with a soft purple/coral glow.
Uses @property --ai-angle for the sweep; hidden under prefers-reduced-motion.

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

* docs(design): OOBE mockup — make the ai-spark actually chase the border

The conic-gradient + @property --ai-angle version interpolated the angle but
Chromium didn't repaint the gradient, so the spark never moved. Rebuild it as
an SVG rect stroke with an animated stroke-dashoffset (a Gemini blue→purple→pink
gradient dash that travels the border once, then dissipates) — stroke-dashoffset
repaints reliably every frame. Hidden under prefers-reduced-motion.

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

* docs(design): OOBE ai-spark — faster, tapered comet tail, theme-aware colors

- Speed: 1.5s → 0.7s lap.
- Tail: uniform round-cap dash → a solid head fading into progressively
  sparser dashes; the drop-shadow glow blurs it into a smooth tapered comet
  (restores the taper the conic version had).
- Colors: per-theme tokens (--ais-1/2/3 + --ais-glow) — deeper/saturated blue
  →purple→magenta on light so it reads on white, brighter on dark.

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

* docs(design): OOBE first card is conjured — spell-cast reveal

Make the first automation card feel summoned rather than placed:

- Faster spark: 0.7s -> 0.5s lap.
- Conjure: the card no longer pops in fully-formed — it materializes
  (opacity 0->1, scale .84->1 with a slight overshoot, blur 7px->0) in sync
  with the spark tracing its border.
- Spell-land: a brief glow pulse (--ais-glow) blooms around the card as the
  spark completes its loop.
- prefers-reduced-motion disables conjure + spell-land alongside the spark.

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

* docs(design): OOBE — soften the conjure/spark effect

Dial the spell-cast reveal back to a subtle shimmer:
- Thinner spark stroke (2.6 -> 2.1) with a softer drop-shadow (3/8px -> 2/5px).
- Lower glow alpha (dark .85 -> .62, light .5 -> .4).
- Gentler spell-land pulse (24px/.85 -> 14px/.4).
- Calmer conjure: less blur (7 -> 4px), smaller scale-up (.84 -> .92) and
  near-zero overshoot.

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

* docs(design): OOBE spark — smooth continuous tapered comet

Replace the segmented SVG dash with one intact line:
- Technique: a conic-gradient comet masked to the border ring and rotated
  (transform repaints reliably, unlike an animated conic angle) — gives a
  single continuous line with a smooth head-to-tail taper.
- Transparency: color-mix bakes translucency into the color line
  (head ~86%, fading to fully transparent at the tail).
- Faster: 0.5s -> 0.4s lap.

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

* docs(design): OOBE — clean up the task card layout & styling

Restyle the automation cards after the "Your availability" reference pattern:
- Hierarchy: the task title now leads the header (icon + bold title, status
  badge top-right); the app name drops to a muted "From Gmail · 2m ago"
  provenance line above the actions.
- Buttons: filled primary + text secondaries (Approve / Modify / Dismiss)
  instead of three bordered buttons; Cancel -> Dismiss.
- Surface: larger radius (13 -> 16px), more padding, a soft floating shadow,
  a middot-separated metric line, and bottom-aligned action rows so equal-
  height cards line up. Spark/conjure ring radii follow the new corner.

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

* docs(design): OOBE cards — real brand logos, drop the tag, condense

- Real product logos (Gmail, Google Calendar, Docs, Drive, Slack full-colour;
  Notion + GitHub monochrome via currentColor so they follow the theme) replace
  the placeholder line icons — on the task cards, connect pills, Thread card,
  and Plan list. Icon chips become tile-less logo holders (no tint/border).
- Remove the status tag/badge from the task-card header (state still reads from
  the action row).
- Condense card height (padding 14->12, tighter header/prov gaps; single-line
  titles now that the badge is gone) and scale the button row down
  (height 32->28, smaller padding/font).

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

* docs(design): OOBE — consistent card buttons, real Notion mark, task drawer

1. Link buttons carry icons in both modes: suggested-mode Modify/Dismiss now
   get the edit / close icons, matching the completed-mode Modify/Revert.
2. Notion logo swapped to the real Notion mark (notebook + N, monochrome via
   currentColor so it follows the theme) instead of the plain geometric N.
3. Task drawer: typing in the composer collapses the full task cards into a
   condensed, scrollable pill row (brand logo + title) above the composer;
   clearing the field — or tapping a pill — re-expands. Same control can seed
   suggested tasks for a returning user / new thread.

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

* docs(design): OOBE — Vision/Foundational versions + attached task drawer

Add a Version switch (toolbar) with two design tracks:

Vision (north-star): the task cards now sit in a bordered "drawer" frame that
docks onto the composer and extends up from it, cards inset within the frame.
The drawer header carries collapse/expand (cards <-> pills) and a dismiss (X)
that hides it behind a "Show suggestions" restore bar. Typing still collapses
to pills. Keeps the connect flow, named greeting, and full mode set.

Foundational (near-term, v2-faithful): scoped for a multi-tenant enterprise
deploy — tools are admin-preconfigured so there's no connect step; no username
unless derivable (nameless greeting + blank account chip); agent modes scoped to
Suggest / Plan / Auto Approve, default Suggest. Uses main's composer and the
plain pills-collapse from the prior commit (no bordered drawer).

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

* docs(design): OOBE — Foundational cards at first step, Vision status line above drawer

1. Foundational first run is now a single populated state: because enterprise
   tools are admin-preconnected, the suggested task cards appear at the first
   step (no empty cold start, no beat scrubber).
2. The branded progress indicator + agent activity string move ABOVE the drawer
   (a relocated status line); the drawer header now carries the subtitle
   top-left ("Approve to run, or tweak first") beside the collapse/dismiss
   controls. Applies across both versions; the frame remains Vision-only.
3. Auto Approve description clarified: auto-approves task types already approved
   plus any task the user requests.
4. Rewrote docs/design/oobe.md to document the Vision/Foundational split,
   Foundational enterprise scoping, the reusable task drawer, and phasing.

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

* docs(design): OOBE — corner-X dismiss, empty-state fallback, drawer title = agent string

- Per-item dismiss: the "× Dismiss" link is gone; each task card gets an X in
  its top-right corner and each collapsed pill gets an X on the right. Dismissed
  items are removed from the strip/pills.
- Empty state: when every suggestion is dismissed, a dashed fallback appears —
  Vision "Coming up with new suggestions" (pulsing), Foundational "Find new
  suggestions" (tap to repopulate).
- Removed the drawer-level dismiss X and the restore bar (dismissal is per-item
  now); the drawer header keeps only the collapse/expand toggle.
- Removed the branded NEAR progress indicator on both versions; the agent
  activity string ("Looking for things to suggest" / "Suggested for you") is now
  the drawer title (upper-left) with the subtitle beneath it. Hidden when collapsed.
- Toggle is pinned top-right and floats above the pills (bg fade + padding) so it
  no longer covers an overflowing pill.
- Foundational is steppable again (scrubber restored) with suggested cards from
  the first step; revert now returns a card to suggested.

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

* docs(design): OOBE — keep drawer title + subtitle on one line

Revert the drawer header to a row layout so the agent string and its subtitle
("Suggested for you  Approve to run, or tweak first") stay inline on a single
line instead of the subtitle reflowing to a second line.

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

* docs(design): OOBE — Foundational approve→automate→complete journey, Modify modal, attachment collapse

1. Foundational now steps through a real flow: beat 0 suggested → approve →
   beat 1 "Automating…" (spinner) → beat 2 completed, repeating for the next
   task, ending all-done. Adds a `running` card state; clicking Approve (either
   version) animates suggested → Automating… → completed (~1s). Drawer title
   tracks the state (Suggested for you / Automating… / Done for you).
2. Attachment collapse: adding an attachment (the composer + button, with a
   removable chip) now collapses the drawer to pills too — alongside typing.
3. Modify opens a modification modal (both versions): title = task name, an
   "adjust before it runs" field, Cancel / Save changes; backdrop over the app.

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

* docs(design): OOBE — state-aware card copy, tighter composer gap, pill tap expands

1. Cards/pills now carry both a suggested (proposal) and completed (result)
   phrasing and switch on state: e.g. "Triage your inbox · 40 unread · 12 need
   replies · From Gmail" while suggested, "Triaged your inbox · 12 replied · 40
   archived · From Gmail · 2m ago" once done. Fixes suggested cards reading as
   already-completed (both versions).
2. Halved the gap between the cards/pills and the composer (Foundational).
3. Tapping a collapsed pill now expands it back to the full task cards (both
   versions); typing/attaching re-collapses (suppression flag so a tap-to-expand
   isn't immediately re-collapsed by lingering composer text).

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

* docs(design): OOBE — 3rd-party auth flows (queued OAuth modal)

Add a reusable modal "browser" OAuth dialog (chrome bar + provider domain,
sign-in account chooser, consent/scopes, Allow) wired into both tracks:

- Vision: the connect panel now *selects* tools; the Connect button opens the
  dialog queued across the selection (sign in once, approve scopes per tool)
  until all are authorized, then advances.
- Foundational: tools are admin-whitelisted but user-authorized — each task card
  starts unconnected with a "Connect <Tool>" CTA; connecting runs the dialog and
  the card becomes an actionable suggestion. Beat journey now walks
  unconnected → connected(suggested) → automating → completed.

Brief updated to match (Foundational connect model + Vision OAuth queue).

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

* docs(design): OOBE — refresh the 5 suggested/automated tasks

Replace the 3 sample cards with the intended task set (both versions):
1. Email triage — archive marketing to "IronClaw Archive", flag urgent (Gmail)
2. Calendar — accept free invites, propose times for conflicts
3. Build your profile — read activity across Gmail/Slack/Telegram (multi-tool)
4. Catch-you-up 24h digest — org summary, flag replies, propose priorities
   (Drive/Notion, multi-tool)
5. Suggest 5 automations — agent drafts its top-5 to approve (no external tool)

Cards now carry a short description line (suggested proposal vs completed
result) instead of the number pairs, custom glyphs for the agent/meta tasks,
and a per-card `conn` tool list so the connect CTA queues the right OAuth
dialogs ("Connect 3 tools" → Gmail→Slack→Telegram). Added a Telegram brand
logo + auth metadata; Foundational beat table + greeting updated for 5 cards.

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

* docs(design): OOBE — match collapsed-pill bottom gap to the task-card gap

The pill row carried 6px bottom padding vs the card strip's 2px, so the pills
sat ~4px farther from the composer. Reduce the task-drawer bottom padding to
match the strip (4px base, 2px Foundational) — pill and card bottoms now sit the
same distance above the composer.

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

* docs(design): OOBE Vision — connect banner confirms then dismisses after auth

After the user authorizes their selected tools through the OAuth queue, the
"Connect your tools" banner flips to a confirmation state — green check icon,
"Tools connected · N authorized", the connected tools shown green, close-X
hidden — then dismisses (~1.3s) as the flow advances to the working/anticipatory
beat. Beat 1 is now that confirmation moment (also reachable via the scrubber).

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

* docs(design): OOBE Foundational — section-level dismiss X for cards + pills

Add a drawer-level close (X) pinned top-right of the suggestions section,
visible in both the expanded task-card state and the collapsed pill row
(Foundational only — Vision keeps its collapse toggle there). Dismissing hides
the whole drawer and drops a "Show suggestions N" restore bar above the
composer; restoring brings it back. Per-item × on each card/pill is unchanged.

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

* docs(design): OOBE Foundational — align the section dismiss X in both states

Center the drawer dismiss X on the "Suggested for you" header (expanded) and on
the pill row (collapsed) via a state-specific top, and move it flush to the
right edge of the card/pill container + composer (right 11px -> 2px). Verified
dy=0 in both states.

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

* docs(design): OOBE — dismiss-X container masks against the real background

The dismiss X used --v2-surface (white) for its fill + left fade, but the pills
sit on --v2-canvas, so pills bled through the gradient. Switch the X container
fill and its left-fade shadow to --v2-canvas so it matches the background behind
the pills — overflowing pills now fade cleanly into the bg (masking effect),
gradient retained. Verified fill == scene bg in light and dark.

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

* docs(design): OOBE Foundational — collapsed dismiss becomes a full-height gutter mask

In the collapsed pill state the dismiss control is no longer a small rounded
square: it fills the drawer height, pins flush to the right edge, and carries a
transparent->canvas gradient so pills fade out and aren't visible past it. The X
sits centred in the gutter. Expanded (cards) keeps the header-aligned X.

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

* docs(design): OOBE Foundational — move "Show suggestions" restore into the composer

Replace the restore bar above the composer with a pill inside the composer, to
the right of the agent-mode selector (reusing the connect-pill style). Tapping
the pill body restores the dismissed suggestions drawer; the pill's X fully
dismisses it (new 'gone' state — drawer and pill both hidden). Removed the dead
restore-bar markup + CSS.

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

* docs(design): OOBE integration proposal & plan — Foundational + Vision phasing

Add a #6918-style proposal package under docs/design/oobe/ (README / PROPOSAL /
PLAN / CHECKLIST) for phasing the OOBE prototype into production:

- Foundational (near-term, ships on current main) then Vision (north-star),
  matching the mockup's two versions; every Vision piece a superset of a
  Foundational one, so nothing is redone.
- Scopes Foundational as shipped-vs-net-new: the connect CTA, busy states,
  agent-mode semantics, and manage-result surface all REUSE code on main
  (extension-auth path, NearProcessIndicator, resolve_gate/global_auto_approve,
  pages/automations); the net-new surface is the card family, the
  AutomationTask events+projection+routes+facade, and the first-run suggestion
  producer.
- Inventories dependencies D-F1..F6 (Foundational) and D-V1..V5 (Vision), each
  with an implementation approach, and maps the work onto the five-layer WebUI
  flow and the #6918 target families.
- Applies the APDD governance kit (docs-first workflow, Feedback & Decisions
  anchor, Critical Bug Fix Log, design track, CUJ baseline).

Companion human-review artifact (schematics/diagrams):
https://claude.ai/code/artifact/734b1b6a-e35d-4736-9ac2-952dcdf84ab4

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

* docs(design): reconcile OOBE proposal + contract to post-#6918 family names

The #6918 family-folder reorg has landed on main; update the proposal package
and the wiring contract to current crate names/paths and fix a stale claim:

- crates now under crates/{contracts,events,domains,product,app}/; renames
  ironclaw_events -> ironclaw_event_log, add ironclaw_event_store (both under
  events/), ironclaw_reborn_composition -> ironclaw_composition, and the webui
  frontend paths move to crates/product/ironclaw_webui/frontend/.
- correct the facade identity: it is RebornServicesApi in
  crates/product/ironclaw_assistant (NOT "ProductSurface" — that is the typed
  capability contract/DTOs in ironclaw_product_contracts).
- reframe "#6918 target families" as the family folders now on main.
- note the triggers-hosted suggester option (D-F2) can reuse the existing
  composition automation wiring (trigger_poller + trusted_submit).
- retire the removed .claude/rules/tool-evidence.md reference -> gateway-events
  / lifecycle; product adapters -> the ProductAdapter surface in ironclaw_host_api.
- mark the F0 merge-to-main + contract-reconciliation boxes done.

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

* Roll back the OOBE prototype code; reposition PR as design artifacts + plan

Per review (IronLoop/CodeRabbit flagged mock automations shown to real users and
an autonomy selector execution ignored), drop the prototype source and make this
branch code-free: crates/ is now identical to main.

- Revert the edits to shipped files (app.tsx, chat-input, empty-state, en.ts,
  button/icons + their tests) and delete the added prototype files (automation
  cards, action bar, mode selector, data seam, hooks, design-preview harness).
- Move AUTOMATION-TASKS-CONTRACT.md out of the code tree into docs/design/oobe/
  (kept as the design reference / proposed wiring).
- Plan of record is now the artifacts + the written plan: add
  docs/design/oobe/integration-review.html (the "IronClaw OOBE — Integration
  Review" page) in-branch, and repoint the former claude.ai artifact links to it
  (rendered via html-preview.github.io).
- Reconcile the package (README/PROPOSAL/PLAN/CHECKLIST/brief + contract): a
  code-free banner, fix links to rolled-back files, and reframe "the prototype
  ships here / mock->fetch swap" as "prototyped earlier + demonstrated in the
  mockup; the first implementation builds fresh." D-F5/D-F4 gating moves to the
  implementation PRs.

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

* docs(design): OOBE mockup — align the Foundational version to shipped v2

The mockup's design tokens already match crates/product/ironclaw_webui/src/styles/app.css
verbatim; this aligns the Foundational version's *treatment* to the shipped
WebChat v2 landing:

- hero switches from the serif exploration face to Geist sans, heavier and larger
  (matching empty-state.tsx's text-4xl/6xl font-semibold hero);
- suggestions become full-width divider rows with a round leading icon (matching
  the shipped grid-cols-[auto_1fr_auto] row treatment) instead of pill chips;
- composer picks up the shipped 20px radius + card-bg + round icon buttons.

All scoped to .v-foundational so the Vision (north-star) version keeps its
distinctive treatment. CSS validated (balanced); in-app browser CDP was wedged,
so verify visually via html-preview.

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

* docs(design): OOBE mockup composer — match main (remove mic, round send, larger, full-width suggestions)

Correct the composer to the shipped chat-input.tsx:
- remove the microphone/dictate button (main has none);
- send button becomes a round primary icon button (paper-plane), replacing the
  labeled "Send ⌘↵" pill, matching Button variant="primary" size="icon-sm" rounded-full;
- enlarge the Foundational composer (min-height 120, 15px field, roomier padding)
  to match main's min-h-[120px] hero composer;
- the suggestion rows below the composer now span the full composer width
  (width:100% on .v-foundational .suggs — they were shrink-to-fit + centered).

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

* docs(design): OOBE mockup — apply composer button treatment to Vision too

The mic-removal and round send-button were already global; the round attach
icon button was still Foundational-scoped, leaving Vision's composer with a
square attach. Make the icon-button treatment global (round, 36px) so the
Vision flow's composer reflects the same Send / attach / no-mic design as
Foundational and main. (Composer *sizing* stays Foundational-scoped — Vision
docks its composer onto the drawer.)

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

* docs(design): OOBE CHECKLIST — adopt epic #7044 success criteria

Additive only: add the epic's Phase-1 success criteria (time-to-first-automation,
first-session activation, suggestion quality) to the Foundational exit gate. No
other plan content changes — the proposal package stays the plan of record; the
epic↔proposal scope conflicts are reconciled in #7044, not here.

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

* docs(design): OOBE Phase-1 (v1) UX update — 6 changes wired to shipped backend seams

Mockup (Foundational-scoped; Vision mock unchanged):
- remove the agent-mode selector (kept in Vision) [1]
- disable the other cards while one job runs [3]
- replace Revert with "+ Automation" (creates a scheduled automation) [4]
- v1 = connect + approve UI, no background jobs [5]
- drop Modify; show completed / error-incomplete status on the card [6]

PROPOSAL: new §2A "Phase 1 (v1) implementation update" specifying how each change
wires to EXISTING backend seams (verified on main) — no new AutomationTask
events/projection needed for v1:
- approve -> POST /threads/{id}/messages (submit_turn -> TurnCoordinator), run in thread [2]
- status/activity -> existing WebChatV2Event stream (running/capability_activity/final_reply/failed)
- one-active-run -> submit_turn DeferredBusy/RejectedBusy
- connect -> extension setup/OAuth + AuthRequired frame
- "+ Automation" -> prompt injection -> builtin.trigger_create -> automations dashboard
- gates -> resolve_gate

Also: fix doc link depth after main renamed docs/design -> docs/internal/design.

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

* docs(design): OOBE Foundational v1 — implementation plan grounded in current main

Add IMPLEMENTATION.md: a concrete build plan for the Phase-1 v1 UX (PROPOSAL §2A),
proving every card action wires to seams already enabled on main and enumerating
the frontend components, the feature-flag gating (the D-F5 merge-safety fix), the
vertical PR slices, and the tests.

Verified-enabled on main: submit_turn via lib/api.ts sendMessage; status via
useChatEvents (folds WebChatV2Event frames → running/final_reply/failed); connect
via extension-pairing-api + AuthRequired; resolve_gate; automations dashboard +
useAutomations; builtin.trigger_create; session feature flags (app/auth.ts
features?.). The one net-new backend piece is the first-run suggestion producer
(D-F2) — slices 1–5 ship frontend-only behind an off-by-default flag; the flag
flips on only when the producer lands. No new AutomationTask events/projection.

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

* feat(webui): OOBE Foundational v1 slice 1 — feature-gated SuggestedTaskCard

First implementation slice of the OOBE Foundational v1 (docs/internal/design/oobe
PROPOSAL §2A / IMPLEMENTATION.md). Presentational + gated only — no backend
wiring, no mock data reachable by real users.

- SuggestedTaskCard: one action row per state per §2A — unconnected→Connect,
  suggested→Approve (no Modify), running→NearProcessIndicator, completed→Completed
  chip + "+ Automation" (no Revert/Modify), failed→"Couldn't complete" + Try again;
  `locked` disables the card (item 3). Pure/presentational (callbacks are props).
- SuggestedTaskSurface: reads the `oobe_suggestions` deployment flag via a shared
  ["session"] query and renders null when off (landing unchanged for real users);
  renders a static demo list only when on. Mounted in empty-state above composer.
- auth.ts: `oobeSuggestionsEnabled` + downstream `useOobeSuggestionsEnabled()`
  (no extra session fetch), off by default.
- i18n: 15 chat.oobe.* keys across all 11 locales (parity).
- Tests: per-state card tests + surface gating tests. Frontend gate green
  (pnpm lint clean; pnpm test 1252 passing).

Later slices wire Approve→submit_turn, Connect→extension setup, +Automation→
trigger_create, and the real suggestion feed; the flag stays off in prod until then.

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

* docs(design): reconcile OOBE package — implementation restarted behind a flag

Slice 1 landed real (gated) code on this branch, so the "code-free" framing is
retired: README status + banner, PROPOSAL banner, CHECKLIST F0, and PLAN now say
implementation is underway behind the off-by-default `oobe_suggestions` flag
(slice 1 gate-green). Add IMPLEMENTATION.md to the README doc index.

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

* feat(webui): OOBE v1 slice 2 — Approve a suggested card runs a foreground turn

Wire the card's Approve to the existing send path (PROPOSAL §2A change 2):
approving submits the task's `approvePrompt` through chat.tsx `handleSend`
(display content = the card title), so it runs as a real foreground agent turn
and the thread streams the activity by reuse — no new event/backend code. The
approved card flips to `running` optimistically; its live completed/failed
status arrives via the thread in a later slice (persistent drawer).

- SuggestedTask: add required `approvePrompt`.
- SuggestedTaskSurface: `onApproveTask` prop + `runningId` state (hook before the
  flag early-return); each card wires approve → setRunningId + onApproveTask.
- empty-state/chat.tsx: thread `onApproveTask` down; chat.tsx adds only
  `handleApproveTask` over the existing `handleSend` (gates/nav untouched).
- Tests: approve reports the task + flips it to running; empty-state forwards the
  prop. Still gated off by default. Gate green (pnpm lint clean; 1254 tests).

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

* docs(design): OOBE IMPLEMENTATION — mark slices 1–2 landed; split 2b (live card status)

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

* feat(webui): OOBE v1 slice 4 — "+ Automation" schedules via prompt injection

PROPOSAL §2A change 4. On a completed suggested card, "+ Automation" submits the
task's `automationPrompt` through the existing `handleSend` (display content
"Set up automation — <title>"), so the agent creates a scheduled automation via
`builtin.trigger_create` (prompt injection — no REST create). The card flips to
an "Automation scheduled" chip optimistically. Mirrors the slice-2 approve wiring.

- SuggestedTask: add required `automationPrompt`.
- card: `scheduled?` prop → completed shows a scheduled chip instead of the button.
- surface: `onAutomationTask` prop + `scheduledId` state; +Automation → set + submit.
- empty-state/chat.tsx: thread `onAutomationTask` down; chat.tsx adds only
  `handleAutomationTask` over the existing `handleSend`.
- i18n: `chat.oobe.status.scheduled` across all 11 locales.
- Tests for the scheduled chip + the +Automation wiring. Gated off by default.
  Gate green (pnpm lint clean; 1257 tests).

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

* docs(design): OOBE IMPLEMENTATION — slice 4 landed; slice 3 (Connect) deferred w/ reason

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

* feat(webui): add oobe_suggestions server feature flag so deployments can enable the OOBE cards

Mirror of the reborn_projects flag: GET /session now emits
features.oobe_suggestions, read from the IRONCLAW_OOBE_SUGGESTIONS env var
(default off). The frontend already reads session.features.oobe_suggestions
(slices 1/2/4), so setting IRONCLAW_OOBE_SUGGESTIONS=1 on a deployment (e.g. the
Railway PR preview) turns the first-run suggestion cards on; unset everywhere
else they stay hidden.

- webui_serve.rs: oobe_suggestions_enabled() env read + builder wiring.
- webui_v2/router.rs: WebUiV2State field + with_/getter.
- webui_v2/handlers.rs: WebUiV2Features.oobe_suggestions + get_session literal.
- test: get_session_reports_oobe_suggestions_feature_from_state_flag (drives the
  real router, asserts features.oobe_suggestions mirrors the state flag).

Note: no Rust toolchain in this environment — cargo check/clippy/test not run
locally; CI + the Railway build compile it. Change is a mechanical mirror of an
existing, passing flag.

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

* fix(webui): OOBE — close the /chat bundle-budget CI failure

The "Initial /chat JavaScript (gzip)" budget (check-bundle-budgets.ts,
219.0 KB) failed at 220.6 KB after slices 1/2/4 landed, because
suggested-task-surface.tsx (+ its card + demo data) was imported eagerly from
empty-state.tsx. Not caught by pnpm lint/test — it's a separate CI job
(WebUI v2 JS lint) this PR's frontend gate never ran locally.

Three-part fix, in order of diminishing-but-real savings:

1. Lazy-load the surface: `React.lazy(() => import("./suggested-task-surface"))`
   + `<Suspense fallback={null}>` in empty-state.tsx, mirroring the existing
   CommandResult/AttachmentPreviewModal pattern in message-bubble.tsx.
   (220.6 -> 220.0 KB — smaller gain than expected, see #2.)
2. Hoist the `useOobeSuggestionsEnabled()` flag check OUT of the lazy module
   into empty-state.tsx (already-eager): the hook's own import (app/auth.ts ->
   api.ts/auth-scope.ts) was already eager-reachable elsewhere, so calling it
   from inside the lazy chunk too forced the bundler to extract those modules
   into their own less-efficient standalone chunks. suggested-task-surface.tsx
   is now purely presentational; empty-state.tsx decides whether to even mount
   the lazy import. (220.0 -> 219.3 KB.)
3. Same fix for NearProcessIndicator: suggested-task-card.tsx no longer imports
   it directly (also already-eager via typing-indicator.tsx); empty-state.tsx
   passes a `renderRunningIndicator` render-prop down through the surface to
   the card instead. (219.3 -> 219.2 KB.)

The remaining 0.2 KB is irreducible: gating the lazy-import decision and the
flag-read hook must live in the eager /chat closure. check-bundle-budgets.ts's
own history shows this is the established path for a legitimate net-new
eager cost — CHAT_GZIP_BUDGET raised 219.0 -> 220.0 KB with the same
documented-rationale-comment convention as every prior increase in that file.

Verified: pnpm build clean; check-bundle-budgets.ts passes (login 134.3 KB/
45.7 KB headroom; /chat 219.2 KB/0.8 KB headroom; largest chunk 435.4 KB raw/
64.6 KB headroom); pnpm lint clean; pnpm test 141 files / 1260 tests, all green.

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

* feat(webui): OOBE v1 slice 5 (partial) — lock other cards while one job runs

PROPOSAL §2A change 3: only one suggested job may run at a time. The card
already supported a `locked` prop (slice 1, disables connect/approve/automation
+ dims the card); the surface just wasn't computing it. Now every card other
than the one actively running gets `locked={runningId !== null && runningId
!== task.id}` — the acting card itself stays interactive so its own
running/completed state remains visible.

Test generically discovers whichever card the vm-harness surfaces (its
componentProps helper collapses a mapped list to the last instance's props, so
the test asserts relative to a discovered task id rather than a hardcoded demo
id) and checks all three states: idle (unlocked), a different card running
(locked), the card itself running (unlocked).

The other half of slice 5 — a live `failed`-frame error/incomplete status —
depends on slice 2b's useChatEvents wiring (not yet landed) and stays open.

Gate green: pnpm lint clean; pnpm test 141 files / 1261 tests; pnpm build +
check-bundle-budgets.ts still pass (219.2 KB / 0.8 KB headroom, unchanged —
logic-only change, no new eager weight).

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

* docs(design): OOBE IMPLEMENTATION — slice 5 half-landed (lock done; failed-status blocked on 2b)

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

* docs(design): OOBE IMPLEMENTATION — retire slice 2b, mark 5 done

2b assumed the surface needed to persist into the thread view for live status.
Traced chat.tsx: EmptyState/MessageList are mutually exclusive (showLanding
ternary) — EmptyState fully unmounts on navigation into a thread, so a
persistent drawer would duplicate the thread's own event/message rendering and
import Vision's docked-drawer architecture into Foundational. The correct
model (already delivered by slices 1/2/5): the card gives instant local
feedback pre-navigation; the thread owns live status once the user is in it.
Card-persistent status for a *returning* user needs a durable record, which is
slice 6's scope, not a new frontend slice.

Also: mark slice 5 fully landed for what's achievable (the lock); the
failed-status half is resolved by the 2b finding, not blocked.

Slice 3 (Connect): recorded the useExtensions() investigation — page-level
hook, no isolated connect primitive; recommend extracting one first.

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

* feat(webui): OOBE v1 slice 3 — Connect reuses the real setup/OAuth modal

An unconnected suggested card's Connect now resolves its `app` to a real
catalog extension and opens the EXISTING extensions setup/OAuth modal
(configure-modal.tsx), rather than cloning the connect flow:

- New pure resolver `pages/chat/lib/connect-extension.ts` maps a card's `app`
  id -> a real `useExtensions()` catalog entry, returning the `configurePayload`
  shape ConfigureModal expects (packageRef + displayName). Tolerant matching
  (normalized, containment) bridges static demo ids and live package refs;
  prefers installed over registry; returns null (no modal) when nothing matches.
- `suggested-task-surface.tsx` calls `useExtensions()`, tracks the connecting
  task + connected ids, and React.lazy-loads ConfigureModal so its OAuth
  watcher/state-machine weight lands in a lazy chunk (eager /chat unchanged at
  219.3 KB, 0.7 KB headroom). Successful save flips unconnected -> suggested;
  an unresolvable app shows a plain notice instead of a dead button.
- New i18n key `chat.oobe.connectUnavailable` across all 11 locales.

Why reuse, not reimplement: useOauthSetup is a ~250-line page-level state
machine keyed on a real packageRef + secret descriptor, not an extractable
helper — cloning its popup/polling/error-mapping would duplicate it and risk
bugs. Driving the one real path keeps OOBE connect and the extensions page in
lockstep.

Tests: connect-extension.test.ts (6, pure) + 4 new surface vm-tests. Full gate
green: pnpm lint, 1271 tests, build + bundle budgets. The live OAuth popup
round-trip is the only uncovered part (needs a real third-party consent grant)
— to be walked in browser QA.

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

* docs(design): OOBE mockup — reconcile provenance note with shipped Foundational v1

The mockup's Foundational flow already matches the shipped SuggestedTaskCard
(found-gated Connect / Approve-only / "Working — activity in the thread" /
Completed + "+ Automation" / "Couldn't complete", single-active lock, no
Modify/Revert, no agent-mode selector). Only the footer provenance note was
stale — it described the retired prototype (AutomationCarousel,
AutomationTaskCard, TaskActionBar Approve/Modify/Cancel · Modify/Revert, agent-
mode pill) as "built".

Updated the note to the actual branch state: SuggestedTaskCard +
SuggestedTaskSurface behind the off-by-default oobe_suggestions flag; the
server flag (IRONCLAW_OOBE_SUGGESTIONS -> /session features.oobe_suggestions);
Approve/+Automation via the existing chat send path; Connect resolving to a
real catalog extension and opening the existing ConfigureModal (no cloned OAuth);
NearProcessIndicator reuse. Carousel/TaskActionBar/agent-mode/Calendar/Plan are
now correctly labeled Vision-only (not built). Backend suggestion producer
(#6993, slice 6) called out as the remaining net-new piece + prod gate.

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

* refactor(webui): retarget OOBE to Vision on the durable suggestions contract (#7694)

Foundational is cut. PR #7694 shipped the durable backend suggestions contract
— the agent-driven producer this package had classified as Vision-tier — so
#6994 becomes its frontend consumer and the static demo model is replaced by
real data.

Docs:
- New VISION-RECONCILIATION.md (governs): what #7694 grants (V2 reveal, V3
  anticipatory states, live card status), the connect-model conflict and its
  resolution, superseded sections, and the keep/change/delete refactor map.
- Marked superseded: PROPOSAL §2/§3.1 P3/§3.2 N3-N5/§4 V1/§2A.3,
  AUTOMATION-TASKS-CONTRACT §§1-3 (events/projection -> typed ScopedFilesystem
  store), IMPLEMENTATION (historical), README (scope retargeted).

Frontend:
- suggestions-api.ts: typed client over the four routes (list/generate/start/
  dismiss) mirroring RebornSuggestion; pollDelayMs clamps the backend retry
  hint so a missing/hostile value can't hot-loop or stall.
- useSuggestions.ts: react-query owner. Polls only while status=generating, at
  the backend's cadence. Generation is never automatic — it costs a model run,
  so `empty` renders a CTA.
- Surface consumes real state: empty -> CTA, generating -> anticipatory
  indicator (V3), ready -> cards, failed -> retry. An existing set survives
  regeneration rather than blanking.
- Approve now calls POST /suggestions/{id}/start; the backend creates the
  thread/run and returns the binding, and the browser navigates to it. No more
  prompt injection through the composer.
- Cards are tool-agnostic: the backend schema carries no app identity and its
  generator is instructed not to assume capability availability, so the
  connect card-state, resolveConnectExtension, and ConfigureModal wiring are
  removed. Connect re-homes to its own catalog-driven surface (V1).
- A started card keeps its durable thread binding and offers "View in thread".
- i18n reduced to the 9 keys actually used, parity across all 11 locales.

Deferred with the contract: "+ Automation" (no backend field/route) and live
run-derived card status (its own slice, now buildable via the bound run_id).

Gate: pnpm lint clean, 1265 tests / 142 files pass, build + bundle budgets pass
(/chat 219.1 KB, down from 219.3).

Cannot QA against a preview yet: #7694 targets native-structured-output, not
main, so the routes are not deployed. Built against the frozen DTOs.

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

* docs(design): Vision-only — parallel cards, remove +Automation, excise Foundational

Per the retarget decisions:
- Cards run in parallel: the single-active lock is gone (each suggestion starts
  its own thread — no backend constraint to reflect). VISION-RECONCILIATION §4.1
  is now a decision, not an open question.
- "+ Automation" removed (no field/route in the shipped contract) — dropped from
  the card, not deferred. §4.2 decided.
- VISION-RECONCILIATION open questions trimmed to the three still open
  (AuthRequired verification, agent modes, replacement UX).

Docs swept for stale references: PROPOSAL/IMPLEMENTATION banners now enumerate
the reversed decisions and mark the bodies historical; README status +
"what this proposes" rewritten to Vision (connect is a separate surface;
approve → start-thread → navigate); oobe.md brief retargeted.

mockup.html: removed the Foundational/Vision toggle and all Foundational scope
— version pinned to Vision, isVision/found branches collapsed to the Vision
path, FOUND_BEATS/FOUND_CAP/HERO_FOUND/CAP_FOUND/MODES.foundational deleted,
.v-foundational CSS + is-locked + item-N comments removed, footer rewritten to
describe the #7694 contract (icon + source_ids, parallel cards). Script
re-verified with `node --check`.

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

* feat(webui): brand icons for suggestion cards (icon + source_ids)

The #7694 author is adding `icon` (brand-icon enum) and `source_ids` (related
extension ids) to the card schema. Build the frontend mapping ahead of it:

- brand-icons.tsx: BrandIconId enum (mirrors the extension-package namespace),
  iconIdForSource() (source-id → icon), resolveIconId() (prefer explicit icon,
  else derive from source_ids[0], else `generic`), and <BrandIcon>. Colored
  marks reuse the license-clean inline SVGs already committed in the OOBE
  mockup; sheets/slides/web/memory/generic are neutral in-house glyphs. Lives in
  the lazy surface chunk — /chat stays 219.1 KB.
- Suggestion type gains optional icon + source_ids; the card renders the
  resolved brand mark. All optional, everything degrades to `generic`, so the
  card is correct before the backend field lands.
- SUGGESTION-ICONS.md: the enum, JSON-schema block, suggested Rust
  SuggestionIconId, and the icon↔source_ids derivation note for the #7694
  author. Records that icon/source_ids reverse the connect-conflict premise;
  connect stays decoupled but per-card connect is reopened as a review question.

No web scraping: assets are in-repo or in-house; brand marks are nominative-use.

Tests: brand-icons.test.ts (13) + a card BrandIcon test. Full gate green:
lint, 1273 tests, build + bundle budgets.

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

* fix(webui): reconcile OOBE frontend to the shipped #7694 contract

#7694 (durable backend suggestions) + #7693 (native structured output) landed
on main and are now merged into this branch — the /api/webchat/v2/suggestions
routes and the RebornSuggestion contract are present here. Reconcile the
frontend to the shipped shape:

- Field is `sources` (1-5 human-readable tool names, for display), not
  `source_ids`. Rename on the Suggestion type.
- `icon` is REQUIRED and enum-constrained, and its values are byte-identical to
  the enum this branch proposed (gmail..generic). It is the authoritative icon
  source. `resolveIconId` now trusts `icon` directly (→ generic fallback) and no
  longer derives from sources (those are free-form display names, not ids) —
  which also removes any icon↔sources drift. Dropped the obsolete
  iconIdForSource/SOURCE_TO_ICON extension-id mapping.
- Docs updated to shipped reality: SUGGESTION-ICONS.md (proposal → shipped
  reference), VISION-RECONCILIATION §3/§5.2/§6.4 (sequencing resolved; source_ids
  → sources; icon authoritative).

Everything else already matched the shipped contract exactly: routes, the
status enum (empty/generating/ready/failed), and the generate/start/dismiss
DTOs.

Gate green on the merged tree: lint, 1362 tests / 162 files, build + bundle
budgets (/chat 221.5 KB under the 222 budget — OOBE stays lazy).

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

* feat(webui): OOBE suggestion surface — Vision polish (drawer, skeleton, reveal, provenance)

Closes the visual gap against the Vision mockup for the affordances that need
no new backend; tracks the rest as follow-ups (VISION-RECONCILIATION §5.1).

- V4 docked drawer frame: the surface now renders as a bordered drawer with a
  "Suggested for you · approve to run, or tweak first" header, docked close to
  the composer (empty/failed CTA states stay frameless). Composer gap tightened
  only when the flag is on, so the non-OOBE landing is byte-unchanged.
- V3 anticipatory beat: the generating state shows the branded NEAR indicator
  over static `.v2-skeleton` tiles instead of a lone line of text.
- V2 reveal: cards get a restrained `.oobe-card-reveal` entrance — reuses the
  sanctioned `v2-page-in` keyframe with a class-selector + !important exception
  and prefers-reduced-motion suppression, per the app.css motion policy (NOT the
  mockup's ad-hoc conic ai-spark sweep, which would bypass the policy).
- Card provenance: renders the suggestion's `sources` as a "From <tools>" line
  (formatSources joins the human-readable names). Modify stays dropped.
- i18n: chat.oobe.subtitle + chat.oobe.from across all 11 locales.

Deferred/tracked follow-ups (not built): live card status (slice 7), V1 connect
panel (slice 8), agent-mode selector, pills-collapse-on-typing, and the named
greeting + client username call-out in the header (V5, per review).

Gate green: pnpm lint, 1366 tests / 162 files, build + bundle budgets (/chat
221.5 KB — all new UI is in the lazy surface chunk, eager route unchanged).

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

* feat(webui): OOBE drawer — close/restore, horizontal strip, subtitle

Interaction polish to match the Vision mockup:

- Subtitle "Approve to run, or tweak first" -> "Approve to run" (11 locales).
- Horizontal scrollable card strip (fixed-width cards, overflow-x with hidden
  scrollbar via .oobe-strip) instead of the reflowing grid — matches the mockup.
- Section close: a × in the drawer header dismisses the whole drawer (distinct
  from per-card dismiss). Drawer-visibility state (open/dismissed/gone) lifted
  to empty-state, wired to the surface via `hidden`/`onClose`.
- Restore pill: a "Show suggestions" pill inside the composer appears once the
  drawer is dismissed; the label reopens it, its × dismisses fully. Lazy-loaded
  (oobe-restore-pill.tsx) so its markup stays out of eager /chat.

Merged latest main (0 behind) first.

Bundle: the close/restore gate + two new eager en.ts keys add ~0.5 KB to the
eager /chat closure (the pill markup and the surface stay lazy); budget bumped
222.0 -> 223.0 KB with documented rationale. /chat measured 222.5 KB.

Tests: +oobe-restore-pill.test.ts, +surface hidden/close tests, +empty-state
drawer/pill tests. Gate green: lint, 1394 tests / 164 files, build + budgets.

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

* fix: keep suggestion icons provider-neutral

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Henry Park <henrypark133@gmail.com>
l3ocifer pushed a commit to l3ocifer/frick-ironclaw that referenced this pull request Sep 3, 2026
…system (Epic nearai#7038) (nearai#7257)

* docs(design-system): proposal, plan & checklist for the WebUI design system (Epic nearai#7038)

Benchmarked on the APDD governance kit and the target-crate-architecture package
(PR nearai#6918): a north-star README + RFC PROPOSAL + phased PLAN + CHECKLIST for the
Storybook + design-system catalog initiative under docs/reborn/design-system/.

Captures the five predefined phases (1-2 landed via nearai#7039, nearai#7043; 3-5 planned),
the Native-M3X-not-Material-Web decision, and — per the request — every Phase 3-5
dependency with a proposed implementation (dark palette, contrast, fonts,
animation, CI/Chromium, MSW). Mermaid schematics render on GitHub; an interactive
review artifact accompanies the package.

Docs-only; references the open Phase-1/2 PRs.

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

* docs(design-system): add self-contained explorer.html review page + link it

Rich, self-contained HTML review aid (the claude.ai artifact converted to a
branch file): HTML/CSS schematics — layer map, five-phase flow, dependency
graph — theme-aware with a standalone toggle, no external/runtime deps so it
renders from the branch (or via html-preview) without a build. Linked from the
package README.

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

* docs(design-system): re-home proposal package to docs/internal/reborn/

main relocated docs/reborn -> docs/internal/reborn (nearai#7206-era restructure); move the
design-system proposal package to match and fix the path/depth references (apdd-kit,
target-architecture, explorer html-preview link).

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

* docs(design-system): track the three-Epic split and refresh phase/PR state

Epic nearai#7038 was split into three tracking issues — nearai#7038 (Phases 1-2),
nearai#7781 (Phase 3), nearai#7782 (Phases 4-5). Record that ownership across the
package and correct the phase/PR state it asserted:

- Epic-ownership table in README / PLAN / CHECKLIST; per-phase and per-WS
  Epic attribution; "Tracks:" headers name all three.
- Phase 1/2 are in review, not landed: nearai#7039 and nearai#7043 were closed after
  the stack became unmergeable; Phase 1 is now nearai#7750 (non-stacked off
  main) and the Phase-2 changeset is preserved on nearai#7042. §7.6 merge order
  and the WS1/WS2 boxes updated to match.
- Frontend path refreshed to crates/product/ironclaw_webui/frontend.
- explorer.html: phase pills, chips, eyebrow and footer follow the same.

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

* docs(design-system): re-home Phase 2 under Epic nearai#7781; nearai#7038 is Phase 1 only

Epic ownership changed again: nearai#7038 narrows to Phase 1 (Storybook catalog,
PR nearai#7750), Phase 2 folds in with Phase 3 under nearai#7781, and the older
Phases 2-3 Epic nearai#7733 is closed as superseded by nearai#7781.

- Ownership tables, "Tracks:" headers, PLAN subgraphs, per-phase and
  per-WS attribution all follow the new mapping.
- PLAN Phase 3 gains the ⚠ "Phase 2 lands before Phase 3" constraint now
  that both sit in one Epic; §7.6 re-labelled as the Phase 1→2 gate.
- explorer.html eyebrow, phase pills, and footer updated; nearai#7733 recorded
  as superseded.

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

* docs(design-system): resolve the approach audit — one governance owner, honest state, named owners

Addresses all five findings on PR nearai#7257's approach audit (e11332d).

SP2 — competing governance records. PROPOSAL §9 (new) makes this package
the single canonical owner of `DESIGN.md`, the `--v2-*` token architecture,
the Storybook catalog/test-harness/MCP, and `.claude/rules/design-system.md`,
and states the alternative call explicitly if a reviewer would rather OOBE
own it. The OOBE package now points here instead of proposing the same work:
D-F6 keeps only its pilot role (the card family is catalogued *through* this
system) across its PROPOSAL §5.6/§8.3/§10.5/§11, README, PLAN F5 and
CHECKLIST F5.

ST3 — unresolvable references. The APDD kit is external and not vendored;
it is described as such rather than linked at `../../../../apdd-kit`. Its
in-repo evaluation is `docs/internal/apdd-governance-kit/` (PR nearai#7255, open),
not `docs/plans/apdd-governance-kit/` — corrected here and in the OOBE
package. PROPOSAL §11 is restructured into resolves-on-`main` / not-in-repo /
proposed-but-unmerged, and `src/design-system/README.md` is given its full
path and marked a Phase-2 deliverable. Every relative link in both packages
resolves.

ST6 — `LANDED` claims. §2.3 becomes "Foundations in flight (not yet on
`main`)": Phase 1 is `IN REVIEW` (nearai#7750), Phase 2 is `PREPARED` with no open
PR (nearai#7042), and each bullet says what `main` actually contains today. §2.4,
§6, the README lede and the explorer masthead carry the same correction.

SD6 — repeated ownership mapping. The Epic table is now a real, canonical
section in README; PLAN, CHECKLIST and explorer.html carry a pointer to it
plus their own per-phase/per-WS attribution, so ownership changes are one
edit.

EI1 — dependencies without owners. PROPOSAL §7 gains an accountability rule
and an owner table: the owner is the Epic carrying the gating phase, made
individual by a dependency sub-issue that must be cut and assigned before
that phase's first PR opens; each [decision] needs a named caller on its
Epic. Owners are repeated per-dependency in §7.1–§7.6, on the README
at-a-glance list and on the explorer's dependency cards, and CHECKLIST WS6
gains the naming gate.

Also merges current `main` (the branch was 26 commits behind, and the OOBE
package the audit cites lives there).

Verified: `scripts/ci/docs_publication_boundary.py` and
`scripts/ci/check-guidance.py` both pass; explorer.html parses with balanced
tags and renders correctly in light and dark.

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

* docs(design-system): address the automated review round — WCAG AA, honest gates, safeguards

Explorer accessibility (CodeRabbit 3724702856). Real, and worse than
reported: `.pill.good` in light was also failing at 3.78:1, which the finding
missed. Adds `--on-spark` and `--accent-strong` tokens and retunes the light
palette — spark `#e21f7e`→`#c9146d`, good `#0f8a5f`→`#0a6e4b`, plan
`#7a7488`→`#5d5869`; dark spark badges flip to dark-on-pink. Every text/background
pair on the page now clears 4.5:1 in both themes (measured: worst is 4.82).
A page proposing a WCAG AA invariant should not fail it.

Epic ownership single-source (3832432430). Declaring the README table canonical
wasn't enough while PLAN/CHECKLIST/explorer restated the mapping. Every
`Epic #NNNN` label is now a *link into* that table (5 in PLAN, 5 in CHECKLIST,
5 explorer pills), and the two prose restatements are gone.

Dependency owners (3832432423). Correct that role placeholders made the gate
non-verifiable. Rather than invent names, the table now records what is actually
assigned — `Sub-issue: not yet cut`, `Assignee: — none`, `Gate: 🔒 closed` on
every row — with a callout stating plainly that no dependency has a named
individual yet and no Phase 3–5 work may open while a row reads `— none`.

Operational safeguards (3722756794, raised three times). A genuine gap: new
§7.0 defines isolation / fallback / rollback / compatibility as exit criteria,
and §7.1–§7.5 each state theirs — MSW proven absent from the production bundle
by an asserted check, fonts with a tested system-fallback stack and
`font-display: swap`, motion degrading to the static baseline on both
reduced-motion and library-load failure, the `app.css` policy line as an
independent kill switch. Mirrored into PLAN phase exit criteria and CHECKLIST
WS3/WS4/WS6.

AGENTS.md as canonical contract (3815505058). The explorer named only
`.claude/rules/design-system.md`; it now names `DESIGN.md` as the tool-neutral
constitution reachable from `AGENTS.md`, with the Claude rule as the adapter.

Smaller corrections: CHECKLIST's WCAG item cited `§7.4/§8-a11y`, neither of
which is the contrast section — now invariant §3.4 / §7.3 (3722756785); PLAN
cited `§7.3–§7.5` for Phase 3 when §7.5 is Phase-4 motion (3832432399);
§2.3 said each path is created by "the PR named beside it" when Phase 2 has an
issue, not a PR (3832432413).

OOBE D-F6 migration completed (3832432393). The prior commit missed the F0
surfaces: PLAN's "(Optional) D-F6 seed" step and decision-round item 5, and
CHECKLIST's "first-draft DESIGN.md seeded" box both still directed a local
seed. Both now point at the owning program, and the retained §5.6 Needs/Approach
text is marked historical.

Verified: docs_publication_boundary.py and check-guidance.py pass; zero broken
relative links across both packages; explorer.html parses with balanced tags and
its computed styles were checked in both themes.

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

* docs(design-system): fix the MSW public/ trap, the motion kill switch, and two stale facts

Four findings from the latest review round; two were verified against live
code and both were real defects in what the previous commit asserted.

MSW would have shipped to production (CodeRabbit 3836710726). §7.2 said to
"generate the worker into `public/`" while its own safeguard claimed `msw` was
provably absent from the production build — a contradiction I introduced.
`frontend/vite.config.ts` sets `publicDir: "public"`, so `public/` is copied
into `dist/`; `crates/product/ironclaw_webui/build.rs` then walks `dist/`
recursively via `collect()` (skipping only `.vite`) and embeds every file into
the shipping binary. A worker in `public/` would be compiled into production
and served by the real WebUI regardless of being a `devDependency`. §7.2 now
carries a ⚠ block explaining the mechanism and directs the worker into a
Storybook-only static dir, with the assertion widened to cover
`mockServiceWorker.js` as well as `msw` chunks, asserted against `dist/`
before build.rs embeds it.

The motion kill switch was not enforceable (3836710728). `app.css`'s
`* { animation: none !important }` stops CSS animation and transitions but
cannot stop a JS spring's RAF loop or its inline transform writes, so calling
that line the kill switch was a guardrail promise the code would not keep.
§7.5 now specifies the mechanism once: one shared disabled-motion signal
behind both `prefers-reduced-motion` and the app switch, read by CSS and every
JS caller; a running spring cancels its RAF loop and writes the static
end-state; a rejected dynamic motion chunk renders the static baseline while a
failed static import stays a build failure; asserted by caller-level tests.
PLAN and CHECKLIST reference it rather than restating it.

§2.1 was factually wrong about the same policy. It claimed `.v2-spin` is the
sole animation exception; `app.css` has five — `v2-marquee-scroll`, `v2-spin`,
`near-pulse`, `near-chase`, and `v2-page-in` on `.oobe-card-reveal`. The
correction also makes the better point: each is `!important` to outrank the
universal rule and each is individually re-suppressed under
`prefers-reduced-motion`, which is the discipline Phase 4 extends rather than
replaces.

AGENTS.md precedence (3836710722). PLAN Phase 2 and CHECKLIST WS2/WS6 listed
`.claude/rules/design-system.md` and the `CLAUDE.md` pointer as governance
deliverables without stating that `AGENTS.md` is the canonical tool-neutral
contract they supplement. All three sites now state the precedence, and WS6
requires later updates to preserve it.

OOBE Epic precision (3836710714). The ownership notes wrote "Phase 2 = nearai#7042",
conflating the tracking issue with the owning Epic. Phases 2–3 sit under Epic
nearai#7781; nearai#7042 tracks the Phase-2 DESIGN.md work specifically. Corrected across
the OOBE PROPOSAL, PLAN and CHECKLIST.

Verified: docs_publication_boundary.py and check-guidance.py pass; zero broken
relative links; the corrected app.css and build.rs claims were each read from
live code rather than taken from the review.

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

* docs(design-system): make the Epic ownership table genuinely single-source

Follow-up to the partial fix in 772fc8c. Linking the phase and workstream
headings was not enough — the phase-to-Epic mapping was still written out in
full in six more places, any of which could drift from the canonical table.

Removed, in favour of a link to README's canonical table:

- PLAN's mermaid subgraphs, which grouped the five phases into three labelled
  Epic boxes. The diagram keeps the phase sequence — its actual job — with a
  caption saying ownership is deliberately not redrawn here. Last round I
  argued removing the grouping would gut the diagram; re-reading it, the
  sequencing carries the meaning and the Epic boxes were pure duplication.
- The `**Tracks:** Epics …` status header in PLAN, CHECKLIST and PROPOSAL
  (README's header now points down to its own table on the same page).
- PROPOSAL §1's per-phase Epic sentence and §11's `Tracking:` line.
- PLAN's coordination note restating the nearai#7733 supersession.
- explorer.html's masthead eyebrow and footer, both of which spelled out the
  full three-Epic mapping; the footer now links the canonical table.

What remains outside the table is per-phase and per-workstream attribution
that already links into it — the form the canonical section explicitly allows —
plus per-dependency owner lines in §7, which name an Epic per dependency
rather than restating the phase mapping.

Verified: docs_publication_boundary.py and check-guidance.py pass; zero broken
relative links; the canonical anchor resolves; explorer.html parses with
balanced tags.

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

* docs(design-system): give every frontend path an explicit base

The taxonomy table, layer map, explorer ladder, and the Phase 5 / WS5 path
lists used bare paths (`design-system/`, `pages/`, `app/routes.ts`) without
stating what they were relative to, while §2.1 documents the source root as
`crates/product/ironclaw_webui/frontend`.

Each surface now states its base once — PROPOSAL §5's taxonomy table, the
README layer map, and the explorer ladder are labelled relative to
`crates/product/ironclaw_webui/frontend/src/` — and the two short Phase 5 /
WS5 lists carry explicit `src/` prefixes instead, since spelling them out
there is shorter than a note.

Every cited path was checked against the live tree; `gateway-layout` is also
corrected to its real filename, `src/layout/gateway-layout.tsx`.

Verified: docs_publication_boundary.py and check-guidance.py pass;
explorer.html parses with balanced tags.

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

* docs(design-system): remove the last phase→Epic copies, including one in README itself

CodeRabbit was right that the finding was still open. The worst copy was in
the file that owns the canonical table: README's "The five phases" table had
its own `Epic` column, a full second mapping sitting a few lines below the
canonical one.

- README's five-phases table drops the `Epic` column and says in a lead-in
  that it covers scope and delivery state only, pointing at the table above.
  The Epic ownership table is now the only place the mapping is written down.
- PROPOSAL §2.3's two bullets drop their `Epic #NNNN` parentheticals — what
  matters there is the PR or issue that lands the artifact.
- §7.6's gate label loses `(Epic nearai#7038 → nearai#7781)`; it reads `Phase 1→2 landing`.
- PLAN's ⚠ Phase-3 ordering note and the "Merge nearai#7750" next-PR step no longer
  name the Epics to make a sequencing point.

What deliberately stays is the per-dependency owner attribution in §7, on the
README dependency list, and on the explorer cards: those assign an owner to a
*dependency*, which is a different axis from the phase mapping. The README
list now says so explicitly — the Epic on each line is derived from the
gating phase via the canonical table, not a second copy of it.

Verified: one `| Epic |` table remains in the package; the reshaped
five-phases table is column-consistent; both CI scripts pass; zero broken
relative links.

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

* docs(design-system): stop asserting a token invariant the tree does not meet

Two findings, both defects in my own recent commits.

The token invariant was stated as fact and is not one. §3 listed "no hardcoded
hex/px in components" among "non-negotiable invariants" in the present tense,
while naming the OOBE card family as the governance pilot. Measured against
`origin/main` under `frontend/src/`, the tree has 347 arbitrary pixel classes
across 93 files — 9 of them inside `design-system/` itself, the layer the
invariant most directly governs — plus 4 `.tsx` files with hardcoded hexes.
The cited pilot, `pages/chat/components/suggested-task-card.tsx`, is among
them. CodeRabbit named one file; the sweep found the real scope.

§3 now says plainly that the invariants are the target state and the bar for
new and touched code, not a description of the tree, and marks which hold
today (1 and 5) and which does not (2). New §3.1 carries the measured gap as
a table, and records a nuance worth keeping: the pilot card is already
*colour*-conformant — every colour on it is a `var(--v2-*)` reference — so the
gap is dimensional, which is why Phase 3's type/space/radius scales are what
close it. The pilot is now described as the pilot *subject*, demonstrating the
governance loop, not as a conformant exemplar. Migration is routed to PLAN
Phase 3 and CHECKLIST WS3, with a gate to stop the count regrowing.

The layer-map path base was wrong for two of its nodes. 2917534 claimed
"every node below is relative to `frontend/src/`", which is false for the
governance node: `DESIGN.md` lands at `…/frontend/DESIGN.md` and
`.claude/rules/design-system.md` at the repository root, while the Storybook
node names catalog sections rather than a directory. Corrected in the README
layer map and the explorer ladder caption.

Every number published here was measured twice, before and after the edit.

Verified: docs_publication_boundary.py and check-guidance.py pass; zero broken
relative links; the new §3.1 table is column-consistent; explorer.html parses
with balanced tags.

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

* docs(design-system): state the invariant-2 backlog in consistent, re-measured units

Two precision findings on yesterday's §3.1, both correct.

The hex row mixed units. "4 hardcoded hexes" in PLAN and CHECKLIST read as
four occurrences, but the measurement was four *files*. Rather than just
relabel, re-measured both axes and split them properly — and scoped the count
to what the invariant actually governs. The invariant is about components, so
`*.test.*` is now excluded, and §3.1 gives files and occurrences per row:

  arbitrary px          91 files / 345 occurrences
  …inside design-system/ 8 files /  38 occurrences
  hardcoded 6-digit hex   3 files /  10 occurrences

The test-inclusive totals (93/347 and 4/13, the figures published yesterday)
are kept in a parenthetical so the earlier numbers remain traceable rather
than silently changed. The pilot card's count is now stated as 5 classes and
enumerated, instead of listing four of the five.

The explorer abbreviated a path. Its ladder caption wrote `…/frontend/DESIGN.md`
where the README gives the full repository-relative path; readers should not
have to reconstruct it. Now `crates/product/ironclaw_webui/frontend/DESIGN.md`.

Every one of the nine figures in this commit was measured directly and
re-verified after the edit.

Verified: docs_publication_boundary.py and check-guidance.py pass; zero broken
relative links; the §3.1 table is column-consistent at 3 columns;
explorer.html parses with balanced tags.

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

* docs(design-system): match PLAN/CHECKLIST wording to the canonical §7.3 and §3.1

Two consistency findings, one of which was a real self-contradiction.

PLAN listed three Phase-3 dependencies while §7 says there are two. §7's
table states outright that "WCAG AA contrast validation is not a seventh
line: it is a standing invariant (§3.4) enforced inside 7.3", yet PLAN's
Phase-3 bullet named it as a peer of dark-palette derivation and
fonts/licensing. The bullet now says there are two, not three, and groups
contrast inside the palette dependency where §7.3 owns it. CHECKLIST WS3's
contrast box carries the same framing.

The backlog figures drifted in units again. PLAN and CHECKLIST said "91
production components" where §3.1 measures "91 files", and dropped
"six-digit" from the hex description. Both now use §3.1's exact wording —
345 occurrences across 91 files, 10 hardcoded six-digit hex values in 3
`.tsx` files — and §3.1 still carries the scope note (`*.test.*` excluded)
that both documents reference, so the shorter phrasing stays unambiguous.
No figure changed; only the words around them.

Left alone deliberately: the README dependency list and the explorer card
still show contrast as its own line, but both already qualify it as "carried
inside/by the palette work", so neither contradicts §7.3 — they give it
visibility without claiming separate ownership.

Verified: the two backlog phrasings now appear identically in both files;
both CI scripts pass; zero broken relative links.

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

---------

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

This branch was successfully deployed

No deployments
ironclaw-ci-preview / ironclaw-pr-6918 — 8e57dd9d Deployed Jul 30, 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: XL 500+ changed lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant