7.2 KiB
PLAN — manual-push-prose-d3 — REVISED r2 (3 lenses + correctness confirmation)
Contract: .claude/tasks/contracts/2026-10-07-manual-push-prose-d3-1530.md
Context
After D1 and D2 every reader of gitflow.autopush in THIS checkout (lib, emitted hooks, unpushed-guard, push-guard, banner) treats an unparseable value as manual: nothing pushes, and the stop is named. Two caveats remain: (a) onboarded projects keep their committed .githooks/ until a session-start reconcile refreshes them, so a stale per-repo hook can still push on an invalid value — the ahead count tells; (b) the soft_deny backstop names only gitflow.autopush false (settings.json is outside D3; TODO). The skill prose written during run C still says "the lib and hooks still push on an invalid value until run D". Two labels say "COMMIT + PUSH" although the step reads the push state. The release executor trusts the dispatcher's version regex alone.
Checklist
- PRECONDITION (executor's first step):
grep -l -- '--default true gitflow.autopush' lib/gitflow.sh hooks/unpushed-guard.sh hooks/session-start.sh githooks/post-commit githooks/post-merge .githooks/post-commit .githooks/post-mergemust print nothing (D1 + D2 landed); any hit → STATUS: BLOCKED, nothing edited. - skills/capitalize/SKILL.md — line ~346 (5C invalid outcome) becomes TWO lines, both single-line bullets, placed where the one line is (still evaluated first):
- **push mode \invalid`, `ahead` > 0 or unknown** → `merged to develop — : treated as manual push mode by every reader, nothing pushed (origin/develop is commit(s) behind, or unknown). Fix the value by hand, then: ! git push origin develop` (append ` once a remote exists` when `ahead` is unknown).- push mode `invalid`, `ahead` = 0 → `merged to develop — : pushed anyway, likely a stale fail-open hook (a session-start reconcile refreshes a stale .githooks/; commit the refresh) or a manual push. Fix the value by hand.`Line ~379 (STEP 6 invalid closing line) becomes two matching lines:- invalid (merged, ahead > 0 or unknown) → `⚠️ + merged to develop — : treated as manual push mode by every reader, nothing pushed (origin/develop behind). Fix the value by hand, then: ! git push origin develop` (+ ` once a remote exists` when unknown)and- invalid (merged, ahead = 0) → `⚠️ + merged to develop — : pushed anyway, likely a stale fail-open hook (refreshed by the next session-start reconcile; commit the refresh) or a manual push. Fix the value by hand.`. STEP 6 is picked by the 5C result, not evaluated in order, so disambiguate the neighbours: line ~371auto-persisted (5C: finish rc 0 AND `ahead` = 0)→auto-persisted (push mode `auto`, finish rc 0 AND `ahead` = 0); line ~378not on origin (merged, `ahead` unknown)→not on origin (push mode not `invalid`, merged, `ahead` unknown). Recap line ~363:merged, gitflow.autopush invalid ( behind)→merged, autopush invalid, nothing pushed ( behind) | merged, autopush invalid, pushed anyway (stale hook or manual push). Line ~375 (--no-push,branch_ahead= 0): add after the template, as an instruction like the :376 precedent:With push mode `invalid`, replace `(auto-push mode)` with `(: pushed anyway, likely a stale fail-open hook or a manual push; fix the value by hand, commit the .githooks refresh)`.Line ~376 (--no-push,branch_ahead> 0 or unknown): its existingWith push mode `invalid`, append ` gitflow.autopush= is not a boolean: fix it by hand`→With push mode `invalid`, append ` : treated as manual push mode, nothing pushed; fix the value by hand`. No "until run D" text remains; no templated: the verb's stderr line is quoted verbatim (it may say "could not read"). No period right after a! git …` command. - agents/client-handover-writer.md — heading
## STEP 5 — COMMIT + PUSH (only if files changed)→## STEP 5 — COMMIT + PUSH STATE READ (only if files changed). Residual push claims in the same step — the current text WRAPS across lines and carries bold markers; use the Read tool and multi-line old_strings: ~545-546Before any commit or push,⏎confirm this is a gitflow repo:→Before any commit, confirm this is a gitflow repo (the pipeline never pushes):; ~553-554**do NOT commit,⏎do NOT push.**→**do NOT commit (and never push).**; ~555-556Commit/push skipped — no gitflow model in this repo; publish the⏎listed changes manually before deploy.→Commit skipped — no gitflow model in this repo; publish the listed changes by hand before deploy.(re-wrap as the file does). Line ~700 (C2-qualified "mini-commit; push state read, never assumed") stays. Verify with the Grep tool (patternpush), never a Bash grep carrying the push word. - skills/client-handover/SKILL.md — step 4 label
**COMMIT + PUSH**→**COMMIT + PUSH STATE READ**; in the same sentenceotherwise (manual push mode, or a hook push that failed)→otherwise (manual push mode, an invalid gitflow.autopush, or a hook push that failed). - agents/release-executor.md — prep span,
### Inputparagraph: after "never bump it." add on its own line:Format check only, by reading the string (never inside a Bash command): <X.Y.Z> must match ^[0-9]+\.[0-9]+\.[0-9]+$ (literal regex text, single backslashes); anything else → STATUS: BLOCKED, nothing created.(prep only: finish's existing### Preconditionsalready requires therelease/<X.Y.Z>branch that only prep creates). Lines ~80-83:in manual push mode they stay local→in manual push mode, or with an invalid gitflow.autopush, they stay local— keepinvalid gitflow.autopushandby reading the stringunbroken on one physical line each (line-based greps).
Edge cases
- Label rename: repo-wide grep for "COMMIT + PUSH" (skills, agents, lib, hooks, rules, README, USAGE, templates, CLAUDE.global.md, CHANGELOG, docs) → only the two renamed lines; in-file references are by step number.
- "Pushed anyway" diagnosis: after D1, an invalid value with
ahead= 0 can only come from a stale per-repo hook (or a human push); the line says so instead of asserting "nothing pushes". - Doc-sync afterwards owns: CHANGELOG
[Unreleased]three sites ("treated as auto", "for this hook a non-boolean value reads as manual", "still push on it as auto"), SETTINGS Push discipline "still push on it as auto; only push-guard fails closed", with the stale-.githooks/scope note. - TODO (outside D3): settings.json soft_deny names only
gitflow.autopush false— add "or an unparseable value" (restriction only) in a later settings run.
Disposition
- honors BDR-114 (fail-closed everywhere → prose must stop saying otherwise, but never claims more than the facts: the ahead count decides), BDR-100/LRN-113 (label rename with citer grep; precondition grep for D1/D2 before any prose change), LRN-104, LRN-198 (version string checked by reading, never interpolated into a check command), BDR-042 (dispatcher decides the number; the executor only formats-checks).