Skip to content

The .taskless/ migration is invisible to the machine interface #178

Description

@thecodedrift

Running check, verify, or test against a .taskless/ tree from an older schema migrates it: files move, taskless.json and .gitignore are rewritten. Measured on a pristine copy of this repo's own tree (schema version 2 → 5), that is six tracked files changed.

This is not a request to stop migrating. check and verify require a specific layout to function at all, so for anyone pinned to * or @latest the alternatives are an automatic migration or a hard failure on every run, and the failure is plainly worse. Migration is a precondition, not a side effect.

The problem is that nothing the caller can read says it happened.

What the caller actually gets

Surface Migration signal
Human stderr one line: Migrating to latest .taskless/ schema...
Human stdout nothing
--json stdout nothing — the envelope has no migration field
Exit code unchanged

So the machine interface is silent. A CI script reading {"success":true,"results":[]} has no way to learn that the working tree was rewritten underneath it, and a person looking at six changed tracked files afterwards has nothing connecting them to the command they ran — the notice names no file, no source version, and no target version.

Two things that are already fine — please don't re-investigate

Both were suspected and neither reproduced on 0.10.2:

  • CI=1 does not suppress the notice. It prints in both environments.
  • --json stdout is valid JSON. The notice goes to stderr, correctly, so JSON.parse(stdout) is safe. (Banner noise seen through pnpm cli comes from pnpm, not from the CLI.)

The gap is not that the notice is misrouted. It is that stderr is the only place it exists.

Suggested shape

  • Add a migration record to the JSON envelope — at minimum from and to schema versions, ideally the paths that moved. A consumer can then log it, fail on it, or ignore it deliberately.
  • Have the human notice name what changed, or how many files, rather than announcing only that something did.

Open question: does test need this?

test migrates, but it may be inheriting rather than requiring it. The call chain is ensureTasklessDirectoryrunMigrations, reached from commands/check.ts, commands/verify.ts, commands/init.ts, commands/onboard.ts, and rules/verify.ts:497 — the last of which is how test picks it up, since test runs verify first.

Unlike a whole-project check, test is handed an explicit rule directory. Whether it needs the entire tree at the current schema, or only the path it was given, is worth establishing before this is designed — it may be that test can operate on an old-layout tree for a path that is already well-formed.

Measured command-by-command, for reference:

command migrates
info no
detect no
verify yes
test yes
check yes

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