docs(02): create gap closure plan for DIAG-02 and Surefire fix

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-11 16:45:22 +01:00
parent d73f265d41
commit 9db053ee59
2 changed files with 162 additions and 2 deletions

View File

@@ -0,0 +1,159 @@
---
phase: 02-transaction-search-diagrams
plan: 04
type: execute
wave: 1
depends_on: ["02-01", "02-02", "02-03"]
files_modified:
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseExecutionRepository.java
- cameleer3-server-app/pom.xml
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/storage/DiagramLinkingIT.java
autonomous: true
gap_closure: true
requirements: ["DIAG-02"]
must_haves:
truths:
- "Each transaction links to the RouteGraph version that was active at execution time"
- "Full test suite passes with mvn clean verify (no classloader failures)"
artifacts:
- path: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseExecutionRepository.java"
provides: "Diagram hash lookup during batch insert"
contains: "findContentHashForRoute"
- path: "cameleer3-server-app/pom.xml"
provides: "Surefire fork configuration isolating ELK classloader"
contains: "reuseForks"
- path: "cameleer3-server-app/src/test/java/com/cameleer3/server/app/storage/DiagramLinkingIT.java"
provides: "Integration test proving diagram hash is stored during ingestion"
key_links:
- from: "ClickHouseExecutionRepository"
to: "DiagramRepository"
via: "constructor injection, findContentHashForRoute call in insertBatch"
pattern: "diagramRepository\\.findContentHashForRoute"
---
<objective>
Close two verification gaps from Phase 2: (1) populate diagram_content_hash during ingestion instead of storing empty string, and (2) fix Surefire classloader conflict so `mvn clean verify` passes.
Purpose: DIAG-02 requirement is architecturally complete but never populated. The test suite breaks in CI due to ELK static init poisoning the shared JVM.
Output: Working diagram linking during ingestion + green `mvn clean verify`
</objective>
<execution_context>
@C:/Users/Hendrik/.claude/get-shit-done/workflows/execute-plan.md
@C:/Users/Hendrik/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/02-transaction-search-diagrams/02-VERIFICATION.md
Prior plan summaries (needed — touches same files):
@.planning/phases/02-transaction-search-diagrams/02-01-SUMMARY.md
@.planning/phases/02-transaction-search-diagrams/02-03-SUMMARY.md
<interfaces>
<!-- Key types and contracts the executor needs. -->
From cameleer3-server-core/.../storage/DiagramRepository.java:
```java
Optional<String> findContentHashForRoute(String routeId, String agentId);
```
From cameleer3-server-app/.../storage/ClickHouseExecutionRepository.java (line 141):
```java
ps.setString(col++, ""); // diagram_content_hash (wired later)
```
The class is @Repository annotated, constructor takes JdbcTemplate only. It needs DiagramRepository injected to perform the lookup.
From cameleer3-server-app/.../storage/ClickHouseDiagramRepository.java:
```java
@Repository
public class ClickHouseDiagramRepository implements DiagramRepository {
public Optional<String> findContentHashForRoute(String routeId, String agentId) { ... }
}
```
</interfaces>
</context>
<tasks>
<task type="auto" tdd="true">
<name>Task 1: Populate diagram_content_hash during ingestion and fix Surefire forks</name>
<files>
cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseExecutionRepository.java,
cameleer3-server-app/pom.xml,
cameleer3-server-app/src/test/java/com/cameleer3/server/app/storage/DiagramLinkingIT.java
</files>
<behavior>
- Test 1: When a RouteGraph is ingested before a RouteExecution for the same routeId+agentId, the execution's diagram_content_hash column contains the SHA-256 hash of the diagram (not empty string)
- Test 2: When no RouteGraph exists for a route, the execution's diagram_content_hash is stored as empty string (graceful fallback)
</behavior>
<action>
**Gap 1 — Diagram hash linking (DIAG-02):**
1. Modify `ClickHouseExecutionRepository` constructor to accept `DiagramRepository` as a second parameter alongside `JdbcTemplate`. The class is `@Repository` and both dependencies are Spring-managed beans, so constructor injection will autowire both.
2. In `insertBatch()`, inside the `BatchPreparedStatementSetter.setValues()` method, replace line 141:
```java
ps.setString(col++, ""); // diagram_content_hash (wired later)
```
with a lookup:
```java
String diagramHash = diagramRepository
.findContentHashForRoute(exec.getRouteId(), exec.getAgentId())
.orElse("");
ps.setString(col++, diagramHash); // diagram_content_hash
```
Note: `findContentHashForRoute` returns the most recent content_hash for the route+agent pair from `route_diagrams` table (ORDER BY created_at DESC LIMIT 1). If no diagram exists yet, it returns empty Optional, and we fall back to empty string.
3. Performance consideration: The lookup happens per-execution in the batch. Since batches are flushed periodically (not per-request) and diagram lookups hit ClickHouse with a simple indexed query, this is acceptable. If profiling shows issues later, a per-batch cache of routeId+agentId -> hash can be added.
4. Create `DiagramLinkingIT` integration test extending `AbstractClickHouseIT`:
- Test 1: Insert a RouteGraph via `ClickHouseDiagramRepository.store()`, then insert a RouteExecution for the same routeId+agentId via `ClickHouseExecutionRepository.insertBatch()`, then query `SELECT diagram_content_hash FROM route_executions WHERE execution_id = ?` and assert it equals the expected SHA-256 hash.
- Test 2: Insert a RouteExecution without any prior RouteGraph for that route. Assert `diagram_content_hash` is empty string.
**Gap 2 — Surefire classloader isolation:**
5. In `cameleer3-server-app/pom.xml`, add a `<build><plugins>` section (after the existing `spring-boot-maven-plugin`) with `maven-surefire-plugin` configuration:
```xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<forkCount>1</forkCount>
<reuseForks>false</reuseForks>
</configuration>
</plugin>
```
This forces Surefire to fork a fresh JVM for each test class, isolating ELK's static initializer (LayeredMetaDataProvider + xtext CollectionLiterals) from Spring Boot's classloader. Trade-off: slightly slower test execution, but correct results.
</action>
<verify>
<automated>cd C:/Users/Hendrik/Documents/projects/cameleer3-server && mvn clean verify -pl cameleer3-server-app -am 2>&1 | tail -30</automated>
</verify>
<done>
- diagram_content_hash is populated with the active diagram's SHA-256 hash during ingestion (not empty string)
- DiagramLinkingIT passes with both positive and negative cases
- `mvn clean verify` passes for cameleer3-server-app (no classloader failures from ElkDiagramRendererTest)
</done>
</task>
</tasks>
<verification>
1. `mvn clean verify` passes end-to-end (no test failures)
2. DiagramLinkingIT confirms diagram hash is stored during execution ingestion
3. All existing tests still pass (search, detail, diagram render)
</verification>
<success_criteria>
- DIAG-02 fully satisfied: transactions link to their active RouteGraph version via diagram_content_hash
- `mvn clean verify` is green (all ~40+ tests pass without classloader errors)
- No regression in existing search, detail, or diagram functionality
</success_criteria>
<output>
After completion, create `.planning/phases/02-transaction-search-diagrams/02-04-SUMMARY.md`
</output>