16 KiB
created, status, requirements, system_design, legacy_specs
| created | status | requirements | system_design | legacy_specs | ||||
|---|---|---|---|---|---|---|---|---|
| 2026-09-14 | completed |
|
|
Tool Payload Retention Implementation Plan
Overview
Add optional cleanup of old tool payloads to /settings/system/data-storage.
Keep tool messages and metadata. Provide savings analysis, a backup choice,
initial cleanup, and daily cleanup under the saved policy.
The user subsequently authorized implementation and native subagent support. The primary session owns integration and verification. No production database maintenance, commit, push, or deployment is included.
Inputs and assumptions
- Requirements
- System design
- Decision
- Age basis: task inactivity, with conservative task/session update protection.
- Initial age: three calendar months. Cleanup remains disabled by default.
- Initial engine: SQLite. Analysis is optional. The backup choice is explicit.
Previous copy-only audits motivated the feature but do not provide its live savings estimate. Different removal rules and eligibility change the result. Do not reuse prior database-wide estimates as a promise for this policy.
Scope
Include policy persistence, supported field removal, analysis, backup preparation, guarded writes, replay protection, removed-output rendering, scheduling, desktop and phone settings, access control, localization, and public documentation.
Exclude compression, cold storage, attachment deletion, full-message deletion, automatic compaction, and changes to Office/filesystem retention settings.
Technical approach
Use one reducer for analysis and cleanup. Ground candidate queries in the existing session message indexes. Preserve marker state at the repository write boundary. Persist only singleton policy/runtime records and bounded progress.
Compose internal/system/toolretention through the system service. Reuse backup
creation and job notifications, while retaining durable preparation state.
Keep all analysis and cleanup work outside startup readiness.
Add an independent settings card and save contributor. Use inline preparation review and existing backup/compaction controls. Reuse the same state model for desktop and phone. No extra release flag is proposed: the setting defaults off.
ASCII UI preview
These views specify hierarchy, actions, and states. Spacing and sample values are illustrative. Product copy must use localization keys.
UI-01: Desktop, disabled policy with optional estimate
Entry: Settings > System > Data & Logs > Database. Office history is maintained independently at Settings > System > Storage > Office retention.
Tool payload cleanup [Off]
Keep tool messages and summaries. Remove old details.
Tasks inactive for [3] [Months v] [Analyze savings]
Estimated payload reduction: <size>
<messages> tool messages across <tasks> tasks
Analyzed <time> | <skipped> unsupported/protected items
Database file shrinking requires a separate compaction.
Last cleanup: Never Next check: Disabled
[Run cleanup now] (disabled)
The existing shared Save/Discard bar owns persisted changes. Analyze uses the draft and does not save or enable it. Policy edits mark the estimate stale.
UI-02: Phone, first-cleanup review
Entry: direct Data & Logs route or the existing phone settings navigation. Use the route scroll owner. Age controls and actions stack for thumb access.
< System Data & Logs
Tool payload cleanup [On*]
Tasks inactive for
[3 ]
[Months v]
[Analyze savings ]
Estimate: <size> of payloads
<messages> messages
Before the first cleanup
Removed details cannot be undone
without restoring a database backup.
( ) Create backup (recommended)
( ) Continue without backup
Backups can take time and disk space.
Last cleanup: Never
[Discard] [Save]
On* denotes an unsaved draft, not effective enablement. Neither radio choice
is submitted automatically. The shared Save bar respects the safe area and
keyboard. Controls have 44px touch targets. No nested confirmation dialog.
Desktop uses the same inline review below its estimate.
UI-03: Progress, failure, and completed states
Analysis: <scanned> messages scanned [Cancel]
Analysis failed: <localized reason> [Retry analysis]
Estimate: Not analyzed / Stale / No eligible payloads
Preparing backup: cleanup blocked [Cancel preparation]
Backup failed: <localized reason> [Retry] [Cancel]
Cleanup: <count> messages processed [Cancel run]
Last cleanup: Partial | <size> removed | <remaining> remaining
Next check: <time> [Run cleanup now]
Read-only users see status and an admin-only explanation. Unsupported engines show an unavailable state. Neither state mounts enabled mutation controls. Partial results remain visible with their failure reason. Canceling a run keeps the policy enabled for the next daily check. Disabling stops later batches.
UI-04: Conversation with removed payload
[tool icon] <original tool title> <original status>
Tool details removed by the retention policy on <date>.
<retained summary, such as exit code or file count>
The same row appears on desktop and phone. It replaces loading/expand-output controls for removed details. Existing message grouping and navigation remain.
UI-01/02 map to AC-001.1–001.7 and AC-002.1/002.2. UI-03 maps to
AC-002.6 and AC-003.1–003.6. UI-04 maps to AC-002.3/002.4.
All abbreviated AC references use the AC-SYSTEM-PAGE-TOOL-PAYLOAD-RETENTION- prefix.
Work orders
The primary session integrates dependent contracts in order. With explicit user authorization, native subagents implemented separate reducer/replay, backup, UI, and browser-test files. Shared runtime integration remains in the primary session.
| Order | Work order | Result |
|---|---|---|
| 1 | Policy, reducer, and analysis | Tested read-only analysis and eligibility boundary |
| 2 | Guarded cleanup and replay | Backup gate, bounded mutation, durable marker |
| 3 | Settings and conversation UI | Usable desktop/phone workflow and removed-output state |
| 4 | Scheduling and integration | Daily operation, restart evidence, docs, full feature verification |
Tests
The test files below cover the implemented behavior. Work orders record verification evidence and assertions about committed database state.
| Criteria | Test location and evidence |
|---|---|
| 001.1–001.3, 001.7, 003.6 | internal/system/toolretention/policy_test.go: defaults, ranges, revisions, authorization, engine gating |
| 001.3–001.5, 003.2 | internal/system/toolretention/analysis_test.go, internal/task/repository/sqlite/tool_payload_retention_scan_test.go: UTC boundaries, no writes, paginated scale, malformed data |
| 002.3/002.4 | internal/task/models/tool_payload_retention_test.go: exact field preservation, unknown structures, idempotence, byte accounting |
| 002.1/002.2/002.5–002.7, 003.3/003.4 | internal/system/toolretention/runner_test.go: backup failure/crash, transactional activity race, policy disable, partial progress |
| 002.4 | internal/task/repository/sqlite/tool_payload_retention_scan_test.go, internal/task/service/service_messages_payload_retention_test.go: stale replacement, replay, resume |
| 003.1–003.4 | internal/system/toolretention/scheduler_test.go: fake clock, startup readiness, daily schedule, busy backoff, restart/cancel |
| 001.4–001.7, 002.1/002.2, 003.4/003.5 | components/settings/system/tool-payload-retention-card.test.tsx: draft, choice, error, job states, independent Office settings |
| 002.4 | Transcript renderer tests and hooks/domains/system/use-tool-payload-retention.test.ts: removed marker, output cache invalidation |
E2E Tests
e2e/tests/system/tool-payload-retention.spec.ts: analyze while disabled, enable with backup, wait for cleanup, reload settings, inspect original tool metadata and removed details in a seeded old task. Protect a recently active task.- Same desktop file: explicit skip, stale estimate, disabled policy, and independent Office retention behavior. Component and backend tests cover backup failure, cancellation, partial results, and restart boundaries.
e2e/tests/system/mobile-tool-payload-retention.spec.ts: repeat the activation and conversation flow at 390px and 320px, including keyboard and safe-area behavior.- Extend existing auth data-storage member-gating tests for denied analysis and
mutations. Use the
authproject and its existing mobile project ownership.
Use disposable fixture databases only. Seed payloads through test fixture helpers, never the user's production database or retained backups. Restore shared settings in teardown. Assertions must prove payload removal, not just a success toast.
Verification
Each work order contains exact commands. Run focused checks after its changes. The final validation covers backend, frontend, browser flows, and documentation.
Design-package checks:
python3 scripts/list-docs.py validate
python3 scripts/lint-spec-files.test.py
python3 scripts/lint-spec-files.py --all
git diff --check -- docs/specs docs/plans/tool-payload-retention docs/decisions
Risks
- Conservative activity and ownership checks can retain old legacy records. Eligibility deadlines also retain large tasks and produce partial results.
- Large legacy JSON needs bounded parsing. Oversize/unknown rows stay intact and reduce achievable savings. Do not conceal these skips.
- Backup and compaction can take substantial time and disk. Keep preparation explicit and do not add either operation to automatic startup work.
- Stale message writes can restore details unless the repository enforces markers.
- SQLite page reuse does not immediately shrink files or existing backups.
- Keep the tool payload and Office save contributors independent. The route design now records both without changing the Office policy.
Verification results
Implementation and final integration validation are complete. No production database or retained production backup was opened for this work.
Design validation on 2026-09-14:
list-docs.py validate: passed, including the new requirement/design pair and ADR.lint-spec-files.test.py: all 36 tests passed.lint-spec-files.py --all: passed.- New-document relative links and whitespace: checked before handoff.
Runtime verification results are recorded below.
Implementation verification (2026-09-14)
- Broad backend tests passed for system, task models, SQLite repositories, task service, handlers, and persistence, including store conformance. Focused race checks passed for the changed reducer/replay, eligibility, backup, maintenance, and retention paths.
- Full backend lint and SQL portability guard passed. Full web lint passed with zero warnings/errors. Typecheck, localization validation, and the i18n ratchet passed. The focused frontend run passed 90 tests; 29 affected tests passed again after lint refinements.
- Fresh managed backend and frontend builds and fixture plugin packaging passed. All eight browser tests passed sequentially: two desktop retention flows, two phone flows (320px/390px), and four desktop/mobile member/admin checks.
go test -race ./internal/system/toolretention -run TestAdmission -count=1 -vproves both transaction orderings and foreground commits between batches. The disposable 307-message fixture took four batches with three intervening foreground commits. It removed 2,101,108 logical bytes and freed 307 pages. The main file stayed at 2,650,112 bytes after cleanup; explicit VACUUM reduced it to 278,528 bytes. These measurements describe this fixture only.- A 250,000-message eligibility fixture hit its 200ms budget and retained the task. The pass exposes that skip as partial. Very large or ambiguous tasks can therefore save less than the configured age alone suggests.
- The optional PostgreSQL replay integration test was skipped because no test DSN was configured. SQLite is the supported retention engine. An initial full task-service race run exceeded its ten-minute limit; the isolated affected tests and the later broad non-race suite passed.
The final cancellation fix passes deterministic regression tests and the full retention package race suite (4.477 seconds). It covers writer-held snapshots, pending preparation, operation-ID handoff, invalid requests, transactional CAS, and failed persistence. Scoped lint reports zero issues. No production database or retained backup was read or modified. No commit, push, or deployment occurred.
Final confirmation after the cancellation fix:
- Fresh managed backend/frontend builds and fixture packaging passed again.
- Both desktop backup/skip browser tests passed against the final backend. The preceding eight-scenario desktop/phone/auth run remains green.
- Full backend lint passed again with zero issues. SQLguard, document index, specification lint, published-page validation, and whitespace checks passed.
- All four work orders are complete. Changes remain uncommitted for review.
Review remediation
Both P2 findings from the uncommitted-workspace review are resolved:
- A normal worker tick recovers orphaned preparation after final-state persistence fails. Revision/operation CAS protects replaced work; cleanup remains disabled and preparation becomes retryable without restart or manual cancellation.
- Guarded replay preserves shell exit-code summaries in live-event metadata and API projections. Unknown large numbers retain precision; removed output stays absent.
Focused RED tests reproduced both failures. Focused race tests cover recovery,
replacement protection, failure handling, real SQLite replay, and projections.
The full retention and model package race suites passed (5.085s and 1.448s).
Logs: /tmp/retention-review-red.log, /tmp/retention-review-replay-red.log,
/tmp/retention-review-green.log, /tmp/retention-review-package-race.log.
No broad build/test rerun, commit, push, deployment, or production data access
was performed during remediation.
Scoped lint passed with zero issues (/tmp/retention-review-lint.log). The
additional running/terminal backup failure-handler race test passed
(/tmp/retention-review-terminal-race.log). Whitespace checks passed.
Approved UX refinement (implemented)
This refinement supersedes the earlier layout previews. Messages compaction uses the existing shared Save changes/Discard controls and explicit backup consent; the automatic schedule is unchanged.
Desktop (bounded card width):
Messages compaction
Remove old tool inputs and outputs; keep message metadata.
Tasks inactive for [3] [Months v] [Analyze savings]
Analysis outcome and timestamp
> Analysis details
------------------------------------------------------
[off] Automatic compaction
Checks every 24 hours while Kandev is running.
First run starts after backup preparation.
[Backup choice appears here when enabling]
Last run: <status and time> > Run details
Next check: <time or Disabled>
[Compact messages now]
Space reuse and database file compaction explanation
Phone: number and unit remain adjacent; Analyze savings takes its own full-width row. Controls and disclosure summaries have 44px touch targets. The existing settings page owns scrolling and the shared Save bar. Partial results, stale estimates, and errors remain visible outside collapsed details.
Validation: focused component/hook tests, desktop backup/skip flows, and phone flows at 320px and 390px, including disclosure and control geometry checks. User requested no commit.
Follow-up presentation package
The settings storage tabs package completed the header tabs and maintenance presentation changes. This package retains its historical implementation results. Its route and copy references are current.