Files
correx/RETRO.md
T
kami 33baaed903 docs: reconcile BACKLOG→RETRO for static_check stage + critique producer (e46777e)
Per the hygiene rule: the §B-§5 static_check stage seam + emitter and the §B-§6/A3
critique-outcome producer are built and unit-verified, so move them out of the live
"missing" list. Both narrowed to their remaining live-QA-gated *activations* (a sandboxed
production CommandRunner for §B-§5; model-emitted CritiqueFindingsRecordedEvents for §6),
with a dated RETRO entry + commit map. Updated QA-reviewer-static-first (the producing
stage now exists — check 4 reframed from "blocked on unbuilt seam" to an activation step)
and its README index line.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 21:52:59 +00:00

135 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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. |
| `db27b34` | Page-scroll the `^x` diff/preview/command fullscreen viewer (`↑↓` line, `PgUp/PgDn` page, `^u/^d` half, `g/G` ends; `scrollDiff()` clamp, 2 tests) + advertise it in the modal hint and the `?` help overlay. Closes the §E approval-ergonomics re-audit. |
| `d247b19` | **Bubble Tea v1 → v2** (`charm.land/{bubbletea,lipgloss}/v2`, Go 1.25). A key-handling shim (`key.go`: v2 `KeyPressMsg` → v1-shaped `keyMsg` at the single `Update` boundary) keeps ~190 match sites untouched. Other v2 breaks handled: `lipgloss.Color` is now a func returning `color.Color` (retyped fields/params); `View()` returns `tea.View` (`render()` builds the string, `View()` carries `AltScreen` — alt-screen is a per-frame field now, not a program option); `WithWhitespaceStyle` replaced `WithWhitespace{Background,Foreground}`; preview dropped `SetColorProfile` (v2 = truecolor by default). Enables literal **Shift+Enter** newline via v2 kitty disambiguation (`Ctrl+J`/`Alt+Enter` kept as non-kitty fallback). Live-QA: `docs/qa/QA-tui-v2.md`. |
| `85af2c6` | **Real terminal cursor in composer + window title.** `View.Cursor` replaces the frame-animated `▏`: a width-1 marker rune (U+E123) is located in the fully-composited frame → blinking `CursorBar` at `(X,Y)`; static `render()` resolves it back to `▏` so screenshots/goldens are unchanged. Nil in normal mode (hidden, vim-correct), suppressed when a modal is open (which keeps `editMode==Insert`). `animating()` no longer ticks in insert mode — the terminal blinks the cursor itself, so an idle insert screen holds still (native text selection survives). `View.WindowTitle` = active session/model. New `cursor_test.go` (3) + updated animating-gate test. |
These are mostly deterministic render/UX changes (verifiable by `go test` + `cmd/preview`).
The v2 migration + native cursor are unit-verified the same way, but their *behavioral* wins
(Shift+Enter, the real blinking cursor, no regressions across the new render layer) need a real
kitty terminal — that's the live-QA gate in `docs/qa/QA-tui-v2.md`.
**§E approval-ergonomics re-audit — DONE (`db27b34`).** Re-checked the band after it gained the
grant scope-picker (`A`) and inline action rows: the spec still holds — single-key `y/n/e` for
T0T2, mandatory second-key confirm for T3+ (`HighTier`), navigable queue with an `i/n` indicator,
docked band never modal-stacks. All covered green by `approval_test.go`. The one gap was the diff
viewer scrolling one line at a time; `db27b34` adds paging. Item moved out of BACKLOG.
---
## 2026-06-22 — reviewer reliability: static_check stage + critique calibration producer (branch `feat/backlog-burndown`)
Two deterministic role-reliability tracks whose consumer halves already existed but had nothing
feeding them. Both built + unit-verified (Gradle green, detekt clean); their *activations* are
model-/sandbox-gated and stay narrowed in BACKLOG.
| Commit | What | Item |
|--------|------|------|
| `e46777e` | **§B-§5 deterministic `static_check` stage seam + emitter.** `StaticCheckStageExecutor` runs a configured tool (`static_tool`/`static_argv` via stage metadata) through the existing `StaticAnalysisRunner` and emits `StaticFindingsRecordedEvent`; `DefaultSessionOrchestrator.enterStage` dispatches any `metadata["stage_type"]=="static_check"` stage to it instead of the LLM subagent and advances on the unconditional exit edge; `TomlWorkflowLoader` gained `stage_type`/`static_tool`/`static_argv` fields; `role_pipeline.toml` carries a `static_check` stage between implementer and reviewer. **No-op until** a sandboxed, workspace-scoped `CommandRunner` is wired + `static_argv` set (live-QA-gated). Tests: `StaticCheckStageExecutorTest` (4) + `StaticCheckStageTest` integration (1). | B §5 |
| `e46777e` | **§B-§6 / A3 critique-outcome producer.** New `CritiqueFindingsRecordedEvent` (+ `CritiqueVerdict`) is the producing side — a critic's findings + verdict per iteration, with `modelHash`. `CritiqueOutcomeCorrelator` (pure, in the reviewer-loop runtime) decides UPHELD / DISMISSED / INCONCLUSIVE per critic and finding id; a hook in `completeWorkflow`/`failWorkflow` correlates recorded findings into `CritiqueOutcomeCorrelatedEvent`s at loop resolution (no-op + idempotent), feeding the existing `:core:critique` calibration projection. **Dormant until** the reviewer/plan-critic emit `CritiqueFindingsRecordedEvent`s (model-gated). Tests: `CritiqueOutcomeCorrelatorTest` (8) + `CritiqueCalibrationWiringTest` integration (1). | B §6 / C-A3 |
Both follow the same shape as the earlier dormant-activation work: the deterministic seam + the
event wiring land and are unit-proven now; the LLM-/sandbox-side activation is the live-QA-gated
follow-up. `docs/qa/QA-reviewer-static-first.md` updated (no longer "producing stage not built").
---
## 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.