Skip to content

docs(architecture): canonical agent-harness layered runtime + correct §6/§10 of ergon spec (BRO-1001)#1190

Merged
broomva merged 2 commits into
mainfrom
docs/agent-harness-architecture-correction
May 8, 2026
Merged

docs(architecture): canonical agent-harness layered runtime + correct §6/§10 of ergon spec (BRO-1001)#1190
broomva merged 2 commits into
mainfrom
docs/agent-harness-architecture-correction

Conversation

@broomva
Copy link
Copy Markdown
Owner

@broomva broomva commented May 8, 2026

Summary

Course correction PR. No code changes. Documents what the agent harness actually is, and corrects two sections of the original ergon spec (§6 + §10) that assumed an architecture that doesn't exist in arcan.

What was wrong

`docs/superpowers/specs/2026-05-05-ergon-v0.1.md` §6 and §10 framed ergon as a parallel session-level runtime that would replace `arcan-harness` over time via an `AgentKind` trait abstraction.

That's wrong on two counts:

  1. `arcan-harness` is not the agent harness. It's a ~300 LOC tool/sandbox utility crate. The actual agent harness is a 7-layer runtime stack distributed across ~25 crates.
  2. Ergon's `Workflow::execute()` cannot replace the tick engine. It's one async fn with no suspend/resume, no replay-from-event-N, no daemon-restart survival. KernelRuntime tick-by-tick is the actual long-horizon agent loop. Workflow-as-async-fn would lose per-tick journal traceability that autonomic / EGRI / branching depend on.

Corrected framing

Ergon supplies one shape of tick body alongside the existing direct-call tick body. Both compose with `aios_runtime::KernelRuntime`. Both produce per-tick events. Neither replaces anything.

Direct tick body (existing) Workflow tick body (BRO-1001)
Implementation `ModelProviderPort.complete` + optional `ToolHarnessPort.execute` `ergon::WorkflowExecutor::run` (multi-turn workflow)
Best for Simple per-turn flows Bounded multi-turn operations (judges, scorers, scrapers)
Per-tick events Kernel-typed `EventKind` variants Kernel events at boundary + `Custom("ergon.stream", ...)` nested under `run_id`
Replay At kernel granularity At kernel + workflow granularity

What this PR ships

Documentation only:

  • NEW `docs/architecture/agent-harness.md` — canonical 7-layer runtime architecture. Maps every layer (L0 kernel contract → L6 process daemons) to its owning crates, walks bottom-up dependency chain + top-down execution trace, defines the two scopes of the agent loop (outer/session vs inner/tick), enumerates built vs pending. This is the doc any future spec should reference when it talks about "the harness."

  • NEW `docs/superpowers/specs/2026-05-08-bro-1001-ergon-tick-body.md` — corrected BRO-1001 design. 13 sections covering: scope, layered position, public API (`TickBodyCtx`, `run_workflow_as_tick`, `WorkflowRegistry`), lifecycle, the small `TickKind` extension to aios-runtime, DoD, open questions, validation criteria, composition trajectory, versioning, ordered impl plan.

  • MODIFIED `docs/superpowers/specs/2026-05-05-ergon-v0.1.md` — added top-level correction note pointing to the architecture doc + new BRO-1001 spec. §6 + §10 marked SUPERSEDED inline. §§0-5, 7-9, 11-13 valid as written.

  • MODIFIED `crates/ergon/ergon/CLAUDE.md` — corrected positioning ("ergon is one shape of tick body, not a parallel session runtime") + canonical layer diagram.

  • MODIFIED `CHANGELOG.md` — Changed entry documenting the correction.

What does NOT change

The ergon trait surface (Workflow, Step, StepCtx, Hook, model wire types, runtime ports, stream sinks), ergon-life-hooks (4 auto-hooks + adapter traits), ergon-life-sinks (Lago / Vigil / Lifegw). All correct as shipped. They're precisely what a tick-body adapter needs.

Why this is a doc-only PR

The course correction was caught before shipping the wrong adapter (BRO-1001 wasn't scaffolded yet). The trait crates already on main are substrate-free and framing-agnostic. The mismatched framing existed only in the spec text + the not-yet-written adapter design. By correcting the docs first, BRO-1001 will be scaffolded against the right design — no retracted code.

Test plan

What's next after merge

  1. Update Linear BRO-1001 description to point at the new spec
  2. After feat(ergon-life-sinks): three Life-flavored stream sinks (BRO-999b) [rebased] #1170 (ergon-life-sinks rebased) merges, scaffold `crates/arcan/arcan-ergon/` per the corrected design
  3. BRO-1001b (separate ticket): arcand wiring for `TickKind` dispatch (small change, feature-flagged)
  4. BRO-1003: bookkeeping-judge port — first real workflow exercising the corrected adapter

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Documentation
    • Added canonical agent-harness architecture documentation outlining the distributed runtime stack and execution scopes.
    • Clarified ErgON positioning: it is a workflow-bodied tick shape that composes with the kernel runtime and does not replace existing systems.
    • Added new specification for the ergon tick-body adapter and workflow execution contract.
    • Updated internal documentation to reflect current ErgON architecture and primitives.

… §6/§10 of ergon spec (BRO-1001)

The framing in `2026-05-05-ergon-v0.1.md` §6 (Composition with arcan)
and §10 (Migration plan) was structurally wrong. Both sections assumed
ergon would replace `arcan-harness` as a parallel session-level
runtime via an `AgentKind` trait abstraction. Reality:

1. `arcan-harness` is a ~300 LOC tool/sandbox utility crate, not the
   agent harness. The actual agent harness is a 7-layer runtime stack
   distributed across ~25 crates (kernel contract, substrate primitives,
   port traits, tick engine, session orchestration, daemons).
2. Ergon's `Workflow::execute()` is one async fn — it cannot replace
   the long-horizon tick engine (`aios_runtime::KernelRuntime`) without
   losing per-tick journal traceability that autonomic / EGRI /
   branching depend on.

Corrected framing: ergon supplies one shape of *tick body*
(workflow-bodied ticks) alongside the existing direct-call tick body.
Both compose with KernelRuntime; both produce per-tick events; neither
replaces anything.

## What this PR ships

**No code changes.** Documentation only:

- **NEW** `docs/architecture/agent-harness.md` — canonical 7-layer
  runtime architecture. Maps every layer L0–L6 to its owning crates,
  walks bottom-up dependency chain + top-down execution trace, defines
  the two scopes of the agent loop (outer/session vs inner/tick),
  enumerates built vs pending. This is the doc any future spec should
  reference when it talks about "the harness."

- **NEW** `docs/superpowers/specs/2026-05-08-bro-1001-ergon-tick-body.md`
  — corrected BRO-1001 design. 13 sections covering: scope (in/out),
  the layered position, public API (TickBodyCtx, run_workflow_as_tick,
  WorkflowRegistry), lifecycle, the small TickKind extension to
  aios-runtime, definition of done, open questions, validation
  criteria, composition trajectory, versioning, ordered impl plan.

- **MODIFIED** `docs/superpowers/specs/2026-05-05-ergon-v0.1.md`:
  added a top-level correction note pointing to the architecture doc +
  the new BRO-1001 spec. §6 and §10 marked SUPERSEDED inline with
  links to the new doc. §§0-5, 7-9, 11-13 valid as written.

- **MODIFIED** `crates/ergon/ergon/CLAUDE.md` with the corrected
  positioning ("ergon is one shape of tick body, not a parallel
  session runtime"). Replaced the spec's old layer-numbering with the
  canonical layer diagram.

- **MODIFIED** `CHANGELOG.md` — Changed entry documenting the
  correction.

## What does NOT change

- ergon trait surface (workflow / step / hook / model / runtime / stream)
- ergon-life-hooks (4 auto-hooks + adapter traits)
- ergon-life-sinks (Lago / Vigil / Lifegw)

All of these are correct as shipped. They're precisely what a tick-body
adapter needs. What changes is the *framing* of how they're integrated.

## Why this is a doc-only PR

The course correction was caught BEFORE shipping the wrong adapter.
ergon (the trait crate) and ergon-life-* (the hooks + sinks) shipped to
main correctly under their original framing — they're substrate-free
trait crates that happen to be useful for either framing. The
mismatched framing was only in the spec text + the not-yet-written
adapter design.

By correcting the docs first, BRO-1001 will be scaffolded against the
right design. No retracted code, no rewritten history.

## Validation

- `cargo check -p ergon -p ergon-life-hooks` — clean (no code change)
- All previous ergon test counts unchanged (#1170 pending merge with
  ergon-life-sinks; this PR independent)
- Markdown only; no compile/lint targets

Linear: BRO-1001 — description will be updated to point at the new
spec after this PR merges. Tracker: BRO-994.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@linear
Copy link
Copy Markdown

linear Bot commented May 8, 2026

BRO-1001

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 8, 2026

Review Change Stack

Warning

Rate limit exceeded

@broomva has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 4 minutes and 14 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: eee7bee0-ad91-496b-814c-efa45446262f

📥 Commits

Reviewing files that changed from the base of the PR and between 83405fc and 6655baf.

📒 Files selected for processing (2)
  • docs/architecture/agent-harness.md
  • docs/superpowers/specs/2026-05-08-bro-1001-ergon-tick-body.md
📝 Walkthrough

Walkthrough

This PR introduces a canonical 7-layer agent harness architecture document, specifies the arcan-ergon tick-body adapter API and lifecycle (BRO-1001), corrects prior ergon v0.1 spec assumptions with supersession markers, updates ergon crate documentation, and records architecture clarifications and new crate additions in the changelog.

Changes

ErgON Architecture and Adapter Design

Layer / File(s) Summary
7-Layer Harness Architecture
docs/architecture/agent-harness.md
Canonical agent harness architecture defining L0–L6 distributed runtime stack, outer session loop (tick-driven, long-horizon, durable replay) vs inner tick loop (direct and workflow tick bodies), dependency chain ordering rules, end-to-end execution traces, workspace layer locations, and stability commitments.
BRO-1001 ErgON Tick-Body Adapter Specification
docs/superpowers/specs/2026-05-08-bro-1001-ergon-tick-body.md
New specification locking arcan-ergon adapter public API: run_workflow_as_tick() entry point, TickBodyCtx per-tick context struct, WorkflowRegistry with type-erasure for name-based dispatch, lifecycle execution within a single tick, journal event nesting under parent run_id, and aios-runtime seam extension via TickKind enum with backward-compatible Direct default.
ErgON V0.1 Spec Corrections
docs/superpowers/specs/2026-05-05-ergon-v0.1.md
Corrects prior spec framing by marking sections 6 and 10 as SUPERSEDED, clarifies that ergon is a tick-body composition shape (not an agent-harness replacement), redirects readers to BRO-1001 tick-body adapter spec, removes incorrect ErgonAgentKind abstraction, and updates status to "Active" with explicit 2026-05-08 correction note.
ErgON Crate Documentation
crates/ergon/ergon/CLAUDE.md
Repositions ergon as a bounded multi-turn workflow shape executing within a single kernel tick, clarifies critical invariant that ergon does not replace KernelRuntime or the tick engine, adds BRO-1001 adapter spec reference, and updates metadata to 2026-05-08.
Changelog and Summary
CHANGELOG.md
Under "Changed": documents the corrected ErgON/arcan-harness/KernelRuntime composition model and enumerates spec sections updated/superseded. Under "Added": records ergon-life-hooks crate, foundational ergon trait surface, hook lifecycle types, autonomous loop body, workflow executor, and arcan-prosopon KernelRuntime-to-Prosopon bridge with opt-in cargo feature.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related issues

  • broomva/life#1145: This PR specs the arcan-ergon adapter design and tick-body API (BRO-1001), while the issue tracks the implementation of that adapter contract.
  • broomva/life#1148: Both address the same ergon architecture and changelog documentation workstream, updating specs and recording design corrections.

Possibly related PRs

  • broomva/life#1152: Both PRs add ergon hook lifecycle and provider-agnostic wire types (hook and model modules), representing related foundational ergon primitives.
  • broomva/life#1151: This PR documents corrections and specs for the ergon crate that was scaffolded and spec'd in the earlier PR; they touch the same ergon crate and documentation content.

Poem

🐰 The harness stands tall, seven layers deep,
Where ergon workflows tick—not forever to keep,
Just one bounded turn in the kernel's grand dance,
With journal events nested in each graceful glance,
No replacement, but composition so neat! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and specifically describes the primary changes: the introduction of a canonical agent-harness architecture document and corrections to sections 6 and 10 of the ergon spec via BRO-1001. The title is concise, clear, and directly reflects the main scope of this documentation-only PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/agent-harness-architecture-correction

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
crates/ergon/ergon/CLAUDE.md (1)

22-30: ⚡ Quick win

Add language identifier to fenced code block.

The code block showing the harness stack position should specify a language identifier for proper rendering and tooling support.

📝 Proposed fix
-```
+```text
 L5 — Session orchestration (arcand::ConsciousnessActor)
 L4 — Tick engine (aios_runtime::KernelRuntime)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/ergon/ergon/CLAUDE.md` around lines 22 - 30, The fenced code block
that lists the harness stack position lacks a language identifier; update the
opening fence to include a plain text language (e.g., change ``` to ```text) so
the block renders correctly and tooling highlights it as plain text—apply this
change to the code block containing the lines starting with "L5 — Session
orchestration (arcand::ConsciousnessActor)" and ending with "L0 — Kernel
contract (aios-protocol)".
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@crates/ergon/ergon/CLAUDE.md`:
- Around line 22-30: The fenced code block that lists the harness stack position
lacks a language identifier; update the opening fence to include a plain text
language (e.g., change ``` to ```text) so the block renders correctly and
tooling highlights it as plain text—apply this change to the code block
containing the lines starting with "L5 — Session orchestration
(arcand::ConsciousnessActor)" and ending with "L0 — Kernel contract
(aios-protocol)".

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4369fa69-8eb1-4379-a264-0230f4d2ea9f

📥 Commits

Reviewing files that changed from the base of the PR and between 67120bf and 83405fc.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • crates/ergon/ergon/CLAUDE.md
  • docs/architecture/agent-harness.md
  • docs/superpowers/specs/2026-05-05-ergon-v0.1.md
  • docs/superpowers/specs/2026-05-08-bro-1001-ergon-tick-body.md

… composition note

Two additions to the architecture + BRO-1001 spec to finalize the
scoping for nous metacognition as workflows:

## docs/architecture/agent-harness.md

New section "Where evaluators live (nous metacognition)" between "The
two scopes of the agent loop" and "Bottom-up dependency chain". Covers:

- **Scope A (inline scoring)** — `NousScoreHook` already shipped in
  `ergon-life-hooks`. Per-turn observation, observe-only failure
  semantics, no workflow ceremony needed.
- **Scope B (block-level evaluation)** — `ergon::Workflow` impls in
  `apps/<judge-name>/`. Multi-step LLM reasoning that produces typed
  verdicts. The bookkeeping-judge (BRO-1003) is the canonical first
  example.
- **Decision rule** — does the evaluator need the autonomous loop?
  If yes, workflow. If no, direct `NousEvaluator` impl in
  `nous-heuristics` / `nous-judge`.
- **Verify-mode composition** — once BRO-1001 + BRO-1003 ship, the
  kernel's `Verify` mode can dispatch to evaluator workflows
  directly via a future `TickKind::VerifyWorkflow` variant. Deferred,
  but architecturally clean.
- **Optional `WorkflowAsNousEvaluator` adapter** — ~50 LOC bridge
  if/when an existing workflow needs to be addressable through
  nous-routing. Cheap, written when needed.
- **Three architectural wins** when evaluators run as workflows:
  per-tick traceability, composability via sub-workflows, automatic
  substrate inheritance (anima / autonomic / lago / vigil / Spec E).

## docs/superpowers/specs/2026-05-08-bro-1001-ergon-tick-body.md

New §6.1 "Composition with OperatingMode::Verify (forward-compatible
note)". Documents that the `TickKind` enum is `#[non_exhaustive]` and
intentionally allows future variants like `VerifyWorkflow` and
`RecoverWorkflow` without committing to them in v0.1. Anchors the
forward-compatibility for future agents reading the spec so they
understand the design is anticipating evaluator-workflow dispatch.

## Linear

Created BRO-1038 — "Ergon §12.7b — arcand wiring for workflow-bodied
ticks (BRO-1001 follow-up)". Documents the daemon-side integration
that follows the kernel-side BRO-1001:

- `AgentKindConfig { Direct, PinnedWorkflow{name} }` on
  `SessionManifest`
- arcand consciousness reads it, sets `tick_input.kind` accordingly
- Behind `--feature workflow-ticks` (disabled by default in v0.1)
- ~1-2 days work; small because BRO-1001 carries the heavy lifting

## What's now finalized for v0.1 scope

- BRO-1001 (kernel-side) — arcan-ergon adapter + TickKind enum
- BRO-1038 (daemon-side) — arcand wiring with feature flag
- BRO-1003 — bookkeeping-judge as first real evaluator workflow
- BRO-1004 — CI gates + final docs

After these four ship, the "evaluators as workflows" architecture is
proven end-to-end. Verify-mode dispatch becomes the natural next
composition.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@broomva broomva merged commit 9f2116f into main May 8, 2026
15 checks passed
@broomva broomva deleted the docs/agent-harness-architecture-correction branch May 8, 2026 10:56
broomva added a commit that referenced this pull request May 8, 2026
…k body (BRO-1001) (#1192)

* feat(arcan-ergon): kernel-side adapter running ergon::Workflow as tick body (BRO-1001)

New `arcan-ergon` crate at `crates/arcan/arcan-ergon/` that runs an
`ergon::Workflow` as the body of one `aios_runtime::KernelRuntime`
tick. Closes BRO-1001's "ergon tick-body adapter" deliverable per
the corrected architectural framing in
`docs/superpowers/specs/2026-05-08-bro-1001-ergon-tick-body.md`
(§6, §10 of the original ergon spec are SUPERSEDED — see PR #1190).

Kernel side (aios-runtime):
- `TickKind` enum on `TickInput` — `Direct` (default, kernel-owned
  single model call) vs `Workflow { name, input }` (delegated).
- `WorkflowTickDispatcher` trait + `WorkflowTickInvocation<'a>` +
  `WorkflowTickOutcome` types so workflow runners (arcan-ergon
  today, future shapes later) plug in without forcing the kernel
  to take on substrate dependencies.
- `KernelRuntime::with_workflow_dispatcher` builder method;
  dispatch logic in `execute_turn` after the
  `Perceive`/`Deliberate`/`StateEstimated` boundary.
- Existing `TickInput` call sites updated to `kind: TickKind::Direct`
  for behavior parity.

arcan-ergon modules:
- `dispatcher` — `ErgonWorkflowDispatcher` implements
  `WorkflowTickDispatcher` against a `WorkflowRegistry`.
- `registry` — type-erased boxed-executor registry keyed by name
  (`BoxedWorkflowExecutor::run_json` does the JSON boundary).
- `provider` — `ModelProviderAdapter` wraps `ModelProviderPort` as
  `ergon::Provider`, translating the kernel's flat shape and
  synthesizing `StreamEvent` sequences from the directives.
- `tools` — `ToolHarnessAdapter` wraps `ToolHarnessPort` as
  `ergon::ToolRegistry`. No capability evaluation here — that lives
  on the dedicated capability hook to avoid double-firing.
- `runtime_handle` — `ModeRuntimeHandle` exposes per-tick
  `OperatingMode` as `ergon::RuntimeHandle`.
- `hooks` — `KernelCapabilityResolver` (real `PolicyGatePort`-backed
  adapter for `CapabilityResolver`, with `ToolCapabilityMap`
  declaring per-tool caps and fail-closed on unknown tools), plus
  `NoopBudgetGate` / `NoopResponseScorer` / `NoopSoulAttester`
  permissive stand-ins for the other three adapter traits — real
  autonomic / nous / anima impls land in follow-up.
- `runner::run_workflow_as_tick` — composes a fully-built
  `ergon::StepCtx` from a `WorkflowTickInvocation`, drives the
  workflow body, returns `WorkflowTickOutcome` with JSON output +
  emitted-event count.

arcan binary now installs an `ErgonWorkflowDispatcher` (with an empty
registry by default) on the kernel runtime at startup. Adopting
daemons override the registry to register their concrete
`ergon::Workflow` impls before the runtime starts serving.

Tests: 16 unit + 4 end-to-end integration tests
(`tests/workflow_tick_e2e.rs`) verifying the workflow tick path
against a real `KernelRuntime` over file-backed event storage:
workflow runs, JSON output ends up in an `ergon.workflow_output`
`Custom` event in the journal, direct ticks still work alongside
the dispatcher, unknown workflows surface clear errors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(arcan-ergon): address CodeRabbit feedback on PR #1192 (BRO-1001)

Five actionable items + two nitpicks from CodeRabbit's review:

1. **Workflow tick lifecycle parity** (`aios-runtime/src/lib.rs`):
   the workflow branch was returning early after dispatch, skipping
   the standard terminal lifecycle (StepFinished + RunFinished) and
   bubbling dispatch failures out as bare anyhow errors. Now mirrors
   the Direct path: emits StepStarted before dispatch, then on
   success appends ergon.workflow_output + StepFinished + RunFinished
   and runs Commit/Reflect/Sleep finalize; on failure appends
   RunErrored, increments error_streak / uncertainty / error_budget,
   drops the runtime into Recover mode, and still finalizes the tick
   so the journal is coherent. The integration test
   `unknown_workflow_routes_to_run_errored_and_recover_mode` (renamed
   + rewritten from `unknown_workflow_yields_error`) asserts the new
   shape: tick returns Ok, mode=Recover, error_streak >= 1, and an
   `RunErrored` event in the journal mentioning the workflow name.

2. **Workspace.members alphabetization** (`Cargo.toml`):
   `crates/arcan/arcan-ergon` was wedged between arcan-commands and
   arcan-console. Moved to the alphabetically correct slot after
   arcan-core.

3. **TickInput doc accuracy** (`aios-runtime/src/lib.rs`): the
   doc-comment referenced `Default::default()` and a `direct()`
   helper that don't exist. Removed the misleading sentence — the
   field is just a normal struct field today and call sites set
   `kind: TickKind::Direct` explicitly.

4. **Provider Message id collision** (`arcan-ergon/src/provider.rs`):
   `ModelDirective::Message` was emitting `StreamEvent::TextStart` /
   `TextDelta` / `TextEnd` with a constant `id="message"`, so a
   completion with multiple Message directives would fail downstream
   sink pairing. Now uses a directive-local `message_idx` counter
   so each Message gets a unique `message-N` id.

5. **Test assertion hardening**
   (`tests/workflow_tick_e2e.rs::workflow_tick_emits_output_event`):
   was using `if let Some && let Custom` chain that would silently
   pass if the event went missing or its kind changed. Now uses
   `.expect()` + `let-else` so a regression fails the test loudly.

Nitpicks:

- **`requires_approval` test** (`arcan-ergon/src/hooks.rs`): added
  `approval_required_tool_fails_until_flow_lands` — exercises the
  BRO-1001 fail-closed path when `PolicyGateDecision.requires_approval`
  is non-empty (the kernel approval flow isn't bridged into ergon
  hooks yet; this regression-tests the temporary fail-closed behavior
  so a future bridge implementation can update the test deliberately).

- **`WorkflowRunInputs` re-export** (`arcan-ergon/src/lib.rs`): now
  re-exported at the crate root alongside `run_workflow_as_tick` so
  callers can construct `ErgonWorkflowDispatcher::new(registry,
  inputs)` purely through `arcan_ergon::*` without reaching into
  the `runner` module.

Test counts: 17 unit (was 16) + 4 e2e (4) all green.
Workspace: cargo clippy --all-targets -- -D warnings clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant