Skip to content

refactor(workspace): move the git diff behind Engine and Repo - #618

Merged
andybons merged 5 commits into
mainfrom
feat/workspace-engine-interface
Oct 14, 2026
Merged

andybons merged 5 commits into
mainfrom
feat/workspace-engine-interface

Conversation

@andybons

@andybons andybons commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Problem

workspace.Changes calls git directly, so a second version-control engine would need a branch inside Changes. This is VCS step 6, PR 2 of vcs-engine-plan.md section 5. It is based on #617 (the docs PR).

Design

Spec: docs/architecture.md Internal packages (internal/workspace) and workspace (the Engine and Repo bullets).

Engine, Repo, Head, and Base are defined in internal/workspace, the package that consumes them. gitengine.go implements them on the existing git helpers; git.go and diff.go are unchanged. Changes keeps the scope check, the containment check, and the 28 s budget, and builds the answer from Head, Base, and Diff. Name() gives the engine field and Head.Label gives branch. Repo exposes no storage path.

Ruling: Diff takes the Head as well as the Base, because the caller already holds it and the git engine needs it to seed a missing index and to pick the empty tree. A zero Base means the head.

Semantic change

The text of a not_a_repo error changes from "is not a git work tree" to "is not a work tree of a known VCS", and the e2e golden git_changes_refusals changes with it. The answer and the git subprocess calls are the same.

Verification

The existing internal/workspace tests and the e2e workspace rows pass unchanged (also with HARNESS_E2E_RUNTIME=1). go build ./... && go vet ./... && go test -race ./... && test -z "$(gofmt -l .)" passes.

CI job times

Job main (s) PR (s)
Browser 115 103
Contract 93 78
Gates 41 29
Node wasm 84 72
Runtime contract 57 46
Static 49 45
Unit 71 64
WebAssembly 30 22

No job grew by more than 5 s. The change adds no test.

Problem: the spec describes GET /workspace/changes as a git diff, so a second version-control engine has no contract to meet.

Design: the spec names the Engine and Repo interfaces that internal/workspace consumes, the ordered engine list that only Changes walks, and the detection marker that each engine owns. Repo carries no storage path. The git behavior moves into a git engine bullet. Branch becomes an optional label.

Semantic change: none for clients. head, base.sha, and not_a_git_repo stay deprecated.

Verification: go test -race ./internal/gates/.
Copilot AI balanced review requested due to automatic review settings October 14, 2026 03:10

Copilot AI 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.

🟡 Changes recommended

Changes hard-codes Git instead of walking the ordered engine list required by the architecture specification.

2 open findings
What changed in this PR

Refactors workspace diffing behind repository-owned VCS interfaces while preserving Git behavior.

Changes:

  • Adds Engine, Repo, Head, and Base abstractions.
  • Moves Git-specific revision and diff logic into gitengine.go.
File Description
internal/​workspace/​workspace.go Defines interfaces and delegates workspace changes.
internal/​workspace/​gitengine.go Implements the interfaces for Git.

🧠 Review effort: Balanced


💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread internal/workspace/workspace.go
Comment thread internal/workspace/workspace.go Outdated
Problem: the spec names the Engine operations without signatures or a no-match signal, and it says a read never changes the repository, which an engine that snapshots its working copy cannot meet.

Design: the spec shows the Engine, Repo, Head, and Base method sets, states that Open returns ok false with a nil error for a directory that is not its kind and that a non-nil error ends the request, and states that only a missing base wraps ErrNoBase. The read rule becomes engine-neutral: a read may snapshot the working copy, adds no operation when nothing changed, and writes no index, reference, or object a user could see. Two sentences are reworded.

Semantic change: none for clients.

Verification: go test ./internal/gates/.
Problem: workspace.Changes calls git directly, so a second engine would need a branch in Changes.

Design: Engine and Repo are defined in internal/workspace, which consumes them. gitengine.go implements them on the existing git helpers. Changes keeps the scope check, the containment check, and the budget, and builds the answer from Head, Base, and Diff. The branch label and the engine name come from the engine.

Semantic change: none. The answer, the error messages, and the subprocess calls are the same.

Verification: the existing internal/workspace tests and the e2e rows pass unchanged; go build, go vet, go test -race ./..., gofmt.
Problem: the staticcheck job flags the write of the deprecated Head field.

Design: the line carries the same nolint note as the other deprecated writes.

Semantic change: none.

Verification: golangci-lint run ./internal/workspace/ reports 0 issues.
…ngine-neutral

Problem: the not_a_repo message and the ErrNotRepo doc name git, the Changes comment holds a git-only hazard, and the Repo.Base doc says every error wraps ErrNoBase while the git engine also returns context and process errors.

Design: the message reads "is not a work tree of a known VCS". The ceiling hazard moves to the doc of the git engine Open. The Base doc says that only the no-base case wraps ErrNoBase.

Semantic change: the message text of a not_a_repo error changes, and the e2e golden changes with it.

Verification: internal/workspace tests and the e2e workspace rows pass.
@andybons
andybons force-pushed the feat/workspace-engine-interface branch from c42dedd to 0e3a493 Compare October 14, 2026 03:55
@andybons
andybons changed the base branch from feat/workspace-engine-docs to main October 14, 2026 04:10
@andybons
andybons merged commit 12b450e into main Oct 14, 2026
8 checks 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.

2 participants