Story: BACKFILL + REMEDIATE — bring the fleet to green on the gitignore baseline #800
Copy link
Copy link
Closed
Labels
dev-leadFor dev-lead agent pickupFor dev-lead agent pickupenhancementFeature requestsFeature requests
Description
BACKFILL + REMEDIATE — bring the fleet to green (SWEEP)
Blocked by STORY2 (needs upsert_gitignore_baseline() / distribution) and STORY3 (needs the check to define "pass").
Why (verified current state)
Only 4 of 10 repos carry the real baseline (bmad-bgreat-suite, TalkTerm, ContentTwin, .github-private). The other 6 have hand-rolled gitignores that would fail the new blocking check:
repo-template, incubator, broodly, google-app-scripts, broodminder-export, markets.
A leaked GCP credentials.json, kubeconfig, or *.tfvars is not ignored in those repos today.
Deliverables
- Remediation hook — wire
upsert_gitignore_baseline()into the compliance remediation path (compliance-remediate.sh/ the audit's Phase-5 issue→fix flow) so a drifted/missing block is auto-fixable, L2 preserved. - Fleet back-fill — insert the marker-wrapped L1 block into the 6 non-baseline repos (+ confirm the 4 existing ones get markers added). Per repo: PR + admin-merge for ruleset-protected repos (add-to-project precedent;
SKIP_OVERRIDESwhere needed). Preserve each repo's existing L2 lines below END. - Verify green — re-run
compliance-audit.sh(or--target_repo) →check_gitignore_baseline= 0 findings fleet-wide.
Acceptance
- All 6 non-baseline repos carry the marker-wrapped L1 block; their prior L2 entries preserved below END.
- Remediation is idempotent (second run is a no-op).
- Compliance audit shows 0
gitignore_baselinefindings across the fleet.
Blocking acceptance (from dry-run, see comment): upsert must preserve baseline negations (no re-ignoring public.pem etc.) and migrate/dedup existing unmarkered baselines. Do NOT run the fleet apply until a clean re-dry-run + negation git check-ignore probe pass.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
dev-leadFor dev-lead agent pickupFor dev-lead agent pickupenhancementFeature requestsFeature requests
Activity
don-petry commentedon Jul 19, 2026
Part of Epic #801.
don-petry commentedon Jul 19, 2026
Ran
scripts/sync-gitignore-baseline.sh --dry-runacross the fleet. It plans 9 INSERT PRs (all non-exempt repos). Two problems make the real apply unsafe with the currentupsert_gitignore_baseline(from #798):1. Negation regression (correctness — BLOCKER)
upsertprepends the marker-wrapped L1 block and keeps the target's existing content below the END marker as "L2". For repos whose ad-hoc.gitignorehas a broad ignore without the baseline's negation, that L2 line re-hides a file the L1 block just re-allowed. Verified withgit check-ignoreon the upsert output:markets→public.pembecomes IGNORED (negation!public.pemdefeated)google-app-scripts→public.pembecomes IGNOREDThe baseline explicitly warns: "a later ignore silently re-hides a previously-negated file." The back-fill would ship exactly that.
2. Full-baseline duplication (hygiene)
Repos that already carry the old unmarkered baseline get the whole 398-line block duplicated:
TalkTerm434 → 831 lines (.env,*.pemeach appear twice)bmad-bgreat-suite,ContentTwinRequired before apply (added acceptance for #800)
upsert_gitignore_baselinemust guarantee baseline negations win — e.g. strip/relocate any pre-existing L2 ignore that would re-hide a baseline-negated path (public.pem,.env.example,*.crt,ca.crt,*.pub, …), or place the block so its negations are evaluated last.--dry-run+ thegit check-ignorenegation-safety probe onmarkets/google-app-scripts/TalkTerm→ all re-allowed files stay un-ignored, no duplication.Evidence probe (reproducible): upsert each repo's live
.gitignore,git inita temp dir with the result,git check-ignore .env.example .env.sample public.pem ca.crt.don-petry commentedon Jul 19, 2026
Dev-Lead Implementation Plan
Issue: #800 — Story: BACKFILL + REMEDIATE — bring the fleet to green on the gitignore baseline
Scope
Wire the shared, idempotent
upsert_gitignore_baseline()(STORY2,scripts/lib/gitignore-baseline.sh) into the compliance remediation path so a missing/driftedpush-protection/gitignore_baselinefinding is auto-fixed via a PR (L2 preserved), instead of being routed toreport_skip.Deliverable mapping
scripts/compliance-remediate.sh. This is the reviewable code artifact of this story.compliance-audit.shre-run showing 0 findings) — these are operational runtime steps: they run the now-wired tooling against the 6 non-baseline repos and re-audit. They mutate other repos and cannot be part of this repo's code PR (see Constraints: "Do not commit, push, or open PRs"). They are executed by the compliance workflow/operator after this hook merges.Implementation Checklist
scripts/compliance-remediate.sh— sourcelib/gitignore-baseline.sh+lib/standards-deploy.sh; resolveSCRIPT_DIR/GITIGNORE_CANONICALscripts/compliance-remediate.sh— addremediate_gitignore_baseline()(extract canonical block → fetch repo.gitignore→upsert_gitignore_baseline→ idempotent no-op skip → DRY_RUN → PR viasd_deploy_via_pr)scripts/compliance-remediate.sh— routepush-protection/gitignore_baselineto the new handler (remove the oldreport_skip)Tests to Write
test/scripts/compliance-remediate/gitignore-baseline.bats— new suite: INSERT (missing.gitignore) opens PR; REFRESH (drifted) opens PR; already-current is a no-op skip; DRY_RUN records planned PR with no mutating gh calls; L2 preserved in PUT payload; PR-create failure → report_failtest/scripts/compliance-remediate/routing-messages.bats— update thegitignore_baselinecase: it now lands on the remediation (PR) table, notskipped.md(behavior changed by this story)Test Command
./node_modules/.bin/bats --print-output-on-failure test/scripts/compliance-remediate/ test/scripts/lib/gitignore-baseline.bats && bash .dev-lead/scripts/dev-lead-lint.shdon-petry commentedon Jul 19, 2026
Dev-Lead: Implementation Complete
Deliverable 1 — Remediation hook (this PR)
Wired the shared, idempotent
upsert_gitignore_baseline()into the compliance remediation path.push-protection/gitignore_baselineis no longer a manualreport_skip— it now auto-fixes via a PR:scripts/compliance-remediate.shsourceslib/gitignore-baseline.sh+lib/standards-deploy.sh.remediate_gitignore_baseline(): extracts the canonical L1 block from the org/.gitignore, fetches the target repo's.gitignore, runsupsert_gitignore_baseline()(L2 below END preserved verbatim), and ships the change throughsd_deploy_via_pr()(PR only — never a direct push to a ruleset-protected default branch).gitignore-baseline, shared withsync-gitignore-baseline.sh) instead of duplicating it.DRY_RUN=truerecords the planned PR and issues zero mutating gh calls.Plan Execution
GITIGNORE_CANONICAL(test seam)remediate_gitignore_baseline()(INSERT / REFRESH / no-op / dry-run / failure paths)push-protection/gitignore_baselineto the new handlertest/scripts/compliance-remediate/gitignore-baseline.bats(7 cases)routing-messages.bats(finding is no longer a skip)gitignore-baseline-tests.yml)Scope note — Deliverables 2 & 3 (operational, not code)
Deliverable 2 (open back-fill PRs + admin-merge on the 6 non-baseline repos) and Deliverable 3 (re-run
compliance-audit.shfleet-wide to confirm 0gitignore_baselinefindings) are runtime operations that mutate other repos. They are executed by running this now-wired remediation (orsync-gitignore-baseline.sh) against the fleet after merge — they are not source changes and fall outside this repo's code PR (per the "do not commit/push/open PRs" constraint).Test Results
Files Changed
scripts/compliance-remediate.sh: source baseline+deploy libs; addremediate_gitignore_baseline(); route the finding to it (was a skip).test/scripts/compliance-remediate/gitignore-baseline.bats: new suite — INSERT / REFRESH (L2 preserved) / marker-less / idempotent no-op / dry-run / PR-failure / reuse-open-PR.test/scripts/compliance-remediate/routing-messages.bats: drop the obsolete "gitignore_baseline skips" case (behavior changed)..github/workflows/gitignore-baseline-tests.yml: shellcheck + bats now covercompliance-remediate.shand its remediate tests.Notes
upsert_gitignore_baseline()and asserted end-to-end by decoding the PR's PUT payload in the new suite.don-petry commentedon Jul 19, 2026
Blocking sub-task for the fleet apply filed as #809 (upsert negation-safety + dedup). #808 delivers the remediation hook (
Part of #800); the apply stays gated until #809 merges and a clean re-dry-run +git check-ignoreprobe pass.feat: implement issue #800 — Story: BACKFILL + REMEDIATE — bring the …
feat: implement issue #809 — upsert_gitignore_baseline must preserve …
don-petry commentedon Jul 19, 2026
Per go/no-go decision: refine output cleanliness before the fleet apply. Filed #817 (conditional negation tail + migrated-comment dedup) — blocks the apply. Tooling is validated & ready (dry-run clean, negation probe green on all 5 sampled repos); apply proceeds after #817 merges and a re-validation.
don-petry commentedon Jul 20, 2026
✅ Fleet back-fill complete — all 9 non-exempt repos now carry the marker-wrapped secrets baseline (single BEGIN/END block, negations verified safe, secrets ignored).
Canary (verified on main): markets#343 (417 lines), TalkTerm#387 (433).
Remaining 7 (merged): google-app-scripts#459, broodly#420, broodminder-export#54, ContentTwin#366, bmad-bgreat-suite#404, incubator#46, repo-template#69.
repo-template#69 was admin-merged: its sole blocker was a pre-existing
add-to-projectinfra failure (missing GitHub-Appclient-idsecret in the repo — unrelated to this change), and one Gemini finding that was a false positive (it read the correct-removal of the dangling# Dev-lead agent working directorycomment as 'left dangling'). Content verified clean before merge.Epic #801 delivered end-to-end: standard → enforcement (error severity) → seed/distribute → remediation hook → negation-safe upsert → clean fleet back-fill.