[NIT] The new §8 Worker Absolute Constraints paragraph is very dense. Consider splitting the final explanatory sentence (starting 'The first two constraints are statically enforced…') into a small sub-list or bullet points to match the visual style of the constraints list above it — this makes it easier to scan which invariant covers which rule.
[NIT] The last sentence of the Issue #157 section ('Regression tests in dispatch.bats statically verify all of these constraints.') runs on from the previous sentence without a line break or paragraph separation, making it slightly harder to read. Minor formatting only.
[NIT] The comment on the Lstat call says 'ModeSymlink can never be set here; this is unreachable' — if it's truly unreachable, the symlink check was removed but the comment is slightly misleading since the Lstat itself is still reached (it's only the symlink mode check that's unreachable). The comment accurately documents the reasoning, but the phrasing 'this is unreachable' could be confused as referring to the Lstat rather than the removed symlink check. A minor clarity issue, not a correctness concern.
[NIT] The sentence 'Regression tests in dispatch.bats verify all of this statically.' is a sentence fragment run-on following the previous sentence without a period before it. Minor prose clarity issue: 'Invariant S10 verifies worker templates contain no close calls and each contains the NEVER-close text. Regression tests...' — this reads fine but the final sentence could be joined or clarified as 'Regression tests in dispatch.bats statically verify all of these constraints.'
[NIT] The InvalidRepo and InvalidPRNumber tests use a linear scan + in-place mutation to override a specific flag value. This is correct but somewhat fragile: if baseSubprocessArgs() ever uses a different quoting style or reorders flags, the scan would still work, but the approach is brittle compared to simply building the slice directly with the desired value. A minor alternative would be to accept that these two tests are special-cases and spell out their args inline (with a comment pointing to baseSubprocessArgs as the template), but the current approach with the !found guard is a reasonable mitigation.
[NIT] The comment 'this is unreachable' on the ModeSymlink dead code path is accurate, but the Lstat call itself remains. Since EvalSymlinks guarantees the path is symlink-free, the fi.Mode()&os.ModeSymlink check (which was removed) was the only code that used this fact. The remaining Lstat is still needed for the size check and existence check, so the code is correct — but the comment 'ModeSymlink can never be set here; this is unreachable' refers to the now-deleted guard. This is fine as written, just slightly confusing phrasing since nothing is actually 'unreachable' in the remaining code — the Lstat itself is very much reached.
[MINOR] S9 is documented as checking 'the dispatch script', but no equivalent S10 (or extension of S8) exists for worker templates. S8 covers 'no merge calls in any worker template', but there is no corresponding invariant for 'no close calls in any worker template'. The new 'Worker Absolute Constraints' section explains the constraint is enforced 'by the template text itself (for workers)', meaning it relies on prose rather than a static check. This is a weaker guarantee than an invariant — a future template edit could silently drop the constraint. Consider whether S8's scope should be expanded, or a new S10 added, to statically verify worker templates contain no close-PR calls.
[NIT] The claim 'All 7 worker templates already contain NEVER close a PR in their ABSOLUTE CONSTRAINTS section from a prior session' is in the PR description but not verifiable from the diff alone. The spec text says 'Every worker template begins with an ⛔ ABSOLUTE CONSTRAINTS section containing these rules' — if this is an invariant worth enforcing, the check-invariants.sh script could grep all worker templates to confirm this, similar to how S8 checks worker templates for merge calls.
[NIT] The flag description string for --doc-map-trusted-ref is quite long for a flag help string. Consider shortening it to fit within a terminal line. This is cosmetic only and has no functional impact.
[NIT] The variable data in ParseDocMapConfigContent is assigned from []byte(content) and then immediately passed to parseDocMapBytes. This is correct and idiomatic, but the intermediate variable data could be inlined as parseDocMapBytes([]byte(content), source) to reduce noise. Minor style only — current code is perfectly fine.