Skip to content

chore: update pull request - #7

Merged
pruge merged 2 commits into
mainfrom
fm/ufm-sync-mode-t01
Aug 24, 2026
Merged

chore: update pull request#7
pruge merged 2 commits into
mainfrom
fm/ufm-sync-mode-t01

Conversation

@pruge

@pruge pruge commented Aug 24, 2026

Copy link
Copy Markdown
Owner

Intent

Extend the /updatefirstmate skill at .claude/skills/updatefirstmate/SKILL.md (same file as .agents/skills/updatefirstmate/SKILL.md via symlink) with a new pull-only upstream-sync mode. Context: pruge/firstmate is a downstream of the true upstream kunchenguid/firstmate; our main carries local commits (the planning-family PRs) while upstream evolves daily, so syncing means merging upstream/main into our main through the no-mistakes validated gate and then running the existing local-refresh flow (bin/fm-update.sh). The current skill only knows fast-forward pulls from origin. Required changes: (1) Frontmatter description must also say the skill performs pull-only upstream sync from kunchenguid/firstmate when the captain says 'sync upstream' (or asks to bring in upstream commits). (2) A new section titled '## Upstream sync (kunchenguid/firstmate -> pruge/firstmate)' placed before '## Safety' containing this procedure: preconditions are that the captain invoked the sync, this repo has no uncommitted tracked changes, and in-flight feature PRs are preferably landed or rebased first so conflicts resolve once; ensure the upstream remote exists (git remote add upstream https://github.com/kunchenguid/firstmate.git) and git fetch upstream main; quantify divergence with git rev-list --left-right --count main...upstream/main and report it; create branch git switch -c sync/upstream-; git merge upstream/main resolving conflicts under the UNION policy which keeps every downstream addition (planning-family skills, their AGENTS.md/docs references, documentation-audiences entries) AND takes upstream's newer machinery everywhere else, preferring upstream where both edited the same lines unless doing so erases a planning-family reference, never deleting downstream-only files; validate locally with bin/fm-lint.sh then full bin/fm-test-run.sh with green required before push; push THROUGH THE GATE with git push no-mistakes sync/upstream- so the pipeline validates independently and opens the PR with its body signature; the captain holds merge authority and merges with a MERGE COMMIT (--merge), never squash, because squashing would orphan upstream ancestry and break future syncs; after landing run bin/fm-update.sh (the existing refresh flow) so every running home fast-forwards onto synced main, re-reads AGENTS.md when told, and nudges secondmates. (3) The Safety section gains a line that upstream is pull-only: nothing is ever pushed to kunchenguid/firstmate. Constraints: keep the existing origin fast-forward flow untouched; style matches the file's voice with one sentence per line and plain dash. Acceptance criteria: description mentions the upstream sync trigger; the new section contains all nine procedure steps plus the pull-only safety line; existing sections unmodified beyond the description.

What Changed

Final changed paths and statuses:

M	.agents/skills/updatefirstmate/SKILL.md
M	AGENTS.md
M	README.md

Risk Assessment

✅ Low: The change is purely additive skill documentation that satisfies every required acceptance criterion verbatim, leaves existing behavior untouched, and carries only a minor informational clarity gap.

Testing

Validated the docs-only skill change by diffing base vs target to prove existing sections were unmodified beyond the description, confirming the symlinked .claude/.agents views match, parsing the frontmatter as YAML to assert the upstream-sync trigger wording, running a focused 24-assertion acceptance verifier against the delivered SKILL.md text (the file itself is the agent-consumed interface), and exercising the real documentation-audience consumer plus its regression test — all green, with output captured as evidence.

Evidence: Focused acceptance-criteria verification of the upstream-sync skill section (24/24 pass)

Source: Focused acceptance-criteria verification of the upstream-sync skill section (24/24 pass)

PASS: frontmatter parses as valid YAML with name updatefirstmate
PASS: new section has exact required title
PASS: new section placed before ## Safety
PASS: new section contains exactly nine numbered procedure steps
PASS: step 2: upstream remote add command
PASS: step 2: fetch upstream main
PASS: step 3: divergence quantification command
PASS: step 4: dated sync branch command
PASS: step 5: merge upstream/main
PASS: step 5: UNION conflict policy named
PASS: step 5: keeps planning-family skills
PASS: step 5: keeps documentation-audiences entries
PASS: step 5: never delete downstream-only files
PASS: step 5: prefer-upstream carve-out
PASS: step 6: local lint validation
PASS: step 6: local full test validation
PASS: step 7: push through the gate only
PASS: step 8: merge-commit authority
PASS: step 8: squash forbidden
PASS: step 8: squash rationale recorded
PASS: step 9: post-landing refresh flow
PASS: step 9: refresh outcomes stated
PASS: Safety: pull-only line present
PASS: Safety: nothing pushed to upstream

result: 24 passed, 0 failed
Evidence: Reusable acceptance verifier script for the updatefirstmate upstream-sync contract

Source: Reusable acceptance verifier script for the updatefirstmate upstream-sync contract

#!/usr/bin/env bash
# Focused acceptance-criteria verification for the updatefirstmate upstream-sync
# skill change. The SKILL.md file IS the delivered interface: the agent harness
# loads this exact text as the skill's trigger description and procedure body.
set -u
ROOT="${1:?usage: verify-upstream-sync-skill.sh <repo-root>}"
FILE="$ROOT/.agents/skills/updatefirstmate/SKILL.md"
pass=0; fail=0
ok()   { pass=$((pass+1)); echo "PASS: $1"; }
bad()  { fail=$((fail+1)); echo "FAIL: $1"; }
has()  { if grep -qF -- "$2" "$1"; then ok "$3"; else bad "$3 (missing: $2)"; fi; }

python3 - "$FILE" <<'PY' && ok "frontmatter parses as valid YAML with name updatefirstmate" || bad "frontmatter YAML"
import re, sys, yaml
text = open(sys.argv[1]).read()
m = re.match(r'^---\n(.*?)\n---\n', text, re.S)
data = yaml.safe_load(m.group(1))
assert data['name'] == 'updatefirstmate'
desc = data['description']
assert 'pull-only upstream sync' in desc
assert '`kunchenguid/firstmate`' in desc
assert '"sync upstream"' in desc
assert 'bring in upstream commits' in desc
PY

has "$FILE" '## Upstream sync (kunchenguid/firstmate -> pruge/firstmate)' "new section has exact required title"

python3 - "$FILE" <<'PY' && ok "new section placed before ## Safety" || bad "section placement before ## Safety"
import re, sys
text = open(sys.argv[1]).read()
assert text.index('## Upstream sync (kunchenguid/firstmate -> pruge/firstmate)') < text.index('\n## Safety\n')
PY

# Nine numbered procedure steps inside the new section.
python3 - "$FILE" <<'PY' && ok "new section contains exactly nine numbered procedure steps" || bad "nine numbered steps"
import re, sys
text = open(sys.argv[1]).read()
sec = text.split('## Upstream sync (kunchenguid/firstmate -> pruge/firstmate)')[1].split('\n## Safety')[0]
steps = re.findall(r'^(\d+)\. \*\*', sec, re.M)
assert [int(n) for n in steps] == list(range(1, 10)), steps
PY

has "$FILE" 'git remote add upstream https://github.com/kunchenguid/firstmate.git' "step 2: upstream remote add command"
has "$FILE" 'git fetch upstream main'                                              "step 2: fetch upstream main"
has "$FILE" 'git rev-list --left-right --count main...upstream/main'              "step 3: divergence quantification command"
has "$FILE" 'git switch -c sync/upstream-<YYYY-MM-DD>'                            "step 4: dated sync branch command"
has "$FILE" 'git merge upstream/main'                                             "step 5: merge upstream/main"
has "$FILE" 'UNION policy'                                                        "step 5: UNION conflict policy named"
has "$FILE" 'planning-family skills'                                              "step 5: keeps planning-family skills"
has "$FILE" 'documentation-audiences entries'                                     "step 5: keeps documentation-audiences entries"
has "$FILE" 'Never delete downstream-only files.'                                 "step 5: never delete downstream-only files"
has "$FILE" 'prefer upstream unless doing so erases a planning-family reference'  "step 5: prefer-upstream carve-out"
has "$FILE" 'bin/fm-lint.sh'                                                      "step 6: local lint validation"
has "$FILE" 'bin/fm-test-run.sh'                                                  "step 6: local full test validation"
has "$FILE" 'git push no-mistakes sync/upstream-<date>'                           "step 7: push through the gate only"
has "$FILE" 'merge commit'                                                        "step 8: merge-commit authority"
has "$FILE" 'never squash'                                                        "step 8: squash forbidden"
has "$FILE" 'orphan upstream ancestry and break future syncs'                     "step 8: squash rationale recorded"
has "$FILE" 'bin/fm-update.sh'                                                    "step 9: post-landing refresh flow"
has "$FILE" 're-reads `AGENTS.md` when told, and nudges secondmates'              "step 9: refresh outcomes stated"

has "$FILE" '**Upstream sync is pull-only.**'                       "Safety: pull-only line present"
has "$FILE" 'Nothing is ever pushed to `kunchenguid/firstmate`'     "Safety: nothing pushed to upstream"

echo
echo "result: $pass passed, $fail failed"
[ "$fail" -eq 0 ]

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

⚠️ **Review** - 1 info
  • ℹ️ .agents/skills/updatefirstmate/SKILL.md:82 - Step 4 ('git switch -c sync/upstream-<YYYY-MM-DD>') branches from current HEAD but never states that the agent must first be on main; the preconditions only cover uncommitted changes. If followed while on another branch, the merge base would silently be wrong. A clarifying sentence ('Start on main') would make the invariant explicit.
✅ **Test** - passed

✅ No issues found.

  • git diff 8802737..06624d5 -- .agents/skills/updatefirstmate/SKILL.md — confirmed the only hunks are the added description sentence, the new section inserted immediately before ## Safety, and one appended Safety bullet; no existing section text was modified
  • diff .claude/skills/updatefirstmate/SKILL.md .agents/skills/updatefirstmate/SKILL.md — symlinked views are byte-identical
  • YAML frontmatter parse via python3+PyYAML — description mentions pull-only upstream sync from kunchenguid/firstmate triggered by "sync upstream" / bringing in upstream commits, and name remains updatefirstmate
  • bash verify-upstream-sync-skill.sh &lt;repo&gt; (focused acceptance verifier, evidence dir) — 24/24 assertions passed covering exact section title, placement before ## Safety, exactly nine numbered steps, all required commands (remote add/fetch, rev-list divergence count, dated sync branch, merge, fm-lint.sh, fm-test-run.sh, git push no-mistakes), UNION policy with planning-family/documentation-audiences carve-outs and never-delete-downstream-files rule, --merge-never-squash rationale, post-landing bin/fm-update.sh refresh outcomes, and the pull-only Safety line
  • bin/fm-doc-audience-check.sh — real consumer of tracked *.md surfaces reports ok (surfaces=77, local_links=266)
  • bash tests/fm-documentation-audiences.test.sh — documentation-inventory regression suite passes
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

@pruge
pruge merged commit af03155 into main Aug 24, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant