Automattic / Automattic/wp-codebox
Stale primary checkout silently ships an out-of-date /usr/bin/wp-codebox (no skew detection / no auto-rebuild)
- Dominant language
- TypeScript
- Stars
- 16
- Forks
- 4
- Avg merge
- 59m
- Merged PRs (30d)
- 131
Description
## Summary
On a live install, `/usr/bin/wp-codebox` is a symlink to the **workspace primary checkout's built dist** (`/var/lib/datamachine/workspace/wp-codebox/packages/cli/dist/index.js`), not an npm-global package. There is currently nothing that detects or prevents that primary from drifting behind `origin/main`, and nothing that rebuilds `dist/` when it does. The result: a fixed bug can stay broken in production indefinitely because the binary points at stale, never-rebuilt source.
This issue tracks adding **skew detection and/or auto-rebuild** so a stale primary can't silently serve an out-of-date CLI.
## How it bit us (concrete incident)
Production was emitting **plain-text** errors on the `recipe-run --json` error path instead of a JSON envelope, which broke a PHP caller doing `json_decode(stdout)` with `did not return valid JSON: Syntax error`. Repro on the stale binary:
```
$ wp-codebox recipe-run --recipe /tmp/x.json --artifacts /tmp/a --json
Unsupported recipe schema in /tmp/x.json # plain text, not JSON, exit 1
$ wp-codebox recipe-run --json
Missing required option: --recipe # plain text, not JSON
```
The actual code fix for this had **already landed** on `main` in commit `3118a438` ("Add command artifact schema contracts (#1059)", 2026-06-16) — `cli-main.ts`'s error sink already consults `wantsJsonOutput(args)` and calls `writeJsonFailure(...)`, and regression tests (`cli-json-failure-smoke`, `cli-unsettled-command-smoke`) are in the `check` smoke group.
But the **primary checkout** was pinned at `eb9a717f` (2026-06-15) with a 2026-06-15 `dist/`, i.e. one day *before* the fix:
- `git merge-base --is-ancestor 3118a438 HEAD` → **NO** (fix not in primary source)
- `grep -c "wantsJsonOutput(args)" packages/cli/src/cli-main.ts` → **0**
- `dist/cli-main.js` built 2026-06-15, no `wantsJsonOutput`
So `/usr/bin/wp-codebox` kept serving the pre-fix behavior even though `main` had been fixed. Meanwhile the deployed WP plugin's recipe-writer had moved ahead, which is what surfaced the `Unsupported recipe schema` mismatch in the first place.
## Resolution applied to the affected host (manual, not a code change)
1. `workspace git pull wp-codebox --allow-primary-refresh` (fast-forward `eb9a717f` → `700fe40d`, clean tree). Fix `3118a438` now in source.
2. `npm run build` → fresh `dist/` carrying `wantsJsonOutput` in `dist/cli-main.js`.
3. Verified the live `/usr/bin/wp-codebox`:
- `recipe-run --json` (missing recipe) → JSON envelope to stdout, exit 1 ✅
- `recipe-run --recipe --json` → JSON envelope to stdout, exit 1 ✅
- `recipe-run` (no `--json`) → plain text to **stderr**, stdout empty, exit 1 (regression preserved) ✅
That fixed *this host*, but nothing stops it recurring on any host whose primary drifts.
## Proposed work (this issue)
Pick one or both:
1. **Skew detection in `doctor`.** Have `wp-codebox doctor` compare the running binary's source revision against `origin/main` (or the configured tracked ref) and flag/warn when the primary that backs the binary is behind, or when `dist/` is older than `src/`. The binary already reports a source fingerprint in `doctor` — extend it to a freshness assertion.
2. **Auto-rebuild on primary refresh.** When the primary checkout is refreshed (`--allow-primary-refresh`), rebuild `dist/` so the symlinked binary can't lag its own source. At minimum, fail loudly if `dist/` is stale relative to `src/`.
### Acceptance criteria
- A stale primary (HEAD behind tracked ref, and/or `dist/` older than `src/`) is **detected and surfaced**, not silently served.
- Refreshing the primary leaves `/usr/bin/wp-codebox` running the refreshed source (either by rebuild or by a hard error that forces one).
- No behavior change when the primary is already fresh.
## Notes
- This is an operational/tooling gap, not a defect in the CLI's runtime behavior — the JSON-envelope fix itself is already correct and tested on `main`.
- The `/usr/bin/wp-codebox` → primary-`dist/index.js` symlink model is the load-bearing detail: it means "deploy" and "binary freshness" are decoupled, so a fresh deploy of the plugin does not imply a fresh CLI binary.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with the `wp-codebox doctor` entry point and the primary refresh path behind `--allow-primary-refresh`; inspect how the binary reports its source fingerprint and how `npm run build` updates `dist/`. Trace the `/usr/bin/wp-codebox` symlink model, then verify that a behind-remote or stale-dist primary is surfaced and that refresh leaves the binary fresh without changing already-fresh behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- git, node.js, typescript
- Domain
- build-system, cli, devops, tooling
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100