Compare commits

...

3 Commits

Author SHA1 Message Date
HAL9000 8077d027e9 Merge master into PR #9247 - keep PR branch CHANGELOG with #9060 entry 2026-04-17 07:34:27 +00:00
HAL9000 06d5474957 docs(changelog): Add entry for #9060 error suppression fix
CI / lint (pull_request) Successful in 27s
CI / typecheck (pull_request) Successful in 52s
CI / quality (pull_request) Successful in 46s
CI / security (pull_request) Successful in 53s
CI / build (pull_request) Successful in 23s
CI / helm (pull_request) Successful in 29s
CI / push-validation (pull_request) Successful in 19s
CI / e2e_tests (pull_request) Successful in 3m45s
CI / integration_tests (pull_request) Successful in 6m45s
CI / unit_tests (pull_request) Successful in 7m50s
CI / docker (pull_request) Successful in 1m43s
CI / coverage (pull_request) Successful in 8m4s
CI / status-check (pull_request) Successful in 1s
2026-04-15 15:50:56 +00:00
HAL9000 55455304be fix(application): Remove error suppression in reactive_registry_adapter.py
Remove two try...except Exception: blocks that were silently suppressing
errors in register_registry_agents(), violating CONTRIBUTING.md fail-fast
policy.

Changes:
- Remove try/except around actor_registry.list_actors() call; exceptions
  now propagate to the caller instead of silently returning
- Remove try/except around route_bridge.agents refresh; exceptions now
  propagate instead of silently resetting to empty dict
- Update docstring to document the fail-fast propagation behaviour
- Update Behave scenarios to verify exceptions propagate correctly:
  * RuntimeError from list_actors() propagates
  * AttributeError from actors without .name attribute propagates
  * TypeError from None actors list propagates

Closes #9060
2026-04-15 15:40:58 +00:00
4 changed files with 152 additions and 193 deletions
+93 -173
View File
@@ -7,6 +7,31 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
### Fixed
- **TDD Non-AssertionError Guard Visibility** (#8294): `apply_tdd_inversion` in
`features/environment.py` now emits its non-assertion exception guard warning to
both the structured logger and `stderr` via a new `_warning_with_stderr` helper.
This makes the guard firing visible in standard Behave console output and CI log
snippets where the structured logging sink may not be displayed. BDD infrastructure
coverage added: a new scenario in `tdd_expected_fail_infrastructure.feature`
asserts that the warning is emitted to stderr when a non-AssertionError exception
is encountered in an `@tdd_expected_fail` scenario, and a second scenario asserts
the warning is NOT emitted when the exception is an `AssertionError`. The
`CONTRIBUTING.md` now documents that `@tdd_expected_fail` step definitions must
signal expected failures via `AssertionError`.
- **Parallel Behave Runner Log Noise Reduction** (#8351): The parallel behave
runner now suppresses captured stdout/stderr for passing worker chunks and
only replays diagnostics for failed, errored, or crashed chunks. This makes
failure output significantly easier to spot in CI and local runs. A worker
crash (unhandled exception) is detected via an all-zero summary and the
captured traceback is always surfaced.
- **Error Suppression in Reactive Registry Adapter** (#9060): Removed two
`try...except Exception:` blocks in `register_registry_agents()` that were
silently suppressing errors. Exceptions from `actor_registry.list_actors()`
and the route bridge refresh now propagate to the caller per the fail-fast
policy.
- **Automation Profile Silent Fallback** (#8232): `_resolve_profile_for_plan` in
`PlanLifecycleService` now raises a clear `ValidationError` when a plan's
automation profile name is not a known built-in profile, instead of silently
@@ -16,6 +41,20 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
logged at debug level for observability.
### Added
- Wired `StrategyActor` into the real plan execution path: `_get_plan_executor`
in `plan.py` now resolves the strategy actor via `resolve_strategy_actor()`
(reading the `actor.default.strategy` config key) instead of always
constructing `LLMStrategizeActor`. `run_strategize` in `PlanExecutor` now
passes `resources` (derived from `plan.project_links`) and `project_context`
to the actor so the LLM prompt receives full project context. Strategy
decisions are serialised as JSON in `plan.error_details["strategy_decisions_json"]`
so `_build_decisions` can reconstruct the full hierarchy (dependency ordering,
parent/child structure) during Execute instead of rebuilding from
`definition_of_done`. `StrategizeStubActor.execute` accepts `**kwargs` for
forward-compatibility. Added BDD coverage for the stored-JSON path,
corrupt-JSON fallback, resource-passing, and stub extra-kwargs scenarios.
(#828)
- **TDD Issue-Capture Test Activation** (#7025): Replaced 234 bare `@skip` tags
across 82 Behave feature files with the correct `@tdd_expected_fail @tdd_issue
@@ -69,14 +108,6 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
Priority-based filtering (Critical/High/Medium/Low) reduces noise. Backlog-groomer
performs intelligent cleanup with age thresholds by priority.
- **OpenAI Quota Fallback to Anthropic Haiku** (#10042): Implemented graceful degradation
for E2E robot integration tests when OpenAI API hits quota limit errors (429, insufficient_quota,
rate_limit). The `StrategyActor` now detects quota-specific errors and automatically falls back
to Anthropic Haiku for strategy decisions, ensuring CI/CD pipelines complete E2E tests even
when the primary provider hits capacity limits. Improved pipeline reliability and reduced false
negatives caused by provider-specific quota issues. Added comprehensive logging for quota error
detection and provider fallback, plus E2E test scenarios for fallback verification.
- **PR Agent Reorganization**: All PR-related agents renamed and reorganized to follow
the `*-pool-supervisor` naming pattern. New agents added: `pr-editor` (safe PR editing
with description preservation), `pr-manager` (unified PR interface), and
@@ -118,6 +149,13 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
`docs/development/automation-tracking.md` and the new
`docs/development/docs-writer.md` reference.
- **ACMS / UKO API Documentation** (`docs/api/acms.md`): Added comprehensive API
reference for the `cleveragents.acms` package covering the four-layer UKO ontology
hierarchy, `VocabularyRegistry`, `ProvenanceInfo`, `UKOClass`, `UKOProperty`,
`UKOVocabulary`, `Layer2Dependency`, `ParadigmVocabulary`, `DetailLevelMapBuilder`,
and all Layer 3 language vocabulary types (Python, TypeScript, Rust, Java).
The new page is linked from the API Reference index and the MkDocs navigation.
### Changed
- **Decision Tree Full ULID Display** (#5825): The `agents plan tree` command now
@@ -151,13 +189,33 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
### Fixed
- **Path Traversal Sandbox Escape via Prefix Collision** (#7558): Fixed
`validate_path()` in `file_tools.py` using `str.startswith()` for sandbox
containment, which allowed sibling directories with a matching name prefix
(e.g. `/tmp/sandbox-escape/` bypassing `/tmp/sandbox/`) to escape the
sandbox. Replaced with `Path.relative_to()` which performs a proper path
prefix check using OS path separators. Added regression test tagged
`@tdd_issue_7558`.
- **Plan Concurrency Race Condition** (#7989): Fixed critical race condition in `execute_plan()` and
`apply_plan()` where concurrent CLI/worker sessions could simultaneously modify the same plan,
corrupting plan state. `LockService` is now wired into the plan lifecycle with plan-level advisory
locking. Each invocation generates a unique caller identity (UUID) to prevent re-entrant lock
acquisition by concurrent sessions on the same plan. Concurrent attempts now raise `LockConflictError`
instead of silently racing. Lock is acquired before phase transition and released in a `finally`
block to ensure cleanup even on error.
- **`--format color` ANSI Output** (#7910): Fixed `format_output` routing the `color` format
option to `_format_plain`, which produced plain uncoloured text instead of ANSI escape
sequences. The `color` format is now routed to `format_output_session` which uses the
`ColorMaterializer` to emit proper ANSI-coloured output. `--format plain` and all other
formats remain unaffected.
- **ContextTierService Thread Safety** (#7547): Added `threading.RLock` to
`ContextTierService` to prevent `RuntimeError: dictionary changed size during
iteration` and data corruption under concurrent plan execution. All public
methods (`store`, `get`, `promote`, `demote`, `evict_lru`, `enforce_staleness`,
`get_metrics`, `get_all_fragments`, `get_hot_fragments`, `get_for_actor`,
`get_scoped_view`, `get_scoped_by_resource`, `get_scoped_metrics`) now acquire
the reentrant lock before accessing the hot/warm/cold tier dicts. The service
was previously documented as single-threaded but registered as a DI Singleton,
causing potential data corruption when parallel subplans shared the same
instance. The `TierRuntimeMixin.enforce_staleness()` and
`ScopedTierMixin.get_scoped_by_resource()` / `get_scoped_metrics()` methods
are also protected. The DI container registration as `providers.Singleton`
is now correct and safe.
- **Validation Gate Empty-Run Guard** (#7508): Fixed `ApplyValidationSummary.all_required_passed`
returning `True` when zero validations were run, silently bypassing the apply gate. The property
@@ -179,6 +237,16 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
`sandbox_root=.cleveragents/sandbox/`, so LLM file output (`FILE:` blocks)
is written to disk during the execute phase. (#4222)
- **SubplanExecutionService fail_fast cancellation** (#7582): Fixed a race condition where
already-running parallel subplans were not cancelled when `fail_fast` fired. Previously,
`Future.cancel()` only prevented queued futures from starting but had no effect on
in-flight futures that completed after `stop_flag` was set — their `COMPLETE` results
were incorrectly included in the merge output. The fix adds a post-completion guard that
overrides any non-`ERRORED`/non-`CANCELLED` result to `CANCELLED` when `stop_flag` is
active, and clears the associated output to prevent it from entering the merge. Also
replaces the O(n) linear `status` lookup in the `as_completed()` loop with an O(1)
`status_map` dict pre-computed before the executor block.
- **Robot Framework TDD Listener Guards** (#5436): Added three guard conditions to the
`tdd_expected_fail_listener` `end_test()` function to prevent blindly inverting ALL test
failures to passes, which was masking infrastructure errors and causing flaky CI behavior.
@@ -187,6 +255,11 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
e2e test files and removed `tdd_expected_fail` from 4 context assembly e2e tests where
bugs were already fixed.
- **PluginLoader entry point prefix validation** (#7476): Parse entry point targets before
import, enforce the module allowlist ahead of loading, and add Behave plus Robot Framework
regression coverage to ensure disallowed prefixes never execute untrusted module-level code
in either unit or integration flows.
- **`issue-state-updater` Bash Script Errors**: Removed problematic bash script examples
that tried to invoke `task forgejo-label-manager` as a bash command (the Task tool cannot
be invoked from bash). Replaced with clear step-by-step operational instructions and
@@ -201,6 +274,11 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
`pr-merge-pool-supervisor` to the product-builder's supervisor launch list (18 total
supervisors). Updated all numeric references, pre-flight checklists, and validation logic.
- `ActionRepository.update()` now uses explicit bulk `sa_delete()` + `session.flush()`
before re-inserting child rows for `action_arguments` and `action_invariants`, fixing
a `sqlite3.IntegrityError: UNIQUE constraint failed` crash when `agents plan use` was
called on an action that already had arguments registered via `action create`. (#4197)
---
## [3.8.0] — 2026-04-05
@@ -224,161 +302,3 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
renders permission requests directly in the conversation stream for single-file
operations. Users can allow/reject with single-key shortcuts (`a`/`A`/`r`/`R`),
navigate with arrow keys, confirm with `Enter`, or press `v` to open the full
permissions screen. (#1004)
- **TUI — Actor thought blocks**: Expandable reasoning trace widgets rendered
inline in the conversation stream with muted styling. Collapsed by default;
expand with `Space` or click. (#1005)
- **UKO provenance tracking**: Every typed triple now carries `sourceResource`,
`validFrom`, and `isCurrent` metadata. A revision chain enables temporal
queries and point-in-time ontology state reconstruction.
- **JSON-RPC 2.0 A2A wire format**: `A2aRequest`/`A2aResponse` fields renamed to
standard JSON-RPC 2.0 names (`method`, `id`, `result`, `error`). The
`A2aVersionNegotiator` handles backward compatibility.
- **Database resource handler**: Full CRUD and checkpoint/rollback support for
SQLite, PostgreSQL, MySQL, and DuckDB resources via the resource DAG.
- **Estimation lifecycle hook**: `actor.default.estimation` config key wires an
estimation actor into the Strategize-to-Estimate lifecycle hook.
- **Persona system**: YAML-backed personas bind actors, argument presets, and scope
references to named identities; persisted in `~/.config/cleveragents/personas/`.
- **Session management**: Create, list, export, and import conversation sessions;
full JSON export/import for portability; Markdown transcript export
(`--format md`) for human-readable sharing.
- **First-run experience**: `ActorSelectionOverlay` guides new users to pick an
actor on first TUI launch; creates a `"default"` persona automatically.
- **Server mode**: `agents server connect` configures a remote CleverAgents server;
Kubernetes Helm chart in `k8s/` for production deployment.
- **A2A integration**: Agent-to-Agent protocol facade wires CLI and TUI to live
application services (session, plan, registry, event).
- **Permissions screen**: TUI overlay for reviewing tool permission requests with
unified, side-by-side, and context diff views; session-scoped allow/reject decisions.
- **Inline permission questions**: `PermissionQuestionWidget` renders single-file
permission requests directly in the conversation stream with single-key shortcuts.
- **Invariant reconciliation**: `InvariantReconciliationActor` runs automatically at
every plan phase transition; failures block the transition and emit `INVARIANT_VIOLATED`.
- **UKO runtime**: Universal Knowledge Ontology query interface, inference engine, and
graph persistence for ACMS context strategies.
### Fixed
- `LangChainChatProvider.name` and `model_id` are now mutable properties with setters,
fixing an `AttributeError` when `PlanService` attempted to resolve provider names after
instantiation. (#1553)
---
## [3.7.0] — 2026-03-15
### Added
- **Interactive TUI** (`agents tui`) — full-screen Textual app with multi-session tabs,
persona switching, slash commands (67 commands across 14 groups), reference picker
(`@`), shell mode (`!`), context-sensitive F1 help, and `Ctrl+T` argument preset cycling.
- **Slash command system** — 67 commands across 14 groups accessible via `/` overlay.
- **Reference picker** — `@` key opens a file/resource reference picker that inserts
references into the input field.
- **TUI persona system** — YAML-backed personas bind actors, argument presets, and scope
references; persisted in `~/.config/cleveragents/personas/`.
- **TUI session export/import** — full JSON round-trip and Markdown transcript export
(`--format md`).
---
## [3.6.0] — 2026-02-28
### Added
- Advanced Context Management System (ACMS) with three-tier context strategy.
- UKO Runtime (Universal Knowledge Ontology) with graph persistence and inference engine.
- Implicit inference engine producing `uko:implicitSiblingOf`, `uko:implicitContains`,
and `uko:implicitDependsOn` triples with confidence 0.7.
---
## [3.5.0] — 2026-02-14
### Added
- Autonomy hardening: advisory locking, validation pipeline, definition-of-done gating.
- Resource DAG with dependency tracking and type hierarchy with multiple inheritance.
- Container resource types (`container.docker`, `container.podman`).
- LSP resource types (`lsp.*`).
---
## [3.4.0] — 2026-01-31
### Added
- ACMS v1 with context scaling strategies.
- Resource type inheritance system (ADR-042).
- Safety profile extraction (ADR-041).
---
## [3.3.0] — 2026-01-17
### Added
- Corrections and subplans support in plan lifecycle.
- Checkpoint and rollback for all resource writes.
- Decision tree versioning and history (ADR-034).
- Decision tree rollback and replay (ADR-035).
---
## [3.2.0] — 2026-01-03
### Added
- Decisions, validations, and invariants in plan lifecycle.
- Validation abstraction layer (ADR-013).
- Invariant system (ADR-016).
- Automation profiles (ADR-017).
- Semantic error prevention (ADR-018).
---
## [3.1.0] — 2025-12-20
### Added
- MCP (Model Context Protocol) adapter and client (ADR-029).
- LSP (Language Server Protocol) client integration (ADR-027).
- Agent Skills Standard (AgentSkills.io) support (ADR-028).
- Skill abstraction definition (ADR-030).
---
## [3.0.0] — 2025-12-06
### Added
- Initial public release of CleverAgents Core.
- Unified `agents` / `cleveragents` CLI entry points.
- Layered architecture: Entry Points → Application → Domain → Infrastructure → Integration → Core.
- Actor system with YAML-defined LangGraph node graphs.
- Tool system with four-stage lifecycle (activate → validate → execute → deactivate).
- Skill system with three-tier progressive disclosure.
- Resource system with DAG and type hierarchy.
- A2A (Agent-to-Agent) protocol facade.
- DI container (`cleveragents.application.container`).
- LangChain/LangGraph integration (ADR-022).
- Provider registry with fallback chain (OpenAI → Anthropic → Google → Azure → OpenRouter → Groq → Together → Cohere).
- Observability: structured logging, metrics, audit trail, token/cost tracking.
- BDD test suite (Behave + Robot Framework).
- Nox automation for lint, typecheck, tests, docs, benchmarks.
- MkDocs-powered documentation with CleverAgents branding.
+9 -12
View File
@@ -35,12 +35,11 @@ Feature: Consolidated Routing
# Feature: Reactive registry adapter coverage
# ============================================================
Scenario: Registry list failure is ignored
Scenario: Registry list failure propagates to caller
Given a reactive stream router and route bridge
And an actor registry that raises on list
When I register registry actors with the adapter
Then no agents are registered
And the route bridge agents remain unchanged
When I attempt to register registry actors with the adapter
Then a RuntimeError is raised
Scenario: Registers only actors with processing methods
@@ -51,20 +50,18 @@ Feature: Consolidated Routing
And the route bridge agents cache includes all listed actors
Scenario: Route bridge cache resets when refresh fails
Scenario: Route bridge refresh failure propagates to caller
Given a reactive stream router and route bridge
And an actor registry that returns actors without names
When I register registry actors with the adapter
Then the route bridge agents cache is cleared
And no agents are registered
When I attempt to register registry actors with the adapter
Then an AttributeError is raised
Scenario: Route bridge cache resets when registry returns none
Scenario: Route bridge refresh failure propagates when registry returns none
Given a reactive stream router and route bridge
And an actor registry that returns none
When I register registry actors with the adapter
Then the route bridge agents cache is cleared
And no agents are registered
When I attempt to register registry actors with the adapter
Then a TypeError is raised
# ============================================================
@@ -61,6 +61,18 @@ def step_register_actors(context):
)
@when("I attempt to register registry actors with the adapter")
def step_attempt_register_actors(context):
"""Attempt registration, capturing any exception that propagates."""
context.raised_exception = None
try:
register_registry_agents(
context.stream_router, context.route_bridge, context.actor_registry
)
except Exception as exc:
context.raised_exception = exc
@then("no agents are registered")
def step_assert_no_agents(context):
assert context.stream_router.agents == {}
@@ -88,3 +100,36 @@ def step_assert_bridge_cache(context):
@then("the route bridge agents cache is cleared")
def step_assert_bridge_cleared(context):
assert context.route_bridge.agents == {}
@then("a RuntimeError is raised")
def step_assert_runtime_error(context):
assert context.raised_exception is not None, (
"Expected RuntimeError but no exception was raised"
)
assert isinstance(context.raised_exception, RuntimeError), (
f"Expected RuntimeError but got {type(context.raised_exception).__name__}: "
f"{context.raised_exception}"
)
@then("an AttributeError is raised")
def step_assert_attribute_error(context):
assert context.raised_exception is not None, (
"Expected AttributeError but no exception was raised"
)
assert isinstance(context.raised_exception, AttributeError), (
f"Expected AttributeError but got {type(context.raised_exception).__name__}: "
f"{context.raised_exception}"
)
@then("a TypeError is raised")
def step_assert_type_error(context):
assert context.raised_exception is not None, (
"Expected TypeError but no exception was raised"
)
assert isinstance(context.raised_exception, TypeError), (
f"Expected TypeError but got {type(context.raised_exception).__name__}: "
f"{context.raised_exception}"
)
@@ -16,11 +16,11 @@ def register_registry_agents(
This expects actor_registry to expose list_actors() and get_actor(name).
Each actor is injected as a callable via process_message_sync if present;
otherwise skips.
Exceptions from actor_registry.list_actors() or route_bridge refresh are
allowed to propagate to the caller per CONTRIBUTING.md fail-fast policy.
"""
try:
actors = actor_registry.list_actors() # type: ignore[attr-defined]
except Exception:
return
actors = actor_registry.list_actors() # type: ignore[attr-defined]
for actor in actors or []:
# Prefer synchronous processing if available
@@ -29,7 +29,4 @@ def register_registry_agents(
# RouteBridge caches agents as a dict; refresh it
if hasattr(route_bridge, "agents"):
try:
route_bridge.agents = {a.name: a for a in actors}
except Exception:
route_bridge.agents = {}
route_bridge.agents = {a.name: a for a in actors}