Skip to content

refactor: remove the remaining version control calls - #23

Merged
zalom merged 22 commits into
mainfrom
plastic/390--no-vcs-commands
Sep 24, 2026
Merged

zalom merged 22 commits into
mainfrom
plastic/390--no-vcs-commands

Conversation

@zalom

@zalom zalom commented Sep 24, 2026

Copy link
Copy Markdown
Owner

What

Plastic now runs no version control command anywhere, not only in session commit and auto take. Each remaining place writes its record and prints the git instruction on its next: line for the person or agent to run. Code whose step no longer matters is deleted.

Why

The owner ruled on 2026-09-24 that every git call in the script library goes, after pull request 21 removed the first two. Tests that built real repositories were slow and could not be scored by the mutation tester.

How

  • Arm and disarm: disarm releases the lock and prints the worktree removal command. The worktree module keeps only path helpers.
  • Intent close: scripts/end-intent and the exec worktree step print the store commit, merge and removal steps. The dirty and merged checks are gone.
  • Scaffold and verify: the repository and base branch come from projects.yml. The diff commands are printed.
  • Node input: the landed commits block is removed.
  • Maintenance, install and update: the maintenance action and update print their commit. Install no longer creates or checks a repository.
  • Graph runner: node worktrees, merges, reaps and rewinds are printed instructions. Sweep and watch read the ledger and files. The merge-in-progress check is deleted.
  • Store worktree sweep: the one-time cleanup script is deleted.
  • Report screen: tag and branch lookups are dropped.
  • Restore: restore-intent-v1 takes a snapshot directory and prints the commands that fill it.
  • Docs: architecture, internals and the help chapters describe the printed instructions.

Tests

  • Tests assert on printed instructions, files, ledger and savepoint lines. No test creates a repository.
  • Each changed test file ran once and passed. CI runs the full suite on this pull request.
  • The change gate reported lint, mutation and complexity findings in runner files.

Worktree.release, .finish, and .merge_branch shelled out to git to
tear down and merge a code worktree Plastic itself never creates.
Arm.disarm now only releases the delivery lock and reports the
git worktree remove instruction (Arm.worktree_removal_instruction)
for a workspace the agent already provisioned; arm/disarm/repair
drop the runner: parameter they no longer need.

Worktree.ShellRunner and the git-shelling helpers still called by
the node-graph runner (current_branch, remove_worktree, prune,
git_repo?) stay for now; part B of intent 390 removes them with
the runner modules that use them.
…tead of running them

ExecWorktree and end-intent shelled out to git to check the code
worktree for dirty or unmerged state and to finish/merge/remove it.
Plastic runs no version control command: exec-worktree now prints the
commit, merge, and worktree-removal steps for the agent to run by
hand, and a delivered close no longer refuses on an unmerged branch
or a dirty worktree (the exit 5 and exit 9 refusals are retired).
Disarm still names the worktree-removal instruction when a worktree
was provisioned.
… without git

ScaffoldIntent.resolve_repo_dir now reads projects.yml only, and
detect_base_branch returns "main" unless a project's project.yml
names a different flow base -- neither shells out to git any more.
diffstat is replaced by diffstat_instruction, which builds the git
diff --stat command as a string for a caller to print or run itself;
BackfillIntent and VerifyIntent's diffstat check both print it instead
of running a git_runner/runner seam.
NodeInput's ledger block ran an injected git log after a reclaim to
list landed commits. Plastic runs no version control command: the
block, its git_runner seam, and the byte-truncation helper built for
it are gone, and full_ledger_text no longer takes files:, repo_dir:,
or git_runner:.
…of running it

MaintenanceGit branched, committed, and merged a scoped store change
through git. Plastic runs no version control command: maintenance-run
now applies each tool's change directly and prints the git add/commit
instruction naming the touched paths. MaintenanceGit and its test are
deleted.
WorktreeSweep and sweep-store-worktrees existed to clean up orphaned
store worktrees from a retired provisioning path; they shelled out to
git to detect and remove them. That path is long gone, so this drops
the module, its CLI, its test, and the three stale core_files manifest
entries left over from earlier deletions in this same effort.
InstallerCore#git_init_if_absent (deleted alongside the worktree-sweep
cleanup) made ~/.plastic its own git repository so update.rb could
later commit re-synced core files. Plastic runs no version control
command: install.rb drops the call site, update.rb's comment now
describes commit_core_files as landing only when the home already
carries its own repository, and the install/new-intent tests that
built a real .git or asserted one exists after a fresh install no
longer do either.
…ce paths

architecture.md, internals.md, locks-and-worktrees.md, and
completion-and-done.md described Worktree.release/finish, a
git-shelled diffstat and em-dash diff, a git-committing
maintenance-run, a git-initialized plastic_home, and an end-intent
that checks for a merged, clean code worktree. All of that is gone
(intent 390: Plastic runs no version control command); these chapters
now describe the printed instructions that replaced each of those
checks.
test/exec_worktree_test.rb still called ExecWorktree.run with the
retired finisher:/status_checker:/runner: seams and asserted on the
dirty-worktree and unmerged-branch refusals those seams drove. It
never got fixed alongside the run() rewrite in the earlier commit,
so verify-change caught 14 argument errors. Rewritten to exercise the
current run(): the printed commit/merge/worktree-remove report, the
nothing-provisioned and no-worktree-recorded paths, the lock/session
and usage-failure exits, and a guard that the module never shells out.
…g them

Absorb, rewind, sweep, watch, dispatch and the worktree module no longer
shell out to git for merge, reset, worktree add/remove, or freshness by
commit. Each prints the instruction and asserts on plain files and
directories instead. The scope check is dropped: NodeReturn's closed
schema carries no file list to measure a diff against. The reaper can no
longer tell a merged branch from an unmerged one, so a terminal node's
worktree is always named for removal now, recorded as a lost capability.
setup_real_repo becomes setup_repo: a plain directory tree registered in
projects.yml, never a git repository - RunnerDispatch only prints its
worktree instruction and RunnerAbsorb only prints its merge instruction
now, so neither needs one. The two real-subprocess rows (concurrency cap,
CLI arm) pre-create each dispatched node's own worktree directory by hand,
standing in for the git worktree add a human would run from the printed
instruction, so node-run's -C target still resolves to the right node.
node_run_cli_test.rb: rename setup_real_repo to setup_repo (a plain
directory, never a real git repo); the stub codex commit mode drops its
real git add/commit and reports a fixed fake sha.

runner_cli_test.rb: drop the git! helper and the two merge-in-progress
tests (the abort-on-a-stuck-merge step is gone); the stale-node-worktree
reap test asserts the printed removal instruction against plain
directories instead of running a real merge and removal; the CHANGELOG
test checks the new intent 390 Unreleased line for five checks instead
of the historical six.

CHANGELOG.md: note under Unreleased that the gate drops its scope check
and now runs five, and that git-touching steps print their instruction
instead of running it.
Replaces the real throwaway git repo (init, worktree add, the git helper)
with a plain directory tree - NodeWorktree.provision never shells out to
git any more, it only ever checks Dir.exist?, so a directory at the exact
repo/worktree path is the whole fixture these rows need.

The two worktree-rollback rows now note that a failed input build or a
refused running write has nothing of its own to roll back on the
worktree side, since provisioning creates nothing itself; the
node-worktree-naming row and the preexisting-worktree row pre-create the
node's worktree directory, standing in for an agent having already run
the printed git worktree add instruction.
…unning it

Owner ruling 2026-09-24: Plastic runs no version control command.
store_commit_instruction replaces store_commit - it names the exact git
add/commit, scoped to the completing intent's own directory plus
INDEX.md (D17: never git add -A), for the closer to run; the dry-run
preview and the real close both print it, and git_toplevel/relative_to
drop out with the git calls they only served.

worktree_changed? drops its git status/rev-list checks (Plastic can no
longer read them itself) and fails open: a code worktree that exists
reads as changed, exactly as an unreadable one used to.

Tests: end_intent_test.rb's five real-git-repo fixtures (the backfill,
store-commit, no-commit, and unrelated-file rows, plus the checklist
row) become plain directories asserting on the printed instruction and
the files it names. end_intent_future_close_test.rb drops its real git
repository entirely - the store is a plain directory and the close's
own commit is checked against printed stdout, never git log.
…running it

Owner ruling 2026-09-24: Plastic runs no version control command.
commit_core_files now prints the git add/commit for ~/.plastic's core
files instead of shelling out through an injected runner; the test
asserts against the printed instruction instead of captured argv.
Plastic itself runs no version control command (owner ruling 2026-09-24),
so git is no longer a runtime dependency this gate needs to probe for -
only of the printed instructions a person or agent runs afterward.
NodeWorktree and Worktree compute every path and branch deterministically
from projects.yml and the intent worktree's own path, with no git call in
that path (owner ruling 2026-09-24). The scratch fixture now builds a
plain directory tree instead of a real git repository, and the git-probe
skip row it existed to prove is gone along with the probe itself.
Plastic runs no version control command. The delivered screen's shipped
version now comes only from outcome.md's own record, falling back to
naming the merge sha (D11) instead of a `git tag --contains` guess, and
prints the command a person can run themselves when a merge sha is known
but no version was recorded. The branch segment falls back to the literal
"main" once a real project repository is known, instead of reading the
repository's actual current or remote-default branch.
Plastic runs no version control command, so restore-intent-v1 no longer
shells out to `git show`/`git rev-parse` to read the v1 snapshot. --at is
now a free-form label kept for the report and revisions.md entry; a new
--snapshot-dir names a directory the caller has already populated with the
v1 content, one file per path, at the same relative path it has under
--plastic-home. With no --snapshot-dir, or a missing file, the tool prints
the exact `git -C <home> show <at>:<path>` command to run and aborts with
no write. The test fixture now builds the v1 snapshot as a plain directory
copy instead of a real git repository.
architecture.md and internals.md still described end-intent checking a
merge with `git merge-base --is-ancestor`, disarm running `git worktree
remove`, and node_worktree.rb shelling out through a `ShellRunner` - all
retired by intent 390. Update both docs to match: Plastic prints the
worktree, merge, and dirty-check instructions instead of running them, and
the retired exit codes (5 and 9) name what used to live there.
Minitest/MultipleAssertions flagged the store-commit-instruction test at
5 assertions against a limit of 3.
@zalom
zalom merged commit f1adecf into main Sep 24, 2026
1 check passed
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