Skip to content

Wire startPushDaemon() in API boot so commits actually propagate to the data remote #37

@themightychris

Description

@themightychris

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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions