# CORREX — RETRO (archive of resolved BACKLOG items) Counterpart to `BACKLOG.md` (the live outstanding list). Items here are **built and unit-verified** (Gradle green). Where a live-QA gate applies, that's called out as a follow-up — this sandbox has no local model / SearXNG / GPU / network, so live-QA could not be run here. --- ## 2026-06-22 — BACKLOG hygiene reconcile + operator-requested TUI wave (branch `feat/backlog-burndown`) **Hygiene reconcile.** Per `BACKLOG.md`'s own maintenance rule, cut the resolved body bullets that were left ticked-but-in-place after the 2026-06-20 burndown and 2026-06-21 grants work. Sections affected: §A (health probes), §B (static-first infra, `CritiqueFinding`, architect contradiction-check), §C (A1/A2 gate code), §D (batch fetch-approval, source events, dynamic egress), §E (render matrix, markdown, session list, idea promotion), §G (turnId/probe/narration), §I (`.cs` symbols, scene validator). Partially-done items were **narrowed to their live follow-up** rather than deleted: §B5 → "static_check stage emitter only", §B6/§C-A3 → "the `CritiqueOutcomeCorrelatedEvent` producer only", §C-A1 → "planner-prompt activation only". The full commit map stays in the BACKLOG "✅ RESOLVED" index; detail is in the tables below. **Operator-requested TUI wave (archived here — never BACKLOG items, like the grants work).** A run of TUI/UX features added on the branch after the burndown, each compiled + `go vet`/`go test` green and rendered via `cmd/preview` before commit: | Commit | What | |--------|------| | `9143d55` | Global input history + stop idle redraws (copy-safe — no redraw churn while selecting text). | | `85bfddf` | Slash-command menu in the chat input. | | `2662156` | Transparent modal backdrops (overlays no longer paint an opaque box over the transcript). | | `ba7ac06` | Transcript message-jump (`^↑`/`^↓` to your prev/next message) + OSC52 clipboard copy. | | `65e5d88` | **Server:** `ListFiles`/`FileList` protocol backing the TUI `@` picker. | | `04d7e26` | `@` file-reference picker in the input. | | `c616982` | **Context:** inject `CLAUDE.md` / `AGENTS.md` as L0 standing context. | | `54f94a5` | Command-palette keybinds + configurable (hideable) status bar. | | `6a06f2e` | Inline action rows in the OUTPUT transcript (tool results / approvals / writes / grants as `RouterEntry` role `action`, interleaved by arrival). | | `f14a83c` | Drop the inline tool-*start* rows (they doubled up with the result rows). | | `531910d` | Transcript free-scroll (`PgUp/PgDn`, `^u/^d`, `esc` snaps to tail-follow; clamped via `outputViewport()`/`buildTranscriptRows`, 2 tests) + help overlay (`?`) + event-inspector `/` filter. | These are mostly deterministic render/UX changes (verifiable by `go test` + `cmd/preview`); the only remaining live look is the §E approval-ergonomics re-audit noted in BACKLOG (the band gained the grant scope-picker + action rows since `d5afcd3`). --- ## 2026-06-21 — wider grants + revoke (branch `feat/backlog-burndown`) Operator-requested (not a prior BACKLOG item): grants that outlive a single session, plus a revoke path. Two commits, each compiled + unit-tested green. | Commit | What | |--------|------| | `c36d41b` | **Cross-session grant scopes (PROJECT/GLOBAL) + revoke.** `GrantScope.GLOBAL(toolName)` added; `PROJECT` made tool-bound. Engine `scopeMatches`: GLOBAL matches the bound tool anywhere, PROJECT when the session's `projectId` (derived from the bound workspace root via `ProjectIdentity.of`) AND tool match. New reserved `GRANT_LEDGER_SESSION_ID` stream holds PROJECT/GLOBAL grants; the approval gate unions the ledger's grants with the session's. `RevokeGrant` → `ApprovalGrantExpiredEvent` on the ledger (reducer already drops it); `ListGrants`/`GrantList` expose the active standing grants. **Server-side T2 grant ceiling removed** per operator request — a grant may now authorize any tier (incl. T3/T4); tool-binding is the remaining guard. New `GrantScopeMatchingTest` (5). | | `8df0ec7` | **TUI: scope picker (A) + standing-grants viewer.** `A` (approve-always) opens a session/project/global picker (SESSION default = old behaviour); `p`/`g` create wider grants. `grants` palette command + `G` shortcut open `OverlayGrants` listing scope/tool/tiers/path with `x`/enter to revoke. `protocol.go`: `TypeGrantList`+`GrantDto`, `RevokeGrant`/`ListGrants` encoders. Both overlays rendered via `cmd/preview` (kinds `grants`, `grant-scope`). | **Why the design:** session grants are event-sourced per-session and die with the session; project/global grants must outlive any one session, so they live in a dedicated ledger stream the gate folds in — keeps grants in the audit log (invariant #9) rather than config. **⚠️ Live-QA gate (move out of RETRO once passed):** unit tests cover the engine matching, reducer, and ledger fold, but the *cross-session* behaviour — create a GLOBAL/PROJECT grant in session A, confirm a **different** session B auto-clears that tool, then revoke and confirm it prompts again — needs a running server + model. Not runnable in this sandbox. --- ## 2026-06-20 — backlog burndown (branch `feat/backlog-burndown`) Nine tracks, each compiled + unit-tested green before commit. | Commit | Track | BACKLOG ref | |--------|-------|-------------| | `f783eed` | `CritiqueFinding`/`CritiqueSeverity`/`CritiqueRole` type + `CritiqueOutcomeCorrelatedEvent` + `core/critique` calibration projection (state/reducer/projector) | B §6 + C-A3 | | `784accb` | `repomap:` turnId namespace requires trailing `:` (no `/repo`↔`/repo2` collision; L3RepoKnowledgeRetriever filter + ProjectMemoryService write) + WorkspaceStateProbe newline fingerprint | G | | `266bbf0` | `EventStoreLatencyProbe` (wired) + `LlamaServerHealthProbe` (+ injectable `LlamaLivenessClient`) + `HealthConfig.eventStoreWarnLatencyMs` | A §4 | | `f715ffa` | `.cs` / Godot-Mono type symbols in `RepoMapIndexer.SYMBOL_PATTERNS` | I | | `0e251d6` | `SceneValidator` — structural `.tscn`/`.tres` (header well-formedness, ExtResource/SubResource id resolution, node parent integrity) | I | | `1df7af5` | Brief echo-back gate: `BriefEchoMismatchEvent` + `BriefEchoComparator`/`BriefEchoExtractor` + `checkBriefEcho` orchestrator gate | C-A1 | | `1a1b5cc` | Stage-level plan checkpointing: `StageCheckpointPassed/FailedEvent` + `StageCheckpointReconciler` + `emitStageCheckpoint` (gated on a locked plan) | C-A2 | | `eae0a0c` | Architect contradiction-check (display-only): `PossibleContradictionFlaggedEvent` + L3-backed `ArchitectContradictionChecker` | B §4 | | `b098d87` | Dedicated `SourceFetchedEvent` / `LowQualityExtractionEvent` (promoted from `ToolExecutionCompletedEvent` metadata; additive), emitted from `SandboxedToolExecutor` | D | | `027ff1f` | Dynamic per-session egress allowlist: `EgressHostsGrantedEvent` + `EgressAllowlist` union helper + `EgressAllowlistProjection`; `NetworkHostRule` delegates to the union | D | | `447fc7a` | Reviewer static-first: `StaticFindingsRecordedEvent` + `StaticAnalysisRunner` (injectable `CommandRunner`; compiler/ktlint/detekt parsers) + `excludeStaticFindingsFromReview` filter, live-wired into reviewer context assembly | B §5 | | `eff8f8d` | Narration-lane lag: stale pause narrations dropped per-approval-request on resolve / per-session on resume (replay-safe) | G | | `1e6699a` | tui-go `go.mod` `go 1.26` → `1.24.2` (1.26 toolchain unreleased/unfetchable) — unblocks Go build/test on released toolchains | E (enabler) | | `da72ee5` | tui-go: markdown rendering for chat turns via `glamour` (dark, per-width memoized), plain-text fallback; other roles/UI untouched | E | | `1f7a5d9` | tui-go session list / resume view: `R` overlay over `GET /sessions`, resume via `POST /sessions/{id}/resume` onto the existing global stream | E | | `2a99e15` | tui-go per-event render-matrix golden tests (37 cases) + a coverage guard that parses `protocol.go` so any new event type without a golden fails | E §2 | | `d5afcd3` | tui-go approval ergonomics: navigable pending-approval queue (no modal stacking) + `y/n/e` keys + tier-gated T3+ arm/confirm | E §3 | | `641051b` | Plan-derived diff manifest: `PlanStage.writes` + `PlanDerivedManifest.deriveAllowedWrites`/`combine`, unioned into `StageConfig.writeManifest` at compile, enforced by the existing containment matcher | B §2 | | `ab7e4be` | Egress allowlist **activation**: `resolveSessionEgressHosts` threads the session's `EgressAllowlistProjection` state into `ToolCallAssessmentInput` at `runPlane2Assessment`, so `NetworkHostRule` now consults the live per-session union (was fed `emptySet()`) | D (activation) | | `4b0024f` | Batch source-list fetch-approval: `POST /sessions/{id}/approve-sources` → `SourceListHosts.extract` (java.net.URI, lower-cased, ports stripped, dossier-line tolerant) → one `EgressHostsGrantedEvent`; live allowlist then auto-clears those web_fetches (no per-URL T2) | D | | `f107ff5` | Idea-board → project-profile promotion: `IdeaPromotedEvent` (board tombstone, like discard) + `ProjectProfileWriter` (escape-aware TOML serialize/write) + `ProjectProfile.withConvention` (deduped) + server `PromoteIdea` handler (loads profile, appends idea text, writes `.correx/project.toml`); also made `SimpleToml`'s reader unescape `\\`/`\"` symmetrically with the writers (fixes pre-existing read/write asymmetry) | E | | `4e08510` | Architect contradiction-check **activation**: `ServerModule.start()` subscribes to the architect stage's `design` `ArtifactCreatedEvent`, resolves decision text (design-schema `approach` field, capped fallback), runs `ArchitectContradictionChecker.check`, appends the non-null `PossibleContradictionFlaggedEvent`. Live-only, never halts. Checker built in `Main.kt` (gated on `project.enabled`) and threaded into `ServerModule`. Replaces the `Main.kt` `TODO(wiring)` | B §4 (activation) | | `64a90e7` | Llama-probe **registration**: `LlamaServerHealthProbe` (266bbf0) wired into the health monitor when a `llamacpp` provider URL is configured — dedicated CIO client (3s timeout, shutdown-hook close) + `HttpLlamaLivenessClient`. Gated so a model-less box reports no spurious `LLAMA_SERVER` DEGRADED. Replaces the `Main.kt` `TODO(wiring)` | A §4 (activation) | ### Follow-ups created this pass (refiled into BACKLOG) - **C-A1 activation** — `planner.md` must emit a `brief_echo` block and `role_pipeline.toml` must set `briefEcho="true"` / `briefEchoSource` for the gate to fire live (model-dependent → live-QA). - **C-A3 producer** — nothing emits `CritiqueOutcomeCorrelatedEvent` yet; the calibration projection has no live feed until a reviewer-loop producer records finding outcomes. - **B §4 wiring** — ✅ DONE (`4e08510`): `ServerModule.start()` now subscribes to the architect `design` artifact and emits the flag. (In-session L3 embedding is NOT needed — the checker filters to PRIOR sessions by design, so it works against prior runs' distilled decisions.) - **A §4 llama wiring** — ✅ DONE (`64a90e7`): the probe is registered in the health monitor (gated on a configured `llamacpp` provider URL) via `HttpLlamaLivenessClient`. (tokens/sec telemetry still rides liveness-only — the `/health` endpoint reports reachability; a throughput feed remains future work but the spec's liveness probe is live.) - **D egress wiring** — ✅ DONE (`ab7e4be`): session egress state is now threaded into `ToolCallAssessmentInput` at `runPlane2Assessment`, so `NetworkHostRule` consults the live union. Batch fetch-approval ✅ DONE (`4b0024f`): `POST /sessions/{id}/approve-sources` emits one `EgressHostsGrantedEvent` for the whole source list. - **B §5 static_check stage** — runner/event/filter complete and the filter is live, but no workflow stage emits `StaticFindingsRecordedEvent` yet (`// TODO(wiring)` in `StaticAnalysisRunner.kt`); needs an event-emitting deterministic stage-type seam. - **E toolchain** — tui-go now builds via auto-downloaded go1.24.2 (`GOTOOLCHAIN=auto`). The committed directive fix assumes 1.26 was unintended; bump if a specific newer release is actually wanted. ### Environment note - A `~/.gradle/gradle.properties` machine-local override was added on this box (`-Xmx768m`, `parallel=false`, kotlin daemon `-Xmx640m`) because the repo's `-Xmx4G` OOM-killed the foreground process on a 1.9 GB machine. **Not committed** — repo defaults intact for higher-RAM machines.