Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion .github/workflows/fix-drift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,15 @@ jobs:
echo "Pinned pre-fix drift report to $PINNED_REPORT (outside the LLM-writable repo checkout)"

# Step 3: Invoke Claude Code to fix
#
# --report reads the PINNED pre-fix report (Step 2b), NOT the default
# in-repo `drift-report.json`. The collector writes its report to
# $RUNNER_TEMP (Step 1, FIX #F3), which is OUTSIDE the repo checkout, so
# the repo-root `drift-report.json` that fix-drift.ts defaults to does not
# exist — without this flag readDriftReport throws "Drift report not
# found" and the fixer never runs. Reading the pinned copy (same source
# the Assert and Create PR steps read) also keeps the fixer's view of the
# drift consistent with the downstream integrity gate.
- name: Auto-fix drift
id: autofix
if: steps.check.outputs.skip != 'true'
Expand All @@ -167,7 +176,8 @@ jobs:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
run: npx tsx scripts/fix-drift.ts
PINNED_REPORT: ${{ runner.temp }}/drift-report.pinned.json
run: npx tsx scripts/fix-drift.ts --report "${PINNED_REPORT}"

# Upload Claude Code output for debugging
- name: Upload Claude Code logs
Expand Down
33 changes: 33 additions & 0 deletions src/__tests__/fix-drift-workflow.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,39 @@ describe("fix-drift.yml — F-A: PRE-fix report pinned outside the LLM-writable
});
});

// ---------------------------------------------------------------------------
// report-path — the Auto-fix step must pass --report from the PINNED copy.
//
// FIX #F3 moved the collector's report to $RUNNER_TEMP (outside the repo
// checkout), so the repo-root drift-report.json that fix-drift.ts defaults to no
// longer exists. The Assert and Create-PR steps were updated to read --report
// from the pinned copy, but the Auto-fix step still ran `fix-drift.ts` with NO
// --report, so it fell back to the missing repo-root path and died with "Drift
// report not found" (readDriftReport) — the recurring drift-job failure. These
// lock that the Auto-fix step reads --report from the pinned copy, matching the
// downstream integrity gate.
// ---------------------------------------------------------------------------
describe("fix-drift.yml — report-path: Auto-fix step reads --report from the pinned copy", () => {
it("passes --report from the PINNED copy into the Auto-fix `fix-drift.ts` invocation", () => {
expect(wfFlat).toMatch(/scripts\/fix-drift\.ts --report "\$\{PINNED_REPORT\}"/);
});

it("does NOT run the Auto-fix step against the default (missing) repo-root drift-report.json", () => {
// The bare `npx tsx scripts/fix-drift.ts` (no --report) is the regression:
// it defaults to the repo-root drift-report.json which FIX #F3 no longer
// writes. Ensure the autofix invocation always carries a --report flag.
expect(wfFlat).not.toMatch(/npx tsx scripts\/fix-drift\.ts(?! --)/);
});

it("exposes PINNED_REPORT as an env in the Auto-fix step", () => {
const idx = wf.indexOf("name: Auto-fix drift");
expect(idx).toBeGreaterThan(-1);
const nextStep = wf.indexOf("\n - name:", idx + 1);
const stepBlock = wf.slice(idx, nextStep === -1 ? undefined : nextStep);
expect(stepBlock).toContain("PINNED_REPORT: ${{ runner.temp }}/drift-report.pinned.json");
});
});

// ---------------------------------------------------------------------------
// FIX (round-4, user-approved) — HUMAN-APPROVAL BACKSTOP. The drift path opens a
// PR but must NEVER auto-merge: the predicate is a strong AUTO-FILTER, not a
Expand Down
Loading