Finalize-phase project-local step that resolves the PR-PENDING era-stamp sentinel in audit.py (and its test mirror) to the real PR number in lock-step, committing and pushing the correction before the merge gate
Resources
1Install
npx skillscat add cuioss/plan-marshall/finalize-step-era-stamp-fill Install via the SkillsCat registry.
Finalize Step — Era-Stamp Fill (project-local)
Project-local executor for project:finalize-step-era-stamp-fill. Resolves thePR-PENDING era-stamp sentinel in the audit-archived-plan-retrospectivesCHECK_ERA map to this plan's real PR number, rewriting audit.py and itstest_audit.py mirror in lock-step and pushing the correction onto the feature
branch before the merge gate so it rides the PR.
This step is project-local (like project:finalize-step-sync-plugin-cache)
because the CHECK_ERA map is a meta-project-only artifact. Consumer projects have
no audit.py, so they never get this step seeded.
mutates_source: true — this step edits source at runtime and pushes it. It is the
concrete reference implementation of the general pre-merge source-edit contract in
`marketplace/bundles/plan-marshall/skills/phase-6-finalize/standards/source-edit-pushability.md`:
a finalize step that edits source MUST run before the branch is merged so the edit
is pushable and covered by CI.
Why PR-PENDING (the guessed-number defect it fixes)
A roadmap plan that reworks a check's mechanics stamps that check's CHECK_ERA
boundary to its OWN PR number — but the PR number is not known until create-pr
runs at finalize. The prior fragile convention was a prose instruction to hand-edit
the number after merge, which is unpushable on main and was silently reverted or
guessed — the guessed-PR-number / post-merge-unpushable era-stamp defect. ThePR-PENDING sentinel is a
provably-invalid PR token: this step resolves it deterministically from the real{pr_number} the dispatcher already threads to finalize steps, and pushes the
correction pre-merge so it rides the PR and is CI-covered.
HEAD-dependency
head_dependent: true — this step's done record asserts a property of tracked source: thataudit.py and its test_audit.py mirror carry no unresolved PR-PENDING sentinel. That is a
verdict over the tree, not a record of an action performed, so it goes stale exactly the way the
governing discriminator predicts — would this verdict change if HEAD changed? Yes: a loop-back
commit landing after this step recorded done can introduce or restore a PR-PENDING token, and the
standing record then lets the sentinel ship unresolved into main — precisely the guessed-PR-number
defect this step exists to prevent. The skipped: true no-op path is the sharpest case, because it
records done while having changed nothing.
The declaration IS the membership marker the dispatcher's re-entry check reads (see
ext-point-finalize-step.md
§ "Implementor Frontmatter"). Re-firing is safe and cheap: the fill is a clean no-op when no sentinel
is present. Capture git rev-parse HEAD immediately before the terminal mark-step-done call and
forward it via --head-at-completion {sha} on the done outcome (Step 4).
Ordering
default:create-pr (20) →
project:finalize-step-era-stamp-fill (21) →
default:ci-verify (22) →
… →
default:branch-cleanup (70, MERGE)order: 21 places this step immediately after create-pr (so {pr_number} is
available) and before ci-verify (so the pushed correction is covered by the CI
run and merges with the branch).
Inputs
{plan_id}— required. Used for themark-step-donecall (Step 4); not passed
to theera_stamp_fill.pyexecutor itself (mirrorsfinalize-step-deploy-target
andfinalize-step-sync-plugin-cache, whose backing scripts likewise take no--plan-id).{pr_number}— required. The real PR number, threaded to finalize steps by the
dispatcher (as it is forci-verify). AcceptsNNNor#NNN.{worktree_path}— the feature-branch worktree root theaudit.py+ test mirror
are resolved against. Under the cwd-pinned model this is the current worktree;
pass.when cwd is already the worktree.
Execution
Inline-only — this step does NOT delegate to a Task agent. The fill is a fast,
deterministic Python script. It is invoked directly (not through the executor)
because it runs at order 21, before the finalize executor-regeneration step (order
85) would add its mapping — mirroring how finalize-step-sync-plugin-cache invokessync.py directly.
1. Invoke the fill executor
python3 .claude/skills/finalize-step-era-stamp-fill/scripts/era_stamp_fill.py run \
--pr-number {pr_number} --worktree-path {worktree_path}The script returns a flat TOON document. On the status: success path it carriesfilled_count, skipped (true | false), and the normalized pr_number
(#NNN); on the status: error path it carries only status and a message
(the filled_count / skipped / pr_number fields are omitted). See the Step 2
table below for the per-outcome field set. It rewrites "PR-PENDING" →"#{pr_number}" in both audit.py and test_audit.py in lock-step; it matches
only the double-quoted map-value form, so prose mentions and an already-resolved
concrete "#NNN" are never touched.
2. Parse the result
| Field | Meaning |
|---|---|
status: success, skipped: true |
No PR-PENDING token present — clean no-op. Record outcome=done; SKIP the commit/push (Step 3). |
status: success, skipped: false |
The sentinel was resolved in filled_count places across the two files. Proceed to commit + push (Step 3). |
status: error |
Bad pr-number or a missing target file. Record outcome=failed and surface message. |
3. Commit and push the correction (only when skipped: false)
The correction MUST land on the feature branch before the merge gate. Commit the two
edited files and push to the branch's upstream (the same push seam the push step
uses):
git -C {worktree_path} add .claude/skills/audit-archived-plan-retrospectives/scripts/audit.py test/plan-marshall/audit-archived-plan-retrospectives/test_audit.pygit -C {worktree_path} commit -F {commit_message_file}Compose the commit message to a temp file under .plan/temp/ with the Write tool
first (multi-line messages never go through a shell argument); a conventional
subject such as chore(audit): resolve PR-PENDING era stamp to #{pr_number} is
appropriate.
git -C {worktree_path} push4. Mark step complete
On the done outcome, resolve the worktree HEAD SHA immediately before the mark-step-done call so
the dispatcher can detect a stale record after a later loop-back commit re-introduces a sentinel
(see § HEAD-dependency). Both skipped: true and skipped: false take this path:
git -C {worktree_path} rev-parse HEADCapture stdout as {sha} and forward it via --head-at-completion:
python3 .plan/execute-script.py plan-marshall:manage-status:manage-status mark-step-done \
--plan-id {plan_id} --phase 6-finalize \
--step project:finalize-step-era-stamp-fill \
--outcome done \
--display-detail "{display_detail}" \
--head-at-completion {sha}On the failed outcome, omit --head-at-completion — the dispatcher retries failed records on
re-entry regardless of HEAD, so the SHA carries no decision value:
python3 .plan/execute-script.py plan-marshall:manage-status:manage-status mark-step-done \
--plan-id {plan_id} --phase 6-finalize \
--step project:finalize-step-era-stamp-fill \
--outcome failed \
--display-detail "{display_detail}"{display_detail} shapes:
skipped: true→"no PR-PENDING sentinel — nothing to fill".skipped: false→"resolved PR-PENDING to #{pr_number} ({filled_count} sites), pushed pre-merge".status: error→ surface the script'smessageverbatim.
Error Handling
| Scenario | Action |
|---|---|
No PR-PENDING token (skipped: true) |
Clean no-op — mark-step-done --outcome done --head-at-completion {sha} so the phase_steps_complete handshake counts the step and a later loop-back commit that re-introduces a sentinel re-fires it |
status: error (bad pr-number / missing file) |
mark-step-done --outcome failed surfacing the script message; the sentinel remains for an operator to resolve |
git push fails |
Record outcome=failed and surface the push failure — the correction must ride the PR, so a failed push is a real finalize failure, not a silent skip |
Canonical invocations
The canonical argparse surface for the backing executor era_stamp_fill.py.
era_stamp_fill — run
python3 .claude/skills/finalize-step-era-stamp-fill/scripts/era_stamp_fill.py run \
--pr-number PR_NUMBER [--worktree-path WORKTREE_PATH]Related
- marketplace/bundles/plan-marshall/skills/phase-6-finalize/standards/source-edit-pushability.md — the general pre-merge source-edit contract this step is the reference implementation of
- .claude/skills/finalize-step-sync-plugin-cache/SKILL.md — sibling project-local inline
script-executorfinalize step - .claude/skills/audit-archived-plan-retrospectives/scripts/audit.py — the
CHECK_ERAmap whosePR-PENDINGsentinel this step resolves - marketplace/bundles/plan-marshall/skills/phase-6-finalize/SKILL.md — finalize phase that invokes this step