Context
Surfaced 2026-08-01 by @tobiu while reviewing a client redeploy checklist, and confirmed on our own plane. The mechanism for off-host backup sync already exists and shipped — #15641 built the hook and its receipts, #16199 made a required off-host run fail after the local receipt. Both closed. This ticket is not about building it.
The gap is that a deployment can have no off-host copy and nothing says so.
Live evidence from this plane's most recent bundle receipt:
"offHostSync": { "status": "disabled", "exitCode": null, "durationMs": null }"disabled" is reported exactly the way a healthy value is reported. Nothing distinguishes "this deployment deliberately accepts local-only backups" from "nobody ever configured this and no one noticed." Today those two states are byte-identical in the receipt.
Precedent, not hypothesis: a deployment lost ~30 memories to this exact shape — one backup root, no off-host copy, and a redeploy that recreates containers. Small blast radius that time because the corpus was smoke-test data. The shape is what matters, not the count.
Live latest-open sweep: latest 12 open issues at 2026-08-01T21:27:41Z. Search sweep on offHostSync / off-host backup across all states: #15641, #16199, #16055, #16201, #16203 all closed; #15639 (opt-in first-boot restore) is adjacent, not equivalent — it covers restore into a fresh deployment, not whether a copy exists to restore from. No A2A [lane-claim] on this scope.
The Problem
The off-host posture is an undeclared default rather than a decision.
#16199 correctly fails a run when off-host sync is required and does not complete. But nothing requires a deployment to state whether it is required. A deployment that never sets it sits at disabled forever, produces green backup receipts indefinitely, and the first evidence that no remote copy exists arrives when someone needs one.
That is the same class as the failures this repo has been closing all week — #16240 (a zero-row bundle reported as a successful backup), #16246 (a dead route reporting active), #16258 (a route never attempted, so never failed). In every case the system was correct about the step it measured and silent about the property that mattered.
Concretely on this plane today, all three true at once:
offHostSync.status: "disabled" — one copy exists, on one disk.
- That copy lives at
…/neomjs/neo/ai/deploy/.neo-ai-data/backups, inside a git checkout and gitignored. git status will never show it; git clean -xdf will delete it.
- The backup lane reports success. Nothing in the receipt, the health surface, or the deployment state says the deployment has no off-host copy.
The Architectural Reality
ai/configBase.mjs:1567 — the offHostSync config block; :1347 documents that a non-empty maintenance.backup.offHostSync.command naming an executable is what arms it.
ai/services/memory-core/helpers/offHostSyncStore.mjs — buildBackupReceipt, which records the offHostSync result block quoted above.
#16199's failure path fires only when the run is required; disabled is not a failure and correctly is not treated as one.
- This is deliberately not a destination question. Where a deployment syncs to (object store, second host, operator-managed) is infrastructure, varies per deployment, and is not ours to pick. The ticket is about making the absence legible and the choice explicit.
The Fix
(Prescription — inference, not observation.)
Require the posture to be declared, and make an undeclared one visible:
- A deployment states its off-host posture explicitly —
required, or an acknowledged local-only. An unset value is neither, and should not silently resolve to "fine".
local-only is recorded where an operator sees it — the backup receipt and the deployment-state surface — as an accepted risk, not as a status word that looks like every other status word.
- A bundle whose deployment declares
required and has no completed off-host result is already handled by #16199; nothing here changes that path.
The bar to hold: after this, "does this deployment have an off-host copy?" is answerable from a surface, without reading a config file and inferring from an absence.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
| off-host posture |
configBase.mjs offHostSync block |
posture is declared (required | acknowledged local-only); unset is not a silent pass |
unset ⇒ surface it as undeclared, never as healthy — surfacing must not itself fail a backup run |
config JSDoc + the local-agent-os README |
a deployment with no off-host copy is distinguishable from one that has a verified copy, without reading config |
| backup receipt |
offHostSyncStore.buildBackupReceipt |
receipt carries the declared posture alongside the run result |
absent posture recorded as undeclared, not omitted |
receipt schema note |
a receipt answers "should there have been a remote copy?" |
Acceptance Criteria
Out of Scope
- Choosing a sync destination. Infrastructure and per-deployment; an operator call, not a code change.
- Backup contents, cadence, retention, or the bundle format.
- The backup root's location —
#16201 moved the default out of the working tree and is closed; that this plane's bind still resolves into a checkout is a deployment-config artifact of the image lag, not this ticket.
- Restore behaviour —
#15639 owns opt-in first-boot restore.
- The receipt's missing
integrity field on this plane. That is #16240 shipped-but-not-deployed (running image is 15 merged PRs behind), not a defect to fix here.
Avoided Traps
- Rebuilding the sync mechanism. It exists (
#15641) and the required-failure path exists (#16199). A ticket that re-implements either would duplicate closed work; the gap is declaration and visibility only.
- Making
local-only a failure. A legitimately local-only deployment must keep working. The defect is silence, not the choice.
- Picking a destination to "finish" the ticket. That converts an operator decision into an agent one and will be wrong for deployments we do not run.
- Reading
disabled as evidence of a decision. It is the unset default. Treating it as an accepted risk that someone already weighed is precisely the inversion this ticket exists to remove.
Related
#15641 — built the off-host sync hook and receipts (closed)
#16199 — fail required off-host runs after the local receipt (closed); this adds the declaration that makes required reachable
#16203 — backups and the graph sharing one disk (closed); same failure-domain concern, storage axis
#16240 — a zero-row bundle is not a recovery source; the sibling "green receipt, unusable artifact" shape
#15639 — opt-in first-boot restore; the consumer of whatever copy this guarantees exists
D#16193 — deployment/IaC; a relocatable Agent OS needs a restorable-from-elsewhere corpus, which a local-only posture cannot provide
Origin Session ID: 713db0da-2239-44ea-ba5b-931be90d34fc
Retrieval Hint: query_raw_memories("offHostSync disabled undeclared posture backup receipt local-only accepted risk"), or ai/configBase.mjs offHostSync.
Context
Surfaced 2026-08-01 by @tobiu while reviewing a client redeploy checklist, and confirmed on our own plane. The mechanism for off-host backup sync already exists and shipped —
#15641built the hook and its receipts,#16199made a required off-host run fail after the local receipt. Both closed. This ticket is not about building it.The gap is that a deployment can have no off-host copy and nothing says so.
Live evidence from this plane's most recent bundle receipt:
"offHostSync": { "status": "disabled", "exitCode": null, "durationMs": null }"disabled"is reported exactly the way a healthy value is reported. Nothing distinguishes "this deployment deliberately accepts local-only backups" from "nobody ever configured this and no one noticed." Today those two states are byte-identical in the receipt.Precedent, not hypothesis: a deployment lost ~30 memories to this exact shape — one backup root, no off-host copy, and a redeploy that recreates containers. Small blast radius that time because the corpus was smoke-test data. The shape is what matters, not the count.
Live latest-open sweep: latest 12 open issues at 2026-08-01T21:27:41Z. Search sweep on
offHostSync/off-host backupacross all states:#15641,#16199,#16055,#16201,#16203all closed;#15639(opt-in first-boot restore) is adjacent, not equivalent — it covers restore into a fresh deployment, not whether a copy exists to restore from. No A2A[lane-claim]on this scope.The Problem
The off-host posture is an undeclared default rather than a decision.
#16199correctly fails a run when off-host sync is required and does not complete. But nothing requires a deployment to state whether it is required. A deployment that never sets it sits atdisabledforever, produces green backup receipts indefinitely, and the first evidence that no remote copy exists arrives when someone needs one.That is the same class as the failures this repo has been closing all week —
#16240(a zero-row bundle reported as a successful backup),#16246(a dead route reporting active),#16258(a route never attempted, so never failed). In every case the system was correct about the step it measured and silent about the property that mattered.Concretely on this plane today, all three true at once:
offHostSync.status: "disabled"— one copy exists, on one disk.…/neomjs/neo/ai/deploy/.neo-ai-data/backups, inside a git checkout and gitignored.git statuswill never show it;git clean -xdfwill delete it.The Architectural Reality
ai/configBase.mjs:1567— theoffHostSyncconfig block;:1347documents that a non-emptymaintenance.backup.offHostSync.commandnaming an executable is what arms it.ai/services/memory-core/helpers/offHostSyncStore.mjs—buildBackupReceipt, which records theoffHostSyncresult block quoted above.#16199's failure path fires only when the run is required;disabledis not a failure and correctly is not treated as one.The Fix
(Prescription — inference, not observation.)
Require the posture to be declared, and make an undeclared one visible:
required, or an acknowledgedlocal-only. An unset value is neither, and should not silently resolve to "fine".local-onlyis recorded where an operator sees it — the backup receipt and the deployment-state surface — as an accepted risk, not as a status word that looks like every other status word.requiredand has no completed off-host result is already handled by#16199; nothing here changes that path.The bar to hold: after this, "does this deployment have an off-host copy?" is answerable from a surface, without reading a config file and inferring from an absence.
Contract Ledger Matrix
configBase.mjsoffHostSyncblockrequired| acknowledgedlocal-only); unset is not a silent passoffHostSyncStore.buildBackupReceiptundeclared, not omittedAcceptance Criteria
local-onlyon at least one operator-facing surface.local-onlydeployment still produces green backups — this must not become a gate that blocks a legitimate local-only setup.#16199's required-and-failed path is unchanged, pinned by a spec that fails if the failure is softened.configBase.mjs.Out of Scope
#16201moved the default out of the working tree and is closed; that this plane's bind still resolves into a checkout is a deployment-config artifact of the image lag, not this ticket.#15639owns opt-in first-boot restore.integrityfield on this plane. That is#16240shipped-but-not-deployed (running image is 15 merged PRs behind), not a defect to fix here.Avoided Traps
#15641) and the required-failure path exists (#16199). A ticket that re-implements either would duplicate closed work; the gap is declaration and visibility only.local-onlya failure. A legitimately local-only deployment must keep working. The defect is silence, not the choice.disabledas evidence of a decision. It is the unset default. Treating it as an accepted risk that someone already weighed is precisely the inversion this ticket exists to remove.Related
#15641— built the off-host sync hook and receipts (closed)#16199— fail required off-host runs after the local receipt (closed); this adds the declaration that makesrequiredreachable#16203— backups and the graph sharing one disk (closed); same failure-domain concern, storage axis#16240— a zero-row bundle is not a recovery source; the sibling "green receipt, unusable artifact" shape#15639— opt-in first-boot restore; the consumer of whatever copy this guarantees existsD#16193— deployment/IaC; a relocatable Agent OS needs a restorable-from-elsewhere corpus, which a local-only posture cannot provideOrigin Session ID:
713db0da-2239-44ea-ba5b-931be90d34fcRetrieval Hint:
query_raw_memories("offHostSync disabled undeclared posture backup receipt local-only accepted risk"), orai/configBase.mjsoffHostSync.