The operational break-glass ops (Owner provision, OP create, halt, Sync backup) are built and oracle-verified. The fourth §B4 line item — the tarS3 archive backend — is recorded as a deliberate deferral, not a silent gap: config.Load fail-closes store=tarS3 (frozen by TestLoadRejectsUnimplementedArchiveStore), tarLocal is the tested baseline every backup/restore path uses today, and offsite/cross-cluster DR is opt-in future work. Supersedes the "S3 remains open" note in the phase-2b peer doc.
3.1 KiB
3.1 KiB
§B4 phase close — S3 archive backend deferred by design (decision record)
- Type: decision / scope record (no code changed)
- Date: 2026-07-08
- Area:
internal/config,internal/backup— the archive-store backend selection - Task: #31 Phase B4 break-glass ops — closes the phase, superseding the phase-2b note in break-glass-backup-peer ("S3 remains open in B4; this does not close the phase").
Decision
The three operational B4 break-glass ops are built, wired into the recovery console menu, and oracle-verified:
| Op | Menu enum | Commit |
|---|---|---|
| Provision/reset Owner | bgProvisionOwner |
(Phase B1 lineage) |
| Add Operator ("OP create") | bgAddOperator |
recovery-console menu |
| Halt a running server | bgHaltServer |
c2ee21a |
| Back up a world now ("Sync") | bgSyncBackup |
7a7c0d5 / f2fc57c / fc748d3 |
The fourth B4 line item — S3 archive backend (tarS3) — is deferred by design, not
left as a silent gap. It is closed as a documented deferral and #31 is done.
Why deferring is safe (not a loose end)
- Fail-closed at config load, frozen by a test.
config.Loadrejectsstore = "tarS3"(andvolumeSnapshot,longhorn) with an error that points the operator at thetarLocalremediation.TestLoadRejectsUnimplementedArchiveStorefreezes exactly this: a config naming an unimplemented backend fails at load, so felis-api can never boot green while the reaper CronJob fails every run and restore silently 503s. tarS3 cannot be selected into a broken state. - Peer to two other deferred backends.
tarS3sits besidevolumeSnapshotandlonghornas recognized-but-unimplemented store names. The spec's own phasing is tarLocal-first ("起步tarLocal… 要异地/跨集群 →tarS3"): the baseline single-node path istarLocal(tar → backup PVC), which is implemented, tested, and the backend every built backup/restore path uses today. - Offsite/cross-cluster DR is the only capability gap, and it is opt-in future work, not a correctness hole in the shipped baseline.
The build path, when offsite DR is wanted
minio-go/v7 is already vendored (the modpack upload lane's internal/submit/s3store.go),
so tarS3 adds no dependency. A future build is bounded:
internal/backup/tars3.go— aWorldArchiverreusing the existing package-levelwriteTarGz/readTarGz/pruneToManifest, streaming the tar to an object viaPutObject(size −1, multipart) and reading it back viaGetObject, mirrorings3store.go's fakeable-client testability.- Store-selection factory in the backup/reaper entrypoint (
store = "tarS3"→ construct the minio-backed archiver) + remove tarS3 from the config fail-closed list (updateTestLoadRejectsUnimplementedArchiveStoreto keep only volumeSnapshot/longhorn). - Inject the S3 Secret into the backup/reaper Job Pods (integration wiring, like the Kaniko S3-context credential path).
The live-S3 upload + Secret-into-Pod would be integration-only verified, exactly as the modpack S3 backend and the pgrepo SQL are.