3.9 KiB
id, title, status, wave, depends_on, plan, requirements, acceptance_criteria, system_design
| id | title | status | wave | depends_on | plan | requirements | acceptance_criteria | system_design | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 02-evidence | Startup evidence | done | 2 |
|
plan.md |
|
|
|
Startup evidence
Scope
Isolated populated SQLite backup and migration timing, deferred registry and retention findings, public troubleshooting documentation.
Exclusions
No backup mechanism replacement, registry conversion, retention redesign, or publication.
Acceptance
- Meet the referenced lifecycle criteria with isolated regression evidence.
- Preserve health identity, timeout overrides, and required persistence gates.
- Record exact verification results and measurement limitations.
Files likely touched
apps/backend/internal/backendapp, internal/persistence, internal/launcher,
internal/db, task repository measurement tests, and owning/public documentation.
Verification
Use the corresponding commands in plan, from their stated directories.
Dependencies
Task 01.
Parallelism
Sequential. No delegation.
Risks
See plan and system design for cancellation and retry retention constraints.
Results
TestStartupMigrationCostsPopulated creates a fresh schema, then rebuilds
only the message table into the legacy shape needed by the recurring startup
backfills. It inserts 24 task sessions and 6,000 messages (one third user
messages), leaves updated_at nullable and empty, and omits prompt_seq so a
replay exercises both migration paths. The test also runs the same
VACUUM INTO snapshot used by production and measures the two backfills
separately after replay. The fixture is isolated under t.TempDir() and can be
reproduced with:
go test ./internal/task/repository/sqlite -run '^TestStartupMigrationCostsPopulated$' -v -count=1
One recorded run on Linux amd64, Go 1.26.0, 11 CPUs, reported:
| Measurement | Result |
|---|---|
| Populated database file before replay | 929,792 bytes |
VACUUM INTO backup |
2,252,800 bytes in 18.99 ms |
| Fresh schema initialization | 48.75 ms |
| Populated replay | 285.06 ms |
task_session_messages.updated_at backfill |
19.25 ms |
| Prompt sequence update plus counter aggregation | 41.52 ms |
The values are observations from one local run, not startup budgets. The
fixture does not model a production database's row distribution, WAL state,
filesystem, CPU contention, provider recovery, or full backup directory. It
does distinguish the liveness and readiness contract: the bootstrap tests keep
/health at 200 while /ready and application routes remain 503 until the
initializer publishes the router, and the launcher health deadline is not
used as the readiness deadline. The evidence does not change VACUUM INTO,
backup retry behavior, or backup-registry and retention design.
Lifecycle regression coverage now includes delayed success past a short health
deadline, active SQL cancellation through NewWithDBContext, worker-only
restore quiescing with restart_required, explicit post-readiness signal
handling, and initializer joining after cancellation.
PR review follow-up also verifies the retry boundaries: pre-migration snapshots
are created in a private staging directory, validated, set to mode 0600, and
installed only after validation; a failed VACUUM INTO destination is removed
when the path did not exist before the attempt. The authenticated system-job
notification path remains on the process lifetime while restore workers are
quiesced. These changes do not alter backup retention or the deferred backup
registry redesign.