2fc2f9f444
Add BDD test coverage for spec clarifications regarding: - Application layer DI exception (container.py) - ULID identifier scope (domain vs internal IDs) - ACMS pipeline protocol contracts - TUI component public interfaces ISSUES CLOSED: #10451
205 lines
12 KiB
Gherkin
205 lines
12 KiB
Gherkin
@spec @clarification @layer_boundary @di_exception @ulid_scope @acms_pipeline @tui_components
|
|
Feature: Spec clarifications — layer boundary DI exception, ULID scope, TUI/ACMS gap-fill
|
|
|
|
As a CleverAgents developer
|
|
I want BDD coverage for the AUTO-ARCH-1 spec clarifications introduced in PR #10451
|
|
So that the following architectural rules can be tested programmatically:
|
|
- Application layer container.py is the sole permitted location for application-to-infrastructure concrete type references
|
|
- Domain entity IDs must be ULIDs; ephemeral internal IDs need not be
|
|
- ACMS pipeline per-stage protocol contracts include storage tier definitions and budget enforcement
|
|
- TUI has 8+ component public interfaces with verifiable checks
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Layer boundary DI exception — container.py as sole permitted location
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@di_exception @layer_boundary
|
|
Scenario: Import analysis confirms container.py references infrastructure types
|
|
Given the source directory is at "src/cleveragents"
|
|
And I examine file "application/container.py"
|
|
Then container.py should import from cleveragents.infrastructure (application-to-infrastructure concrete type references)
|
|
|
|
@di_exception @layer_boundary
|
|
Scenario: Non-container application files must not import infrastructure types directly
|
|
Given the source directory is at "src/cleveragents"
|
|
And I examine all files in "application/services/" for imports
|
|
Then no file outside container.py should import from cleveragents.infrastructure with a concrete class
|
|
And application modules may only depend on domain model interfaces
|
|
|
|
@di_exception @layer_boundary
|
|
Scenario: container.py is the designated DI exception per spec clarification
|
|
Given the source directory is at "src/cleveragents"
|
|
When I check that cleveragents/application/container.py imports infrastructure types
|
|
Then "container.py" should be listed as the sole permitted location for application-to-infrastructure concrete references
|
|
And ADR-003 (Dependency Injection Framework) section on layer boundaries should cite this exception
|
|
|
|
@di_exception @layer_boundary
|
|
Scenario: container.py imports from domain models and infrastructure simultaneously
|
|
Given the file "src/cleveragents/application/container.py" is readable
|
|
Then container.py should import domain types such as AIProviderInterface, AnalyzerRegistry, InMemoryGraphBackend, InMemoryTextBackend
|
|
And container.py should import infrastructure types such as UnitOfWork, CheckpointRepository, SessionRepository, LLMTraceRepository
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# ULID scope — domain entity IDs must be ULIDs; ephemeral internal IDs don't have to be
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@ulid_scope @spec_clarification_10451
|
|
Scenario: Domain entity Plan uses ULID for plan_id field
|
|
When I verify the domain model for "Plan" at cleveragents.domain.models.core.plan
|
|
Then the plan model should have a plan_id field typed as a ULID string (26 chars, Crockford alphabet)
|
|
|
|
@ulid_scope @spec_clarification_10451
|
|
Scenario: Decision entity uses ULID for decision_id
|
|
When I verify the domain model for "Decision" at cleveragents.domain.models.core.decision
|
|
Then the decision model should have a parent_plan_id field typed as a nullable ULID
|
|
And the decision model should have a plan_id field typed as a ULID string
|
|
|
|
@ulid_scope @spec_clarification_10451
|
|
Scenario: Actor entity uses a namespaced identifier (not raw ULID)
|
|
When I verify the domain model for "Actor" at cleveragents.domain.models.core.actor
|
|
Then the actor model should use an actor_id field as its persistent identity format
|
|
|
|
@ulid_scope @spec_clarification_10451
|
|
Scenario: Child plans identified solely by ULID (no namespaced name) — spec clarification
|
|
When I verify subplan identity rules in the specification
|
|
Then child plans should use ULID identifiers only, not namespaced names
|
|
And all operations on child plans reference them by plan ID (ULID)
|
|
|
|
@ulid_scope @spec_clarification_10451
|
|
Scenario: Ephemeral internal IDs are exempt from ULID requirement
|
|
When I verify the ephemeral context fragment model
|
|
Then ContextFragment should have a fragment_id field typed as any str (not mandated to be ULID)
|
|
And the specification should clarify that domain entity identifiers must be ULIDs
|
|
And ephemeral internal identifiers need not conform to ULID format
|
|
|
|
@ulid_scope @spec_clarification_10451
|
|
Scenario: Resource identifier uses ULID consistently
|
|
When I verify the domain model for "Resource" at cleveragents.domain.models.core
|
|
Then all resource identifiers should be ULIDs (resource_ulid field)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# ACMS pipeline per-stage protocol contracts with storage tier and budget enforcement
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@acms_protocol @per_stage_contract
|
|
Scenario: Phase 1 components define Pipeline Protocol interfaces
|
|
Given the ACMS pipeline specification at docs/specification.md section "Context Assembly Pipeline"
|
|
And I identify the Phase 1 — Strategy Orchestration components
|
|
Then Phase 1 should have exactly three components: StrategySelector, BudgetAllocator, StrategyExecutor
|
|
And each component must be defined as a @runtime_checkable Protocol
|
|
|
|
@acms_protocol @per_stage_contract
|
|
Scenario: Phase 2 (Fragment Fusion) protocol interfaces are specified
|
|
Given the ACMS pipeline specification at docs/specification.md section "Context Assembly Pipeline"
|
|
And I identify the Phase 2 — Fragment Fusion components
|
|
Then Phase 2 should have exactly four components:
|
|
| Component | Protocol |
|
|
| FragmentDeduplicator | FragmentDeduplicatorProtocol |
|
|
| DetailDepthResolver | DetailDepthResolverProtocol |
|
|
| FragmentScorer | FragmentScorerProtocol |
|
|
| BudgetPacker | BudgetPackerProtocol |
|
|
|
|
@acms_protocol @per_stage_contract
|
|
Scenario: Phase 3 (Context Finalization) protocol interfaces are specified
|
|
Given the ACMS pipeline specification at docs/specification.md section "Context Assembly Pipeline"
|
|
And I identify the Phase 3 — Context Finalization components
|
|
Then Phase 3 should have exactly two components: PreambleGenerator and SkeletonCompressor
|
|
And each must be defined as a @runtime_checkable Protocol
|
|
|
|
@acms_protocol @per_stage_contract
|
|
Scenario: BudgetPacker enforces token budget limit (storage tier definition)
|
|
Given the ACMS pipeline modules are available
|
|
When I assemble with strategy "tiered" and budget 200 tokens from hot + warm tier fragments
|
|
Then the payload total tokens should not exceed the specified budget of 200
|
|
And BudgetPackerProtocol should guarantee total_tokens <= budget.max_tokens
|
|
|
|
@acms_protocol @per_stage_contract
|
|
Scenario: StrategyExecutor handles strategy failures gracefully with circuit breaking
|
|
Given a pipeline with a custom coordinator that has a per-strategy cost cap
|
|
When I coordinate with a budget of 100 tokens using the capped coordinator
|
|
Then the coordination result should list strategies used without raising unhandled exceptions
|
|
|
|
@acms_protocol @per_stage_contract
|
|
Scenario: Fragment deduplication retains highest relevance score for duplicates
|
|
Given fusion fragments with duplicates by URI and content
|
|
When I fuse with a budget of 500 tokens
|
|
Then the coordination fragment count should be less than or equal to total distinct resources
|
|
And each unique resource_uri should appear at most once in the output
|
|
|
|
@acms_protocol @per_stage_contract
|
|
Scenario: SkeletonCompressor integrates with parent plan context hierarchy
|
|
Given the ACMS pipeline specification describes skeleton compression for child plans
|
|
When a child plan's ContextRequest is assembled via ACMSPipeline
|
|
Then the payload should include skeleton_fragments derived from parent context
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# TUI component public interfaces — 8+ components with verifiable checks
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@tui_component @public_interface
|
|
Scenario: TUI widgets module exports exactly the documented component classes
|
|
Given the source directory is at "src/cleveragents"
|
|
When I enumerate widgets exported from "tui/widgets/__init__.py"
|
|
Then the following widget public interfaces should be present:
|
|
| Component |
|
|
| ActorSelectionOverlay |
|
|
| HelpPanelOverlay |
|
|
| PermissionQuestionWidget |
|
|
| PersonaBar |
|
|
| PromptInput |
|
|
| ReferencePickerOverlay |
|
|
| SlashCommandOverlay |
|
|
| ThoughtBlockWidget |
|
|
|
|
@tui_component @public_interface
|
|
Scenario: All TUI widget classes are Textual-compatible with _StaticBase base
|
|
Given the source directory is at "src/cleveragents"
|
|
When I check each TUI widget file for its base class
|
|
Then every widget in tui/widgets/ should derive from a Static base (Textual or Fallback)
|
|
And this provides graceful degradation when Textual is not installed
|
|
|
|
@tui_component @public_interface
|
|
Scenario: PromptInput exposes mode-aware behavior (normal, command, shell, multi-line)
|
|
When I verify the PromptInput class interface at cleveragents.tui.widgets.prompt
|
|
Then PromptInput should support InputMode enum values for mode-dependent symbol rendering
|
|
And PromptInput should emit a PromptSubmitted event on submission
|
|
|
|
@tui_component @public_interface
|
|
Scenario: PersonaBar provides content update API
|
|
Given the TUI persona bar module is importable
|
|
When I check PersonaBar's public methods
|
|
Then PersonaBar should have a set_content method for updating display text
|
|
|
|
@tui_component @public_interface
|
|
Scenario: ReferencePickerOverlay exposes suggestion population API
|
|
Given the TUI reference picker module is importable
|
|
When I check ReferencePickerOverlay's public methods
|
|
Then ReferencePickerOverlay should have a set_suggestions method accepting query and suggestion list
|
|
|
|
@tui_component @public_interface
|
|
Scenario: HelpPanelOverlay provides context-sensitive help rendering
|
|
Given the source directory is at "src/cleveragents"
|
|
Then HelpPanelOverlay should derive from a base Static widget class with _load_static_base
|
|
|
|
@tui_component @public_interface
|
|
Scenario: Throbber widget defined and documented in specification (8th+ component beyond widgets/)
|
|
Given the TUI app module imports widgets
|
|
When I verify throbber.py exists in tui/widgets/
|
|
Then ThrobberWidget should be a valid widget class with update visibility and animation methods
|
|
|
|
@tui_component @public_interface
|
|
Scenario: TUI total public interface component count meets 8+ requirement
|
|
When I count all classes exported from cleveragents.tui.widgets
|
|
Then the total component count should be at least 8
|
|
And the following minimum set must all be present:
|
|
| Component |
|
|
| ActorSelectionOverlay |
|
|
| HelpPanelOverlay |
|
|
| PermissionQuestionWidget |
|
|
| PersonaBar |
|
|
| PromptInput |
|
|
| ReferencePickerOverlay |
|
|
| SlashCommandOverlay |
|
|
| ThoughtBlockWidget |
|
|
| ThrobberWidget |
|