Task · CXO-0002

Run the drift probe on a schedule and alert on it

Description

Migrated from the former GitHub issue tracker.\nFollows on from e3cb67d.

clbprobe detects an archive format change in ~6s across 1.4GB. Run by hand it catches drift whenever someone remembers to run it. The failure it guards against is silent: a field that gains a second JSON type makes Go’s decoder abandon the whole event, which looks like slightly fewer turns, not like an error.

Scope:

Traps: sampling proves nothing about rare shapes - the rarest real shapes occur ~10 times in 1.32M records, so -full belongs on a slower cadence. Absence findings are informational by design and must never page. -update from a sampled scan is warned against for good reason: regenerating from -full is the only correct way to accept a change.

Acceptance Criteria

Definition of Done

Implementation Plan

Wave 1: replace the non-runnable scheduled workflow with the frozen in-process probe, embed the full-scan baseline, expose findings, then wire and verify live.

Implementation Notes

State at migration (2026-08-14), verified in the checkout rather than taken from the issue:

Decision 2026-09-03 (Rob to confirm before the wave): AC #2 is satisfied IN-PROCESS, not by GitHub Actions. rknightion is a User account with no runner groups and public-repo CI must not run on self-hosted runners, so scheduled-archive-probe.yml can never go live; delete it. codexlb2otel already tails the live archive, so it runs the sampled probe itself on a schedule (config block probe: enabled/interval, default 24h, sampled) against an embedded baseline and emits codexlb.archive_drift_findings (gauge, {finding}) by codexlb.selfobs.severity in breaking|new|info. The alert rule and the legacy panel already reference that name. Evidence the guard is needed: today’s probe against the synced corpus reports 7 breaking and 576 new findings (see CXO-0007) that nothing had watched for since 2026-08-09.

L5 implemented at commit 472ff94: added internal/drift with injectable baseline and scanner seams, immediate plus interval scheduling, sampled or full archive scanning, metric-ready finding counts for breaking, new, and info, last run time and error stats, and tests for severity aggregation, scheduled repeats, error-stat retention, and an injected protocol type change caught end to end. Deleted the non-runnable self-hosted scheduled workflow. Updated dashboards/alerts/drift-breaking.yaml to use codexlb_archive_drift_findings with codexlb_selfobs_severity=“breaking”. Validation passed: gofmt, go test -race -count=1 ./internal/drift, go vet ./internal/drift, and git diff check. Wiring to the embedded baseline and OTLP remains in the root integration pass. Decisions: run immediately on startup before the interval; retain the last successful finding counts when a later scan errors while updating LastRun and LastError.

Root wiring landed at 6a54f61. Camden runs the in-process sampled probe immediately at startup with a 24 hour interval. Live m7kni values after the partial-SHA deployment were breaking=2, new=172, and info=75; the breaking alert query and dashboard panel use the real metric and label. The two breaking findings are tracked in CXO-0024 and must not be baselined without classification. Final just check passed at 334a4db; final-SHA deployment remains CXO-0025.

Final Summary

Replaced the unrunnable scheduled workflow with an immediate and periodic in-process archive drift probe, exported bounded severity metrics, and wired the breaking alert. Focused race tests, injected protocol-drift coverage, final just check, and live m7kni values prove the implementation. The full corpus suite remains explicitly unproven.

View the source file on GitHub