Commit Graph

98 Commits

Author SHA1 Message Date
kami 7d7e524756 feat(workspace): WorkspaceResolver trust pipeline + allowed_workspace_roots
Resolve a client-supplied workspace dir safely: canonicalize via toRealPath,
reject privileged locations, clamp to [tools] allowed_workspace_roots (permissive
when unset, logged), fall back to the boot default on any rejection. PathJail made
non-internal so the server can reuse its symlink-safe containment. (Axis 2 Phase A, task 4.)
2026-06-02 19:57:03 +04:00
kami d1c6774d05 feat(artifacts): config-driven custom artifact kinds with schema validation
Users declare artifact kinds in [[artifacts]] (id + schema_path to a JSON-schema file + llm_emitted); ConfigArtifactKind registers them at startup via createWorkflowLoader(extraKinds). New JsonSchemaValidator validates any non-built-in kind generically against its declared deriveJsonSchema(), so an LLM-emitted custom kind is checked against its shape, never trusted. Removed the dead payloadSerializer from the ArtifactKind contract. Schema source is path-to-file (not inline TOML — the hand-rolled parser can't nest).
2026-06-02 13:58:23 +04:00
kami 97ad456778 feat(tools): collapse-consecutive-duplicates compression rule
adr-0003 §1.3 dedup: collapse runs of identical adjacent lines into `line (×N)`, order-preserving and lossless (count retained). Wired into ShellTool's default spec before HeadTail so the head/tail window holds distinct content. Safe as a default, unlike DropMatching.
2026-06-02 13:57:57 +04:00
kami 94f7ad0ee9 fix: workflow inference chain — surface llama-server errors, user-turn-last, bundle-relative prompts
- LlamaCppInferenceProvider: check HTTP status and surface the real error body instead of masking it as a ChatCompletionResponse deserialization failure
- PromptRenderer: render the live conversation layer (L1) last so the user turn is the final message (fixes Qwen 'No user query found' 500 when L3 recall is present)
- TomlWorkflowLoader: resolve stage prompts relative to the workflow file's own dir (bundle), CWD-independent; config-dir fallback for globals
- SessionOrchestrator: hard-fail a stage whose declared prompt can't resolve (was a silent user-less request)
- move healthcheck prompts next to the example workflow (examples/workflows/prompts/)
2026-06-01 23:23:29 +04:00
kami 55a18b4b3a feat: correx-managed model lifecycle slice 5 — Go TUI model swap + telemetry
Go TUI decodes model.changed / model.list / resource.status and renders a
status-bar VRAM/GPU%/RAM gauge plus a models overlay (m key / palette 'models'):
lists configured models with the resident one marked, enter swaps (SwapModel),
c clears the pin (ClearModelPin). All three new server messages are
non-event-bearing control/gauge frames, applied immediately like
provider.status_changed.

Server addition required for the picker: ServerMessage.ModelList (model.list,
NonEventMessage) sent once in the initial snapshot from
ManagedInferenceRouter.availableModelIds()/currentModelId() — the TUI otherwise
cannot enumerate swap targets.

Completes the 5-slice model-lifecycle feature. ./gradlew check green; go build/vet clean.

Plan: docs/plans/2026-05-31-model-lifecycle-management.md (slice 5 of 5).
2026-06-01 13:36:01 +04:00
kami 7b1df95627 feat: correx-managed model lifecycle slice 4 — resource telemetry
Vendor-agnostic ResourceProbe (commons): NvidiaResourceProbe reads nvidia-smi
(injectable runner) for whole-device VRAM/util and /proc/<pid>/status for the
managed llama-server RSS, both fail-soft to null; UnavailableProbe for non-GPU
hosts / the static path. DefaultModelManager.currentPid() + LlamaProcess.pid
expose the managed pid. ServerMessage.ResourceStatus (resource.status,
NonEventMessage, all-nullable) pushed every 2.5s on the global stream plus one
in the initial snapshot. Live gauge only — never event-sourced (feeds no core
decision), so invariants #8/#9 hold. Main wires the NVIDIA probe on the managed
path when nvidia-smi is present, else UnavailableProbe.

Tests: csv parsing (single/multi/malformed), gpu+rss combine, fallbacks.

Plan: docs/plans/2026-05-31-model-lifecycle-management.md (slice 4 of 5).
2026-06-01 12:36:38 +04:00
kami 7341ab578e feat: correx-managed model lifecycle slice 3 — manual swap + pin
ManagedInferenceRouter owns a live @Volatile pin (decision D1): swap(modelId)
makes a model resident and pins it; clearPin() releases it. Pin is highest
precedence in route() (pin > stage.modelId > capability > default). New
SwapModel/ClearModelPin client messages handled in GlobalStreamHandler via
ServerModule.modelSwapper (null on the static path). ServerMessage.ModelChanged
(model.changed) mapped from ModelLoadedEvent/ModelUnloadedEvent — the swap's load
event surfaces to clients through streamGlobal, so the handler doesn't push it
directly. Tests: pin precedence + swap/clear, Model* -> ModelChanged.

Plan: docs/plans/2026-05-31-model-lifecycle-management.md (slice 3 of 5).
2026-06-01 11:48:24 +04:00
kami 382194b498 feat: correx-managed model lifecycle slice 2 — per-stage model selection
StageConfig.modelId; InferenceRouter gains a backward-compatible model-aware
route() overload (default ignores modelId, so static routers and test fakes are
unaffected). New ManagedInferenceRouter (infra commons) resolves a target model
per stage (stage.modelId > capability match > default) and ensureLoaded()s it
before routing, returning the live managed provider — its id changes with the
resident model, so there is no stale health cache to invalidate on swap.
ModelManager.ensureLoaded default delegates to the idempotent load(). Main wires
the managed router on the [[models]] path; the static path keeps DefaultInferenceRouter.

Plan: docs/plans/2026-05-31-model-lifecycle-management.md (slice 2 of 5).
2026-06-01 11:35:51 +04:00
kami e45a626cc4 feat: correx-managed model lifecycle slice 1 — config + manager factory + boot/shutdown
[[models]] config (ModelConfig/ModelsSettings) parsed by ConfigLoader;
InfrastructureModule.createModelManager + modelConfigToDescriptor; Main.kt
managed boot path spawns the default llama-server when [[models]] is present
(static [[providers]] path preserved when absent) and kills it on shutdown.

Plan: docs/plans/2026-05-31-model-lifecycle-management.md (slice 1 of 5).
2026-06-01 11:03:05 +04:00
kami 5beb866036 feat: rehydrate L3 metadata from event log on startup
TurboVec persists vectors via the sidecar but kept entry metadata
(sessionId/turnId/text) only in an in-memory map, so restarting with
backend=turbovec silently dropped every query hit (the id→metadata
lookup missed). Rebuild that map from the ChatTurnEvent log at startup.

- RehydratableL3MemoryStore: capability interface for stores whose
  vectors persist independently of the JVM. TurboVec implements it;
  InMemory deliberately does not (its vectors are volatile too).
- L3MetadataRehydrator replays ChatTurnEvents into the metadata map.
  No embedder: the query path never reads entry.vector, so vectors
  stay in the sidecar and metadata comes from the event log (the
  source of truth, invariant #1). Short-circuits for non-rehydratable
  backends before scanning the log.
- Wired into Main before the server accepts queries; no sidecar spawn.

Backfill of never-embedded history (needs the embedder) is a separate
follow-up. The in_memory non-durability warning already exists.
2026-05-31 22:08:52 +04:00
kami d03479cea7 feat: tool-declared output compression (Tier A)
Tools can declare how their output is compressed before it enters the
context pack, replacing uniform handling. Open-threads 6.3 / ADR-0003.

- core:tools/compression: ToolOutputCompressor interface,
  IdentityCompressor default, declarative OutputCompressionSpec +
  CompressionRule (StripBlankLines, StripLeadingWhitespace,
  DropMatching, HeadTail), and the pure DeclarativeCompressor engine
  (regexes compiled at construction; bypassOnError passes raw on
  non-zero exit; never throws on input).
- Tool gains `outputCompressor` (default IdentityCompressor). FileReadTool
  strips blanks + leading whitespace; ShellTool strips blanks + head/tail.
- SessionOrchestrator applies the resolved tool's compressor on the
  ToolResult -> ContextEntry path only. Raw output stays authoritative
  in the event log (invariant #6); compression is a pure function of
  (raw, exitCode, spec), so no new event and replay stays deterministic.
- Spec is @Serializable/config-shaped (JSON round-trip tested). No
  custom-tool-from-config path exists today, so first-party tools wire
  in code; TOML-declared compression rides along when that path lands.

Tier B (format-aware parsers: failures-only test output, git-log oneline)
is a documented per-tool extension behind the interface, not built here.
2026-05-31 21:20:16 +04:00
kami ff166ed311 feat: plane-2 rules read declared param roles instead of guessing args
Add ParamRole and a defaulted Tool.paramRoles to the tool contract; built-in
tools declare which params carry effects: file_read/write/edit -> path=PATH,
shell -> argv=EXEC_COMMAND. PathContainmentRule / ExecInterpreterRule /
NetworkHostRule now inspect only the declared params when roles are present, and
fall back to the looksLikePath / leading-token / extractHost heuristic only for
un-enriched (e.g. custom) tools - so a custom FILE_WRITE tool is still
containment-checked. Shared extractParamStrings flattens String and List<*>
(argv) values. SessionOrchestrator.runPlane2Assessment resolves the tool once
and passes tool.paramRoles into the assessment input.

This retires the arg-guessing from the first-party path: a slashy edit 'content'
arg is no longer mis-flagged as a path.
2026-05-31 16:15:22 +04:00
kami 97d03eb7bd chore: remove orphaned MaterializingArtifactWriter, gitignore healthcheck output
DefaultMaterializingArtifactWriter and its MaterializingArtifactWriter interface
were test-only orphans after the sandbox dual-write retirement (95e79bf) - no
production wiring, never instantiated outside their own test. Delete all three.
Add healthcheck_*.txt to .gitignore (one-off generated output).
2026-05-31 16:15:11 +04:00
kami 95e79bffb8 refactor: retire sandbox dual-write; file tools write in-place into workspace 2026-05-31 10:39:58 +04:00
kami 3c90ac4aef feat: FileMutationReverser undo primitive + shared AtomicFileWriter 2026-05-31 10:36:47 +04:00
kami b778c06f6c feat: capture file pre/post-image to CAS and emit FileWrittenEvent 2026-05-31 10:34:30 +04:00
kami 7ad29c3e01 feat: atomic temp+swap file writes (crash-safe) 2026-05-31 10:13:04 +04:00
kami a063c89718 fix: symlink-safe, fail-closed jail for filesystem tools 2026-05-31 08:48:40 +04:00
kami e6239515bd feat: L3 memory retrieval on the router read path (record-only)
When a user sends input, embed it, query L3 across all sessions, dedup
against in-session turns, and record the retrieval as an event so replay
is deterministic (invariant #9). Hits land in RouterState; context
injection follows in a later slice.

- Add L3MemoryRetrievedEvent + L3RetrievedHit (registered in eventModule)
- RouterState.lastRetrievedMemory + reducer case; RouterTurn carries turnId
- RouterConfig.retrievalK (default 5)
- Harden L3 write path: runCatching + visible logging, cancellation
  re-thrown; event append stays ahead of the L3 write
- Warn prominently when the non-durable in_memory L3 backend is selected
2026-05-30 14:36:30 +04:00
kami d68c76ee3c feat: switchable router embedder and L3 backends via config
Adds [router.embedder] and [router.l3] sections to CorrexConfig with
backend selectors. Ships LlamaCppEmbedder that hits llama.cpp's
/embedding endpoint (handles OpenAI-compatible, simple, and array
response shapes; validates dimension). InfrastructureModule gains
createEmbedderFromConfig and createL3MemoryStoreFromConfig that
dispatch on backend value.

Defaults preserve current behavior (noop embedder + in-memory L3).
Switching to "llamacpp" / "turbovec" is a config-only change — no code
edits required. For turbovec backend, the bundled python sidecar
script is extracted from classpath to ~/.cache/correx/ on first use.
2026-05-30 01:23:14 +04:00
kami 9f171d3236 feat: wire L3 write path via Embedder into router
Introduces Embedder contract in core:inference with a NoopEmbedder
default (zero vector) and wires both Embedder and L3MemoryStore into
DefaultRouterFacade. Each ChatTurnEvent emission now embeds the turn
content and writes a corresponding L3MemoryEntry, so cross-session
memory is captured at the source of truth (the event emission point).

InfrastructureModule defaults to NoopEmbedder + InMemoryL3MemoryStore
so the system runs without an external embedding model or vector store
wired. The TurboVec adapter stays unwired for now; switching to it is
a configuration concern (Epic 12 config layer).

Also gitignores apps/tui/logs/ (Kotlin TUI runtime logs, pre-Go rewrite).
2026-05-30 01:01:40 +04:00
kami 6feef150c9 feat: scaffold cross-session router memory (L3) with turbovec sidecar
Defines the L3MemoryStore contract in core:router (entry, query, hit,
in-memory test default) and a new infrastructure:router:turbovec module
that adapts turbovec via a Python sidecar over stdin/stdout JSON-Lines.

Adapter manages the subprocess via ProcessBuilder with lazy start,
mutex-serialized requests, and shutdown via withTimeout. Wire-format
metadata that turbovec doesn't store (sessionId, turnId, text) is kept
in an in-memory map for now — durable persistence ships with the
upcoming ChatTurnEvent.

Not yet wired into RouterFacade, InfrastructureModule, or DI. Embedding
generation source is a separate concern.
2026-05-30 00:40:27 +04:00
kami d276148e2c fix: store actual rendered prompt artifact instead of contextpack.toString()
Extract message-rendering logic from LlamaCppInferenceProvider into a
provider-agnostic PromptRenderer in core:inference. SessionOrchestrator
now serializes the rendered ChatMessage list as JSON for the prompt
artifact, so the audit trail reflects what the LLM actually saw.

Resolves the TODO at SessionOrchestrator.kt:691.
2026-05-30 00:32:38 +04:00
kami 1cad2bbde1 fix: set default capabilities on LlamaCpp provider to unblock router
LlamaCppInferenceProvider was created with empty capabilities, causing
NoEligibleProviderException when the router requested ModelCapability.General.
FirstAvailableRoutingStrategy requires declared capabilities to cover all
requested ones — empty set satisfied nothing.

Add a DEFAULT_LLAMA_CAPABILITIES constant with General, Coding, Reasoning,
Summarization, and ToolCalling scores, and pass it through createLlamaCppProvider()
to ModelDescriptor. Existing callers get sensible defaults automatically.

This is the root cause of the 'router not connected — epic 14' placeholder:
the server-side error (capability mismatch) sent a ProtocolError instead of a
RouterResponseMessage, so the TUI never set routerConnected=true.
2026-05-29 20:59:16 +04:00
kami f7f237e29f fix: complete all P3 audit findings — empty modules, docs drift, detekt, worktree
P3-1: Delete 17 empty Gradle modules (core:agents/observability/policies/stages,
      infrastructure:scheduler/security/telemetry, all 7 plugins/*, all 3
      interfaces/*). Zero source files, zero dependents, identical build.gradle
      stubs. Remove from settings.gradle. Keep .adoc spec docs as roadmap refs.
P3-2: Fix docs drift — rename :core:orchestration to :core:kernel in
      core-orchestration-submodule-spec.md, rewrite stale chat-transcript
      modules-and-spec.md as proper doc.
      (CLAUDE.md Router context isolation clarification is local-only,
       file is gitignored.)
P3-3: Reduce detekt maxIssues from 999999 to 120 (actual current count ~107).
      (CLAUDE.md detekt description updated locally; file is gitignored.)
P3-4: Remove stale locked worktree agent-a98d45277ce4b0040 (contained only
      cosmetic test style changes and an unused kotlinx-datetime dep).
2026-05-29 01:09:22 +04:00
kami 7936251d6b fix: complete all P2 audit findings — dead code, NPE guard, hygiene
P2-1: Guard SessionId NPE with safe-call in SessionsReducer
P2-2: Remove 16 dead event classes + reducer branches; replace with live orchestration events in tests
P2-3: Standardize ChatInput divergences — guard CancelSession, single-arg ProtocolError
P2-4: Remove dead TuiToolRecord.diff and ToolDisplayStatus.REQUESTED
P2-5: Remove dead streamLive from SessionEventBridge
P2-6: Extract SessionsReducerContext data class for 6+ param method
P2-7: Replace StageId("none") sentinel with TypeId.NONE
P2-9: Add TypeId.random() factory on all type-alias IDs
P2-10: Add KDoc on schemaVersion documenting reserved-for-migration
P2-8: Verified RouterReducer string-template already correct (TypeId value class toString)
2026-05-29 01:01:45 +04:00
kami cdee5f2245 fix: harden event store, serialization, and grant engine; wire router chat
Event log integrity (sole source of truth):
- SqliteEventStore: serialize append/appendAll under a Mutex, enable WAL +
  busy_timeout + synchronous=NORMAL, roll back on any Throwable. Replaces the
  app-computed `SELECT MAX(seq)+1` read-modify-write that dropped events under
  concurrent appends (race was invisible to CI: only the in-memory store and
  single-threaded :memory: tests were ever exercised).
- Serialization: encodeDefaults + ignoreUnknownKeys, explicit @SerialName on all
  46 EventPayload subclasses and event-referenced enum constants, @Serializable on
  RiskLevel/RiskAction. Guards the append-only log against silent corruption from
  future class renames, field removals, or default-value changes.

Approval/grant security (Invariant: approvals cannot widen authority):
- Tier authorization is now a ceiling (request.tier.level <= max granted) instead
  of set membership; SESSION grants bind to a specific toolName instead of matching
  everything; handleCreateGrant rejects empty/over-tier/scopeless grants.

Router chat wiring (Phase 0-2): ChatInput round-trip, StartChatSession from IDLE,
router-panel layout, workflows behind Ctrl+W.

Tests: SqliteEventStore concurrency, serialization round-trip + discriminator
stability + unknown-key tolerance, adversarial grant scope/tier; updated existing
approval and reducer tests for the new grant semantics and StartChatSession effect.
2026-05-28 22:39:15 +04:00
kami e05532e7b2 feat: implement CreateGrant handler and grant-aware approval engine
- GlobalStreamHandler.handleCreateGrant validates scope (SESSION/STAGE)
  and sends ProtocolError to client on validation failure instead of
  silent log.warn + drop.
- Derive event stageId directly from GrantScope type, removing
  redundant stageIdForEvent tuple.
- SessionOrchestrator integrates ApprovalEngine to check active grants
  before requesting user approval for T2+ tool calls.
- ContextEntry gains EntryRole (SYSTEM/USER/ASSISTANT/TOOL) field for
  proper chat message role mapping.
- RouterContextBuilder.build is now suspend; uses Tokenizer for
  accurate token estimation with fallback to character-based estimate.
- LlamaCppInferenceProvider maps EntryRole to ChatMessage role instead
  of heuristic layer-based inference.
2026-05-28 14:06:58 +04:00
kami 3b24c7e91a feat: shell execution correctness + artifact_field_equals condition
- Add  field to ProcessResultArtifact ("success"/"failed")
- Materialize ToolResult.Failure as a failed ProcessResult artifact
  in the orchestrator, with artifact lifecycle events emitted
- Non-recoverable ToolResult.Failure now fails the stage ("FATAL:")
  instead of being silently fed back as LLM context
- Fix enterStage to return Continue on non-retryable failures,
  enabling back-edge transitions (fix/retry loops)
- Add ArtifactFieldEquals transition condition with flat and
  nested dot-notation field access + FieldOperator enum
  (eq, neq, gt, gte, lt, lte)
- Wire artifact_field_equals through ConditionFactory and
  TomlWorkflowLoader (condition_field, condition_operator)
- Cache ProcessResult artifact content for evaluation context
- Add 16 tests covering all condition operators and error cases
- DefaultTransitionResolver catches condition evaluation errors
  and returns Blocked instead of crashing
2026-05-26 17:28:51 +04:00
kami 2165d1b899 feat(tui): diff viewer, workflow picker, cursor support, and approval reconnect fix
- Add unified diff viewer for file_write/file_edit tools across all layers:
  ToolReceipt.diff → DiffUtil (LCS-based) → SandboxedToolExecutor → ToolCompleted
  → TuiToolRecord.diff → DiffViewer widget (colored +/- lines)
- Add workflow selection panel: WorkflowList server message, WorkflowListPanel
  widget, ↑↓ seamlessly extends into workflow picker from session list
- Add cursor/caret support: inputCursor in TuiState, CursorLeft/CursorRight
  actions and key events, AppendChar inserts at cursor, Backspace deletes before
- Colorize event history strip (green/red/yellow/blue by type) and input bar
  (blue/yellow prompt, cyan session name, blue keybindings)
- Show 5 recent events instead of 3; increase event strip height to 6
- Remove lastEventAt sort so display and navigation use consistent order
- Fix approval reconnect: register pending approvals with ApprovalCoordinator
  during snapshot replay so lookupSession works after reconnect
- 167 tests pass (126 TUI + 41 server)
2026-05-26 14:44:27 +04:00
kami ac05ad8733 chore(clean up): remove unused imports, unnecessary object impls, concurrency/coroutine issues, trailing commas, etc. 2026-05-24 22:56:19 +04:00
kami 70420083ac feat(server-02): promote EventStore to global-sequence store with subscribeAll
StoredEvent gains sessionSequence: Long (per-session monotonic); existing
sequence field becomes the global monotonic cursor across the entire store.
SqliteEventStore allocates both counters inside the same BEGIN IMMEDIATE
transaction and emits to a global MutableSharedFlow after commit.
InMemoryEventStore mirrors this with an AtomicLong global counter and a
suspend-on-overflow SharedFlow. EventStore interface gains subscribeAll()
and lastGlobalSequence(). Contract tests updated and extended to cover
global-sequence and cross-session subscribeAll invariants.
2026-05-24 22:23:43 +04:00
kami fc7b879891 feature(event-sourcing): baseline for the architecture review fixes.
- fixed the tool overlay in tui.
- fixed tool calling - added schemas.
- getting all sessionIds via event store.
- instead of sending all events on the replay - there's a new way for replaying.
- session snapshot is now a thing getting sent for previously created sessions.
- added logging to important parts.
- revert workflowId from WorkflowCompletedEvent.
2026-05-24 18:57:56 +04:00
kami f827685ed0 chore(damn): detekt, build, tests, formatting
fixed detekt issues where possible.
fixed disttar failing build because tools is added twice in the server module.
added workflowId where required.
fixed some tests not being recognized because of runBlocking without explicit return type.
formatting + imports.
2026-05-22 00:10:05 +04:00
kami 2c459da009 feat(router): implement Epic 14 — core:router module
Implements the full conversational router facade: RouterState, RouterReducer,
RouterProjector, RouterRepository, RouterContextBuilder, RouterFacade, protocol
types, WebSocket wiring, infrastructure factory, and deterministic test suite.

Also fixes spec divergences found in post-implementation review:
- Add SteeringNote domain object to core:context (epic prerequisite)
- Rename RouterFacade.handleChat → onUserInput per spec interface contract
- Add in-memory ConcurrentHashMap conversation history to DefaultRouterFacade
- Make RouterRepository.getRouterState suspend
- Rename RouterConfig.keepLast → conversationKeepLast, fix defaults (6, 4096)
- Refactor InfrastructureModule.createRouterFacade to self-assemble internally
- Fix FileReadTool: allowedPaths was dead constructor param (@SuppressUnusedParameter);
  now stored as private val and enforced in validateRequest
- Disable koverVerify on modules tested via testing/ submodules or with
  hardware/integration dependencies (24 modules); build gate now passes clean
2026-05-21 15:06:20 +04:00
kami 3365208d3a chore(cleanup): remove dead Module stubs and unused imports; restore deferred files
Deletes 21 Module.kt scaffolding objects that were never wired into any DI
registry. Removes unused imports across 8 production and 3 test files.

Restores StageExecutor, CyclePolicyResolver, PolicyValidation, and
ReplayContractTest — these are deferred features, not dead code.
2026-05-19 13:43:21 +04:00
kami 71a73a4fa2 chore(audit): tool path resolution, config file, dead code removal, static analysis cleanup
Tool fixes:
- FileWriteTool, FileEditTool: resolve relative paths against workingDir instead of JVM cwd
- FileReadTool: remove allowedPaths restriction — reads are unrestricted
- ShellTool: add workingDir for ProcessBuilder, remove environment().clear(), fail-open when allowedExecutables empty

Config:
- Add [tools] section to config.toml: sandbox_root, working_dir, shell_allowed_executables, default_system_prompt_path
- Three-level resolution: env var > config file > hardcoded default
- OrchestrationConfig sandboxRoot and defaultSystemPromptPath now sourced from CorrexConfig
- Single defaultOrchestrationConfig in ServerModule, shared by SessionRoutes and GlobalStreamHandler

Dead code:
- Delete EventTypes.kt — orphaned string constants duplicating serialization annotations

Static analysis:
- Remove 10 unused imports across 9 files
- Remove redundant return in ReplayOrchestrator
- Remove redundant suspend from ApprovalCoordinator.handleResponse
- Fix unreachable InputMode.None branch in InputBar
- Enable full detekt rule sets in detekt.yml
2026-05-19 12:48:47 +04:00
kami c0efa0ef03 fix(kernel+infra): tool approval gate and executor cleanup
- SessionOrchestrator: wire T2/T3/T4 approval gate before tool execution;
  emit OrchestrationPausedEvent/ApprovalRequestedEvent, await decision,
  return rejection as ERROR context entry so LLM sees the denial;
  propagate tool ERROR entries as StageExecutionResult.Failure
- SandboxedToolExecutor: remove dead code and simplify
- InfrastructureModule: minor wiring cleanup
- LlamaCppInferenceProvider / build.gradle: related build fixes
2026-05-19 00:05:08 +04:00
kami 15d1e09c44 feat(tools): add description and parametersSchema to Tool interface; wire FileWriteTool materialization 2026-05-18 21:39:36 +04:00
kami 24df3b55b3 feat(infra:llama_cpp): GBNF grammar converter, tool_calls in ChatMessage, tool definitions in request, L2 context handling 2026-05-18 21:39:27 +04:00
kami 5fad29850f feat(infra:artifacts-cas): DefaultMaterializingArtifactWriter — sandbox validation, file write, Blake3 hash 2026-05-18 21:39:18 +04:00
kami a5dc983a57 feat(workflow): typed produces slots — StageConfig uses TypedArtifactSlot, TOML accepts {name, kind} objects 2026-05-18 21:39:08 +04:00
kami 219e2c762e feat(cas): content-addressed artifact store (steps 1–8)
New core:artifacts-store interface + infrastructure/artifacts-cas
implementation: segment files + SQLite index, Blake3 hashing,
group-commit fsync via flushBefore, recovery tail-scan, manual
compactor, and oldest-first disk-cap evictor.

Inference events now carry promptArtifactId / responseArtifactId;
orchestrators put bytes before emitting. SqliteEventStore wraps
its txn in artifactStore.flushBefore so segment data is fsynced
before the event commit, making the crash window non-corrupting
(TailScanner re-indexes orphan tail records on reopen).

Compactor and evictor are mutually exclusive via maintenanceMutex.
Step 9 (cloud sync) deferred to a later epic.

See docs/reviews/2026-05-18-cas-steps-1-8-review.md for the final
review.
2026-05-18 12:22:38 +04:00
kami 7d46f46f01 fix(server): event capturing and necessary logic for smoke test. 2026-05-17 03:21:42 +04:00
kami f77efce10b debt(pre-router): resolved most of the technical debt that was noted while finishing epic-12 and epic-13. 2026-05-17 03:21:26 +04:00
kami 2207a37549 epic-13: add cli and tui entry point, finish epic. 2026-05-17 03:20:43 +04:00
kami ce723afc8b refactor(imports): optimize imports 2026-05-17 03:19:57 +04:00
kami c77277af0b epic-12: after epic audit and init commit 2026-05-17 03:19:39 +04:00