Commit Graph

340 Commits

Author SHA1 Message Date
kami dbc677a5f1 docs(backlog): record llama-probe registration (64a90e7) + event-store probe in RETRO
A§4 LLAMA_SERVER probe is now registered (gated on a llamacpp provider URL); EVENT_STORE
latency probe was already wired (266bbf0). Both move to RETRO. Remaining A§4: tokens/sec
throughput feed (health endpoint is reachability-only) + live health TUI pane.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 08:26:19 +00:00
kami 64a90e74a9 feat(health): register LlamaServerHealthProbe (A§4)
Wire the built-but-unregistered LlamaServerHealthProbe (266bbf0) into the health monitor:
when a `llamacpp` provider URL is configured, add an HttpLlamaLivenessClient-backed probe
(dedicated CIO client, 3s per-ping timeout, shutdown-hook close) to the probe list. Gated
on a configured provider URL so a model-less box never reports a spurious LLAMA_SERVER
DEGRADED. Replaces the Main.kt TODO(wiring). main() is not unit-tested; the probe + client
are already covered by 266bbf0 — compile + :apps:server:test + detekt green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 08:25:25 +00:00
kami 3302930b00 docs(backlog): record B§4 activation (4e08510) in RETRO
Architect contradiction-check is now live (server subscribes to the architect design
artifact and emits the display-only flag). All cleanly unit-verifiable deterministic
backlog tracks are now landed; what remains is model-dependent activations (live-QA
gated) and deep session-lifecycle work (§H) better done with live testing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 08:08:14 +00:00
kami 4e08510045 feat(server): activate architect contradiction-check hook (B§4)
Wire the display-only ArchitectContradictionChecker (eae0a0c) live: ServerModule.start()
subscribes to the architect stage's `design` ArtifactCreatedEvent, resolves the decision
text (prefers the design schema's `approach` field; falls back to the capped artifact
text), runs checker.check(...), and appends the non-null PossibleContradictionFlaggedEvent.
Live-only and never halts a stage (runCatching). Checker built in Main.kt gated on
project.enabled (same L3 "project:" namespace ProjectMemoryService.persist populates) and
threaded into ServerModule as a nullable param. Replaces the standing TODO(wiring) in Main.kt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 08:07:33 +00:00
kami 1a707f0b7f docs(backlog): record idea-promotion (f107ff5); mark plan-comparison blocked
f107ff5 (idea-board -> profile promotion) moves to RETRO. Plan-comparison view marked
BLOCKED: no plan-candidate event exists server-side (only workflow.proposed), so there
is no wire shape to render or unit-verify until a multi-candidate planner lands.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 07:32:49 +00:00
kami f107ff554c feat(router): idea-board -> project-profile promotion (E)
Promote an auto-captured idea from the cross-session board into the curated per-repo
profile at <workspaceRoot>/.correx/project.toml as a `conventions` entry. New
IdeaPromotedEvent tombstones the idea off the board (IdeaReader treats it like a
discard) and records the promotion as a fact; the server PromoteIdea handler loads
the profile, appends the idea text (deduped via ProjectProfile.withConvention), and
writes it back. Adds ProjectProfileWriter (escape-aware TOML serialize/write) and
makes SimpleToml's reader unescape \\ and \" symmetrically with the writers
(fixes a pre-existing read/write asymmetry surfaced by the round-trip test).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 07:30:43 +00:00
kami eeb6830387 docs(backlog): record egress activation + batch-approval (D) in RETRO
ab7e4be (egress activation) and 4b0024f (batch source-list approval) move to RETRO;
§D is now fully landed except the standalone web-approval client (needs network/SearXNG).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 07:15:15 +00:00
kami 4b0024f7d9 feat(research): batch source-list fetch-approval (D)
POST /sessions/{id}/approve-sources extracts distinct hosts from a source list
(SourceListHosts.extract) and emits one EgressHostsGrantedEvent for the session, so
the live per-session egress allowlist auto-clears subsequent web_fetches to those
hosts — approve the list once instead of per-URL.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 07:07:23 +00:00
kami ab7e4be848 feat(toolintent): activate per-session egress allowlist (D)
ToolCallAssessmentInput gains sessionEgressHosts; SessionOrchestrator resolves it at
the assessment build site by folding EgressHostsGrantedEvents through
EgressAllowlistProjection. NetworkHostRule now enforces session-granted hosts (union
with static), replacing the emptySet() TODO — the allowlist built in 027ff1f is live.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 21:43:25 +00:00
kami ef20557c9c docs(backlog): record B2 plan-derived manifest in RETRO
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 21:18:51 +00:00
kami 641051b9ef feat(workflow): plan-derived diff manifest (B§2)
PlanStage gains a `writes` field (planner-declared workspace-relative paths/globs);
PlanDerivedManifest.deriveAllowedWrites + combine union it with the static baseline.
ExecutionPlanCompiler wires the union into StageConfig.writeManifest, enforced by the
existing ManifestContainmentRule via the same glob matcher (no parallel matcher).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 21:16:34 +00:00
kami c52dbde4b4 docs(backlog): record E approval ergonomics in RETRO
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 16:41:26 +00:00
kami d5afcd345a feat(tui-go): approval ergonomics — queue + tier-gated confirm (E §3)
- pending approvals are a navigable queue (PendingQueue/PendingIdx; ↑↓/jk, count
  shown), no modal stacking; resolve removes the specific gate by request id
- y/n/e keys (approve/reject/steer); T0–T2 act on one key, T3+ requires arm+confirm
  ("press y again"), any other key disarms; reject/steer/auto never gated
- snapshot restore now rehydrates the full pending list, not just the first

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 16:40:49 +00:00
kami 35596dc723 docs(backlog): record E session-list + render-matrix in RETRO
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 16:31:08 +00:00
kami 2a99e15383 test(tui-go): per-event render-matrix golden tests (E §2)
Table-driven render assertions (37 cases over 42 protocol Type* constants), driven
through applyServer and asserted ANSI-stripped on stable defining text. Coverage
guard parses every Type* from protocol.go and fails if a kind is neither covered
nor explicitly classified non-rendering. Pins width/theme/timestamp; no behavior change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 16:30:25 +00:00
kami 1f7a5d96a7 feat(tui-go): session list / resume view (E)
R opens a navigable overlay of recent sessions (GET /sessions: short id, status,
workflow/stage, relative age); enter resumes via POST /sessions/{id}/resume, which
replays onto the existing global /stream (no WS re-dial). Fetch/resume errors surface
in the overlay, never panic. stdlib-only (ws.Client.HTTPBase derives the base URL).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 16:22:27 +00:00
kami 46a71ee84c docs(backlog): record B5, G, E (markdown + go.mod fix) in RETRO
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 16:16:00 +00:00
kami da72ee5b80 feat(tui-go): render markdown in chat turns (E)
renderMarkdown wraps charmbracelet/glamour (dark style, per-width memoized) and is
hooked into the router chat-turn render path; falls back to plain content on any
glamour error so the TUI never crashes or loses text. Other roles/UI untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 16:12:16 +00:00
kami 1e6699a360 fix(tui-go): go.mod directive 1.26 -> 1.24.2 (1.26 toolchain unreleased)
`go 1.26` is not a fetchable/released toolchain, so released Go cannot build the
module ("toolchain not available"). 1.24.2 is the minimum the deps require
(charmbracelet/x/ansi needs >= 1.24.2) and is a real toolchain; the directive is a
floor, so newer Go still works. Bump if a specific newer release is intended.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 16:07:36 +00:00
kami eff8f8dbdf fix(narration): drop stale pause narrations once approval resolves (G)
Pause narrations are tagged with a pauseKey; a per-session pending-pause set gates
the lane worker so a resolved/resumed pause is skipped instead of blending with the
current status. ApprovalDecisionResolved drops the specific request's pause;
OrchestrationResumed clears all session pauses. Replay-safe (no recorded events change).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 16:02:09 +00:00
kami 447fc7a43e feat(kernel): reviewer static-first infra (B§5)
- StaticFinding/StaticFindingSeverity + StaticFindingsRecordedEvent (registered + test)
- StaticAnalysisRunner over an injectable CommandRunner; parses compiler/ktlint/detekt
  finding formats (lenient) into StaticFindings
- excludeStaticFindingsFromReview pure filter, live-wired into SessionOrchestrator
  context assembly so static-tool findings are kept out of the reviewer's context
- static_check pipeline stage left as a documented TODO (needs an event-emitting
  deterministic stage-type seam that doesn't exist yet)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 15:36:06 +00:00
kami eb9b1aee65 docs(backlog): record egress allowlist (027ff1f) in RETRO
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:15:44 +00:00
kami 027ff1f6ff feat(toolintent): dynamic per-session egress allowlist (D)
- EgressHostsGrantedEvent (registered + serialization test): additive per-session
  egress grants (e.g. an approved research source list)
- EgressAllowlist pure union helper + EgressAllowlistProjection (folds grants per
  session); NetworkHostRule delegates to the union, preserving exact/suffix semantics
- rule not yet fed the session set live (ToolCallAssessmentInput has no sessionId);
  precise TODO(wiring) left. batch fetch-approval skipped (needs approval-flow surgery)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:14:48 +00:00
kami 18bde7ca38 docs(backlog): archive 9 resolved tracks to RETRO.md + refile follow-ups
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 11:53:07 +00:00
kami b098d87075 feat(research): dedicated SourceFetched + LowQualityExtraction events (D)
- promote research fetch quality + content_sha256 from ToolExecutionCompletedEvent
  metadata to first-class SourceFetchedEvent / LowQualityExtractionEvent (registered
  + serialization test); existing metadata write kept intact (additive)
- emitted from SandboxedToolExecutor on research-fetch tool completion, guarded on
  the url/content_sha256/quality markers; reuses the extractor's LOW_QUALITY marker

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 11:49:26 +00:00
kami eae0a0ccf6 feat(memory): architect contradiction-check (B§4, display-only)
- PossibleContradictionFlaggedEvent + RelatedDecision (registered + serialization test)
- ArchitectContradictionChecker: L3 similarity retrieval over prior decisions,
  threshold-gated, fake-testable; non-blocking (surfaces candidates only)
- live wiring left as documented TODO (needs an architect-decision emit hook +
  in-session decision embedding into L3)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 11:31:39 +00:00
kami 1a1b5cc5ed feat(kernel): stage-level plan checkpointing (C-A2)
- StageCheckpointPassed/FailedEvent (registered + serialization test): per-stage
  reconciliation of produced artifacts vs the locked plan's produces-slots
- StageCheckpointReconciler (pure) + tests
- emitStageCheckpoint wired in after verifyProduces, runs regardless of its
  pass/fail (verifyProduces still owns the halt); gated on an ExecutionPlanLocked
  in the session log so non-plan workflows are unaffected

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 10:53:41 +00:00
kami 1df7af5b85 feat(kernel): brief echo-back gate (C-A1)
- BriefEcho model + BriefEchoMismatchEvent (registered + serialization test)
- BriefEchoExtractor: parses the planner's brief_echo block and the original
  brief's referenced-files/symbols/acceptance-criteria dimensions
- BriefEchoComparator: conservative diff — a dropped acceptance criterion or an
  invented file path halts; dropping a file/symbol alone does not
- checkBriefEcho gate chained into the post-stage flow after groundBriefReferences;
  opt-in via stageConfig.metadata["briefEcho"], fails the stage (retryable) on
  divergence with re-grounding feedback
- prompt/workflow activation (planner.md emitting brief_echo; role_pipeline
  metadata) left as live-QA follow-up

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 10:42:49 +00:00
kami 0e251d6083 feat(validation): structural .tscn/.tres scene validator
Standalone SceneValidator(content) -> ValidationReport: header well-formedness,
ExtResource/SubResource id resolution, node parent-path integrity. Not wired into
any pipeline (validation layer only; scene editing is a later epic). (BACKLOG I)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 10:05:44 +00:00
kami f715ffa540 feat(repomap): index C#/Godot-Mono (.cs) type symbols
Conservative type-declaration pattern (class/interface/struct/enum/record);
no method capture to avoid false positives. (BACKLOG I)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 09:32:02 +00:00
kami 266bbf0269 feat(health): EventStore latency + llama-server liveness probes
- EventStoreLatencyProbe: times a side-effect-free lastGlobalSequence read,
  wired into HealthMonitor; HealthConfig.eventStoreWarnLatencyMs (BACKLOG A §4)
- LlamaServerHealthProbe: liveness + tokens/sec degradation trend, injectable
  client (HttpLlamaLivenessClient over Ktor); deterministic unit tests
- llama probe left unregistered (TODO) — HttpClient not in monitor scope yet

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 08:39:26 +00:00
kami 784accb08d fix(memory): trailing-delimiter turnId namespace + newline fingerprint
- repomap: tag prefix match requires trailing ':' so /repo can't match /repo2
  (L3RepoKnowledgeRetriever filter + ProjectMemoryService write; the existing
  existsByTurnIdPrefix check already included the delimiter)
- WorkspaceStateProbe fingerprint joins entries with newline to match docstring
- regression test for /repo vs /repo2 non-collision

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 08:08:49 +00:00
kami f783eed4be feat(critique): structured CritiqueFinding + per-model calibration projection
- CritiqueFinding/CritiqueSeverity/CritiqueRole shared type (BACKLOG B6)
- CritiqueOutcomeCorrelatedEvent + serialization registration (BACKLOG C-A3)
- core/critique module: CriticCalibration state/reducer/projector, keyed by (modelHash, role)
- schema+projection only; live reviewer-loop producer wiring deferred

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 07:45:23 +00:00
kami b1c0f88dee docs(backlog): add BACKLOG + QA plan template
Synthesize the five 2026-06-13 design specs and session memory into a
single outstanding-work list. Header rules: resolved items move to
RETRO.md; every finished feature gets a live-QA plan before it counts as
resolved. Add docs/qa/TEMPLATE.md as the observable-evidence QA form.
2026-06-14 14:51:22 +04:00
kami 02e963d6cc feat(tui-go): idea board viewer
OverlayIdeas (opened with I, global/cross-session) lists the idea board in the
artifact-viewer shell: ↑↓ to move, x/d to remove (sends DiscardIdea, optimistic
drop), esc to close. Pull-based via ListIdeas -> idea.list.
2026-06-14 14:36:13 +04:00
kami 04e931c860 feat(server): idea board list + discard
ListIdeas -> idea.list (StreamQueries folds the board from the log, replay-neutral)
and DiscardIdea -> append IdeaDiscardedEvent landed in the capturing session, then
reply with the refreshed board. IdeaDto on the wire.
2026-06-14 14:33:11 +04:00
kami 400ae5729a feat(router): rubber-duck idea capture + feed
The rubber-duck path emits a fenced {"ideas":[…]} block; Ideas.parse strips it
from the chat turn and onUserInput records an IdeaCapturedEvent each (CHAT only).
IdeaReader folds eventStore.allEvents() into the active cross-session board, and
DefaultRouterContextBuilder injects a capped "## Ideas" entry — router-only, so
workflow stages never see it. Extended SYSTEM_PROMPT option (d) to capture ideas.
2026-06-14 14:25:49 +04:00
kami 3ac0a140ec feat(events): idea capture/discard events
IdeaCapturedEvent(ideaId, sessionId, text, timestampMs) + IdeaDiscardedEvent
(ideaId, sessionId) tombstone, registered in eventModule. The cross-session idea
board is rebuilt from these via eventStore.allEvents(); discard hides without
deleting (invariant #1).
2026-06-14 14:21:40 +04:00
kami b563d9841d feat(tui-go): workflow-propose choice panel
Render a workflow.proposed frame as a single-select picker with a manual-answer
slot: ↑↓/jk to choose, enter to launch, e for custom, esc to peek away. Picking
a candidate sends StartSession (and focuses the launched session); the custom
slot continues the conversation via ChatInput. Reuses the modal helpers from the
clarification view.
2026-06-14 13:29:34 +04:00
kami b62b6e09a1 feat(server): workflow.proposed WS frame
Map WorkflowProposedEvent to a workflow.proposed ServerMessage carrying the
candidates + original request. No new ClientMessage: a pick reuses StartSession
(launch the chosen workflow seeded with the request) and the manual-answer slot
reuses ChatInput.
2026-06-14 13:29:01 +04:00
kami fc373e11eb feat(router): emit structured workflow proposals from triage
The triage system prompt now appends a fenced json propose_workflows block;
WorkflowProposals.parse strips it from the visible chat turn and onUserInput
records a WorkflowProposedEvent (CHAT only). Candidate ids are validated against
the registered workflows (invariant #7) so an invented id never reaches the
operator. Bumped a token-budget test for the larger prompt.
2026-06-14 13:28:51 +04:00
kami 8d4bc0b2dd feat(events): workflow-proposal event model
ProposedWorkflow + WorkflowProposedEvent(sessionId, proposalId, prompt,
candidates, originalRequest), registered in the polymorphic eventModule.
Records the router's triage suggestion of candidate workflows as a
non-authoritative fact the operator acts on.
2026-06-14 13:28:41 +04:00
kami 8ea8d7530d feat(prompts): analyst emits structured clarification questions
Replace the inline "Q:"-prefixed-summary convention with a structured
`questions` array of {prompt, options?, multiSelect?, header?} objects that
rides in the analysis artifact (allowed by additionalProperties:true, skipped
by JsonSchemaValidator). The kernel parses it to drive the producer-exit
clarification loop; the TUI renders it as an interactive form.
2026-06-14 13:04:06 +04:00
kami 218a98034e feat(tui-go): interactive clarification question view
Render stage clarification questions as an AskUserQuestion-style form:
header chip, prompt, selectable option chips, and a free-text custom slot.
Arrow/hjkl nav, space to select, e for custom, enter to submit. Submit
guards on all-answered and sends ClarificationResponse; the parked stage
re-runs with the answers in context.
2026-06-14 13:00:59 +04:00
kami 6242b590e4 feat(server): clarification WS protocol + wiring
Surfaces the clarification loop over the wire: ServerMessage.ClarificationRequired
(clarification.required, carrying the structured questions) is mapped from
ClarificationRequestedEvent; ClientMessage.ClarificationResponse carries the
operator's answers and is routed to orchestrator.submitClarification on both
the global and session streams. Reuses the core ClarificationQuestion/Answer
types as the wire shape. Round-trip tests for both directions.
2026-06-14 03:35:59 +04:00
kami 939331d895 feat(kernel): producer-exit clarification loop
When a stage produces an LLM artifact carrying a non-empty questions
array, the orchestrator parks the run, records ClarificationRequested,
awaits the operator's answers (submitClarification seam), records
ClarificationAnswered, injects the answered Q&A as an L2 USER entry, and
re-runs the same stage so the questions are resolved by the role that
asked them. Runs on a dedicated pendingClarifications map and the
enterStage success-branch loop, so a clarification round never consumes
the failure-retry budget; capped at three rounds. Integration test covers
the happy path and the cap.
2026-06-14 03:31:30 +04:00
kami df0144582a feat(events): clarification questions model + events
Adds the vocabulary for a stage raising open questions to the operator:
ClarificationQuestion/ClarificationAnswer value types, the
ClarificationRequested/ClarificationAnswered events (registered in the
event module), a ClarificationRequestId, and ClarificationQuestions.parse
— a lenient, fence-tolerant reader that pulls an optional questions array
out of an LLM artifact (shared by orchestrator and server).
2026-06-14 03:31:30 +04:00
kami a38ac1b3c9 feat(tools): file_read lists directory entries
When given a directory path, file_read now returns its entries (sorted,
sub-directories suffixed '/') instead of failing. The tool description
and path-param schema advertise this so the model discovers it rather
than giving up after a missing-file probe. Generalises file_read into a
'read this path' primitive; the existing PathJail/Plane-2 containment
already covers directories.
2026-06-14 03:13:22 +04:00
kami 1de3e94990 fix(research): flatten source_dossier schema to correx's flat JsonSchema
The schema declared sources as an array of objects, which correx's flat
JsonSchema model can't represent (JsonSchemaProperty has no nested
properties). The strict config loader rejected it at startup, silently
disabling the source_dossier artifact kind. Flatten sources to an array
of strings (URL-prefixed per-source notes), update the gather prompt to
match, and add ResearchSchemaLoadTest to guard every shipped research
schema against the strict loader.
2026-06-14 03:13:22 +04:00
kami 378ee39b19 feat(research): enable research tools by default
[tools.research].enabled now defaults true, matching shell/file tools. Safe because
web_fetch is T2 — nothing leaves the machine without operator approval regardless of
the flag; the flag only controls whether the tools are registered. web_search (T1) hits
only the configured SearXNG endpoint.
2026-06-13 23:26:25 +04:00