Simplify the retention implementation from #10: collection on/off is startup-only, so no shared collection-control table or timestamp fence is needed. Positive retention-period changes remain live. Request-time visit-outcome capture is separate and is not included here.
Operational contract
Stop and drain both services before changing between zero and positive retention, then restart them with the new configuration. Deploy the matching web/worker code together; migration 0004 removes a table used by the previous binaries.
A live on/off candidate is rejected as a whole by both processes, with a coordinated-restart warning. The worker does not automatically restart for that change, even when the candidate also changes database paths: restarting the purger before the old writer drains would be unsafe. This deliberately gives up guarantees for unsupported live edits followed by independent process restarts.
3 ↔ 9 ↔ 12: still reloads live and requests immediate retained-history cleanup.
Positive → 0: takes effect after the coordinated restart. Web starts without a recorder/Piscina pool; the service pauses its native schedule and purges existing visits once at startup. Empty storage creates no cleanup run.
0 → positive: takes effect after restart and starts ordinary recording and the native schedule.
Implementation
Add 0004_remove_visit_collection; do not rewrite landed 0003. Remove the control-table type, helper exports, fenced INSERT, conditional resume purge, and resumption transaction. Restore a normal single-row INSERT returning its ID.
Keep the retention timestamp index, bounded 1,000-row cleanup, UTC calendar cutoff, transactional migration/write-lock safety, and existing DB ownership/cleanup.
Make the web recorder a startup-owned optional resource. Remove its mutable enabled state and live-enable API. An absent recorder omits the optional recordVisit method rather than assigning undefined or creating a dummy recorder.
Name the admission policy dropVisitIfOverLimit: drop the whole incoming event at 1,000 outstanding events or above the existing 32 KiB payload budget. Never truncate fields. Queue-full, oversized-event and unavailable-recorder warnings are distinct and bounded to once per cause per recorder, without raw payloads.
Keep When-style service/workflow organization, Directory's tslog, native hourly UTC scheduling and persisted 1–60-second scheduled-only jitter. Startup/manual cleanup is immediate; no custom scheduler or per-visit workflow.
Update the editor-schema description to state the restart requirement. No new configuration knob, dependency, API, statistics query, UI, or product README change.
Verification
Final readability, correctness/security, test-quality, and When/Directory reference-parity reviews are clean; affected re-reviews cover the approved optional-property correction.
Full pnpm verify passed: 456 unit tests, 7 web integration tests, and 5 service-process cases, plus schema/build/type/format/ESLint checks. Svelte reports zero errors/warnings.
Process smoke covers compiled/source startup, database-path restart, live 9 → 3 cleanup, rejected live 0 without purge or auto-exit, and occupied-port partial-startup cleanup. Shutdown must be natural and output fully drained.
Fresh offline pruned production artifact tested outside the repository: dependencies resolve inside the artifact, tslog is present/Pino absent, control table is absent, ordinary insertion works, positive retention prunes live, live zero is rejected, ordered zero startup purges, positive restart records again, native schedule pauses/resumes, private health works, and all three service runs exit naturally with code 0 and secret-safe output. This exercises the actual service plus compiled DB insertion helper; the existing web HTTP integration covers compiled Piscina ingestion/draining.
Scoped web/worker/config/DB lint, Changesets status and Git whitespace checks pass. Committed blobs match every reviewed/passing file hash.
No new standalone migration test or concurrency harness was added. Tests for the removed live-zero/fence guarantees were replaced with the chosen restart-only contract.
Remote CI must pass on this new head; the results above are local. Agent-run Docker/Compose validation was not performed. No owner data/configuration was accessed or modified, and no merge, release, tag or deployment was performed.
Commit: b075740 — refactor(analytics): make collection changes restart-only.
## Purpose
Simplify the retention implementation from #10: **collection on/off is startup-only**, so no shared collection-control table or timestamp fence is needed. Positive retention-period changes remain live. Request-time visit-outcome capture is separate and is not included here.
## Operational contract
**Stop and drain both services before changing between zero and positive retention, then restart them with the new configuration.** Deploy the matching web/worker code together; migration `0004` removes a table used by the previous binaries.
A live on/off candidate is rejected as a whole by both processes, with a coordinated-restart warning. The worker does **not** automatically restart for that change, even when the candidate also changes database paths: restarting the purger before the old writer drains would be unsafe. This deliberately gives up guarantees for unsupported live edits followed by independent process restarts.
- `3 ↔ 9 ↔ 12`: still reloads live and requests immediate retained-history cleanup.
- Positive → `0`: takes effect after the coordinated restart. Web starts without a recorder/Piscina pool; the service pauses its native schedule and purges existing visits once at startup. Empty storage creates no cleanup run.
- `0` → positive: takes effect after restart and starts ordinary recording and the native schedule.
## Implementation
- Add `0004_remove_visit_collection`; **do not rewrite landed `0003`**. Remove the control-table type, helper exports, fenced INSERT, conditional resume purge, and resumption transaction. Restore a normal single-row INSERT returning its ID.
- Keep the retention timestamp index, bounded 1,000-row cleanup, UTC calendar cutoff, transactional migration/write-lock safety, and existing DB ownership/cleanup.
- Make the web recorder a startup-owned optional resource. Remove its mutable enabled state and live-enable API. An absent recorder omits the optional `recordVisit` method rather than assigning `undefined` or creating a dummy recorder.
- Name the admission policy `dropVisitIfOverLimit`: drop the whole incoming event at 1,000 outstanding events or above the existing 32 KiB payload budget. Never truncate fields. Queue-full, oversized-event and unavailable-recorder warnings are distinct and bounded to once per cause per recorder, without raw payloads.
- Keep When-style service/workflow organization, Directory's tslog, native hourly UTC scheduling and persisted 1–60-second scheduled-only jitter. Startup/manual cleanup is immediate; no custom scheduler or per-visit workflow.
- Update the editor-schema description to state the restart requirement. No new configuration knob, dependency, API, statistics query, UI, or product README change.
## Verification
- Final readability, correctness/security, test-quality, and When/Directory reference-parity reviews are clean; affected re-reviews cover the approved optional-property correction.
- **Full `pnpm verify` passed: 456 unit tests, 7 web integration tests, and 5 service-process cases**, plus schema/build/type/format/ESLint checks. Svelte reports zero errors/warnings.
- Process smoke covers compiled/source startup, database-path restart, live `9 → 3` cleanup, rejected live `0` without purge or auto-exit, and occupied-port partial-startup cleanup. Shutdown must be natural and output fully drained.
- Fresh offline pruned production artifact tested outside the repository: dependencies resolve inside the artifact, tslog is present/Pino absent, control table is absent, ordinary insertion works, positive retention prunes live, live zero is rejected, ordered zero startup purges, positive restart records again, native schedule pauses/resumes, private health works, and all three service runs exit naturally with code 0 and secret-safe output. This exercises the actual service plus compiled DB insertion helper; the existing web HTTP integration covers compiled Piscina ingestion/draining.
- Scoped web/worker/config/DB lint, Changesets status and Git whitespace checks pass. Committed blobs match every reviewed/passing file hash.
No new standalone migration test or concurrency harness was added. Tests for the removed live-zero/fence guarantees were replaced with the chosen restart-only contract.
**Remote CI must pass on this new head; the results above are local.** Agent-run Docker/Compose validation was not performed. No owner data/configuration was accessed or modified, and no merge, release, tag or deployment was performed.
Commit: `b075740` — `refactor(analytics): make collection changes restart-only`.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Purpose
Simplify the retention implementation from #10: collection on/off is startup-only, so no shared collection-control table or timestamp fence is needed. Positive retention-period changes remain live. Request-time visit-outcome capture is separate and is not included here.
Operational contract
Stop and drain both services before changing between zero and positive retention, then restart them with the new configuration. Deploy the matching web/worker code together; migration
0004removes a table used by the previous binaries.A live on/off candidate is rejected as a whole by both processes, with a coordinated-restart warning. The worker does not automatically restart for that change, even when the candidate also changes database paths: restarting the purger before the old writer drains would be unsafe. This deliberately gives up guarantees for unsupported live edits followed by independent process restarts.
3 ↔ 9 ↔ 12: still reloads live and requests immediate retained-history cleanup.0: takes effect after the coordinated restart. Web starts without a recorder/Piscina pool; the service pauses its native schedule and purges existing visits once at startup. Empty storage creates no cleanup run.0→ positive: takes effect after restart and starts ordinary recording and the native schedule.Implementation
0004_remove_visit_collection; do not rewrite landed0003. Remove the control-table type, helper exports, fenced INSERT, conditional resume purge, and resumption transaction. Restore a normal single-row INSERT returning its ID.recordVisitmethod rather than assigningundefinedor creating a dummy recorder.dropVisitIfOverLimit: drop the whole incoming event at 1,000 outstanding events or above the existing 32 KiB payload budget. Never truncate fields. Queue-full, oversized-event and unavailable-recorder warnings are distinct and bounded to once per cause per recorder, without raw payloads.Verification
pnpm verifypassed: 456 unit tests, 7 web integration tests, and 5 service-process cases, plus schema/build/type/format/ESLint checks. Svelte reports zero errors/warnings.9 → 3cleanup, rejected live0without purge or auto-exit, and occupied-port partial-startup cleanup. Shutdown must be natural and output fully drained.No new standalone migration test or concurrency harness was added. Tests for the removed live-zero/fence guarantees were replaced with the chosen restart-only contract.
Remote CI must pass on this new head; the results above are local. Agent-run Docker/Compose validation was not performed. No owner data/configuration was accessed or modified, and no merge, release, tag or deployment was performed.
Commit:
b075740—refactor(analytics): make collection changes restart-only.