6 · Commit & freeze the vendor
Objective — earn the whole section: verify the frozen author/vX baseline from Create the project, push develop + the author branch + tag to the private remote, cut your working branch, and prove the seam is clean.
Steps at a glance:
- Verify the pristine baseline exists — confirm the frozen vendor import and tag exist before pushing, so later work has a trustworthy rollback and diff anchor.
- Safety-check before pushing — Never trust that
.gitignoreis perfect — prove it before anything hits the remote. - Push to the private remote — push the protected baseline to the private remote, so the pristine vendor history is backed up before setup work continues.
- Cut your working branch — With the baseline frozen and pushed, create the branch the rest of the playbook commits against.
- Verify the seam — prove the baseline branch, working branch, and pristine tag line up, so future vendor updates compare against the right seam.
Background
Section titled “Background”Create the project already created the pristine vendor baseline — the immutable snapshot you diff against at every vendor update. This page pushes that baseline; it does not re-commit vendor source mixed with AI files.
flowchart TD V["verify author-vX tag<br/>+ author/vX branch"] -->|missing| L["legacy: run Create the project<br/>baseline commit"] V -->|present| P["push develop +<br/>author branch + tag"] P --> W["git checkout -b<br/>Setup/Initial-Launch"] W --> S["seam check<br/>.env + vendor/"]1. Verify the pristine baseline exists
Section titled “1. Verify the pristine baseline exists”-
Confirm the frozen branch, tag, and pristine import commit from AI dev environment setup — this page verifies those outcomes; it does not recreate the vendor import.
Required outcome Where created Verified here T1 vendor import commit Create the project §6 git log develop --onelineshows pristine + C2–C6author/vX.X.XbranchSame git branch --list 'author/*'author-vX.X.XtagSame git tag --list 'author-*'Terminal window git tag --list 'author-*'git branch --list 'author/*'git branch --show-current # expect develop (or your working branch after Verify & gate)git log develop --oneline -6 # expect C1…C6 (pristine + five AI commits)git log author/v${VERSION} -1 --oneline 2>/dev/null || git log -1 --oneline# Expected: author-vX.X.X tag + author/vX.X.X branch; log shows pristine import message- ✅
author-v${VERSION}tag andauthor/v${VERSION}branch exist locally.
- ✅
-
If either is missing — you skipped the baseline commit. Go back to Create the project · pristine baseline before continuing. Do not run a mixed
git add .import here.- ✅ Baseline present — continue. If missing — stop and create it on Create the project only.
2. Safety-check before pushing
Section titled “2. Safety-check before pushing”Never trust that .gitignore is perfect — prove it before anything hits the remote.
-
Scan the working tree for anything that must not be committed.
Terminal window git status | grep -E "vendor/|node_modules/|\.env$" && echo "STOP! Fix .gitignore!" || echo "Safe"git check-ignore -q _source/ && echo "_source ignored OK" || echo "FAIL: /_source/ must stay ignored"# Expected: "Safe" — no vendor/, node_modules/, or .env in the status- ✅ Prints
Safe. If it printsSTOP!, fix.gitignorebefore continuing.
- ✅ Prints
3. Push to the private remote
Section titled “3. Push to the private remote”-
Add the remote and push
develop, the author branch, and the tag.Terminal window git remote add origin "$GITHUB_REPO" 2>/dev/null || git remote set-url origin "$GITHUB_REPO"git push -u origin developgit push origin "author/v${VERSION}" "author-v${VERSION}"# Expected: develop, author/vX.X.X, and author-vX.X.X all pushed to origin- ✅ On GitHub, the branches dropdown shows
develop+author/vX.X.X, and Tags showsauthor-vX.X.X.
- ✅ On GitHub, the branches dropdown shows
-
Set the GitHub default branch to
develop. The empty repo was created beforedevelopexisted, so enforce the default branch immediately after the first push creates it. In setup-new,developis the active work and PR target;mainremains the protected release/tag branch.Terminal window REPO=$(gh repo view --json nameWithOwner -q '.nameWithOwner')gh repo edit "$REPO" --default-branch developgh repo view "$REPO" --json defaultBranchRef -q '.defaultBranchRef.name'# Expected: develop- ✅ The verify command prints
develop.
- ✅ The verify command prints
-
🤖 Activate the local pre-push hook — the interim signing gate that runs on this clone before each push. The repo ships
.githooks/pre-push(committed); thecore.hooksPathpointer is a local git setting, so every clone must opt in once.Terminal window git config core.hooksPath .githooks# Verify it fires: a push containing any unsigned non-baseline commit is now rejected locally.- ✅
git config --get core.hooksPathprints.githooks.
- ✅
3b. 👤 Enable signed-commit protection on the remote (USER step)
Section titled “3b. 👤 Enable signed-commit protection on the remote (USER step)”-
👤 Confirm the prerequisite once. Branch protection (the classic API below) on a private repo under a free personal account requires GitHub Pro. On a free account, use a Ruleset instead (Option B) — rulesets enforce signed commits on private repos at no extra cost. Public repos and org/Team plans can use either.
- ✅ You know which path applies: Pro / org → Option A or B · free personal + private → Option B (Ruleset).
-
👤 Option A — branch protection via
gh(one command per branch). ReplaceOWNER/REPOwith the real slug. Run fordevelopnow; re-run formain(the setup-new release branch) the moment it exists.Terminal window # Require signed commits on develop (idempotent — safe to re-run)gh api -X PUT "repos/OWNER/REPO/branches/develop/protection/required_signatures" \-H "Accept: application/vnd.github+json"# Later, when main exists:gh api -X PUT "repos/OWNER/REPO/branches/main/protection/required_signatures" \-H "Accept: application/vnd.github+json"# Verify (expects: "enabled": true)gh api "repos/OWNER/REPO/branches/develop/protection/required_signatures" \-H "Accept: application/vnd.github+json" --jq .enabled- ✅ The verify call prints
truefordevelop(and latermain).
- ✅ The verify call prints
-
👤 Option B — Ruleset via the GitHub UI (works on free private repos, no Pro). This is the fallback when Option A returns
403/Upgrade required, and the most robust path overall.- GitHub → your repo → Settings → Rules → Rulesets → New ruleset → New branch ruleset.
- Name it e.g.
require-signed-commits; set Enforcement status → Active. - Under Target branches → Add target → Include by pattern, add
develop(andmain, orInclude default branch). - Under Rules, tick Require signed commits.
- Create.
- ✅ The ruleset shows Active and lists
develop(+mainonce it exists) under target branches.
-
👤 Re-apply when
mainis born. The release branch usually doesn’t exist yet at Phase 2. Add the same rule/ruleset target before the first production merge — track it on the checklist below so it isn’t forgotten.- ✅
maincarries an identical signed-commit rule before any code merges into it.
- ✅
4. Cut your working branch
Section titled “4. Cut your working branch”With the baseline frozen and pushed, create the branch the rest of the playbook commits against.
Option A (default):
-
Branch off
developfor the working branch.Terminal window git checkout developgit checkout -b Setup/Initial-Launch# Expected: now on Setup/Initial-Launch, branched from develop- ✅
git branch --show-currentprintsSetup/Initial-Launch.
- ✅
Option B — cut a phase-scoped branch instead (see Branch strategy · Option B CLI appendix):
git checkout developgit checkout -b Setup/Phase-2-Code-Repo# Expected: git branch --show-current → Setup/Phase-2-Code-Repo- ✅ Working branch matches the model recorded in
Zaj-PROJECT.md.
5. Verify the seam
Section titled “5. Verify the seam”-
Prove secrets and installed vendor never entered history.
Terminal window git log --all --full-history -- .env # → nothinggit log --all --full-history -- vendor/ # → nothinggit log author/v${VERSION} -1 --oneline 2>/dev/null || truegit diff author/v${VERSION} develop --stat | head -20# Expected: .env and vendor/ logs empty; diff shows AI/bootstrap files on develop beyond pristine- ✅ Both
.envandvendor/logs are empty; optional stat diff confirms develop moved forward from the frozen author tree.
- ✅ Both
Checklist
Section titled “Checklist”Do not mark this step done until every box below is checked.
- 🤖 Baseline verified —
author/vX.X.X+author-vX.X.Xexist locally (created at Create the project). - 🤖
developpushed to the private remote (includes C1–C6 after Verify & gate). - 🤖 Remote default branch verified —
gh repo view --json defaultBranchRef -q '.defaultBranchRef.name'printsdevelop. - 🤖 Local pre-push hook active —
git config --get core.hooksPathprints.githooks(interim gate;--no-verifybypasses it). - 👤 Signed-commit protection enabled on the remote — GitHub Require signed commits on
develop(viagh api .../required_signaturesor a Settings → Rules → Ruleset). Free personal + private repo → use a Ruleset (Pro not required). - 👤
mainrule queued — same signed-commit rule applied tomain/production before the first production merge (the branch usually doesn’t exist yet at Phase 2). - 🤖 Snapshot on remote —
author/vX.X.Xbranch andauthor-vX.X.Xtag pushed. - 🤖 Working branch checked out —
Setup/Initial-Launch(or your Option B branch). - 🤖 Seam clean —
git log --all -- .env vendor/returns nothing.