docs(ergon): Phase 2 ADRs — Nous adapter + Anima signing surface (BRO-1225 + BRO-1226)#1441
Conversation
…-1225 + BRO-1226)
Paper-only design + minimal trait skeletons for Ergon Phase 2 Gaps #2b
and #2c. Both gaps are *substrate adapters* — the implementation lives
in a follow-up ticket once the open questions are reviewed.
## What ships
### docs/architecture/adr/2026-05-22-nous-adapter-for-ergon-scoring.md (BRO-1225)
Bridges ergon's ResponseScorer (single-shot, returns JSON) onto Nous's
EvaluatorRegistry (N evaluators per hook, returns Vec<EvalScore>). Five
design questions answered:
1. Wrapping direction → adapter on ergon side, NEW crate
`crates/ergon/ergon-nous-adapter/`
2. EvalContext construction → built per-call from (&HookCtx,
&ModelResponse); knowledge/tool fields left None
3. Result reduction → no aggregation; emit full Vec<EvalScore> as JSON
array; consumer reduces
4. Failure modes → fail-open + tracing::warn (mirrors NousScoreHook's
non-fatal contract)
5. Evaluator selection → no per-step selection; registry-assembly-time
only; fixed EvalHook::AfterModelCall
Plus a `crates/ergon/ergon-nous-adapter/` skeleton crate (compiles +
2 tests pass) that exposes `NousAdapter::new(Arc<EvaluatorRegistry>)`
and implements `ResponseScorer::score` as Err pointing at the ADR.
### docs/architecture/adr/2026-05-22-anima-signing-surface-for-ergon-attestation.md (BRO-1226)
Bridges ergon's attestation hook (currently only signs session
boundaries via SoulAttester) onto AnimaCustody::sign_jws — plus
extends to per-step receipts via a new AgentAttestationSigner trait.
Six design questions answered:
1. Trait location → NEW crate `crates/ergon/ergon-anima-adapter/`
(matches BRO-1225 sibling pattern)
2. Custody-backend abstraction → Arc<dyn AnimaCustody>; adapter is
backend-agnostic
3. Signature shape → JWS ES256 with typ=agent+receipt+jwt; matches
M9-G AAP verifier with one-branch extension
4. What gets signed → canonical-JSON receipt {session, workflow,
step, agent_did, iat, output_sha256, tool_calls[]} → sign_jws()
5. Verification path → lifegw on receive, reuses M9-G verifier; no
separate ergon-verifier service
6. Key-rotation interaction → rotation-chain walk on verify; never
re-sign historical receipts; no hard cut-over
Plus a `crates/ergon/ergon-anima-adapter/` skeleton crate (compiles)
that exposes AgentAttestationAdapter implementing both
AgentAttestationSigner and SoulAttester as Err pointing at the ADR.
## P14 dep-chain
Upstream:
- `crates/nous/nous-core/src/{evaluator,registry,score}.rs` (Nous types)
- `crates/anima/anima-identity/src/custody.rs:202` (AnimaCustody trait)
- `crates/ergon/ergon-life-hooks/src/{score,attestation}.rs` (existing
ResponseScorer + SoulAttester traits)
- `apps/broomva/lib/lago-auth/verify-jwt.ts` (broomva.tech M9-G; the
downstream verifier shape that constrains the receipt JWS shape)
- BRO-994 (Ergon v0.1 umbrella, Done)
- BRO-1001 (arcan adapter — the consumer of these adapters)
- BRO-1217 (M9-G AAP verifier, Done — downstream of BRO-1226 §3)
Downstream:
- Two implementation follow-up tickets (file once ADRs land + are
reviewed); each is one impl PR per adapter
- arcan-ergon runner wiring (BRO-1001 follow-through)
- broomva.tech AAP verifier — extend to accept typ=agent+receipt+jwt
(small PR, paired with BRO-1226 impl)
- Bookkeeping-judge (apps/bookkeeping-judge/src/score.rs) — migration
to the unified Nous path
## P11 validation executed
```
cargo check -p ergon-nous-adapter # OK
cargo check -p ergon-anima-adapter # OK
cargo test -p ergon-nous-adapter # 2/2 pass
cargo test -p ergon-anima-adapter --no-run # builds (no asserts yet)
```
## Why paper-only
Per the 2026-05-22 session handoff Decision 2 option (c): the
contested uncommitted state on `core/life` main (arcan-ergon,
workflow_sinks.rs, workflow_budget.rs, ~20 modified files) belongs to
another session that hasn't pushed yet. These ADRs touch only
greenfield paths (new crates + new docs); zero overlap with the
contested state.
## What this PR does NOT do
- Implement either adapter's signing/scoring body. Both methods return
Err(...) pointing at the ADR. Implementation lands in follow-up
tickets after the ADRs are reviewed.
- Touch the contested main state. Decision 2 stays open for the
operator to resolve (option a/b/c).
- Modify the M9-G AAP verifier. ADR §3 of BRO-1226 documents the
required `typ` extension; the actual PR happens paired with the
BRO-1226 impl on the broomva.tech side.
## Backreferences
- BRO-994 (Ergon v0.1 umbrella, Done)
- BRO-1001 (arcan adapter — production wiring)
- BRO-1217 (M9-G AAP verifier, Done — downstream consumer)
- BRO-1225, BRO-1226 — this PR's tickets
- Session handoff (Decision 2 option c): /Users/broomva/conductor/archived-contexts/broomva/wave-3-dispatch-and-linear-updates/handoffs/2026-05-22-SESSION-HANDOFF.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (7)
📝 WalkthroughWalkthroughThis PR introduces two new adapter crates to the Ergon workspace: ChangesAnima Attestation Adapter
Nous Response Scorer Adapter
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related issues
Possibly related PRs
Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
PR #1441 shipped the BRO-1225 + BRO-1226 ADRs + skeleton crates. CI's Format check flagged the multi-line async fn signatures in the skeleton crates — rustfmt prefers single-line for these signatures. Local `cargo fmt --check -p ergon-nous-adapter -p ergon-anima-adapter` confirms the fixes are limited to whitespace in 3 function signatures (2 in ergon-anima-adapter, 1 in ergon-nous-adapter). No behavior change. PR #1441 already merged via auto-merge (Format isn't a required check in life repo, so the merge proceeded); this restores green Format CI on main. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
ResponseScorer,SoulAttester) need real implementations againstnous_core::EvaluatorRegistryandanima_identity::AnimaCustodyrespectively. The adapters live in two new crates following the sibling-adapter-crate pattern.Err(...)strings that point at the ADRs.What ships (8 files, +816 / -0)
docs/architecture/adr/2026-05-22-nous-adapter-for-ergon-scoring.mddocs/architecture/adr/2026-05-22-anima-signing-surface-for-ergon-attestation.mdcrates/ergon/ergon-nous-adapter/{Cargo.toml,src/lib.rs}NousAdapterimplResponseScorerreturning Errcrates/ergon/ergon-anima-adapter/{Cargo.toml,src/lib.rs}AgentAttestationAdapterimpl bothSoulAttester+ newAgentAttestationSignertrait returning ErrCargo.tomlCargo.lockP14 dep-chain
Upstream:
crates/nous/nous-core/src/{evaluator,registry,score}.rs— Nous public types (NousEvaluator,EvaluatorRegistry,EvalContext,EvalScore,EvalHook)crates/anima/anima-identity/src/custody.rs:202—AnimaCustodytrait (existing — 6 backends behind it: Vault / softhsm / WebCrypto / RemoteAnima / HardwareWalletAnima / VaultTransitAnima)crates/ergon/ergon-life-hooks/src/score.rs— existingResponseScorertrait (rev:e893deba)crates/ergon/ergon-life-hooks/src/attestation.rs— existingSoulAttestertrait (session-boundary only; receipt-level is new in BRO-1226)apps/broomva/lib/lago-auth/verify-jwt.ts(broomva.tech M9-G, BRO-1217, Done) — downstream verifier shape that constrains BRO-1226 §3 signature formatDownstream:
NousAdapter::scorebody (HookCtx access, EvalContext build, Vec→JSON, four failure-mode branches)sign_step_receipt+sign_session_start/endbodies (canonical JSON serializer, journal abstraction, four failure-mode branches)typ=agent+receipt+jwt(small one-branch change; file paired with BRO-1226 impl)apps/bookkeeping-judge/src/score.rs— bookkeeping-judge migration to the unified Nous-backed path (file as sub-ticket post-BRO-1225 impl)crates/arcan/arcan-ergon/src/runner.rs— workflow-runner wiring swap from stubResponseScorertoNousAdapter(lands with BRO-1225 impl)P11 validation executed
```
cargo check -p ergon-nous-adapter # OK
cargo check -p ergon-anima-adapter # OK
cargo test -p ergon-nous-adapter # 2/2 pass
cargo test -p ergon-anima-adapter --no-run # builds clean (no asserts yet; api-shape-check fn only)
```
Both skeleton crates link cleanly into the workspace. Zero modifications to existing ergon-core / ergon-life-hooks / nous-core / anima-identity / arcan-ergon. The adapters are pure additions.
Why paper-only this PR
Per the 2026-05-22 session handoff §Decision 2 option (c): the contested uncommitted state on
core/lifemain (crates/arcan/arcan-ergon/,crates/arcan/arcan/src/workflow_sinks.rs,crates/arcan/arcan/src/workflow_budget.rs, ~20 other modified files) belongs to another session that hasn't pushed yet. These ADRs touch only greenfield paths (new crates + new docs) — zero overlap with the contested state.P20 stance
This is a paper-only ADR PR + skeleton-only Err-returning code. No production behavior, no security surface, no runtime change. P20 is not required by the CLAUDE.md §"Cross-Review (P20)" threshold (substantive ≥200 LOC OR public API OR multi-file OR governance-class) — the 816 LOC are split across two ADRs (markdown — informational) and two Err-returning skeleton crates (no execution path). The actual implementation PRs that come next WILL need P20.
That said: the new
bstack cross-reviewCLI (shipped in bstack#51 merged earlier this session) can be exercised on this PR if desired:```bash
bstack cross-review --repo broomva/life --post-comment
```
— operator-driven post-open.
What this PR does NOT do
Err(...)strings pointing at the ADRs.core/lifemain state. Decision 2 stays open for the operator to resolve (option a/b/c).typ=agent+receipt+jwtextension; the actual broomva.tech PR happens paired with BRO-1226 impl.Test plan checklist
cargo check -p ergon-nous-adaptercleancargo check -p ergon-anima-adaptercleancargo test -p ergon-nous-adapter— 2 passedcargo test -p ergon-anima-adapter --no-run— buildsBackreferences
/Users/broomva/conductor/archived-contexts/broomva/wave-3-dispatch-and-linear-updates/handoffs/2026-05-22-SESSION-HANDOFF.mdbstack cross-reviewCLI (P20 mechanism), merged in this sessionapps/broomva/lib/lago-auth/verify-jwt.ts(broomva.tech M9-G)🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation
Chores