---
name: full-path-symlink-sync
slug: full-path-symlink-sync
created: 2026-05-16
status: in-progress
---

# Quick: full-path deploy must sync /data/client-assets/current

## Root cause

`.github/workflows/deploy-staging.yml` full-path job calls `flyctl deploy` which
image-swaps the rebno-staging machine. The image bundles the freshly built client
at `/app/public/`. However `STATIC_ASSETS_DIR=/data/client-assets/current` and
`apps/server/src/static-assets.ts` prefers the env path whenever it exists, so
the server keeps serving the previous fast-path release that `client-release.sh`
populated. Full-path never updates the volume symlink — that's the gap.

Discovered Phase 06.6 operator UAT 2026-05-17 (bundle hash `index-DjmLGbtm.js`
on disk vs `index-CbpOzv5W.js` actually served). Manual remediation
documented in memory `fly-fullpath-deploy-data-symlink-gap.md`.

## Fix

Reuse fast-path's `scripts/client-release.sh` from the full-path job. The
"Build client (staging mode)" step already emits to `apps/server/public/` on
the runner, so the tarball-and-swap recipe transplants 1:1.

After "flyctl deploy → rebno-staging", before "Dispatch async soak", insert:

1. **Tarball static output** — `tar -czf client-assets-<sha>.tgz -C apps/server/public .`
2. **Upload tarball** — `flyctl ssh sftp put` to `/tmp/client-assets-<sha>.tgz`
3. **Upload release script** — `flyctl ssh sftp put` to `/tmp/client-release-<sha>.sh`
4. **Extract + atomic swap** — `flyctl ssh console -C "bash /tmp/client-release-<sha>.sh <sha>"`

Same script, same `mv -T` atomic swap, same GC retention. No new code in
`client-release.sh`. Net effect: full-path leaves `/data/client-assets/current`
pointing at the same content as `/app/public/` in the just-deployed image.

## Verify

After commit, next push to main with a server-touching diff will exercise the
new steps. Operator can also `gh workflow run deploy-staging.yml` from a
no-op commit. Probe DevTools `document.querySelector('script[type="module"][crossorigin]')?.src`
must equal `apps/server/public/.vite/manifest.json`'s `index.html.file` hash.

## Scope

- `.github/workflows/deploy-staging.yml` — full-path job only. Fast-path
  unchanged.
- No changes to `scripts/client-release.sh`.
- No changes to `apps/server/src/static-assets.ts`.
- Memory `fly-fullpath-deploy-data-symlink-gap.md` updated to record fix.
