Skip to content

Latest commit

 

History

History
748 lines (571 loc) · 31.2 KB

File metadata and controls

748 lines (571 loc) · 31.2 KB

NOTE: This is the canonical provider-independent contract. Both provider wrappers must load it in full.

Provider-neutral host abstractions

  • Resolve supporting assets and relative script paths against .claude/skills/repo-sync/; the canonical prose lives here while implementation assets remain with the compatibility launcher.
  • A named skill call means the host's skill-dispatch primitive. An Agent, Explore agent, workflow, or sub-agent means an isolated task/action invocation with fresh context and the requested capability tier. Provider wrappers map these roles to their native APIs.
  • Model tier names in inherited procedures describe capability roles. Resolve them through config/model-tier-map.json; an unavailable required capability returns required_tool_missing rather than weakening a gate.
  • Never expose hidden chain-of-thought. Preserve only decisions, evidence, commands, structured artifacts, and operator-facing rationale required by this contract.

Repo Sync

Bidirectional sync between a plan document and GitHub issues. Creates, updates, closes, and enriches issues so GitHub mirrors the plan's structure and any fresh-context LLM picking up a step has enough context in the issue body to start work.

Principle: optimize for LLM effectiveness, not human-noise reduction

Issue bodies should be substantive. A fresh-context model reading gh issue view #N should understand:

  • What to build (not just a name)
  • Where in the codebase (specific files)
  • How to know it's done (concrete acceptance)
  • What it depends on (prior issues, blocked-by relationships)
  • Build-phase flags (reviewers, isolation, --ui when frontend is touched)
  • Where the canonical design lives (build doc + section anchor)
  • Whether the step can run in parallel with neighbors (declared explicitly, not left for the operator to infer)

Lean bodies (just "What to build" and a footer) tax every future session that picks up that issue. Treat enrichment as a first-class output, not optional polish. Issue count and inbox tidiness are human-experience costs the operator is fine paying — don't optimize for them at the expense of the LLM-context-effectiveness above.

Operator preference (HEAVY) — autonomous + bundled UI + parallel

This skill propagates the operator's strong workflow preference through every issue it writes. Three dials, applied to every step body:

  1. Autonomous build readiness. Step bodies must contain enough acceptance detail (Done when) for /build-step to verify PASS without asking the operator a follow-up. Bodies that force a human ping mid-build are a regression. When enriching, prioritize concrete acceptance over prose.

  2. UI-bundle declaration. If a step's Files touch frontend/, change a /api/... shape consumed by the dashboard, or modify WebSocket payloads, the issue body's Flags (recommended) line MUST include --ui and the Done when MUST reference UI evidence (Playwright screenshot, dashboard smoke, or any project-specific UI/dashboard smoke commands defined in the project's CLAUDE.md). Code-only acceptance on frontend-touching work is the gap repo-sync is here to close — flag any existing issue that violates this and propose enrichment.

  3. Parallelism declared explicitly. If a step has no Depends on and shares no Files with another open step in the same phase, the body MUST note **Parallel-safe with:** #M (and the reciprocal noted on #M too). Sequential is fine, but none — strictly sequential MUST carry a one-line justification (e.g. "Step N+1 imports this module"); a bare "strictly sequential" without a reason is a defect — the parallelism choice must be visible in the issue, not hidden in the operator's head.

These dials are applied during CREATE, ENRICH, and UPDATE — not just on first write. A pre-existing rich body that lacks the UI-bundle declaration on a frontend-touching step still counts as needing ENRICH.

When to use

  • Plan steps were added, removed, or reworded after issues were created
  • Existing issues have lean bodies that need richer context (--enrich)
  • Cutting issues for a new phase from its build doc
  • User says: "sync issues", "update GitHub issues", "enrich step issues", "issues are out of date"

When NOT to use

  • Closing a single issue after a step completes — just gh issue close N
  • Bulk-closing issues from a deleted plan (use gh issue list ... | xargs gh issue close)

Prerequisites

Run the plan pipeline in order. /repo-sync is step 4 of 5:

  1. /plan-init or /plan-feature — produce plan.md.
  2. /plan-review — gap-check before sync.
  3. /plan-wrap — clean-context check before sync.
  4. /repo-sync — mint or update issues from the plan.
  5. /build-phase — execute the steps.

Skipping /plan-review or /plan-wrap before sync is the N+1 rework trap: one plan edit becomes N+1 edits — the plan file plus every step issue body that needs the same fix. /repo-sync mints fresh-context-LLM-targeted issue bodies straight from the plan, so plan-only ambiguities (undefined IDs, unexplained acronyms, lingering TBDs) bake into every issue.

For an autonomous pre-flight that runs the chain unattended, use /plan-expedite --plan <path> — it chains plan-review --autofix → plan-wrap --autofix → repo-sync → session-wrap in one shot.

Canonical workspace-level statement of the chain lives in dev/.claude/rules/plan-and-issue-flow.md § Order.


Arguments

Arg Required Default Description
--plan yes -- Path to plan/build-doc (e.g. documentation/plans/phase-d-build-plan.md)
--phase no inferred Phase identifier (B, D, E, 6, 7, F, G, G.2, 9, etc.) — letters and numbers both supported. Inferred from filename if omitted.
--scope no both umbrella, steps, or both
--enrich no false Update existing-issue bodies if richer content is now in the plan
--dry-run no false Print issue-change preview and exit without applying — for validation before commit
--force no false Proceed despite missing evidence that the plan-review and plan-wrap prerequisite gates ran.

Phase identifier conventions

Phases can be:

  • Numeric: Phase 0, Phase 1, ..., Phase 9 — common for substrate/operational tracks
  • Letter: Phase A, Phase B, Phase D, ..., Phase G — common for capability tracks
  • Sub-phase: Phase G.1, Phase G.2, Phase G.3 — for multi-step phases that fork

Numbering gaps are allowed and intentional (e.g. project skipped Phase C during a merge; project may skip Phase 8 to align with pre-existing issue titles). The skill honors the plan as-written — does NOT try to fill gaps.

Step numbering within a phase uses dot notation in the build doc (e.g. D.1, D.2, 7.1, G.2.1) but issue titles use the friendlier Phase X Step N: form.

Issue title patterns the skill recognizes:

  • Umbrella: Phase X — <name> (e.g. Phase D — Build-order z-statistic)
  • Step: Phase X Step N: <name> (e.g. Phase D Step 1: Audit reward_rules.json)
  • Sub-phase umbrella: Phase X.M: <name> (e.g. Phase G.2: Zerg bot)
  • Sub-phase step: Phase X.M Step N: <name>

Step-detection formats supported in plan docs

The skill scans the plan for any of:

  • ### Step N: <name> — heading style
  • ### Phase X Step N: <name> — explicit phase heading
  • #### Step N: <name> — sub-heading style
  • - **Step N:** <name> — list style
  • | X.N | <description> | — table row in a Scope / Build-steps section

For table-row format, the description is the step title; richer body content must be pulled from explicit per-step subsections OR the doc is flagged as lean (see "Doc richness check").


Flow

Step 0 — Pre-flight: resolve and verify target repo

Before proceeding to issue mutation, verify plan-review and plan-wrap have each been run on the target plan. Accept evidence such as a checkpoint entry or Status: DONE on the corresponding review steps. If evidence for either gate is absent, emit a WARNING naming the missing prerequisite evidence and halt unless the operator supplied the explicit --force flag. Do not silently skip prerequisite gates.

gh resolves the target repo from cwd by walking up to the nearest .git/. The dev/ workspace root is itself a git repo with its own remote (aberson/coding-root), so running gh from dev/ silently lands on aberson/coding-root instead of the intended project subdirectory. Resolve and echo the repo before any mutating call:

cd <absolute-project-dir>
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
DEFAULT_BRANCH=$(gh repo view --json defaultBranchRef -q .defaultBranchRef.name)
echo "Target repo: $REPO (default branch: $DEFAULT_BRANCH)"

Confirm the printed Target repo: matches the intended project. If it does not, stop — the cwd is wrong.

$DEFAULT_BRANCH is the <default-branch> placeholder every body template below interpolates into its ../blob/<default-branch>/ doc links. Resolve it — never assume. GitHub has defaulted new repos to main since 2020, so a hardcoded master 404s every minted build-doc link, and a hardcoded main merely inverts the same defect for a repo that genuinely still uses master. When the build doc lives in a DIFFERENT repo than the issues (a cross-repo plan), resolve that repo's branch instead — gh repo view <owner>/<repo> --json defaultBranchRef -q .defaultBranchRef.name — because the link must resolve against the repo that actually hosts the doc.

Wrong-directory guard: before this gh issue sync, warn if the resolved target project repo != the repo gh resolves from cwd's remote (advisory, never blocks) — per working-directory.md § Wrong-directory guard; reference impl Test-WrongDirGuard.

For every subsequent gh call in the run, pass -R <owner>/<repo> defensively so cwd-resolution cannot drift mid-run:

gh -R aberson/Alpha4Gate issue create ...
gh -R aberson/Alpha4Gate issue list ...

Equivalent fix: cd into the project subdirectory before invoking gh (e.g., cd Alpha4Gate && gh ...). The -R flag is preferred because it survives mid-run cwd changes.

Step 1 — Read the plan and infer phase

Read --plan. If --phase not specified, infer from filename (phase-d-build-plan.mdD; phase-9-build-plan.md9; improve-bot-evolve-plan.md → check # Phase X ... H1 in content).

Extract:

  • Umbrella metadata: title (from # <H1>), goal, prerequisites, effort, kill criterion, validation
  • Step list: every step matching one of the supported formats

For each step, capture from per-step subsections if present:

  • Problem / What to build
  • Files / Files to modify / Files touched
  • Existing context
  • Done when / Acceptance
  • Flags (build-step flags like --reviewers code --isolation worktree)
  • Depends on
  • Produces

If steps are table-only (sparse), flag this and run the richness check (below).

Step 2 — Doc richness check (the LLM-effectiveness gate)

For each step, count populated rich-fields out of 6: {Files, Done when, Flags, Existing context, Produces, Depends on}.

  • Rich step: ≥ 3 fields populated
  • Lean step: ≤ 2 fields populated

If >50% of steps are lean:

WARNING: <plan> has N of M lean steps (only title + description).

Issues created from lean steps will be lean too. Every fresh-context
LLM session that opens those issues will need to drill into the build
doc or source code for context the issue body should have.

Per the LLM-effectiveness principle (memory:
feedback_optimize_for_llm_over_human_noise.md), the recommendation is:

  1. Enrich the build doc first with per-step Files / Done when /
     Flags / Existing context sections.
  2. Then re-run this skill (or run with --enrich for an existing
     issue set).

Continuing — issue bodies will reflect the plan's current shape.
Operator can re-run /repo-sync after enriching the plan if higher-
fidelity issues are needed.

Surfacing this cost is mandatory; the warning is a printed observability note that proceeds automatically without prompting. The operator can re-run /repo-sync after enriching the plan when richer issues are needed — but no halt mid-sync.

Step 3 — Fetch existing GitHub issues

# jq requires POSIX classes — no \d / \w / \s / \. (see Common mistakes § Perl-style regex escapes)
gh issue list --state all --limit 200 --json number,title,body,state \
  --jq '.[] | select(.title | test("^Phase [A-Z0-9]+([.][0-9]+)?( Step [0-9]+)?:|^Phase [A-Z0-9]+([.][0-9]+)? — "))'

This regex matches both umbrella titles (Phase X — ...) and step titles (Phase X Step N: ...) across numeric, letter, and sub-phase numbering. Falls through to the legacy (Phase \d+ )?Step \d+: if the new pattern returns nothing (back-compat).

3.1 — Cross-plan collision check

When a repo holds issues from multiple plans, step keys (Phase X Step N) collide and a new plan's step may match a stale issue belonging to an unrelated, possibly closed prior plan.

The disambiguator is the body footer /repo-sync writes. There are TWO footer shapes — both encode the source-plan path and the parser must recognize both. In the rendered issue body the plan path is a markdown link (square-bracket label wrapping the path, parenthesis URL ../blob/<default-branch>/ plus that same path) so the path is clickable from the GitHub issue — never a code-spanned path followed by a parenthetical "linked to" phrase.

  • Create path (see Body template — step): *Synced from by /repo-sync at <git-short-sha>* (with <plan> rendered as the markdown link described above).
  • Enrich / update path (see Update / enrich): *Enriched by /repo-sync from <build-doc-path> @ <git-short-sha>*

Long-lived issues that have been re-synced carry the second shape; the parser must match both or every previously enriched issue falls through as "footer missing" — exactly the issues most likely to be cross-plan-colliding.

Regex shapes the parser must match:

  • Create: Synced from \[(.*?)\]
  • Enrich: Enriched by /repo-sync from (.+?)( @ |$)

Algorithm: for each issue that matched a plan step in the Step 3 fetch above, parse the footer's plan path from the issue body — from EITHER Synced from [<plan>] OR Enriched by /repo-sync from <build-doc-path>. If that plan path differs from the current --plan argument's path, classify the match as a CROSS-PLAN COLLISION (the issue belongs to a different plan; the step key collision is incidental).

Action: emit a WARN: cross-plan collision line in the Step 5 preview output for each collision. No halt — autonomous default still executes; the operator sees the warning in the preview but the run proceeds without prompting. Collided issues are excluded from ENRICH / REOPEN candidate lists (treat as stale w.r.t. this plan).

Example warning line in the preview:

WARN: cross-plan collision — issue #123 "Phase D Step 3: foo"
  plan footer: documentation/old-plan.md
  --plan arg:  docs/archived-plans/repo-sync-improvements-plan.md
  classify as: stale (do not ENRICH, do not REOPEN)

Footer-absent issues (legacy or hand-authored) cannot be classified by this check; fall through to the existing title-prefix match behavior. Add (footer missing) to the preview note so the operator knows the check could not run on that issue.

Always-surface contract. The rendered Step 3.1 output MUST state the two recognized footer shapes explicitly — even when no existing issues were matched in Step 3. This makes the parser's footer-aware classification visible and auditable in every run, not only runs that exercise it.

Required Step 3.1 header line in the rendered output:

Footer shapes recognized:
  Create:  Synced from [<plan>](...)
  Enrich:  Enriched by /repo-sync from <build-doc-path> @ <sha>

When no issues were matched, follow with (no existing issues to classify). When issues exist, list each with its footer plan path or (footer missing) per the algorithm above. Either way, neither footer shape is omitted from the output, so enriched-path issues are never silently treated as footer missing.

Step 4 — Match and diff

Match plan entries to existing issues by title prefix:

  • Umbrella: Phase X — <anything> matches plan's H1 phase
  • Step: Phase X Step N: <anything> matches plan step X.N or Step N within the phase

Classify into buckets:

Bucket Condition Default action
CREATE umbrella Plan has phase, no umbrella issue Create with full body
CREATE step Plan step has no matching issue Create with rich body
ENRICH Issue exists, body is lean (≤2 sections), plan now has richer content Update body (auto if --enrich OR if plan has clear new fields)
UPDATE Issue exists but title or body changed substantively Update
CLOSE Issue exists, plan step removed Close with comment
NO-OP Issue exists, body is rich, no plan change Skip

Step 5 — Preview

Print all proposed changes grouped by phase:

repo-sync: documentation/plans/phase-d-build-plan.md (Phase D)

  Build doc richness: 3/8 steps rich, 5/8 lean

  CREATE umbrella  Phase D — Build-order z-statistic (reward refactor)
  CREATE step      Phase D Step 1: Audit reward_rules.json (rich body)
  CREATE step      Phase D Step 2: Define z schema (rich body)
  CREATE step      Phase D Step 3: build_order_reward.py (lean — Files missing)
  ENRICH           Phase D Step 5 (#168) — body lacks Done when + Files
  UPDATE           Phase D Step 7 (#170) — title changed
  CLOSE            (none)
  NO-OP            (none)

If --dry-run was specified, stop here and print:

Dry-run complete. No changes applied.

Otherwise, proceed directly to Step 6 — print Applying changes now... and execute. Do not prompt for confirmation. The preview is the operator's read-out, not a halt point; autonomous orchestration (/build-phase, /plan-expedite) depends on this.

--dry-run flag

When /repo-sync --dry-run is invoked, the preview above is printed but no changes are applied. The skill exits cleanly with the message Dry-run complete. No changes applied. Use this to validate plan→issue mapping before committing to a sync.

Step 6 — Execute (one tool call per gh action)

Process in this order:

  1. Umbrella issues first (so step issues can reference them)
  2. Step issue creates
  3. Step issue enrichments + updates
  4. Closes last

Each gh issue create/edit/close is its own Bash tool invocation, OR a loop in one Bash with explicit per-iteration error handling. Do NOT batch with && — one failure must not break the chain.

Body delivery — always use --body-file

All gh issue create/edit calls in this skill MUST deliver bodies via --body-file <path>, never inline --body "$(cat <<EOF ... EOF)". The inline heredoc form silently truncates or parser-tangles bodies that contain nested quote levels (code spans, quoted text, tables) — see dev/.claude/rules/windows-shell.md § gh / jq.

Use a Windows-safe temp path:

  • Bash: $LOCALAPPDATA/Temp/ (e.g. C:/Users/<user>/AppData/Local/Temp/)
  • PowerShell: $env:TEMP

POSIX /tmp/ is invisible to gh.exe on Windows (different temp roots).

The Create / Update / Close templates below all assume this delivery method.

Body template — umbrella

**Umbrella:** #<master-plan-umbrella-issue-if-exists>
**Blocked by:** Phase <prerequisite-phase-if-any>
**Build doc:** `<build-doc-path>` (linked to `../blob/<default-branch>/<build-doc-path>`)
**Track:** <track-from-plan>

## Goal

<goal paragraph from plan>

## Work (N steps)

- [ ] **#<step-1-issue>** Step 1: <name>
- [ ] **#<step-2-issue>** Step 2: <name>
...

(Step issue numbers populated after step creates — re-edit umbrella in Step 7.)

## Acceptance

<validation / acceptance from plan>

## Effort

<effort estimate from plan>

## Kill criterion

<kill criterion from plan>

Body template — step

## Build step N of M — Phase <X> (umbrella #<umbrella-issue>)

**Build doc:** `<build-doc-path>` (linked to `../blob/<default-branch>/<build-doc-path>`) §<section> Step <X.N>

### What to build
<full description from plan, not abbreviated>

### Existing context
<from plan's "Existing context" section if present, scoped to this step>
<otherwise: omit (will be flagged in summary)>

### Files to modify/create
<file list from plan if present>
<otherwise: omit (flagged in summary)>

### Done when
<acceptance from plan, specific not generic>
<otherwise: "All tests green, mypy strict + ruff clean. See umbrella for phase-level gate.">

### Flags (recommended)
<build-step flags from plan if present, e.g. `--reviewers code --isolation worktree`>
<if step touches frontend/, /api/ shapes, or WebSocket payloads: ALSO include `--ui`>

### Depends on
<previous step issue # if known, or "none">

### Parallel-safe with
<list any open step issue # in the same phase that shares no Files and no
Depends-on with this step. When no such peers exist, write
`none — strictly sequential (<one-line justification>)`. The justification
is REQUIRED — bare "strictly sequential" without a reason hides the
choice from the operator. Acceptable justifications: "Step N+1 imports
this module", "shares <Files entry> with #X", "soak gate after Step N
must finish first". When the plan is lean (no Depends on, no Files
declared), default to listing peers as parallel-safe rather than
collapsing to strictly sequential.>

### Produces
<list from plan if present>

### Operator workflow notes (autonomous + UI-bundle + parallel)
- This step is intended to run end-to-end via `/build-step` without
  mid-iteration check-ins; the `Done when` above is the verification gate.
- If `--ui` is in the Flags line above, UI evidence (Playwright screenshot,
  or any project-specific UI/dashboard smoke commands defined in the
  project's `CLAUDE.md`) is part of acceptance, not a follow-up.
- Parallel-safe pairs above can be dispatched in parallel worktrees by
  `/build-phase`.

---
*Synced from `<plan>` (linked to `../blob/<default-branch>/<plan>`) by /repo-sync at <git-short-sha>*

The footer with the source path + SHA helps a future LLM verify whether the issue body is current vs the build doc.

Sections without source content can be omitted, but **issues missing

2 of {Existing context, Files, Done when, Flags, Produces} are flagged in the summary** as candidates for follow-up enrichment.

Update / enrich

# Windows-safe temp path; POSIX /tmp/ is invisible to gh.exe.
BODY_FILE="$LOCALAPPDATA/Temp/repo-sync-issue-$NUMBER.md"
cat > "$BODY_FILE" << 'BODYEOF'
<full new body following template>

---
*Enriched by /repo-sync from <build-doc-path> @ <git-short-sha>*
BODYEOF
gh issue edit <NUMBER> --title "<title>" --body-file "$BODY_FILE"
rm "$BODY_FILE"

Close

gh issue close <NUMBER> --comment "Closed by /repo-sync — step removed from plan."

Step 7 — Re-edit umbrellas with step references

After step issues are created, edit each phase's umbrella issue to include the Work checklist with actual issue numbers:

## Work (N steps)

- [ ] **#164** Step 1: Audit reward_rules.json
- [ ] **#165** Step 2: Define z schema
...

This creates bidirectional cross-refs that an LLM can follow either direction. Without this, the umbrella has stale <step-1-issue> placeholders or a generic (steps will be cut by /repo-sync) note, which forces the LLM to do a separate gh issue list to find them.

Step 8 — Report

The final line of the report MUST surface this skill's plan-pipeline position — step 4 of 5: after /plan-review + /plan-wrap, before /build-phase — so the operator and any fresh-context downstream LLM see at a glance what runs next. The breadcrumb is non-optional.

repo-sync complete for Phase D (umbrella #114)
Plan pipeline: /plan-review + /plan-wrap → /repo-sync (step 4 of 5) → /build-phase

  Created: 1 umbrella, 8 step issues (#164–#171)
  Enriched: 0
  Updated: 0
  Closed:  0

  Body richness: 3/8 issues fully rich; 5/8 missing Files/Existing-context
  Cross-refs: umbrella #114 updated with step issue links

  Recommendation: build-doc step richness was lean (5/8). Consider
  enriching documentation/plans/phase-d-build-plan.md with explicit
  per-step Files / Done when / Existing context sections, then
  re-run with --enrich to bring issues to richer state.

The /build-phase next-step runs in the project repo (the Step 0 target), so name it: Next: /build-phase --plan <plan> — run in <absolute-project-dir>.

Next-step commands name their target directory, and the proactive project-switch message fires on a cwd≠project mismatch with no pin, per transition-directory-contract.md.

If new issues were created, the operator (or the orchestrator) backfills the plan's **Issue:** lines so /build-phase can post progress updates — e.g., via the pattern below. The skill itself does not back-propagate; surfacing the pattern is enough for the operator to run once after sync.

Copy-paste bulk-fill snippet (Python). Adapt the ISSUE_MAP from the sync output's "Created" / "Enriched" mapping:

# Backfill **Issue:** #N lines after /repo-sync.
# Save the sync output's "Created" or "Enriched" mapping as
# {step_number: issue_number}, e.g.:
ISSUE_MAP = {
    1: 164,   # Step 1 -> issue #164
    2: 165,
    # ...
}

import re, pathlib
# REPLACE <plan-file> with your plan's actual filename,
# e.g. "documentation/phase-rs-plan.md".
plan = pathlib.Path("documentation/<plan-file>")
text = plan.read_text(encoding="utf-8")
for step_n, issue_n in ISSUE_MAP.items():
    # Match Step N heading, then the immediately-following
    # **Issue:** line (which may be #N, TBD, or empty).
    # No re.DOTALL: `.` does not match newlines, so `.*?\n`
    # stays within a single line and the bullet-eater group
    # matches only consecutive single-line bullets. If a step
    # is missing its **Issue:** bullet entirely, the pattern
    # fails to match for that step and the script safely skips
    # it (no cross-step contamination).
    # The `(?:- )?` makes the list-bullet prefix OPTIONAL: plans
    # use BOTH `- **Issue:**` and bare `**Issue:**` styles, and a
    # bullet-only pattern silently substitutes NOTHING on a
    # bare-style plan (re.subn count=0 looks like success).
    pattern = (
        rf"(### Step {step_n}:.*?\n(?:(?:- )?\*\*[^*]+\*\*.*?\n)*?"
        rf"(?:- )?\*\*Issue:\*\* )(#\d+|TBD|)"
    )
    text = re.sub(pattern, rf"\g<1>#{issue_n}", text)
plan.write_text(text, encoding="utf-8")

Verification — after a fully-populated backfill, the following returns empty (no remaining TBD or blank **Issue:** values). REPLACE <plan-file> with your plan's actual filename:

grep -nE "Issue:\*\*\s*(TBD\s*$|#\s*$|$)" documentation/<plan-file>

This pattern is one instance of the broader bulk-placeholder-fill discipline (see feedback_bulk_placeholder_fills.md). Background and rationale in investigation docs/investigations/skill-deep-dives/repo-sync/03-issue-blank-lines-kill-build-phase.md.


Matching rules (extended)

Issue matching is prefix-based on the step key. The skill normalizes:

  • Whitespace
  • Phase notation: Phase DPhase D (no normalization across letter/digit; B != 2; D != 4)
  • Sub-phase: Phase G.2 Step 1 matches plan G.2.1 or Step 1 within phase G.2

Manually renamed issue titles still match as long as the step prefix (Phase X Step N or Phase X.M Step N) is preserved.


Edge cases

  • Cross-plan step-key collision: Step keys collide when a repo holds issues from multiple plans (Phase D Step 3 exists in plan A and plan B). The Step 3.1 check (see Flow) flags these via the body footer's plan path. Workaround for new plans that share step keys with closed prior plans: bypass /repo-sync for the new plan and create issues manually with namespaced titles (<feature> — Phase X Step N: <name>); those manual issues will not be re-matched by future runs. See investigation docs/investigations/skill-deep-dives/repo-sync/01-step-key-collision.md.
  • Closed issue, step still in plan: Log it as an informational note in the sync report and skip mutation (do not reopen, do not prompt). The operator can reopen manually if needed.
  • Multiple issues match same step key: Warn and skip — user must resolve manually.
  • Plan has no umbrella H1, just steps: Skip umbrella creation; only step issues.
  • No steps found: Error: No steps found in <path>. Expected "### Step N:", "### Phase X Step N:", or "| X.N | ... |" table row.
  • No GitHub repo: See Step 0 — Pre-flight. The resolve command halts early if no repo is found.
  • Numbering gaps: If plan jumps from Phase 7 to Phase 9 (intentional), don't try to create Phase 8. Honor the plan as written.
  • Existing umbrella, plan adds new steps: Create new step issues + re-edit umbrella to add their links.
  • Step issue exists but lean, build doc still lean: ENRICH would be a no-op. Recommend doc enrichment in summary; do not edit issue.

Common mistakes

Batching gh calls in one shell command

  • Fix: One gh issue create/edit/close per call, separate Bash tool invocations OR a loop in one Bash with explicit per-iteration error handling.

Halting mid-sync for confirmation

  • Fix: Preview-then-execute is the default; no (y/n) prompt. Operators who want preview-only behavior pass --dry-run. Autonomous orchestrators (/build-phase, /plan-expedite) depend on this — a mid-sync halt breaks them.

Matching by issue number instead of title prefix

  • Fix: Issue numbers change. Always match by the step-key prefix in the title.

Using Perl-style regex escapes in --jq filters

  • Fix: jq's regex engine does NOT accept \d, \w, \s, \. (and most other Perl-style shorthand). It silently rejects the filter or returns empty matches — failing the classification, which then surfaces as duplicate-issue CREATEs in Step 5 preview. Use POSIX classes or literal character sets:

    Avoid Use
    \d [0-9]
    \w [a-zA-Z0-9_]
    \s [ \t\n\r] (POSIX whitespace; or the named class with single-bracket pairs the engine supports)
    \. [.]

    Prefer regex-free forms when the prefix is fixed: startswith("Phase D") beats test("^Phase D") and sidesteps the escape limit entirely.

    Reference: feedback_jq_regex_escape_limits.md and investigation docs/investigations/skill-deep-dives/repo-sync/13-jq-regex-escaping.md. PowerShell-specific quoting issues for gh -q are documented in dev/.claude/rules/windows-shell.md § gh / jq.

Lean bodies on creation

  • Fix: Run the doc richness check first. If steps are lean, propose enriching the build doc before creating issues. Don't normalize lean issues as the steady state.

Forgetting umbrella back-references

  • Fix: After creating step issues, edit the umbrella to include the Work checklist with issue numbers. Bidirectional links matter.

Ignoring sub-phase notation

  • Fix: Phase G.2 is its own phase, not "Phase G". Match titles accordingly.

Skipping the doc-richness warning

  • Fix: A lean issue taxes future LLM sessions every time someone opens it. Surface this cost explicitly; default to enriching the doc first.

Treating issue creation as one-shot

  • Fix: --enrich exists because issues drift behind build docs over time. Re-run the skill after each plan revision.