Added critical warning block and step-by-step checklist to product-builder.md
to ensure the agent always follows the correct workflow:
1. Launch 15 supervisors via curl to http://localhost:4096/session/:id/prompt_async
2. Monitor them with bash sleep loop (60 seconds between checks)
3. Re-launch any that exit
Key changes:
- ⚠️ Critical execution model warning at top (what to do / what NOT to do)
- 📊 Execution flow diagram showing all phases
- ✅ Step-by-step Phase C checklist (C.1: Pre-flight, C.2: Launch, C.3: Monitor)
- 🔒 Clearer permission blocks with explicit bans on implementation agents
- 📝 Comments explaining why supervisors use curl not Task tool
This prevents the product-builder from trying to implement issues directly,
which is the supervisors' job. Product-builder is a process supervisor (like
systemd), not a worker.
This TDD test captures the buggy behavior where `NamespacedName.validate_namespace()`
and `validate_name()` accept names starting with digits, violating the spec requirement
that namespace and name components must start with a letter (consistent with
`_BARE_NAME_RE` in project.py).
Three failing scenarios demonstrate the bug:
1. parse() accepting namespace starting with digit ("123abc/my-action")
2. constructor accepting name starting with digit (local/"123-action")
3. constructor accepting namespace starting with digit ("999org"/valid-name)
Tagged with @tdd_expected_fail per Bug Fix Workflow.
Implements #2145
Blocks #2147
Both slow_integration_tests and e2e_tests sessions require a database
(via setup_workspace() in helper scripts) but were not using the
pre-migrated template DB optimization already present in unit_tests,
integration_tests, and coverage_report.
Changes:
- slow_integration_tests: add _create_template_db() call, set
CLEVERAGENTS_TEMPLATE_DB env var, upgrade from robot to pabot for
parallel execution, add NO_COLOR/PYTHONPATH/PATH/compileall setup,
add --include slow / --exclude discovery/code_blocks/wip/E2E/tdd_fixture
tag filters, and update docstring.
- e2e_tests: add _create_template_db() call and set
CLEVERAGENTS_TEMPLATE_DB env var. The existing setup_workspace()
in helper_e2e_common.py already checks this env var and copies the
template instead of running 25+ Alembic migrations.
No changes to test helper files are required since setup_workspace()
already implements the fast-path copy logic when CLEVERAGENTS_TEMPLATE_DB
is set.
ISSUES CLOSED: #2334
Agent evolver identified a critical systematic pattern:
- Pattern: The backlog groomer was closing PRs as 'duplicates' of their
linked tracking issues. A PR containing 'Closes #N' was being treated
as a duplicate of issue #N, when it is actually the implementation
delivery vehicle for that issue.
- Evidence: At least 12 PRs were incorrectly closed (#1219, #1236, #1247,
#1269, #1267, #953, #1198, #1220, #1237, #1238, #1246, #1248) — all
with the same 'Duplicate Detected' comment pattern from groomer-1.
- Fix: Added explicit instructions to skip PRs during duplicate detection,
added a guard in the analysis loop pseudocode, and added a rule in the
Important Rules section.
This change requires human approval before taking effect.
ISSUES CLOSED: #2180
Add PermissionQuestionWidget API documentation to docs/api/tui.md including
method table, key bindings, PermissionDecisionEvent dataclass, and
render_permission_question() helper reference. Add corresponding CHANGELOG
entry under [Unreleased] Added section.
Refs: #997
Implement inline permission question widget for quick allow/reject
decisions within the conversation stream with file diff context.
ISSUES CLOSED: #997
Align Unicode box-drawing blocks and related tables in specification.md,
ADR-044/045/046, and reference pages for consistent MkDocs rendering.
ISSUES CLOSED: #1171
Consolidate duplicate Added/Fixed headings in [Unreleased] section into single canonical sections per Keep a Changelog format. Add new entries for DomainBaseModel (#1941) and TDD bug-capture test (#1094).
Co-authored-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
Co-committed-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
Add a new Behave TDD regression scenario that persists corrupt automation-profile JSON and verifies repository reads do not leak raw JSONDecodeError. The scenario is tagged with @tdd_bug, @tdd_bug_989, and @tdd_expected_fail so it currently inverts the intentional assertion failure and will require tag removal when bug #989 is fixed.\n\nAlso stabilize an unrelated integration fixture in robot/resource_dag.robot by sharing a single SQLAlchemy session in inline scripts; this removes nondeterministic visibility of flushed resource-type rows and keeps required nox integration quality gates deterministic for this branch.\n\nISSUES CLOSED: #1094
Agent evolver identified a systematic pattern:
- Pattern: PR stale/conflict cascade
- Evidence: 11+ PRs were approved but closed without merge due to
conflicts. PRs #1248, #1247, #1237, #1236, #1220, #1219, #1238,
#1246, #1269 were all bulk-closed as stale. Reviewer notes on
#1248, #1220, #1219, #1252 explicitly mention 'merge blocked by
conflicts'. With 16 parallel workers, master moves fast and branches
created minutes earlier are already behind by the time PRs are created.
- Fix: Add a rebase-onto-latest-master step (Phase 3, Step 3.0) in
ca-issue-worker before committing and creating the PR. This ensures
the branch is current when the PR is opened, dramatically reducing
the chance of merge conflicts when the reviewer processes it.
This change requires human approval before taking effect.
Agent evolver identified a systematic pattern:
- Pattern: UAT tester filing bugs for features already being implemented
- Evidence: 25+ UAT bugs filed for TUI MainScreen features (#1329-#1355)
that already had open implementation PRs (#1219, #1236, #1237, #1238,
#1246, #1247, #1248, etc.). The tester reported 'missing sidebar',
'missing tab bar', 'missing escape navigation' etc. while PRs
implementing these exact features were open and under review.
- Fix: Add step 4 to duplicate avoidance requiring the tester to check
for open PRs before filing 'missing feature' bugs.
This change requires human approval before taking effect.
- Add missing 'nox -s format -- --check' step (parity with ci.yml)
- Add NOX_DEFAULT_VENV_BACKEND: uv to global env and each nox step
- Fix quality gates script invocation (was using invalid nox session '3.13')
- Fix report artifact paths to match actual nox session output locations
(build/coverage.json and build/bandit-report.json instead of build/reports/)
- Add mkdir for build/reports before writing quality-trend.json
ISSUES CLOSED: #1537
BREAKING CHANGE: Supervisors can no longer use Task tool to launch workers
Major refactor of the permission model for product-builder and all 15
continuous supervisors to enforce strict separation: supervisors MUST use
curl/prompt_async via bash to launch workers, and CANNOT use the Task tool.
Key Changes:
1. Product-Builder Permissions (product-builder.md):
- Removed ALL Task permissions for supervisors (previously had 17)
- Kept Task permissions ONLY for 7 one-shot agents:
ca-project-bootstrapper, ca-ref-reader, ca-issue-finder,
ca-session-persister, ca-product-verifier, ca-milestone-reviewer,
ca-final-reporter
- Restricted bash to: echo, curl, sleep, jq only
- Removed Phase B (Architecture) and Phase C.1 (Planning)
- Updated to launch 15 supervisors (up from 13)
2. New Continuous Supervisors:
- ca-architect: Converted from one-shot to continuous supervisor
Monitors for spec needs, new milestones, ambiguities
- ca-epic-planner: Converted from one-shot to continuous supervisor
Monitors for milestones without issues, incomplete epics
3. All 15 Supervisors - Standardized Permissions:
- Removed ALL Task permissions for launching workers
- Workers MUST be launched via curl to OpenCode Server prompt_async API
- Added 'jq *' for JSON parsing (replacing python3)
- Restricted bash to specific commands only (deny all, allow specific)
- Git commands restricted to specific operations (clone*, fetch*, etc.)
- Directory operations (cd, mkdir, rm -rf) only where needed
4. Supervisor-Specific Updates:
- issue-implementor: Removed ca-issue-worker task permission
- ca-continuous-pr-reviewer: Added git + directory ops, removed worker tasks
- ca-uat-tester: Added read-only file/git commands, removed self-dispatch
- ca-bug-hunter: Restricted git to read-only, removed self-dispatch
- ca-test-infra-improver: Added read-only commands, removed self-dispatch
- ca-human-liaison: Removed ca-epic-planner/ca-architect task permissions
- ca-agent-evolver: Added git + directory operations
- ca-architecture-guard: Added read-only + git clone operations
- ca-spec-updater: Added git + directory operations
- ca-backlog-groomer: Removed ca-epic-planner task permission
- ca-docs-writer: Added git + directory operations
- ca-timeline-updater: Added git + directory operations
- ca-project-owner: Minimal permissions (curl, jq, sleep only)
Impact:
- Proper separation of concerns: supervisors orchestrate, workers execute
- No possibility of supervisors blocking on Task tool calls
- True fire-and-forget worker launching via prompt_async
- Consistent permission model across all 15 supervisors
- Maximum parallelism with proper isolation
Architecture now enforces: Product-builder → 15 supervisors → N workers
All launched via curl/prompt_async, NO Task tool for supervisors.
Introduce DomainBaseModel in src/cleveragents/domain/models/base.py that
defines the single shared model_config (str_strip_whitespace, validate_assignment,
arbitrary_types_allowed=False, populate_by_name, use_enum_values) previously
duplicated verbatim across five domain model files.
Update 14 classes across five files to inherit from DomainBaseModel instead
of pydantic.BaseModel directly, removing all inline model_config duplication:
- aimodelscredentials/ai_models_credentials.py (ModelProviderOption)
- aimodelserrors/ai_models_errors.py (ModelError, FallbackResult)
- aimodelsproviders/ai_models_providers.py (ModelProviderExtraAuthVars,
ModelProviderConfigSchema)
- auth/auth.py (AuthHeader, TrialPlansExceededError, TrialMessagesExceededError,
BillingError, ApiError, ClientAccount, ClientAuth)
- planconfig/plan_config.py (PlanConfig, ConfigSetting)
Pure structural refactor — no behavioral changes. Models with different
configurations (acms, aimodels_custom, etc.) are left untouched.
Add BDD feature (22 scenarios) and Robot integration tests (8 test cases)
verifying inheritance, config correctness, and no-duplication invariants.
ISSUES CLOSED: #1941
Centralize E2E initialization in common suite setup so DB-dependent CLI commands no longer rely on per-suite or per-test init workarounds. This also sanitizes suite-home names to prevent invalid path-derived initialization failures in isolated Robot runs.
ISSUES CLOSED: #1023
Add explicit aiohttp>=3.13.4 dependency constraint to pyproject.toml to remediate CVE-2026-34515, a high-severity open redirect vulnerability. The lockfile already resolves aiohttp to 3.13.5 which satisfies the constraint.
Closes#1544
Consolidates all per-job uv cache key prefixes across CI workflow files into a single shared key, eliminating redundant package downloads. Also adds missing uv cache steps to the build job and nightly-quality.yml.
Closes#1535
Restores the working OpenCode server mode + curl-based async supervisor
launch functionality from commit 9bbec0e6 (2026-04-02) and updates it for
the current 13-supervisor architecture.
Changes applied to 7 agent files (938 insertions, 221 deletions):
1. product-builder.md: Restored from 9bbec0e6 and updated for 13 supervisors
- Full bash permissions for curl/sleep
- Server URL: http://localhost:4096
- Launch via POST /session + POST /session/:id/prompt_async
- Session resume (adopts existing [CA-AUTO] sessions)
- Added ca-test-infra-improver and ca-project-owner to launch sequence
- Updated concurrent worker calculations (~5N + ~8 singletons)
2. issue-implementor.md: Restored curl-based worker dispatch
- 10-second polling loop with bash sleep
- Worker sessions via prompt_async
- Session resume for existing workers
3. ca-continuous-pr-reviewer.md: Restored curl dispatch pattern
4. ca-uat-tester.md: Restored curl pool mode
5. ca-bug-hunter.md: Restored curl pool mode
6. ca-test-infra-improver.md: Added self-dispatch permission
7. ca-session-cleanup.md: Restored utility agent
Architecture: 5 pool supervisors (N workers each) + 8 singleton supervisors
= 13 total supervisors running async via prompt_async.
Replaces the broken prompt_async implementation from commit 074c472e that
removed supervisors from task permissions without working server launch.
To use: Start OpenCode with --port 4096, then launch product-builder.
Refs: commit 9bbec0e6 (working version), commit 074c472e (broken version)
Add explicit aiohttp>=3.13.4 dependency constraint to pyproject.toml to
remediate CVE-2026-34515, a high-severity open redirect vulnerability in
aiohttp that affects the A2A server HTTP transport, MCP tool source
fetching, and agent communication layers.
The uv.lock already resolves aiohttp to 3.13.5 which satisfies the
>=3.13.4 constraint. Adding the explicit constraint ensures vulnerable
versions (<3.13.4) cannot be installed even if upstream transitive
dependency constraints are loosened.
ISSUES CLOSED: #1544
Rewrites the A2aRequest and A2aResponse Pydantic models to use the field
names mandated by the JSON-RPC 2.0 specification, fixing a fundamental
protocol compliance issue that prevented external A2A-compliant clients
from communicating with the server.
Changes:
- A2aRequest: a2a_version→jsonrpc (fixed '2.0'), request_id→id,
operation→method; auth field removed (not in JSON-RPC 2.0)
- A2aResponse: a2a_version→jsonrpc, request_id→id, status+data→result
(success path), timing_ms removed; added _result_xor_error validator
enforcing mutual exclusion of result and error fields
- A2aLocalFacade.dispatch(): updated to use request.method, request.id,
result=data, error=A2aErrorDetail(...)
- A2aHttpTransport.send(): updated to use request.method
- CLI call sites (session.py, plan.py): updated A2aRequest(method=...)
and response.result / response.error field access
- All existing A2A Behave step files updated to new field names
- New 35-scenario Behave feature (a2a_jsonrpc_wire_format.feature)
covering serialisation, deserialisation, validation, and facade dispatch
- New 7-test Robot Framework suite (a2a_jsonrpc_wire_format.robot)
for end-to-end wire format verification
ISSUES CLOSED: #1501
Extended `_print_actor()` to render the full spec-required output for
`agents actor add`: the Actor Added panel now includes a Type field, and
three additional panels (Config, Capabilities, Tools) plus a success
status line are rendered when `show_add_panels=True`.
- Add `Type:` field to the Actor Added panel (from `config_blob["type"]`)
- Implement Config panel: Path, Hash, Options count, Nodes count, Edges count
- Implement Capabilities panel: bulleted list (rendered only when non-empty)
- Implement Tools panel: Rich table with Tool, Read-Only, Safe columns
(rendered only when non-empty; string tool entries default to yes/yes)
- Add `✓ OK Actor added` success status line after all panels
- Pass `config_path` and `show_add_panels=True` from `add()` command
- Add Behave BDD scenarios covering each new panel and the success line
- Add Robot Framework integration test verifying the full rich output
ISSUES CLOSED: #1499
Add ULID format validation to all v3 plan commands to prevent users from
accidentally mixing legacy ('agents tell') and v3 ('agents plan use')
workflows. The two systems use separate storage backends and cannot be
mixed; this change detects the mismatch early and provides actionable
error messages.
Changes:
- Add _validate_plan_ulid() with proper Crockford Base32 regex
(^[0-9A-HJKMNP-TV-Z]{26}$, re.IGNORECASE) that correctly rejects
invalid characters (I, L, O, U), hyphens, and wrong-length strings
- Add _PLAN_ULID_RE compiled regex and _ULID_VALIDATION_ERROR_MSG constant
with actionable guidance explaining the legacy/v3 incompatibility
- Apply ULID validation to all v3 commands: execute_plan,
_lifecycle_apply_with_id, lifecycle_apply_plan, plan_status,
plan_errors, cancel_plan (only on user-provided IDs, not auto-discovered)
- Update _LEGACY_DEPRECATION_MSG and tell/build command warnings to
explicitly state that the two workflows are INCOMPATIBLE and cannot be mixed
- Add comprehensive BDD tests in features/plan_ulid_validation.feature
with step definitions using Typer CLI runner (not subprocess)
- Update CONTRIBUTING.md with 'Workflow Choice: Legacy vs. v3 Plan
Lifecycle' section documenting the incompatibility and migration path
ISSUES CLOSED: #1560
The TLS handshake failure on git.dev.cleveragents.com was caused by the
hostname being absent from the certificate's Subject Alternative Names
(SANs), or by SNI virtual-host misconfiguration on the server side.
This commit delivers the repository-side remediation:
- scripts/check-tls-cert.py: New TLS certificate health-check script.
Connects to a hostname, verifies the certificate's SANs include the
target hostname, checks expiry, and reports errors/warnings. Accepts
an injectable SSLContext for unit testing without real network access.
Supports wildcard SAN matching and configurable expiry warning threshold.
- docs/development/ops-runbook.md: New ops runbook documenting the full
certificate renewal procedure (Let's Encrypt/certbot and manual CA),
SNI misconfiguration diagnosis steps, expiry monitoring with cron, and
recommended alert thresholds (30/14/7/0 days).
- features/tls_certificate_check.feature: 14 Behave scenarios tagged
@tdd_issue @tdd_issue_1543 covering: missing SAN detection, valid SAN
acceptance, expired certificate detection, expiry warning threshold,
TLS handshake errors, connection timeouts, connection refused, wildcard
SAN matching, and _hostname_matches_san unit tests.
- features/steps/tls_certificate_check_steps.py: Step definitions for
the above feature, using unittest.mock to inject SSL contexts and
socket connections so no real network calls are made.
- mkdocs.yml: Added Ops Runbook to the Development section navigation.
The actual server-side certificate renewal (adding git.dev.cleveragents.com
as a SAN and reloading the web server) must be performed by the server
administrator following the procedure in docs/development/ops-runbook.md.
Closes#1543
ISSUES CLOSED: #1543
Add deterministic BDD feature and step definitions to resolve the
flaky-test detection alert for test_example_flaky_test (issue #1542).
Root cause: the async-job heartbeat step previously relied on a fixed
time.sleep(0.01) that was insufficient on fast CI runners. When two
consecutive datetime.now(UTC) calls returned the same microsecond value
the 'heartbeat updated' assertion failed intermittently.
The busy-wait guard (already present in async_execution_steps.py) is
the correct fix. This commit adds a dedicated feature that:
- Validates the heartbeat timestamp strictly advances after the
busy-wait (the primary test_example_flaky_test scenario)
- Covers rejection of heartbeat recording for queued and completed jobs
- Adds a bounded heartbeat step that asserts the busy-wait terminates
within a wall-clock budget, preventing infinite hangs on broken clocks
ISSUES CLOSED: #1542
- Add _EVENT_TYPE_TO_METHOD class-level mapping (ClassVar[dict[str, str]]) to
convert A2A event types to JSON-RPC 2.0 method names:
TaskStatusUpdateEvent → task/statusUpdate
TaskArtifactUpdateEvent → task/artifactUpdate
- Refactor SseEventFormatter.format() to produce JSON-RPC 2.0 notification
envelope: {"jsonrpc": "2.0", "method": "...", "params": {...}}
- Move event data fields into params object; include taskId (from plan_id)
in params when plan_id is present, per spec §Streaming Architecture
- Remove non-spec fields (event_id, event_type, timestamp, plan_id) from
the data payload; these remain in SSE envelope headers (event: and id:)
- Update BDD feature to verify JSON-RPC 2.0 structure for both event types,
events with/without plan_id, custom data in params, and exclusion of
non-spec fields
- Fix pre-existing type errors in step definitions: replace try/except
ImportError pattern with direct imports and use behave.runner.Context
for proper static typing (0 pyright errors)
ISSUES CLOSED: #1502
Move the large embedded `_BEHAVE_PARALLEL_CLI_SOURCE` string constant out of
noxfile.py and into a standalone `scripts/run_behave_parallel.py` module.
The `_install_behave_parallel()` helper now reads the script from disk via
`Path(__file__).parent / 'scripts' / 'run_behave_parallel.py'` instead of
embedding the source as a raw string literal. This allows ruff to lint and
type-check the runner independently, and makes noxfile.py significantly
shorter and easier to read.
No functional changes: the installed `behave-parallel` entry point is
identical to the previous embedded version. Parallel and sequential modes,
coverage integration, and the multiprocessing fork model are all preserved.
Fixed two SIM105 lint violations in the extracted script (replaced
try/except/pass with contextlib.suppress).
ISSUES CLOSED: #1538