Skip to content

fix(gate): make TDD enforcement work on non-git/generated projects#11

Merged
agjs merged 2 commits into
mainfrom
fix/tdd-enforcement
Jun 17, 2026
Merged

fix(gate): make TDD enforcement work on non-git/generated projects#11
agjs merged 2 commits into
mainfrom
fix/tdd-enforcement

Conversation

@agjs

@agjs agjs commented Jun 17, 2026

Copy link
Copy Markdown
Owner

The bug

TDD enforcement (test-sibling-required, default ON since 0.14.0) populated its "files the agent changed" list from `git diff`. In a non-git project that returns nothing, so the rule short-circuited with zero violations — a freshly generated app (e.g. a scaffolded Vite/React project) shipped with zero tests and a green gate. That's the headline use case: scaffold a new project with tsforge.

It worked in tsforge's own repo (a git repo), which is why our evals never caught it.

The fix

Stop asking git. Enforcement now reads `ctx.touched` — the set of files the agent actually wrote this session, tracked in-process in `runToolCalls` and threaded into `settleGate`. Works regardless of whether the directory is a git repo.

Strictly a superset of the old behavior:

  • Git project → still enforced (and now also covers root-level files that git's `--relative` was fumbling).
  • Non-git / generated project → now enforced.

The `test-sibling-required` rule now iterates `changedFiles` directly (not `sourceFiles ∩ changed`), with a local `seen` dedup. `.tsx`/`.jsx` components remain exempt by design (in-loop unit tests for presentational components are low-value and stall from-scratch web builds); `.ts` logic is enforced. `TSFORGE_TDD=0` still opts out (downgrades error→warn).

Verification

  • New regression test `packages/core/tests/tdd-enforcement.test.ts` (3 cases, non-git temp dir): impl-only stays red; impl+test goes green; `TSFORGE_TDD=0` lets impl-only pass. These fail on the old code, pass on the fix.
  • Full `bun run validate` green: 1075 pass, 0 fail.
  • Live headless deepseek run on a real non-git temp dir: asked for `slug.ts`; the model created it, the gate went red on the missing test, and it responded by writing `slug.test.ts` before reaching GREEN. End-to-end proof through the real CLI.

Follow-up (not in this PR)

The live run surfaced a separate papercut: under TS6 + `moduleResolution: "bundler"`, `import ... from "bun:test"` is rejected (`TS2664`/`TS2307`), so the model spent extra turns before working around it with ambient globals. Worth a future `bun:test` shim / pre-seeded test globals so generated projects don't trip on it.

The 0.14.0 TDD gate scoped test-sibling-required to `git diff`, so it no-op'd in
any non-git directory — including a freshly generated project, which therefore
shipped with zero tests and a green gate (reported on a generated tictactoe app).

- Scope enforcement to the files the AGENT actually wrote this session
  (ctx.touched, populated in runToolCalls) instead of git. Works in any dir.
- The rule iterates the changed set directly (not sourceFiles ∩ changed), so a
  root-level file is covered too, not just files under src/.
- Exempt presentational `.tsx`/`.jsx` components (testing every component in-loop
  makes from-scratch web builds get stuck — the buildStaged canary); enforce on
  `.ts` logic. Put testable logic in `.ts`.
- Drop the git dependency (gitChangedFiles) entirely.

New tdd-enforcement.test.ts proves it on a NON-git project: an untested .ts logic
file stays red, adding the test goes green, TSFORGE_TDD=0 opts out. Full validate
1075 pass.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request replaces the git-based changed files detection with an in-memory tracking mechanism (ctx.touched) to record files created or edited by the agent during a session. This ensures change-scoped meta-rules, such as test-sibling-required, function correctly in non-git environments. Additionally, .tsx and .jsx files are now exempt from test-sibling requirements, and a new test suite has been added to verify TDD enforcement in non-git projects. Feedback on these changes includes a recommendation to lazily initialize ctx.touched to prevent potential runtime errors if it is undefined, and a suggestion to normalize path separators to forward slashes in the rule's warning message for cross-platform consistency.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/core/src/loop/turn.ts Outdated
Comment thread packages/core/src/meta-rules/rules/testing/test-sibling-required.ts Outdated
@agjs agjs merged commit ab190f7 into main Jun 17, 2026
8 checks passed
@agjs agjs deleted the fix/tdd-enforcement branch June 17, 2026 22:05
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