diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md
index 4232a6aee..fa6aa2d2a 100644
--- a/docs/troubleshooting.md
+++ b/docs/troubleshooting.md
@@ -206,3 +206,413 @@ gstack-config set codex_reviews disabled
**Expected result.** Later reviews print `Codex review skipped (codex_reviews disabled)`
or `CODEX_MODE: disabled`, and /ship and /review show the outside review as not run.
+
+---
+
+## /ship, /review and /document-release
+
+
+### `Shipped without a version change: no version source is configured (no VERSION file, no .gstack/version-path). ...`
+
+**Meaning.** /ship found no version file it owns: there is no `VERSION`, no
+`.gstack/version-path`, or release automation (release-please, Changesets,
+semantic-release, a workspace monorepo, a placeholder package.json version)
+owns the version. This is `not run` for the version bump.
+
+**What is kept.** Everything else ships. No bump, no CHANGELOG version header,
+no `vX.Y.Z` PR title prefix.
+
+**Fix.** To have /ship version releases, create `VERSION`, or pin the file:
+
+```bash
+echo package.json > .gstack/version-path && git add .gstack/version-path
+```
+
+**Expected result.** The next /ship bumps that file and writes a CHANGELOG header.
+
+
+### `gstack-version-bump: classify: version source is broken: ...`
+
+**Meaning.** The pinned version file does not exist, is empty, unreadable, or
+contains no parsable version. /ship stops instead of inventing `0.0.0.0`.
+
+**What is kept.** Nothing was written.
+
+**Fix.** Repair that file, or correct `--version-path` / `.gstack/version-path`.
+
+**Expected result.** `gstack-version-bump classify` prints the current version.
+
+
+### `Plan completion audit: not run (no plan is bound to this branch and no docs/designs/ file matches). Fix: ...`
+
+**Meaning.** /ship and /review audit a PR against the plan bound to its branch
+(plan mode, /autoplan, or a `Plan: ` line in the PR body). With none bound
+and no matching `docs/designs/` file, they no longer pick the newest unrelated
+plan; the audit is `not run`.
+
+**Fix.** Add `Plan: docs/designs/.md` to the PR body, or run /autoplan.
+
+**Expected result.** The next /ship or /review prints the audit against that plan.
+
+
+### `gstack-learnings-search: bun not found on PATH, so learnings could not be read. Fix: ...`
+
+**Meaning.** Learnings search (and `gstack-timeline-read`, "the timeline") needs
+Bun. It exits 127 instead of looking like "no learnings".
+
+**Fix.** Install Bun from https://bun.sh, then `cd && ./setup`.
+
+**Expected result.** Skills print your prior learnings again.
+
+
+### `LEARNINGS: unavailable ()`
+
+**Meaning.** A skill's learnings lookup failed (often Bun is missing). Skills
+used to show nothing here, which looked like "no learnings".
+
+**What is kept.** Your learnings file is untouched; the skill continues without them.
+
+**Fix.** Read the reason in parentheses. If it names Bun, install it and re-run
+`./setup`.
+
+
+### `gstack-learnings-log: could not create a temp file in , so the learning was not recorded. Fix: ...`
+
+**Meaning.** The learnings, question and preference logs write through a temp
+file in `${TMPDIR:-/tmp}`. A sandbox that blocks it used to drop the entry silently.
+
+**Fix.** `export TMPDIR=` and log again.
+
+
+### `CALIBRATION: not calibrated: no recorded signals`
+
+**Meaning.** Your logged answers matched no psychographic signal, so /plan-tune
+has nothing to calibrate from. It no longer says "calibrated".
+
+**Fix.** Answer more registered questions, then `gstack-developer-profile --derive`.
+
+
+### `gstack: earlier data for this project is in projects/ (a worktree's old bucket). Merge it: ...`
+
+**Meaning.** Linked worktrees now share the main checkout's project identity.
+Learnings and checkpoints a worktree wrote under its own old bucket still exist.
+
+**Fix.** Merge them (logs are de-duplicated, conflicts listed, nothing overwritten):
+
+```bash
+gstack-slug --adopt-legacy --from
+```
+
+Or stop the reminder: `gstack-slug --adopt-legacy --dismiss `.
+
+---
+
+## Design skills
+
+
+### `DESIGN_NOT_AVAILABLE: --version exited ` (or `timed out after 10s`, `is not installed`, `no timeout/gtimeout/perl ...`)
+
+**Meaning.** Design skills now run `"$D" --version` with a 10-second deadline
+before claiming `DESIGN_READY`. Exit 137 means macOS killed the binary at launch
+(a bad code signature); setup prints the same condition as
+`design unavailable: is killed at launch (exit 137) after re-signing`.
+
+**What is kept.** Nothing was generated or spent.
+
+**Fix.** Re-run setup, which rebuilds and re-signs the binary:
+
+```bash
+cd && ./setup
+```
+
+If the message names a missing timeout tool, install coreutils (`gtimeout`) or perl.
+
+**Expected result.** The next design skill prints `DESIGN_READY`.
+
+
+### `TASTE_PROFILE_UNAVAILABLE: could not resolve the project slug (gstack-slug failed). Fix: run ./setup.`
+
+**Meaning.** /design-consultation and /design-shotgun load your taste profile.
+This says it could not be found, instead of acting as if you had none.
+
+**Fix.** `cd && ./setup`.
+
+
+### `image was generated but could not be saved to (); kept at `
+
+**Meaning.** The paid image generation succeeded but writing it to the round
+folder failed (disk or permissions). gstack never buys the same image twice.
+
+**What is kept.** The image, at the printed temp path.
+
+**Fix.** Free disk space or fix the folder's permissions, then
+`cp `.
+
+---
+
+## Codex and other env-var hosts
+
+
+### `gstack: no install found (tried ). Fix: ./setup --host from your gstack checkout; ./setup --status shows it.`
+
+**Meaning.** On Codex, Factory, OpenCode, Cursor, Copilot and Kiro every bash
+block finds gstack on its own: an exported `GSTACK_ROOT` (with `bin/` and
+`lib/`), then a repo-local install, then the host's global install
+(`$CODEX_HOME/skills/gstack` on Codex). None existed.
+
+**Fix.**
+
+```bash
+cd && ./setup --host codex # or your host
+./setup --status
+```
+
+**Expected result.** `./setup --status` lists the install and says the router is
+a real file and its section links resolve.
+
+
+### `router is a symlink, which Codex skips` / `section links: N of M broken (first: ...)`
+
+**Meaning.** `./setup --status` checks each registered install. Codex ignores a
+symlinked SKILL.md, and a broken section link means a carved skill cannot load
+its next step.
+
+**Fix.** `cd && ./setup --host ` (the command is printed).
+
+
+### `saved your edited to (setup rewrites gstack's SKILL.md copies on every run)`
+
+**Meaning.** Installed router and nested SKILL.md files are now real copies,
+rewritten by every setup. Your hand edit was saved first.
+
+**What is kept.** Your edit, at ``. Move the customization into your own skill.
+
+
+### `error: could not back up an edited SKILL.md copy under ; the previous runtime root is unchanged`
+
+**Fix.** Fix permissions on `/backups`, then `./setup --host `.
+
+
+### `ERROR: is not a gstack checkout; nothing was changed. Re-run Step 2.` / `INSTALL_DIR is not set: re-run Step 2 ...`
+
+**Meaning.** /gstack-upgrade now checks, before any git command, that it is
+inside gstack's own checkout. A block ran without the path Step 2 printed, so it
+stopped instead of touching your project.
+
+**Fix.** Run Step 2 again and prefix the block with `INSTALL_DIR=`.
+
+
+### `//SKILL.md is bytes, over the 160,000-byte limit. Fix: carve sections with usesLazySections() for this skill.`
+
+**Meaning.** For contributors: hosts read at most 160,000 bytes of one SKILL.md.
+`bun run gen:skill-docs` fails in the repo and warns under `--install-root`.
+
+---
+
+## Setup and auto-update
+
+
+### `gstack auto-update: setup did not finish (); installed skills may be out of date. gstack retries automatically. Fix now: cd && ./setup`
+
+**Meaning.** The pull worked but setup (or migrations) failed. gstack no longer
+says "just upgraded". It retries after 1 hour, then 6, then 24, and prints this
+line once per session start. A `(bun not found on PATH)` reason means install
+Bun first.
+
+**What is kept.** The previous install stays active.
+
+**Fix.** Run the printed command.
+
+
+### `gstack auto-update: git pull did not finish (exit N: ...); gstack is not updating. Fix now: ...`
+
+**Fix.** `cd && git pull --ff-only && ./setup`.
+
+
+### `CSO unavailable: its native helper was not built (windows-msvc-compile)`
+
+**Meaning.** Visual Studio's compiler was found but the /cso native helper did
+not compile. setup prints the first compiler error. It used to say "install
+Visual Studio".
+
+**Fix.** Fix the printed compiler error, then re-run `./setup`.
+
+
+### `removed the AskUserQuestion preference hook: it breaks Conductor's native AskUserQuestion (#2207). ...`
+
+**Meaning.** In Conductor, setup no longer installs the plan-tune
+question-preference hook and removes one it added before. The other plan-tune
+hooks stay.
+
+**Fix.** To keep it anyway: `gstack-config set plan_tune_hooks yes`, then `./setup`.
+
+
+### `Error: browse_extension_id '' is not a Chrome extension ID ... Existing value left unchanged.`
+
+**Fix.** Copy the 32-letter ID (letters a to p) from `chrome://extensions`, then
+`gstack-config set browse_extension_id `.
+
+---
+
+## Browser
+
+
+### `Chromium at GSTACK_CHROMIUM_PATH= failed to launch: ...`
+
+**Meaning.** Headless browse and make-pdf now use `GSTACK_CHROMIUM_PATH`
+(NixOS, macOS 13). That binary could not start.
+
+**Fix.** Point `GSTACK_CHROMIUM_PATH` at a working Chromium, or
+`unset GSTACK_CHROMIUM_PATH` to use gstack's bundled one.
+
+
+### `Headed Chromium profile is in use by Chromium PID (started by PID : ). ...`
+
+**Meaning.** Headed browse keeps one profile per project
+(`/.gstack/chromium-profile`). A live browser owns this one, and
+browse never kills it. `... is locked by PID on another host ()`
+means the lock came from another machine through a synced folder.
+
+**Fix.** Close that browser, or `export CHROMIUM_PROFILE=`. For the
+other-host case, stop it there, or remove `/SingletonLock` once you are
+sure nothing uses it.
+
+
+### `[browse] Headed browse now keeps a profile per project ...`
+
+**Meaning.** First use copies your logins from `~/.gstack/chromium-profile`
+when no browser is using it; otherwise it starts fresh and prints how to import.
+`browse profiles` lists them, `browse profiles prune --days 30` removes idle ones.
+
+
+### `Blocked: is a cloud metadata or link-local address` / `... resolves to a cloud metadata or link-local address`
+
+**Meaning.** Browse refuses 169.254.0.0/16 (including container credential
+endpoints), 100.100.100.200, fe80::/10 and fc00::/7 in every numeric spelling,
+including after a redirect or a page-driven navigation. The tab is reset to
+`about:blank` and the command fails. This cannot be overridden.
+
+
+### `forbidden origin` from the sidebar terminal
+
+**Meaning.** The terminal accepts only gstack's extension. A self-built or forked
+extension has a different ID. `BROWSE_EXTENSION_ID` is no longer read.
+
+**Fix.** `gstack-config set browse_extension_id `.
+
+
+### `hint: "" looks like a CSS selector`
+
+**Meaning.** Bare `browse type ` types into the focused element. The first
+word looked like a selector, so it was typed as text.
+
+**Fix.** `browse type --selector '' ` (put text that starts with `--`
+after `--`).
+
+
+### `server-node.mjs not found. Run bun run build` (Windows)
+
+**Fix.** `cd && bun run build`.
+
+
+### `[freeze] Hook helpers out of date (partial upgrade?)`
+
+**Meaning.** `check-freeze.sh` and `hook-extract.sh` come from different gstack versions.
+
+**Fix.** `cd && ./setup` (or `/unfreeze`).
+
+---
+
+## Memory and gbrain
+
+Every message below is also in [docs/gbrain-sync-errors.md](gbrain-sync-errors.md)
+with more detail, along with the per-page ingest messages (`FAILED`,
+`re-queued`, `quarantined`, reconcile progress, kept-on-this-machine notices).
+
+
+### `database host unreachable (); your gbrain config is unchanged. Fix: check network or VPN, then re-run /sync-gbrain.`
+
+**Meaning.** A DNS or connection error reaching your gbrain database. It used to
+look like a broken config, and setup stripped brain features while offline.
+
+**Fix.** Restore the network or VPN, then `/sync-gbrain`.
+
+
+### `[memory-ingest] ERR: gbrain reported N failure(s) it did not attribute to a staged page ... Refusing to advance state.`
+
+**What is kept.** Nothing is marked saved, so nothing is lost. After three such
+runs gstack bisects the batch and quarantines the page that breaks it.
+
+**Fix.** Re-run `/sync-gbrain`.
+
+
+### `[memory-ingest] reconcile: not run (...)`
+
+**Meaning.** After upgrading, gstack re-checks transcripts it had marked saved
+and re-imports the ones missing from your brain. That check needs a local gbrain.
+
+**Fix.** `/setup-gbrain`, then `gstack-memory-ingest --reconcile` (`--dry-run` to preview).
+
+
+### `[memory-ingest] ERR: another memory ingest (pid ) is writing ; not run.`
+
+**Fix.** Wait for it to finish, then re-run `/sync-gbrain`.
+
+
+### `[memory-ingest] ERR: could not save ingest state : .`
+
+**Fix.** Fix permissions or free disk space under your gstack state root, then `/sync-gbrain`.
+
+
+### `curated artifacts pushed to git, but gbrain source has 0 indexed pages. Fix: gbrain sync --source , then re-run /sync-gbrain`
+
+**Fix.** `gbrain sync --source `, then `/sync-gbrain`.
+
+
+### `dream: skipped — the installed gbrain cannot run only the resolve_symbol_edges phase, and the full dream cycle costs about 35 minutes ...`
+
+**Meaning.** `/sync-gbrain --dream` (and `--full`'s auto-build) now runs only the
+call-graph phase. Your gbrain cannot scope it, so nothing ran.
+
+**Fix.** `gstack-gbrain-install`, then `/sync-gbrain --dream`. Or run the full
+cycle yourself: `gbrain dream --source `.
+
+
+### `call graph for : unknown: installed gbrain does not expose cycle_freshness`
+
+**Fix.** `gstack-gbrain-install`.
+
+
+### `[gbrain-sync] gbrain source : path unavailable (); gstack skips it.`
+
+**Meaning.** A deleted worktree's code source. gstack never removes it on its own.
+
+**Fix.** Preview, then remove the ones gstack can prove belonged to this machine:
+
+```bash
+gstack-gbrain-sync --prune-gone-worktrees --dry-run
+gstack-gbrain-sync --prune-gone-worktrees
+```
+
+---
+
+## Push guard (redaction)
+
+
+### `db.url_with_password` HIGH on `postgres://postgres:postgres@db...` (pre-push BLOCKED)
+
+**Meaning.** The default `postgres:postgres` pair is exempt only on `localhost`
+or `127.0.0.1`. A service name like `@db` says nothing about where the URL ends
+up deployed, so it still blocks.
+
+**Fix.** Use `postgres://postgres:postgres@localhost:5432/...` in local and CI
+config, or read the URL from an env var. If the credential is real, rotate it.
+Bypass once: `GSTACK_REDACT_PREPUSH=skip git push`.
+
+
+### `pii.ip_public` MEDIUM on a four-part version number
+
+**Meaning.** The line does not declare the value as a version.
+
+**Fix.** Write it as `version: 1.2.3.4`, `"version": "..."` or `v1.2.3.4`.
+MEDIUM findings do not block pushes.
diff --git a/lib/gate-outcomes.ts b/lib/gate-outcomes.ts
index ff1687b8b..9436c7814 100644
--- a/lib/gate-outcomes.ts
+++ b/lib/gate-outcomes.ts
@@ -78,6 +78,116 @@ export const GATE_OUTCOMES = {
summary: 'outside reviews are turned off (codex_reviews=disabled)',
fix: 'gstack-config set codex_reviews enabled',
},
+ no_version_source: {
+ state: 'not_run', anchor: 'ship-no-version-source',
+ summary: 'no version source is configured, or release automation owns it',
+ fix: 'create VERSION, or write the version file path (for example package.json) to .gstack/version-path',
+ },
+ version_source_broken: {
+ state: 'unavailable', anchor: 'ship-version-source-broken',
+ summary: 'the configured version file is missing, empty, unreadable or malformed',
+ fix: 'fix that file, or correct --version-path / .gstack/version-path',
+ },
+ no_plan_bound: {
+ state: 'not_run', anchor: 'plan-audit-not-run',
+ summary: 'no plan is bound to this branch and no docs/designs/ file matches',
+ fix: 'add "Plan: " to the PR body, or run /autoplan',
+ },
+ bun_missing: {
+ state: 'unavailable', anchor: 'learnings-bun-missing',
+ summary: 'bun not found on PATH, so learnings (or the timeline) could not be read',
+ fix: 'install Bun (https://bun.sh), then re-run ./setup',
+ },
+ learnings_unavailable: {
+ state: 'unavailable', anchor: 'learnings-unavailable',
+ summary: 'the learnings search failed, so prior learnings were not loaded',
+ fix: 'read the reason in parentheses; install Bun if it is missing, then re-run ./setup',
+ },
+ tmpdir_unwritable: {
+ state: 'unavailable', anchor: 'log-tmpdir-unwritable',
+ summary: 'could not create a temp file in ${TMPDIR:-/tmp}, so the entry was not recorded',
+ fix: 'point TMPDIR at a writable directory',
+ },
+ not_calibrated: {
+ state: 'not_run', anchor: 'plan-tune-not-calibrated',
+ summary: 'not calibrated: no recorded signals',
+ fix: 'answer more registered questions; run gstack-developer-profile --derive to recount',
+ },
+ variant_save_failed: {
+ state: 'unavailable', anchor: 'design-variant-save-failed',
+ summary: 'the image was generated but could not be saved to the output path (kept in the temp dir)',
+ fix: 'free disk space or fix permissions on the output dir, then copy the kept file from the printed path',
+ },
+ design_unavailable: {
+ state: 'unavailable', anchor: 'design-not-available',
+ summary: 'the design binary could not start (it exited, timed out, was killed at launch, or is not installed)',
+ fix: 'cd && ./setup',
+ },
+ taste_profile_unavailable: {
+ state: 'unavailable', anchor: 'design-taste-profile-unavailable',
+ summary: 'the project slug could not be resolved, so your taste profile was not loaded',
+ fix: 'run ./setup',
+ },
+ no_install_found: {
+ state: 'unavailable', anchor: 'gstack-no-install-found',
+ summary: 'no gstack install for this host was found from this shell',
+ fix: './setup --host from your gstack checkout; ./setup --status shows it',
+ },
+ db_unreachable: {
+ state: 'unavailable', anchor: 'gbrain-db-unreachable',
+ summary: 'the gbrain database host is unreachable; your gbrain config is unchanged',
+ fix: 'check network or VPN, then re-run /sync-gbrain',
+ },
+ ingest_batch_refused: {
+ state: 'unavailable', anchor: 'memory-ingest-unattributed-failures',
+ summary: 'gbrain reported failures it did not attribute to a page, so nothing was marked saved',
+ fix: 're-run /sync-gbrain; after three refusals gstack finds and sets aside the page that breaks the batch',
+ },
+ reconcile_not_run: {
+ state: 'not_run', anchor: 'memory-reconcile-not-run',
+ summary: 'the post-upgrade transcript check did not run (gbrain missing, or the brain is remote over HTTP)',
+ fix: 'run /setup-gbrain, then gstack-memory-ingest --reconcile',
+ },
+ ingest_locked: {
+ state: 'not_run', anchor: 'memory-ingest-locked',
+ summary: 'another memory ingest is writing the state file',
+ fix: 'wait for it to finish, then re-run /sync-gbrain',
+ },
+ ingest_state_unsaved: {
+ state: 'unavailable', anchor: 'memory-ingest-state-unsaved',
+ summary: 'the ingest state file could not be saved',
+ fix: 'fix permissions or free disk space under your gstack state root, then re-run /sync-gbrain',
+ },
+ artifacts_not_indexed: {
+ state: 'unavailable', anchor: 'gbrain-artifacts-not-indexed',
+ summary: 'curated artifacts were pushed to git, but gbrain has 0 indexed pages for them',
+ fix: 'gbrain sync --source , then re-run /sync-gbrain',
+ },
+ dream_unscoped: {
+ state: 'not_run', anchor: 'gbrain-dream-skipped',
+ summary: 'the installed gbrain cannot run only the call-graph phase, and the full dream cycle takes about 35 minutes',
+ fix: 'gstack-gbrain-install, then /sync-gbrain --dream',
+ },
+ cycle_freshness_unknown: {
+ state: 'unavailable', anchor: 'gbrain-cycle-freshness-unknown',
+ summary: 'the installed gbrain does not expose cycle_freshness, so call-graph status is unknown',
+ fix: 'gstack-gbrain-install',
+ },
+ update_incomplete: {
+ state: 'unavailable', anchor: 'auto-update-incomplete',
+ summary: 'auto-update pulled gstack, but setup or migrations did not finish',
+ fix: 'cd && ./setup',
+ },
+ cso_helper_unbuilt: {
+ state: 'unavailable', anchor: 'cso-windows-msvc-compile',
+ summary: 'MSVC is installed but the /cso native helper failed to compile',
+ fix: 'fix the printed compiler error, then re-run ./setup',
+ },
+ chromium_path_failed: {
+ state: 'unavailable', anchor: 'browse-chromium-path-failed',
+ summary: 'the Chromium at GSTACK_CHROMIUM_PATH could not launch',
+ fix: 'point GSTACK_CHROMIUM_PATH at a working Chromium, or unset GSTACK_CHROMIUM_PATH',
+ },
} as const satisfies Record;
export type GateReason = keyof typeof GATE_OUTCOMES;