# Superretometer v0.6.4 — Direction-Aware Justification + Fail-Closed Enumeration

**Release date:** 2026-09-06  
**Release tag:** \`v0.6.4\`  
**Source:** commit referenced by the \`v0.6.4\` tag  
**CI:** PASS — Python 3.10, 3.12, 3.13

---

## 1. What Changed (Code Diff)

### New Exception
- `cognitive_harness.exceptions.IncompleteEnumerationError` — raised when a FULL_REQUIRED analysis cannot guarantee complete graph enumeration.

### StorageInterface Extensions
- `enumeration_complete` property — backends declare whether `list_all_kos()` returns every KO in the graph or may miss entities.
- `get_outgoing_relations(ko_id)` — returns relations where the KO is the source.
- `get_incoming_relations(ko_id)` — returns relations where the KO is the target.

### Relation Sets
- `JUSTIFICATION_INBOUND` = `{SUPPORTS, VALIDATES}` — relations that flow *into* a claim.
- `JUSTIFICATION_OUTBOUND` = `{DEPENDS_ON, DERIVED_FROM}` — relations that flow *out of* a dependent.

### WarrantAnalyzer Changes
- BFS is now direction-aware: inbound relations (SUPPORTS, VALIDATES) are traversed as incoming edges to a claim; outbound relations (DEPENDS_ON, DERIVED_FROM) are traversed as outgoing edges from a dependent.
- `detect_all_anti_patterns()` checks `storage.enumeration_complete` and raises `IncompleteEnumerationError` if False.
- Cycle detection uses direction-aware traversal to avoid false positives from mixed-direction graphs.

### InMemoryStorage Changes
- `compute_impact_set()`: direction-aware. Evidence changes propagate to supported claims (following SUPPORTS inbound). Prerequisite changes propagate to dependents (following DEPENDS_ON outbound).
- `get_justification_path()`: direction-aware traversal using the inbound/outbound relation sets.
- Implements `get_outgoing_relations()` and `get_incoming_relations()`.

### Test Fixture Changes
- SUPPORTS relations are no longer embedded in KO relations. Created explicitly with `storage.create_relation(evidence, conclusion, SUPPORTS)`.

---

## 2. What It Means (Semantic Diff)

This release corrects the fundamental direction semantics of the justification graph. The change is not cosmetic — it changes what "warrant" means computationally.

### Before v0.6.4 (Incorrect)
SUPPORTS edges were treated as outgoing from the conclusion:

```
claim --SUPPORTS--> evidence   (wrong — reads as "claim supports evidence")
```

This meant BFS from a claim would traverse *away* from its evidence, finding dependents instead of justifiers. Warrant computation followed the wrong direction.

### After v0.6.4 (Correct)
SUPPORTS edges are incoming to the conclusion:

```
evidence --SUPPORTS--> claim   (correct — reads as "evidence supports claim")
```

The four justification relation types have distinct direction semantics:

| Relation | Source | Target | Traversal | Meaning |
|---|---|---|---|---|
| `SUPPORTS` | evidence | claim | **Incoming** to claim | Evidence supports a conclusion |
| `VALIDATES` | validator | claim | **Incoming** to claim | A validator validates a claim |
| `DEPENDS_ON` | dependent | prerequisite | **Outgoing** from dependent | A claim depends on a prerequisite |
| `DERIVED_FROM` | derived | source | **Outgoing** from derived | A claim is derived from a source |

### Warrant Traversal
Warrant analysis now performs a direction-aware BFS:
- To find what **justifies** a claim: traverse **incoming** SUPPORTS and VALIDATES edges.
- To find what a claim **depends on**: traverse **outgoing** DEPENDS_ON and DERIVED_FROM edges.

This matches the epistemic model: warrant flows *from evidence to claim*, not the reverse.

### Cycle Detection
Cycle detection is direction-aware. A cycle requires a directed path that returns to the origin. Previously, bidirectional traversal on undirected edges produced false cycle positives when, for example, `A SUPPORTS B` and `C DEPENDS_ON B` formed an apparent loop.

### Fail-Closed Enumeration
`enumeration_complete` distinguishes between two classes of backends:

1. **Complete enumeration** (`enumeration_complete = True`): `list_all_kos()` returns every KO. FULL_REQUIRED analyses (`detect_all_anti_patterns`, `list_review_required`) execute normally.

2. **Incomplete enumeration** (`enumeration_complete = False`): `list_all_kos()` may miss entities (e.g., Memory HTTP backend uses search-based pagination). FULL_REQUIRED analyses raise `IncompleteEnumerationError` instead of producing potentially incomplete results.

LOCAL_COMPLETE_ADJACENCY operations (warrant, gates, impact, justification path) remain usable because they only require the local adjacency of a single KO, not the complete graph.

---

## 3. Migration Guide for Custom Storage Backends

If you implement a custom `StorageInterface`, you must add two methods and one property:

### Required Additions

```python
from cognitive_harness.interfaces import StorageInterface

class MyStorage(StorageInterface):
    @property
    def enumeration_complete(self) -> bool:
        """Can list_all_kos() guarantee every KO is returned?"""
        return True  # or False if search-based pagination

    def get_outgoing_relations(self, ko_id: str) -> list[Relation]:
        """Relations where ko_id is the source."""
        ...

    def get_incoming_relations(self, ko_id: str) -> list[Relation]:
        """Relations where ko_id is the target."""
        ...
```

### If You Cannot Guarantee Complete Enumeration

Set `enumeration_complete = False`. This is appropriate for:
- Backends using search-based pagination (e.g., Memory HTTP adapter)
- Backends with filtering, rate limits, or cursors that may skip entities
- Backends where the graph is larger than what can be enumerated in one session

Effect: `detect_all_anti_patterns()` and `list_review_required()` will raise `IncompleteEnumerationError`. Callers must handle this.

### Backward Compatibility

Existing methods (`create_ko`, `get_ko`, `delete_ko`, `create_relation`, `list_all_kos`) remain unchanged. Only additions to the contract.

---

## 4. New Guarantees

### Fail-Closed for FULL_REQUIRED Analyses
When `enumeration_complete` is False, analyses that require the complete graph will not produce partial results. They raise `IncompleteEnumerationError`. This is a design choice: incomplete anti-pattern detection is worse than no detection (you may act on missing false negatives).

### Direction Semantics Are Specified, Not Assumed
The justification graph direction model is explicit:
- `JUSTIFICATION_INBOUND` and `JUSTIFICATION_OUTBOUND` are defined relation sets.
- WarrantAnalyzer, impact propagation, and cycle detection all use direction-aware traversal.

### Impact Propagation Is Direction-Correct
- Evidence KO changes → impact flows to claims that are supported by that evidence (incoming SUPPORTS).
- Prerequisite KO changes → impact flows to claims that depend on that prerequisite (outgoing DEPENDS_ON).

---

## 5. What Should You Understand Differently in v0.6.4?

**The justification graph is directional.** Relations have semantics encoded in their direction. `A SUPPORTS B` means A is evidence for B, and warrant flows from A to B. Traversing SUPPORTS "in reverse" (from B back to A) follows incoming edges to B.

**Not all backends can enumerate the complete graph.** The `enumeration_complete` property makes this explicit. A backend can provide local adjacency (warrant, gates, impact, justification path) without providing global enumeration (anti-pattern detection, review listing).

**Fail-closed is a feature.** Getting an `IncompleteEnumerationError` on a Memory HTTP backend tells you: "I cannot guarantee I've checked the entire graph." This is more honest than silently returning results that may be missing anti-patterns in unenumerated regions.

**Test fixtures model correct direction.** SUPPORTS relations are now created with the evidence as source and the conclusion as target. If your test fixtures embedded relations in KOs, migrate to explicit `storage.create_relation(evidence, conclusion, SUPPORTS)` calls.

---

## 6. Known Limitations

- **Memory HTTP backend:** `MemoryAdapter.list_all_kos()` uses search-based pagination and cannot guarantee complete enumeration. `enumeration_complete = False`. FULL_REQUIRED analyses fail closed.
- **Migration burden:** Custom `StorageInterface` backends must implement `get_outgoing_relations()` and `get_incoming_relations()`. No shim or adapter is provided.
- **No automated migration for test fixtures:** Existing tests with embedded SUPPORTS relations will need manual updates to use explicit `create_relation()` calls.

---

## 7. Validation Evidence

| Check | Result |
|---|---|
| Test suite | 69 pass |
| Identity mapping tests | 12 pass |
| Live Admin acceptance | 11 pass |
| CI Python 3.10 | PASS |
| CI Python 3.12 | PASS |
| CI Python 3.13 | PASS |
| Restart persistence | PASS |
| Fail-closed enumeration | PASS (IncompleteEnumerationError on HTTP backend) |
