Land the unmerged branch backlog: targets, archived-target deploys, flake-backed jobs, sync preflight, fleet evidence #578

Merged
gmackie merged 13 commits from mega/2026-09-15 into main 2026-09-15 20:23:42 +00:00
Owner

Lands the salvageable work from the 50 unmerged ForgeGraph branches as one integration, built additively on main (cherry-pick / three-way apply, no history rewriting — pushed commits are immutable under jj).

What is in here (13 commits)

  • traffic: the one-box carries a copy of every production secret
  • web: transpile @preflight/runreport, unblocking the deploy build
  • ops/fleet: Phase 0 recovery baseline + workspace-fleet evidence (docs/ops/evidence/workspace-fleet/2026-08-26)
  • fg: db migrate-data survives a live source and slow D1 loads
  • ci: fg ci failures — structured CI failures for agents
  • agent: persist OCI/node-service secrets env outside tmpfs
  • docs: Forgejo token revocation field report; TODOS entry for the working GIT_SERVER_TOKEN path
  • targets: a blocked target delete explains itself — counts referencing deployments and scheduled jobs, returns 409 with the counts, and catches a late FK violation instead of 500ing (replaces main's simpler guard; existing delete tests updated for the two count queries)
  • deploy: archived targets (config.disabled) are kept out of every deployment plan, an explicit deploy of one is refused, and a stage whose only targets are archived no longer falls back to the legacy app platform (woven into main's one-box-aware target selection); sandbox host-input allow rules are prioritized
  • jobs: scheduled jobs may be flake-backed — flakeAttribute is accepted and stored, and a manifest naming both or neither of command/flakeAttribute is rejected; agent validates the manifest and parses the nix store path
  • sync: a friendly node name in nodeId is treated as already resolved, so preflight stops reporting a spurious nodeId diff

Deliberately not included (already on main, verified line-by-line)

  • feat/creator-oidc-client, -2 — 100% of added lines present in apps/web/src/lib/auth.ts
  • feat/agent-cf-worker-telemetry — superseded by telemetryWorkerVars/patchWranglerVars (writes vars into wrangler config for plain-wrangler and OpenNext apps; has tests). The branch's --var flag approach duplicated two symbols and broke the build.
  • push-kstkloonulxp web side — the config-apply handler already resolves a friendly name in either nodeId or node; only the Go preflight fix was still missing.
  • fix/archive-deployment-targets — subset of fix/host-sandbox-input-priority
  • 7 other "land" branches applied empty (already merged via squash PRs)

Verification

  • apps/web deploy route suite: 39/39 (incl. 4 archived-target cases and 2 new flake-job cases)
  • targets + config-apply suites: 9/9; packages/api plan-deployments: 7/7
  • go test — cmd/fg/commands, internal/jobrunner, internal/sandbox, cmd/agent: ok
  • tsc --noEmit on apps/web: no new errors vs main (same tree)

Known

  • The new targets/__tests__/route.test.ts imports the packages/api test-db helper, so it is classified into the database lane and does not run in the default suite.
  • Pre-integration tips of all 50 branches are tagged preland/<branch>.

🤖 Generated with Claude Code

Lands the salvageable work from the 50 unmerged ForgeGraph branches as one integration, built additively on main (cherry-pick / three-way apply, no history rewriting — pushed commits are immutable under jj). ## What is in here (13 commits) - **traffic**: the one-box carries a copy of every production secret - **web**: transpile `@preflight/runreport`, unblocking the deploy build - **ops/fleet**: Phase 0 recovery baseline + workspace-fleet evidence (`docs/ops/evidence/workspace-fleet/2026-08-26`) - **fg**: `db migrate-data` survives a live source and slow D1 loads - **ci**: `fg ci failures` — structured CI failures for agents - **agent**: persist OCI/node-service secrets env outside tmpfs - **docs**: Forgejo token revocation field report; TODOS entry for the working `GIT_SERVER_TOKEN` path - **targets**: a blocked target delete explains itself — counts referencing deployments *and scheduled jobs*, returns 409 with the counts, and catches a late FK violation instead of 500ing (replaces main's simpler guard; existing delete tests updated for the two count queries) - **deploy**: archived targets (`config.disabled`) are kept out of every deployment plan, an explicit deploy of one is refused, and a stage whose only targets are archived no longer falls back to the legacy app platform (woven into main's one-box-aware target selection); sandbox host-input allow rules are prioritized - **jobs**: scheduled jobs may be flake-backed — `flakeAttribute` is accepted and stored, and a manifest naming both or neither of `command`/`flakeAttribute` is rejected; agent validates the manifest and parses the nix store path - **sync**: a friendly node *name* in `nodeId` is treated as already resolved, so preflight stops reporting a spurious nodeId diff ## Deliberately not included (already on main, verified line-by-line) - `feat/creator-oidc-client`, `-2` — 100% of added lines present in `apps/web/src/lib/auth.ts` - `feat/agent-cf-worker-telemetry` — superseded by `telemetryWorkerVars`/`patchWranglerVars` (writes vars into wrangler config for plain-wrangler *and* OpenNext apps; has tests). The branch's `--var` flag approach duplicated two symbols and broke the build. - `push-kstkloonulxp` web side — the config-apply handler already resolves a friendly name in either `nodeId` or `node`; only the Go preflight fix was still missing. - `fix/archive-deployment-targets` — subset of `fix/host-sandbox-input-priority` - 7 other "land" branches applied empty (already merged via squash PRs) ## Verification - `apps/web` deploy route suite: 39/39 (incl. 4 archived-target cases and 2 new flake-job cases) - targets + config-apply suites: 9/9; `packages/api` plan-deployments: 7/7 - `go test` — `cmd/fg/commands`, `internal/jobrunner`, `internal/sandbox`, `cmd/agent`: ok - `tsc --noEmit` on `apps/web`: no new errors vs main (same tree) ## Known - The new `targets/__tests__/route.test.ts` imports the packages/api `test-db` helper, so it is classified into the database lane and does not run in the default suite. - Pre-integration tips of all 50 branches are tagged `preland/<branch>`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
The CLI promised the one-box "shares production's database and secrets".
The secrets half was false: Worker secrets are per-worker and write-only,
the deploy pushed only what ForgeGraph's store held, and the name-parity
check that already existed was advisory by default — it wrote a
`traffic.canary_secrets` event and the deploy shifted anyway. On
2026-09-02 a playtrek canary missing AUTH_GOOGLE_ID/AUTH_GOOGLE_SECRET
served 10% of production for 13 minutes with sign-in 404ing, every probe
green, two minutes from auto-promote (docs/field-reports/2026-09-02).

- Enforcement is now on by default. A proven gap is a
  `CanarySecretGapError`; `onDeploymentReported` drains the split
  straight to `failed` with the gap as its reason while the weight is
  still 0. FG_TRAFFIC_CANARY_SECRET_ENFORCE=0 restores advisory mode.
- `fg secret import --from-worker <primary>` closes the gap: it reads the
  write-only values back through a `wrangler dev --remote` preview of a
  tiny reader Worker (no deployment is created) and files them in the
  store, so every later deploy syncs them. Names-only --dry-run, --keys,
  --all; DB-routing keys are withheld; empty values are never stored.
- `fg traffic status` now prints what each event said: the missing
  names on `traffic.canary_secrets`, the message on
  `traffic.metrics_error`, from→to on `traffic.state`, and the split's
  last error. Both were bare kind names before.
- Help text and the fg-cli skill state the real contract.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 737670c1da0515c578cd94df8b344ac09b43b84c)
(cherry picked from commit 2bc99035b2)
With the registry 401 fixed by #505, @preflight/runreport installs — and
the next thing breaks: the deploy build fails with

  ./node_modules/@preflight/runreport/src/index.ts
  Error: Unknown module type

The package publishes a compiled dist/ AND an exports map pointing at
source:

  main:    "./dist/index.js"
  exports: { ".": "./src/index.ts" }

exports wins over main, so every resolver gets raw TypeScript. Adding it
to transpilePackages — where the workspace packages that also ship TS
already live — lets Turbopack compile it.

This is a consumer-side unblock, not the real fix: the package should
export dist/. Filed as such so main can deploy again.

Verified locally: next build compiles successfully, 205 static pages —
the same step that was failing on main.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CMpzX1b6swjezEptw3T71f
(cherry picked from commit e34bf7fb1f)
(cherry picked from commit 5f2f2882c60d577c5b37e8eaa72670b7bc813dd3)
Two failures seen copying preflight-app (91k rows) to D1:

- The client's default 15s HTTP timeout is sized for control-plane calls;
  a D1 load POST for one batch of a wide table regularly exceeds it, and
  the copy died with 'context deadline exceeded' at random offsets.
  migrate-data now gives its client five minutes per request.
- The source is live. Rows written after a parent table was read but
  before its child was reached referenced parents the target never got,
  and D1 enforces the foreign key, so pf_workflow_event failed with
  SQLITE_CONSTRAINT_FOREIGNKEY. All reads now run in one REPEATABLE READ,
  read-only transaction: every table sees the same instant, and later
  writes are picked up by the next idempotent run.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 0c67dee722)
(cherry picked from commit 09315522c5)
Env files for OCI worker and custom node services were written to
/run/secrets/forgegraph — tmpfs, wiped on reboot — while the systemd
units reference them via --env-file. After any node reboot those
services crash-loop with "parsing file ... no such file or directory"
until the next deploy (bit twenty's worker on hetzner-worker,
2026-07-04). Move to /var/lib/forgegraph/secrets, matching the nix
deploy path which already persists secrets at /etc/forgegraph/env with
the same 0600 permissions.

Existing units keep their /run path until their next deploy rewrites
the unit. nixgen.go still references /run/secrets for stack services —
its writer lives outside the agent, so it is left paired as-is.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 6093aaf2d7032c59c93be7a6df0282cae34c9d5c)
The admin PAT scrubbed in #161 (chore/security-scrub-token-gitleaks) was
also the credential the Bob review->repair->merge pipeline used in three
places (worker BOB_FORGEJO_TOKEN secret, hetzner-bob runner git remotes,
ad-hoc API). Revoking it silently dead-locked autonomous dispatch for ~23h.

This note captures the incident timeline, the three token locations, the
fix (swap to the credentials.json forgejo_token), and a rotation checklist
so a future credential scrub updates the Bob fleet instead of breaking it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit 5e0f460f27)
Integrated from branch ops/forgejo-token-expired for the 2026-09-15 mega PR.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Integrated from branch fix/stack-sync-default-branch for the 2026-09-15 mega PR.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Integrated from branch fix/host-sandbox-input-priority for the 2026-09-15 mega PR.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Integrated from branch fix/jobs-flake-deploy for the 2026-09-15 mega PR.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
fix(sync): treat a friendly node name in nodeId as already resolved
All checks were successful
CI / gitleaks (pull_request) Successful in 8s
CI / storybook (pull_request) Successful in 1m56s
CI / web-build (pull_request) Successful in 3m35s
forgegraph/ci CI passed
CI / ci (pull_request) Successful in 11m3s
8634f2b4d1
Integrated from branch push-kstkloonulxp for the 2026-09-15 mega PR.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Author
Owner

Preview environment is live: https://pr-578-forgegraph.forgegraf.com

Deployed 8634f2b4 with the beta stage's environment. It redeploys on every push and is destroyed when this PR closes.

Preview environment is live: https://pr-578-forgegraph.forgegraf.com Deployed `8634f2b4` with the beta stage's environment. It redeploys on every push and is destroyed when this PR closes.
gmackie scheduled this pull request to auto merge when all checks succeed 2026-09-15 20:20:57 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
gmackie/ForgeGraph!578
No description provided.