The instance moved 1.25.4 -> 1.27.1 during #743, which left a set of deliberately version-pinned CI claims dated rather than wrong. The population was re-derived from `git ls-files` instead of from the issue's own 9-key list, which found ~21 claim sites across workflows, scripts, tests, docs and records. Re-confirmed unchanged on 1.27.1: * an `if:`-skipped job still reports commit-status `skipped`, a distinct state * `compare/{base}...{head}` still serves no `files` * no agent-side cancel route (POST 404, and live swagger has no cancel path at all) * `review-verdict.yml`'s `branches: [main]` still suppresses the run off a non-main base Re-derived from a constructed corpus rather than a sample, because two arbitrary PRs showed only two of the values: the PR file-status vocabulary is changed/added/renamed/ deleted over 200 PRs. All four were already in the closed allow-list, so that set is now evidenced rather than partly presumed. Newly measured, replacing source-attestation. All three arms ran on throwaway scratch-base protection rules, so `main`'s rule was never touched (its updated_at is unchanged at 2026-08-05): * `block_admin_merge_override: false` lets an admin force_merge past an ABSENT required context (HTTP 200); flipping only that field to `true` refuses the identical call (HTTP 405) - the negative control that makes it attributable * an absent required context BLOCKS, so the merge gate does not fail open when review-verdict.yml never runs * `enable_bypass_allowlist` is NOT a better-targeted substitute: enabled with an empty username list, the admin force_merge still succeeded * trap: the PR API reports `mergeable: true` while that same merge is refused, because the field reflects conflict-freedom and ignores branch protection Left explicitly dated rather than silently refreshed, each with its reason: push-supersession auto-cancel is no longer observable on this repo (no workflow triggers on a non-main push, and main refuses direct pushes), and the scope-enum / reqRepoWriter / write:package-403 items need a scoped PAT rather than a read-only probe. review-verdict.yml carries three more 1.25.4-dated comments and is deliberately untouched here: #763 is in-progress on that file and its paging work overlaps them. Refs: #747 Decisions-Edit: yes Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
9.4 KiB
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 or 1.27.1 (#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)