The gap
The API boot path never calls repo.startPushDaemon(). The deploy plan (PR #35) shipped:
- The deploy key mounting in Helm
GIT_SSH_COMMAND env wiring in the entrypoint
- Documentation in
docs/operations/secrets.md and deploy.md
…but no actual startPushDaemon() call in apps/api/src/store/boot.ts (or anywhere else). So commits made via store.transact land in the local working tree at CFP_DATA_REPO_PATH and are never pushed to CFP_DATA_REMOTE.
This fell between storage-foundation's closeout (which deferred "deploy key wiring" to deploy) and deploy's scope (which focused on container/Helm/CI artifacts).
What to wire
In apps/api/src/store/boot.ts (or a small plugin):
if (env.CFP_DATA_REMOTE) {
const daemon = await repo.startPushDaemon({
remote: 'origin',
branch: env.CFP_DATA_BRANCH ?? 'main',
backoff: 'exponential',
});
// Wire events
daemon.on('push', ({ commit, durationMs }) => log.info({ commit, durationMs }, 'pushed'));
daemon.on('retry', ({ attempt, nextDelayMs }) => log.info({ attempt, nextDelayMs }, 'push retry'));
daemon.on('error', ({ err, attempt, reason }) => {
if (reason === 'non-fast-forward') {
log.error({ err: String(err), attempt }, 'push rejected non-fast-forward — manual reconciliation needed');
} else {
log.warn({ err: String(err), attempt }, 'push failed');
}
});
// Graceful shutdown on SIGTERM/SIGINT (Fastify onClose hook)
}
NFF detection (gitsheets v1.0.5)
The error handler above already discriminates reason: 'non-fast-forward' from transient errors per PushFailureReason in gitsheets v1.0.5+. On NFF, the daemon won't retry (terminal), and the API should log loud + ideally page somebody (no automated reconciliation in v1).
Acceptance
- Boot path starts the daemon when
CFP_DATA_REMOTE is set
- A commit produced via
store.transact is observed pushed (test against a local bare remote)
- Daemon stop on SIGTERM (Fastify shutdown hook)
- NFF rejections are logged with the
non-fast-forward reason, no retry spin
fastify.pushDaemon.status() exposed via a hidden admin route or just the logs
Out of scope
- Multi-remote replication (gitsheets internal #157 deferred path is "stop daemon, pull, restart")
- The actual cluster stand-up + deploy-key generation (that's #36)
The gap
The API boot path never calls
repo.startPushDaemon(). The deploy plan (PR #35) shipped:GIT_SSH_COMMANDenv wiring in the entrypointdocs/operations/secrets.mdanddeploy.md…but no actual
startPushDaemon()call inapps/api/src/store/boot.ts(or anywhere else). So commits made viastore.transactland in the local working tree atCFP_DATA_REPO_PATHand are never pushed toCFP_DATA_REMOTE.This fell between storage-foundation's closeout (which deferred "deploy key wiring" to deploy) and deploy's scope (which focused on container/Helm/CI artifacts).
What to wire
In
apps/api/src/store/boot.ts(or a small plugin):NFF detection (gitsheets v1.0.5)
The error handler above already discriminates
reason: 'non-fast-forward'from transient errors perPushFailureReasonin gitsheets v1.0.5+. On NFF, the daemon won't retry (terminal), and the API should log loud + ideally page somebody (no automated reconciliation in v1).Acceptance
CFP_DATA_REMOTEis setstore.transactis observed pushed (test against a local bare remote)non-fast-forwardreason, no retry spinfastify.pushDaemon.status()exposed via a hidden admin route or just the logsOut of scope