Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
72 changes: 72 additions & 0 deletions .codex/plans/2026-04-28-session-repair-v1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Session Repair V1: Interrupted Transcript Terminalization

## Summary

Implement a focused session repair feature that fixes the root cause: daemon crashes can leave a persisted session transcript with an incomplete final turn, causing AI SDK replay parts and tool calls to remain permanently "streaming" even after the session is stopped.

The v1 repair is append-only. It provides automatic boot repair for crashed/error sessions and explicit agent-manageable repair via HTTP, UDS, and CLI with dry-run support.

## Key Changes

- Add `session.RepairSession(ctx, opts)` in `internal/session`.
- Add stable repair types:
- `RepairOpts{SessionID, DryRun, Force}`
- `RepairResult{SessionID, Issues, Actions, Persisted}`
- `RepairIssue{Code, Severity, TurnID, Detail}`
- `RepairAction{Code, TurnID, EventID, Persisted}`
- Repair behavior:
- Append a canonical `error` event when the final persisted turn lacks `done` or `error` and the session is stopped with `agent_crashed` or `error`.
- Append interrupted synthetic `tool_result` events before the terminal `error` when the interrupted turn has dangling `tool_call` events.
- Report invalid JSON, corrupt metadata, event DB failures, sequence anomalies, and lineage concerns without destructive mutation.
- Treat sequence gaps as diagnostics only; do not truncate or resequence.
- Boot integration:
- Run automatic repair during boot for stopped sessions with `agent_crashed` or `error`.
- Log structured summary counts.
- Public surfaces:
- `POST /api/sessions/:id/repair?dry_run=true&force=false` for HTTP and UDS.
- `agh session repair <id> --dry-run --force -o json`.
- Add OpenAPI/contract `SessionRepairResponse`.

## Test Plan

- Unit tests in `internal/session` for terminal event repair, dangling tool repair, dry-run, consistency no-op, force behavior, invalid JSON, corrupt metadata, and sequence diagnostics.
- Transcript/store tests proving repaired UI messages are no longer stuck in streaming states and appended repair events preserve monotonic sequence ordering.
- HTTP/UDS/CLI tests for repair endpoint/command and error mapping.
- Boot/integration tests proving automatic repair is idempotent after daemon restart.
- Verification: focused Go tests, `make codegen`, `make codegen-check`, web type/test gates if generated types change, and full `make verify`.

## Web/Docs Impact

- `web/`:
- `web/src/generated/agh-openapi.d.ts` — regenerated `repairSession` operation and payload types from OpenAPI.
- `web/src/systems/session/types.ts` — session repair response/query aliases derived from generated contract types.
- `web/src/systems/session/adapters/session-api.ts` — `repairSession` client for `POST /api/sessions/{id}/repair`.
- `web/src/systems/session/hooks/use-session-actions.ts` — `useRepairSession` mutation invalidating session detail, history, transcript, events, and lists.
- `web/src/systems/session/mocks/fixtures.ts` and `web/src/systems/session/mocks/handlers.ts` — MSW fixture/handler for session repair.
- No route/component UI change — checked `web/src/routes/_app/**` and `web/src/systems/session/components/**`; v1 is intentionally agent/operator-manageable via CLI/HTTP/UDS, not a visible web control.
- `packages/site`:
- `packages/site/content/runtime/cli-reference/session/repair.mdx` — generated CLI reference for `agh session repair`.
- `packages/site/content/runtime/cli-reference/session/index.mdx` and `packages/site/content/runtime/cli-reference/session/meta.json` — generated CLI navigation updates.
- `packages/site/content/runtime/core/sessions/lifecycle.mdx` — conceptual crash/transcript repair behavior.
- `packages/site/content/runtime/core/sessions/resume.mdx` — resume flow mentions append-only transcript repair before replay.
- `packages/site/content/runtime/core/operations/troubleshooting.mdx` — operator runbook includes dry-run/manual repair.
- `packages/site/content/runtime/api-reference/index.mdx` — no direct file edit; OpenAPI-backed API reference receives `repairSession` via `openapi/agh.json`.

## Extensibility / Agent Manageability / Config Lifecycle

- `Extensibility`:
- none — checked extension manifests, hooks, skills/capabilities, tools/resources, bundles, registries, bridge SDKs, MCP sidecars, and protocol docs; repair is a session persistence operation and does not add an extension point or protocol surface.
- `Agent manageability`:
- CLI: `agh session repair <id> --dry-run --force -o json`.
- HTTP: `POST /api/sessions/{id}/repair?dry_run=true&force=false`.
- UDS: same route and payload as HTTP.
- Structured output: `SessionRepairResponse` with `issues`, `actions`, `persisted`, `tool_call_id`, and `tool_name`.
- Error contracts: 400 for invalid repair options, 404 for unknown sessions, non-persisting diagnostics for invalid transcript/event conditions.
- `Config lifecycle`:
- none — checked `config.toml` keys/defaults, structs, merge/overlay behavior, validation, examples, docs, and tests; v1 adds no configuration.

## Assumptions

- Default repair mode is Boot + manual.
- No schema migration is required for v1.
- No truncation, resequencing, row deletion, UI-only state coercion, lint suppression, ignored errors, sleeps, or retry loops are acceptable.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
---
provider: coderabbit
pr: "58"
pr: "84"
round: 1
created_at: 2026-04-24T00:56:58.862771Z
created_at: 2026-04-28T17:21:46.348991Z
---

## Summary
Expand Down
54 changes: 54 additions & 0 deletions .compozy/tasks/badges-design/reviews-001/issue_001.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
status: resolved
file: packages/ui/src/components/pill-group.tsx
line: 19
author: coderabbitai[bot]
provider_ref: thread:PRRT_kwDOR5y4QM5-Mtcr,comment:PRRC_kwDOR5y4QM68GEz-
---

# Issue 001: _⚠️ Potential issue_ | _🟠 Major_
## Review Comment

_⚠️ Potential issue_ | _🟠 Major_

**Replace hard-coded pixel classes with DESIGN.md tokens.**

Line 9, Line 17, Line 18, Line 62, Line 89, and nearby classes introduce raw px values (`[5px]`, `[10px]`, `[20px]`, `[22px]`, `[2px]`, `[3px]`, `[14px]`, `[7px]`, `[9px]`). In `packages/ui/src`, these should come from design tokens only to keep the system consistent.


As per coding guidelines, "`**/{web,packages/ui,packages/site}/src/**/*.{ts,tsx,css}`: Pull design tokens from `DESIGN.md` ... never invent values in UI code."


Also applies to: 62-63, 89-90

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against the current code and only fix it if needed.

In `@packages/ui/src/components/pill-group.tsx` around lines 9 - 19, The PillGroup
component contains hard-coded pixel classes (e.g., rounded-[5px], text-[10px],
h-[20px], h-[22px], px-2 (if representing 8px/10px), and other
[14px],[7px],[9px] usages) which must be replaced with the design token
equivalents from DESIGN.md; update the class strings inside
packages/ui/src/components/pill-group.tsx (the variant block for active and
size, base class string, and any other nearby class values referenced in this
file) to use the canonical DESIGN.md tokens (CSS custom properties or token
utility classes used across the repo) instead of raw px values, mapping each
specific token (rounded, font-size, height, padding, gap) to the appropriate
DESIGN.md name so no new numeric values are invented and all sizes reference the
shared tokens.
```

</details>

<!-- fingerprinting:phantom:poseidon:hawk -->

<!-- This is an auto-generated comment by CodeRabbit -->

## Triage

- Decision: `valid`
- Root cause: `PillGroup` still encodes badge/segment dimensions with raw arbitrary pixel classes (`rounded-[5px]`, `h-[22px]`, `p-[3px]`, `text-[9px]`, etc.) instead of design-system tokens or token-derived utilities.
- Fix approach: replace raw px classes with existing design tokens where available (`--radius-chip`, `--radius`, `text-badge`, spacing scale) and add minimal shared component sizing custom properties in `packages/ui/src/tokens.css` where DESIGN.md defines values that do not already have a token.
22 changes: 22 additions & 0 deletions .compozy/tasks/badges-design/reviews-001/issue_002.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
status: resolved
file: packages/ui/src/components/pill.test.tsx
line: 12
severity: nitpick
author: coderabbitai[bot]
provider_ref: review:4190677522,nitpick_hash:955795c2492d
review_hash: 955795c2492d
source_review_id: "4190677522"
source_review_submitted_at: "2026-04-28T16:30:00Z"
---

# Issue 002: Extract inline object-shape types to named interfaces.
## Review Comment

Lines 12–15 define `WithMotion` props as an inline object shape `{ reducedMotion: "always" | "never"; children: ReactNode; }`, and line 31 defines `it.each<{ tone: PillTone; bg: string; text: string }>` as an inline generic argument. Per coding guidelines (`**/*.{ts,tsx}: Prefer interface for defining object shapes in TypeScript`), extract both to named `interface` declarations above their respective scopes.

## Triage

- Decision: `valid`
- Root cause: `WithMotion` props and the `it.each` row object are inline object shapes, which weakens readability and violates the repository preference for named interfaces for object shapes.
- Fix approach: introduce named interfaces for the motion wrapper props and tone expectation table rows, then reuse them in the test.
22 changes: 22 additions & 0 deletions .compozy/tasks/badges-design/reviews-001/issue_003.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
status: resolved
file: packages/ui/src/components/stories/pill-group.stories.tsx
line: 13
severity: nitpick
author: coderabbitai[bot]
provider_ref: review:4190677522,nitpick_hash:ddb6a4664b0d
review_hash: ddb6a4664b0d
source_review_id: "4190677522"
source_review_submitted_at: "2026-04-28T16:30:00Z"
---

# Issue 003: Minor: Clarify component description.
## Review Comment

The description says "Renamed from the legacy `PillGroup`" but the component is now named `PillGroup`. Consider updating to clarify what it was renamed *from* (e.g., "Replaces the legacy `Pills` segmented toggle").

## Triage

- Decision: `valid`
- Root cause: the Storybook description says `PillGroup` was renamed from `PillGroup`, which is self-contradictory and does not explain the legacy primitive being replaced.
- Fix approach: rewrite the description to state that `PillGroup` replaces the legacy segmented toggle/pills usage.
22 changes: 22 additions & 0 deletions .compozy/tasks/badges-design/reviews-001/issue_004.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
status: resolved
file: packages/ui/src/components/stories/pill.stories.tsx
line: 11
severity: nitpick
author: coderabbitai[bot]
provider_ref: review:4190677522,nitpick_hash:2450eb2c3284
review_hash: 2450eb2c3284
source_review_id: "4190677522"
source_review_submitted_at: "2026-04-28T16:30:00Z"
---

# Issue 004: Typo in component description.
## Review Comment

Line 14 reads "replaces `Pill`, `Pill`, `KindChip`..." with duplicate "Pill" entries. This should list the distinct components being replaced (e.g., `MonoBadge`, `StatusDot`, `KindChip`, etc.).

## Triage

- Decision: `valid`
- Root cause: the `Pill` Storybook component description repeats `Pill` several times and names removed/legacy primitives unclearly.
- Fix approach: update the description to list distinct replacements (`MonoBadge`, `StatusDot`, `KindChip`, `WireChip`, connection indicator composition) and keep the story copy aligned with the current `Pill` + `Pill.Dot` API.
100 changes: 100 additions & 0 deletions .compozy/tasks/badges-design/reviews-001/issue_005.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
---
status: resolved
file: web/src/components/design-system-showcase.test.tsx
line: 205
author: coderabbitai[bot]
provider_ref: thread:PRRT_kwDOR5y4QM5-Mtcw,comment:PRRC_kwDOR5y4QM68GE0G
---

# Issue 005: _⚠️ Potential issue_ | _🟡 Minor_
## Review Comment

_⚠️ Potential issue_ | _🟡 Minor_

<details>
<summary>🧩 Analysis chain</summary>

🏁 Script executed:

```shell
#!/bin/bash
# Check if kind-chip is exported from the network system's public barrel
rg -n "export.*KindChip" web/src/systems/network/index.ts 2>/dev/null || echo "No barrel export found"

# Check how kind-chip is imported in the showcase
rg -n "kind-chip" web/src/components/design-system-showcase.tsx
```

Repository: compozy/agh

Length of output: 149

---

🏁 Script executed:

```shell
#!/bin/bash
# Check the actual structure of the network system
echo "=== Network system public barrel content ==="
cat web/src/systems/network/index.ts 2>/dev/null || echo "File not found"

echo -e "\n=== Check if kind-chip file exists ==="
find web/src/systems/network -name "*kind-chip*" -type f

echo -e "\n=== Check what's exported from kind-chip ==="
if [ -f "web/src/systems/network/components/kind-chip.tsx" ]; then
rg -n "^export" web/src/systems/network/components/kind-chip.tsx
fi
```

Repository: compozy/agh

Length of output: 3435

---



</details>

**Fix cross-system import to use public barrel.**

The showcase imports `KindChip` from `@/systems/network/components/kind-chip`, which violates the guideline: "Cross-system imports: Only through the public barrel (`@/systems/<domain>`). Never reach into another system's internals."

`KindChip` is not currently exported from `@/systems/network`'s public barrel. Either:
1. Export `KindChip` from `web/src/systems/network/index.ts` and update the showcase to import from `@/systems/network`
2. Move `KindChip` to a shared location outside the network system if it's a general-purpose component

Update the test's allowed imports list to match the corrected import path once resolved.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/design-system-showcase.test.tsx` around lines 199 - 205,
The showcase is importing KindChip directly from
"@/systems/network/components/kind-chip" which breaks cross-system import rules;
either export KindChip from the network public barrel (add an export in
web/src/systems/network/index.ts) and change the showcase import to
"@/systems/network", or move KindChip to a shared location and import from that
new public barrel; after doing that, update the allowed Set in
design-system-showcase.test.tsx to replace
"@/systems/network/components/kind-chip" with the new public import path
"@/systems/network" (or the new shared barrel path) so the test reflects the
corrected import.
```

</details>

<!-- fingerprinting:phantom:poseidon:ocelot -->

<!-- This is an auto-generated comment by CodeRabbit -->

## Triage

- Decision: `valid`
- Root cause: `design-system-showcase.tsx` imports `KindChip` from `@/systems/network/components/kind-chip`, so the test's allowed import list preserves a cross-system internal import.
- Fix approach: export `KindChip` from the network public barrel, change the showcase import to `@/systems/network`, and update this test's allowed import set. This requires the minimal adjacent edit to `web/src/systems/network/index.ts` because the barrel currently does not expose `KindChip`.
53 changes: 53 additions & 0 deletions .compozy/tasks/badges-design/reviews-001/issue_006.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
status: resolved
file: web/src/components/design-system-showcase.tsx
line: 139
author: coderabbitai[bot]
provider_ref: thread:PRRT_kwDOR5y4QM5-Mtc1,comment:PRRC_kwDOR5y4QM68GE0M
---

# Issue 006: _⚠️ Potential issue_ | _🟠 Major_
## Review Comment

_⚠️ Potential issue_ | _🟠 Major_

**Import `KindChip` via the network public barrel, not an internal path.**

Line 139 pulls from another system’s internal component path, which breaks system boundaries.


<details>
<summary>Suggested fix</summary>

```diff
-import { KindChip } from "@/systems/network/components/kind-chip";
+import { KindChip } from "@/systems/network";
```
</details>
As per coding guidelines, `web/src/**/*.{ts,tsx}`: Cross-system imports: Only through the public barrel (`@/systems/<domain>`). Never reach into another system's internals.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/design-system-showcase.tsx` at line 139, The import of
KindChip in design-system-showcase.tsx uses an internal path and violates
cross-system rules; update the import to use the network system's public barrel
instead (replace the current "@/systems/network/components/kind-chip" import
with an import from "@/systems/network" that exposes KindChip) so the component
is consumed via the network public API rather than an internal file.
```

</details>

<!-- fingerprinting:phantom:poseidon:hawk -->

<!-- This is an auto-generated comment by CodeRabbit -->

## Triage

- Decision: `valid`
- Root cause: `design-system-showcase.tsx` directly reaches into `network/components/kind-chip`, violating the system boundary rule for cross-system imports.
- Fix approach: re-export `KindChip` from `@/systems/network` and import through that public barrel. The required barrel export is a minimal adjacent edit to `web/src/systems/network/index.ts`.
Loading
Loading