docs(spec): document GitWorktreeSandbox, ContextTierHydrator, and idempotent execute dispatch #6988

Closed
HAL9000 wants to merge 1 commits from spec/architecture-cycle2-impl-clarifications into master
+22 -1
View File
@@ -19272,6 +19272,12 @@ Different resource types require different sandbox strategies:
Pros: natural rollback, diff support, efficient
Cons: requires git
**Implementation class**: `GitWorktreeSandbox`
The concrete implementation allocates a temporary directory via `tempfile.mkdtemp(prefix="ca-sandbox-<plan_id>-")`, removes the empty directory, and then runs `git worktree add -b cleveragents/plan-<plan_id> <temp_path> HEAD`. As a result, the sandbox root lives under the operating system's temp directory (for example, `/tmp/ca-sandbox-…`) rather than inside the repository. LLM-generated file output is committed on branch `cleveragents/plan-<plan_id>`, which Apply later merges into the project's active branch via `git merge`.
**Non-git fallback**: `_create_sandbox_for_plan()` (docs CLI) returns `(flat_root, None)` when no linked `git-checkout` resource exists. In that case the sandbox root is `.cleveragents/sandbox/` under the current working directory and Apply copies files back into the project with `shutil.copy2`. No alternate `filesystem_copy` strategy object is instantiated inside `GitWorktreeSandbox`.
**2. Filesystem copy sandbox**
* Copy project directory to a sandbox directory
@@ -43423,7 +43429,7 @@ Every A2A method routes to a specific Application-layer service method. The foll
| A2A Extension Method | Service Method |
| :------------------- | :------------- |
| `_cleveragents/plan/use` | `PlanService.create_plan()` |
| `_cleveragents/plan/execute` | `PlanLifecycle.execute()` |
| `_cleveragents/plan/execute` | `PlanLifecycle.execute()`**idempotent**: if the plan has already reached execute or apply phase, the dispatch is silently skipped (no error). This prevents duplicate dispatch errors in multi-agent scenarios where the same plan may receive multiple execute signals. |
| `_cleveragents/plan/apply` | `PlanLifecycle.apply()` |
| `_cleveragents/plan/cancel` | `PlanService.cancel()` |
| `_cleveragents/plan/status` | `PlanService.get_status()` |
@@ -44794,6 +44800,21 @@ This temporal chain is what enables the `temporal-archaeology` strategy to find
| **Warm** | Recent decision contexts, plan context snapshots | `context.tiers.warm.retention-hours` (default: 24h) | Scoped query via plan hierarchy | Current + recently-expired nodes |
| **Cold** | Archived decision contexts, historical UKO snapshots | `context.tiers.cold.retention-days` (default: 90d) | Full historical query | All temporal versions |
##### Context Tier Hydration
Before the Context Assembly Pipeline runs, the tier service must be populated with fragments from the project's linked resources. This is performed by the **`ContextTierHydrator`** component:
1. **File discovery** — reads files from linked `git-checkout` resources via `git ls-files`; falls back to `os.walk` for non-git `fs-directory` resources.
2. **Fragment creation** — creates `TieredFragment` objects for each discovered file and stores them in the `ContextTierService`.
3. **Injection point** — hydration runs before context assembly in the execute actor's `execute()` method.
The `ContextTierHydrator` receives its dependencies (`tier_service`, `project_repository`, `resource_registry`) via **constructor injection** at the CLI factory level (`_get_plan_executor`). Services must not call `get_container()` directly — this is an architectural invariant for all ACMS components.
**Sandbox root**: LLM file output (`FILE:` blocks) is written to the sandbox root returned by `_create_sandbox_for_plan()`. With a git worktree sandbox this is the temporary worktree path (for example, `/tmp/ca-sandbox-…`); when no git resource exists the fallback root is `.cleveragents/sandbox/` under the current working directory.
!!! warning "ContextFragment metadata type constraint"
When `detail_depth` or `relevance_score` values are stored in the `metadata` dict (e.g., for Pydantic model serialization), they must be serialized as **strings** (`str(value)`), not as `int` or `float`. Pydantic validation will reject non-string metadata values.
#### Scoped Views and Plan Subgraph Projection
##### Resource Scope Resolution