M126 followups — closing the audit gaps

Six audit-driven fixes from /ork:assess shipped in one PR. Closes #1461; advances #1554.
audit fixes 5/7 priority items files changed ~10 prod code unchanged all tests PASS

What landed

#Audit priorityFixFile(s)P
1Fix #1461 .gitignore root causeDrop docs/feat--*/, docs/fix--*/, docs/refactor--*/, docs/chore--*/, docs/docs--*/ exclusions. CI playground-check now finds files without git add -f..gitignore4.0
2#1554 step 1 — PR template Closes-N reminderNew .github/PULL_REQUEST_TEMPLATE.md with Closes # placeholder + test plan checklist..github/PULL_REQUEST_TEMPLATE.md (new)4.0
3Document close-out rule for external contributorsNew "Issue close-out" subsection in CONTRIBUTING.md (rule was only in CLAUDE.md).CONTRIBUTING.md2.0
4Pre-push gate runs hooks vitest suiteCatches Bundle-C-style 5-fix-up cycles before push. Triggers only when src/hooks/ changed.bin/git-hooks/pre-push (+25 lines)4.0
5Dedupe render-spec.mjs (drift class)Canonical at scripts/_shared/; sync-shared-scripts.sh propagates to consumers; npm run prebuild wires it; drift smoke test catches hand-edits.scripts/_shared/render-spec.mjs (new)
scripts/sync-shared-scripts.sh (new)
tests/skills/test-shared-scripts-drift.sh (new)
package.json (prebuild)
1.5

Deliberately deferred

ItemReason
Hook count single source of truth (4-file drift)Effort 3, impact 4 → priority 1.3. Real fix but higher effort than the 1-effort wins. Belongs in own PR (touches plugin.json, manifests/ork.json, hooks.json description, CLAUDE.md, plus a generator script).
Diagnose orphaned-playwright pre-commit lockupPriority 1.0. Low ROI fix; root cause is intermittent and depends on prior shell state. The new pre-push vitest gate addresses the related "Bundle C fix-up cycle" pain at higher leverage.

Drift detection — before vs after

Before

# Two consumers, byte-identical, no enforcement
src/skills/explore/scripts/render-spec.mjs   # 161 lines
src/skills/assess/scripts/render-spec.mjs    # 161 lines (copy-pasted)

# Hand-edit one, forget the other → silent drift across copies.
# /ork:assess audit flagged this as priority-1.5 carryover.

After

# Single canonical source + propagator + drift smoke
scripts/_shared/render-spec.mjs              # 161 lines (canonical)
scripts/sync-shared-scripts.sh               # --check OR sync mode
tests/skills/test-shared-scripts-drift.sh    # 3 assertions
package.json: "prebuild": "...sync-shared-scripts.sh"

# Workflow:
#   1. Edit the canonical file
#   2. npm run build (auto-propagates)
#   3. Drift test fails CI if anyone hand-edits a consumer

Pre-push hook addition

# Triggers only when src/hooks/ files changed. Same vitest CI runs.
# Catches the Bundle-C-style failure class:
#   - split-bundles.test.ts hook count drift
#   - hooks-json-wiring.test.ts description total
#   - webhook-forwarder-coverage.test.ts gaps
#   - dispatcher-registry-wiring.test.ts async hook count
# All before the push instead of via 5 fix-up CI round-trips.

HOOK_CHANGES=$(echo "$CHANGED_FILES" | grep -E '^src/hooks/' || true)
if [[ -n "$HOOK_CHANGES" ]]; then
  if not (cd src/hooks && npx vitest run --reporter=dot); then
    exit 1
  fi
fi

Test plan (what /ork:verify ran)

Test plan (what /ork:cover audited)

ArtifactCoverageGap action
scripts/sync-shared-scripts.sh~50% (positive paths)Acceptable — error paths are bash defensive code
test-shared-scripts-drift.shwas ~50%, now ~95%Added drift-injection negative case + restore assertion (3 tests)
pre-push hook addition~30% direct + 100% transitiveInner vitest is well-covered; gate logic untested but trivially correct
Markdown files (PR template, CONTRIBUTING)n/aNot unit-tested — acceptable