Skip to content

[Hackathon] fix(test): honor --dry-run in test scaffold #454

Open

Description

@moussa12345678

Verified against (commit SHA or released version)

commit 988c035

Discord Username / User ID

hacker18283737

What does this improvement do?

Problem. testsprite test scaffold --dry-run --out <path> performs real filesystem writes. The global --dry-run contract promises no writes — DOCUMENTATION.md ("--dry-run is a global flag that emits a canned sample matching the API contract without writes or charges"; the Global flags table: "These apply to every command: --dry-run | Preview without writes or charges"), and the CHANGELOG's original definition ("every command runs end-to-end without touching the network, credentials, or the local filesystem"). runScaffold in src/commands/test.ts (the --out branch, ~L6146–6159 at 988c035) never reads opts.dryRun: it resolves the path, then opens the output sink, writes the body, and renames it onto the target — exactly as in normal mode — and prints Scaffold written to <path>.

Impact. Verified against a clean build of main at the SHA above, in a throwaway temp directory:

  • testsprite test scaffold --dry-run --out fresh.plan.json → creates fresh.plan.json (exit 0) and reports Scaffold written to … — an unexpected side effect under a no-write flag.
  • testsprite test scaffold --dry-run --force --out existing.json → overwrites an existing file's contents (sentinel bytes replaced by the scaffold) — silent data loss under --dry-run.
  • testsprite test scaffold --dry-run --out existing.json (no --force) → exits 5 (already exists: … Pass --force to overwrite) instead of previewing.
  • Control (sibling, same flag plumbing): testsprite test code get test_xxx --dry-run --out x.py prints [dry-run] would write code body (693 bytes) to x.py and creates nothing.

Why this is a bug and not intended. The sibling commands that write user-content files all preview under --dry-run and write nothing: test code get --out (its code comment: "Dry-run: no fetch, no fs…"), test failure get --out (its comment on a "written to" message under dry-run: "would be a lie here"), test artifact get --out, and the pure-local ci init github ("no files changed"). test scaffold was added later (CHANGELOG 0.3.0) without the guard; no test covers scaffold × dry-run anywhere. One deliberate dry-run file write does exist as a documented carve-out — --report junit --report-file writes a canned diagnostic sidecar (CHANGELOG 0.3.0) — but that is a changelog-documented, CI-sidecar artifact, whereas --out is the user's authored-content destination whose normal-mode contract explicitly says "Never clobber silently." Scaffold's dry-run write is undocumented, unprotected, and untested, and its success message is false under the flag's contract.

Expected behavior. Under --dry-run, test scaffold --out should preview (stderr line like [dry-run] would write scaffold (<n> bytes) to <path>, stdout mirroring the no---out mode) and create/modify nothing.

Details / implementation notes

Scope. runScaffold in src/commands/test.ts — specifically the --out branch only (no --out dry-run is already side-effect-free). Distinct from:

Suggested acceptance criteria (one concern; the guard belongs before the write, mirroring test code get):

  1. --dry-run --out <nonexistent> creates no file (red today).
  2. --dry-run --force --out <existing> leaves the existing file's bytes untouched (red today).
  3. Dry-run reports a truthful preview (e.g. [dry-run] would write scaffold (<n> bytes) to <path>), never Scaffold written to …; stdout mirrors the no---out mode (text: scaffold body; --output json: the same JSON payload as without --out).
  4. Design choice to confirm: with an existing target and no --force, dry-run currently exits 5 (already exists… Pass --force). Recommended: preview with exit 0, matching test code get's documented rationale ("in dry-run the point is 'show me the shape, no side effects'") and ci init's guard placement; the alternative (keep the validation error under dry-run, as test failure get does for its output dir) is defensible too — flagging so the fix deliberately picks one. Same question for the invalid-parent case (currently exit 5 under dry-run).
  5. Normal mode unchanged: file created; overwrite without --force still exits 5; --force still overwrites (existing tests must stay green).
  6. --out path validation in normal mode unchanged.
  7. Regression tests added (unit, plus optionally a --dry-run smoke entry for scaffold in the subprocess P6 block); no runtime dependencies; optional one-line DOCUMENTATION.md note may ride the fix PR.

Reproduction (from a clean build of 988c035; any temp dir):

$ testsprite test scaffold --dry-run --out fresh.plan.json ; echo "exit=$?"; ls fresh.plan.json
Scaffold written to …/fresh.plan.json        # stderr
exit=0
…/fresh.plan.json                            # file EXISTS — should not

Confirmations

  • I have searched existing issues and this is not a duplicate. (Full-text search of open issues and PRs for "scaffold" and "dry-run", plus closed-issue searches, re-verified immediately before filing; happy to be pointed at anything missed.)
  • I have provided my Discord identity above for reward coordination.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions