Base: this branch contains the foundation commit (PR #4, feature/backups-foundation, not merged yet); the verify work is the single commit d2fcf74 on top, so it rebases cleanly. Merge #4 first, then retarget/rebase this onto develop.
What it does
Verify backup (backupVerify, record action on backups_run, streamed ETL with Review/Result lines). STORAGE (head every object incl. every file-store object in the file index; sizes, provider SHA-256 where present) then CONTENT (decrypt hook via ArtifactTransform.unwrap, gunzip, parse every row with the codec incl. exact round trip, recount, recompute sha256Stored/sha256Raw/rowsHash per table, re-hash every referenced file-store object against its SHA-256 key, bounded by fileReverifyDays using backups_file_object.lastVerifiedDate). TEST_RESTORE through a ScratchTarget interface; MEMORY implementation restores every table into cloned in-memory table metadata, compares counts and rowsHash, restores files to qqq-verify/<runKey>/, re-hashes, drops. RDBMS_SCHEMA is a stub that fails with a clear ERROR (needs the restore writer).
Writes backups_verification rows, updates backups_run.verificationStatus and backups_plan.lastVerified* (CONTENT or deeper).
backupCheckSla (scheduled every slaCheckIntervalSeconds when a scheduler is configured): OK, LATE, FAILING, MISSING_IN_STORAGE (head on manifestKey, positive cached 1h), UNVERIFIED, ABANDONED (RUNNING heartbeat older than 10 min, run marked ABANDONED), OWNER_INVALID (planOwnerValidator hook), UNKNOWN for a brand-new plan. Daily bucket listing for orphans and debris.
Alerts: every alert of the spec table with stable dedupe keys, raised and resolved through BackupAlertSink; backups.plan.missed is raised by the SLA checker itself, independent of any heartbeat.
AlertsQBitAlertSink: reflective, optional adapter for the Alerts producer SPI (QRun-IO/qqq#1108, not in RC.4); no-op without the Alerts qbit; declares the 9 alert types.
BackupsHealthIndicator (optional dep qqq-middleware-health), ESB events (optional dep qqq-esb, fire and forget), BackupsMetrics Prometheus text (cached 60s).
Stand-ins
Alerts SPI bound by reflection (tested against a same-shape test double) until RC.5; replace with direct QAlerts calls.
/metrics/backups route is a documented stub: needs qqq-middleware-javalin; the app calls BackupsMetrics.renderCached().
Decrypt hook is BackupsQBitConfig.withArtifactTransformResolver(keyRef -> ArtifactTransform); replace with the core key provider (#1107) when it ships.
Spec sections 10.1, 10.2, 10.4 and 4.5.
**Base:** this branch contains the foundation commit (PR #4, `feature/backups-foundation`, not merged yet); the verify work is the single commit `d2fcf74` on top, so it rebases cleanly. Merge #4 first, then retarget/rebase this onto `develop`.
## What it does
- **Verify backup** (`backupVerify`, record action on `backups_run`, streamed ETL with Review/Result lines). STORAGE (head every object incl. every file-store object in the file index; sizes, provider SHA-256 where present) then CONTENT (decrypt hook via `ArtifactTransform.unwrap`, gunzip, parse every row with the codec incl. exact round trip, recount, recompute sha256Stored/sha256Raw/rowsHash per table, re-hash every referenced file-store object against its SHA-256 key, bounded by `fileReverifyDays` using `backups_file_object.lastVerifiedDate`). TEST_RESTORE through a `ScratchTarget` interface; MEMORY implementation restores every table into cloned in-memory table metadata, compares counts and rowsHash, restores files to `qqq-verify/<runKey>/`, re-hashes, drops. `RDBMS_SCHEMA` is a stub that fails with a clear ERROR (needs the restore writer).
- Writes `backups_verification` rows, updates `backups_run.verificationStatus` and `backups_plan.lastVerified*` (CONTENT or deeper).
- **backupCheckSla** (scheduled every `slaCheckIntervalSeconds` when a scheduler is configured): OK, LATE, FAILING, MISSING_IN_STORAGE (head on manifestKey, positive cached 1h), UNVERIFIED, ABANDONED (RUNNING heartbeat older than 10 min, run marked ABANDONED), OWNER_INVALID (`planOwnerValidator` hook), UNKNOWN for a brand-new plan. Daily bucket listing for orphans and debris.
- **Alerts**: every alert of the spec table with stable dedupe keys, raised and resolved through `BackupAlertSink`; `backups.plan.missed` is raised by the SLA checker itself, independent of any heartbeat.
- **AlertsQBitAlertSink**: reflective, optional adapter for the Alerts producer SPI (QRun-IO/qqq#1108, not in RC.4); no-op without the Alerts qbit; declares the 9 alert types.
- `BackupsHealthIndicator` (optional dep qqq-middleware-health), ESB events (optional dep qqq-esb, fire and forget), `BackupsMetrics` Prometheus text (cached 60s).
## Stand-ins
- Alerts SPI bound by reflection (tested against a same-shape test double) until RC.5; replace with direct `QAlerts` calls.
- `ScratchTarget.RDBMS_SCHEMA` stub (TODO: restore agent's writer, #1111).
- `/metrics/backups` route is a documented stub: needs qqq-middleware-javalin; the app calls `BackupsMetrics.renderCached()`.
- Decrypt hook is `BackupsQBitConfig.withArtifactTransformResolver(keyRef -> ArtifactTransform)`; replace with the core key provider (#1107) when it ships.
## Small edits outside this area
`BackupsQBitConfig` (new fields), `BackupsProcesses.processes()` (one line), `BackupsQBitProducer` (alerts bind), `BackupsTables` (plan field `verifyFileSamplePercent`), `BackupEngine.signal` (one line: ESB event), pom (two optional deps).
## Tests
`./mvnw verify`: 69 tests, jacoco gates met (80% instruction). Failure injection: deleted manifest, corrupted/truncated/replaced part, deleted file-store object, wrong file checksum, provider checksum mismatch, wrong key, no decrypt hook. SLA states on a synthetic clock; alerts raised and resolved through a recording sink.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
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.
Spec sections 10.1, 10.2, 10.4 and 4.5.
Base: this branch contains the foundation commit (PR #4,
feature/backups-foundation, not merged yet); the verify work is the single commitd2fcf74on top, so it rebases cleanly. Merge #4 first, then retarget/rebase this ontodevelop.What it does
backupVerify, record action onbackups_run, streamed ETL with Review/Result lines). STORAGE (head every object incl. every file-store object in the file index; sizes, provider SHA-256 where present) then CONTENT (decrypt hook viaArtifactTransform.unwrap, gunzip, parse every row with the codec incl. exact round trip, recount, recompute sha256Stored/sha256Raw/rowsHash per table, re-hash every referenced file-store object against its SHA-256 key, bounded byfileReverifyDaysusingbackups_file_object.lastVerifiedDate). TEST_RESTORE through aScratchTargetinterface; MEMORY implementation restores every table into cloned in-memory table metadata, compares counts and rowsHash, restores files toqqq-verify/<runKey>/, re-hashes, drops.RDBMS_SCHEMAis a stub that fails with a clear ERROR (needs the restore writer).backups_verificationrows, updatesbackups_run.verificationStatusandbackups_plan.lastVerified*(CONTENT or deeper).slaCheckIntervalSecondswhen a scheduler is configured): OK, LATE, FAILING, MISSING_IN_STORAGE (head on manifestKey, positive cached 1h), UNVERIFIED, ABANDONED (RUNNING heartbeat older than 10 min, run marked ABANDONED), OWNER_INVALID (planOwnerValidatorhook), UNKNOWN for a brand-new plan. Daily bucket listing for orphans and debris.BackupAlertSink;backups.plan.missedis raised by the SLA checker itself, independent of any heartbeat.BackupsHealthIndicator(optional dep qqq-middleware-health), ESB events (optional dep qqq-esb, fire and forget),BackupsMetricsPrometheus text (cached 60s).Stand-ins
QAlertscalls.ScratchTarget.RDBMS_SCHEMAstub (TODO: restore agent's writer, #1111)./metrics/backupsroute is a documented stub: needs qqq-middleware-javalin; the app callsBackupsMetrics.renderCached().BackupsQBitConfig.withArtifactTransformResolver(keyRef -> ArtifactTransform); replace with the core key provider (#1107) when it ships.Small edits outside this area
BackupsQBitConfig(new fields),BackupsProcesses.processes()(one line),BackupsQBitProducer(alerts bind),BackupsTables(plan fieldverifyFileSamplePercent),BackupEngine.signal(one line: ESB event), pom (two optional deps).Tests
./mvnw verify: 69 tests, jacoco gates met (80% instruction). Failure injection: deleted manifest, corrupted/truncated/replaced part, deleted file-store object, wrong file checksum, provider checksum mismatch, wrong key, no decrypt hook. SLA states on a synthetic clock; alerts raised and resolved through a recording sink.🤖 Generated with Claude Code