# Session-workflow, CI-triage & review-process decisions (#542) How we *work* — orchestration, CI-run triage, review routing, worktree and parallel-session hygiene, and the tooling gotchas that have cost real sessions. Distinct from the engineering "why the code does X" records: nothing here decides product behaviour. These records were extracted from `docs/handoffs/chicorytv-issue-queue.md` in #542. That doc had become the **only** copy of most of this knowledge — an inventory found ~30 of ~38 lore bullets had no decision record at all — so it was neither retrievable via the catalog nor safe from a careless prune. The rules are now records; the handoff doc keeps the instruction and points here for the why. Related: `release-ci-governance.md` (merge/release gates and hooks), `startup.parallel-orientation` (session-start tracks), `session.shared-checkout-refresh` (session-end shared-tree refresh). --- — it is noise, not a cause. Grep for the failure marker, not for the word "error". next session debugging a phantom. Split the two counts explicitly. runners, so high load is not always CI's own doing. one of the 4 runner slots while doing it, which is a real cost with several parallel sessions. conflating them leads to load-watching behaviour that this record forbids. *before* theorising about a cause. rather than diagnosis. suite in exchange for fixing one known-slow case. local verdict; it is not the first line of defence. the merge record can be re-read later. cheap fast private check is skipped in favour of the expensive slow shared one. real" and let a starving fix ship. Send the fix approach up with the finding. timer that fires once more than the author pictured. failure mode a second, differently-scoped reviewer catches. still holds. refresh script that mitigates it. This record covers the git-state failure mode only. #216. route mutates only the ref, so the merge lands without disturbing the owner's tree. tests". A `git status` in the new worktree before the first build catches this in one command. hides exactly the change the golden net exists to surface. not the agent. the `review` label and milestone. A milestone is **not** required — backlog is unmilestoned. the single most contended file across parallel sessions. ``` claimed local admin makes its Setup-gate spec unreachable. not the overlay inputs. Route branding verification through a real channel playout instead. retrying the same call. names, then update this record once verified. settle on and the browser tool hangs. and write the structured close comments the applicable `AGENTS.md` / `CLAUDE.md` protocol requires. feature's issue for its end-state *before* choosing between a switch and a wall. commit `f93458c7`, where it was dropped by a later prune rather than disproved.) rule, which is the habit being built. inventing one) and an explicit statement of who owns the printed PID. ## Records formerly in this file Each record below moved to its own file under `records/` (ersatztv#610); the rationale is unchanged. Resolve by **key** — that is the stable identity. A date-based pointer from another doc or an old issue comment should land here and then follow the link. - 2026-07-21 — "Make X consistent with Y" review findings are new code and get new-code scrutiny (#542) — [`process.consistency-fix-new-code-scrutiny`](records/process/consistency-fix-new-code-scrutiny.md) - 2026-07-21 — A dropped subagent connection is transient; resume, don't restart (#542) — [`process.subagent-drop-resume`](records/process/subagent-drop-resume.md) - 2026-07-21 — A killed CI job reports `conclusion: failure`; read the log tail before diagnosing the diff (#542) — [`ci.killed-job-triage`](records/ci/killed-job-triage.md) - 2026-07-21 — A lock/channel "no cross-release" verdict must enumerate every producer via grep (#542) — [`process.lock-ownership-enumerate-producers`](records/process/lock-ownership-enumerate-producers.md) - 2026-07-21 — A lone `decisions lifecycle` red is a known infra flake: do nothing (#542) — [`ci.decisions-lifecycle-flake`](records/ci/decisions-lifecycle-flake.md) - 2026-07-21 — An infra-shaped red under host load is not a code failure (#542) — [`ci.infra-shaped-red-under-load`](records/ci/infra-shaped-red-under-load.md) - 2026-07-21 — Arm the CI monitor at PR-open, via the commit-status endpoint (#542) — [`ci.monitor-armed-at-pr-open`](records/ci/monitor-armed-at-pr-open.md) - 2026-07-21 — BOM/format pre-push detection: use the `xxd` loop, and run `dotnet format --include` under `bash -c` (#542) — [`process.bom-format-detection-recipe`](records/process/bom-format-detection-recipe.md) - 2026-07-21 — Batch your pushes: there is no agent-side cancel route on Gitea 1.25.4 (#542) — [`ci.batch-pushes-no-cancel-route`](records/ci/batch-pushes-no-cancel-route.md) - 2026-07-21 — Before deleting a "workaround", enumerate every behavior it provided (#542) — [`process.enumerate-workaround-behaviors-before-deleting`](records/process/enumerate-workaround-behaviors-before-deleting.md) - 2026-07-21 — Bound parallel builds by FREE RAM, never regenerate goldens (#542) — [`process.build-concurrency-limits`](records/process/build-concurrency-limits.md) - 2026-07-21 — Build and verify locally, then trust it; CI confirms (#542) — [`ci.verify-locally-ci-confirms`](records/ci/verify-locally-ci-confirms.md) - 2026-07-21 — Channel branding is NOT testable through the troubleshooting-playback API (#542) — [`testing.troubleshoot-path-cannot-test-branding`](records/testing/troubleshoot-path-cannot-test-branding.md) - 2026-07-21 — Claim with `in-progress` before working; claiming is not collision safety (#542) — [`process.parallel-session-claim`](records/process/parallel-session-claim.md) - 2026-07-21 — Do not gate or throttle pushes on host health (#542) — [`ci.no-host-health-gating`](records/ci/no-host-health-gating.md) - 2026-07-21 — Every open issue carries a `priority:` label — run the H12 audit at session end (#542) — [`process.issue-qualification-audit`](records/process/issue-qualification-audit.md) - 2026-07-21 — Fix onto an unmerged feature branch by branching off it and FF-pushing (#542) — [`process.branch-off-feature-branch`](records/process/branch-off-feature-branch.md) - 2026-07-21 — Gitea's `?milestones=` issue filter silently no-ops on names containing `:` or `+` (#542) — [`ci.gitea-milestone-filter-noop`](records/ci/gitea-milestone-filter-noop.md) - 2026-07-21 — Harden a soon-to-grow feature with a runtime posture, not a hardcoded clamp (#542) — [`process.harden-with-runtime-posture-not-clamp`](records/process/harden-with-runtime-posture-not-clamp.md) - 2026-07-21 — Heavy-render web tests need explicit per-test vitest timeouts on the CI VM (#542) — [`ci.web-test-per-test-timeouts`](records/ci/web-test-per-test-timeouts.md) - 2026-07-21 — Independent cross-model review is mandatory on risky diffs; a skip is a stated, auditable exemption (#542) — [`process.independent-review-rubric`](records/process/independent-review-rubric.md) - 2026-07-21 — Launch Codex cheap workers via `codex exec`, not `spawn_agent` (#542) — [`process.codex-cheap-worker-launch`](records/process/codex-cheap-worker-launch.md) - 2026-07-21 — Live-E2E runs BEFORE the push, and downloads are curled, not browsed (#542) — [`testing.live-e2e-prepush-timing`](records/testing/live-e2e-prepush-timing.md) - 2026-07-21 — Local build/test gate + cold-context review run BEFORE the push, not after (#542) — [`process.local-gate-before-push`](records/process/local-gate-before-push.md) - 2026-07-21 — Never commit or merge inside a worktree you did not create (#542) — [`process.foreign-worktree-plumbing-merge`](records/process/foreign-worktree-plumbing-merge.md) - 2026-07-21 — One worktree, one committing agent (#542) — [`process.one-worktree-one-committing-agent`](records/process/one-worktree-one-committing-agent.md) - 2026-07-21 — Playwright-MCP: curl download endpoints, never open a tab or `window.open` (#542) — [`testing.playwright-mcp-download-and-recovery`](records/testing/playwright-mcp-download-and-recovery.md) - 2026-07-21 — Review disagreement on a gate PR escalates to the frontier judge — and the proposed FIX escalates with it (#542) — [`process.review-disagreement-frontier-judge`](records/process/review-disagreement-frontier-judge.md) - 2026-07-21 — Run `scripts/e2e-local.sh` against a FRESH config dir; a reused one hangs the readiness probe (#542) — [`testing.e2e-local-fresh-config-dir`](records/testing/e2e-local-fresh-config-dir.md) - 2026-07-21 — The PR routine is a fixed sequence: validate locally, then push, then only follow-up commits (#542) — [`process.pr-routine-sequence`](records/process/pr-routine-sequence.md) - 2026-07-21 — The shared tree at /Users/timothy/ersatztv is read-only and tells you nothing about `main` (#542) — [`process.shared-tree-readonly`](records/process/shared-tree-readonly.md) - 2026-07-21 — `cancelled` is not `failure`; a cancelled run is no verdict (#542) — [`ci.cancelled-is-not-a-verdict`](records/ci/cancelled-is-not-a-verdict.md) - 2026-07-25 — E2E cleanup kills only the PIDs it started; never a `pkill -f` pattern (#586) — [`testing.e2e-cleanup-scope-by-pid`](records/testing/e2e-cleanup-scope-by-pid.md) - 2026-07-25 — Name the model tier for every dispatched agent; a PreToolUse gate makes the silent default visible (#583) — [`process.per-agent-model-routing`](records/process/per-agent-model-routing.md)