Repository navigation
Description
Problem
Part of #588. Split the two vendoring drift gates out of #330 as one reviewable PR. Their shell logic must move to Go without changing what a staged payload or untracked file means.
Evidence on origin/main at a0347a715fab580ece45edfcb3d13509620459a8: the Go-module gate is .devtools/tasks/go.toml:272; the vendir gate is .devtools/tasks/vendir.toml:50. Existing tests cover untracked files, personal excludes, repository ignores, staged payloads, and non-vendoring modules in tests/tasks/vendor.bats:31; whole-payload scope is checked in tests/tasks/languages.bats:169.
Acceptance criteria
- AC1:
devtools:vendor-checksucceeds with its existing skip message and invokes no Go regeneration whenvendor/modules.txtis not tracked. - AC2: For a tracked vendor manifest, Go dependency regeneration runs tidy before vendor and stops if either operation fails.
- AC3:
devtools:check-vendoredresyncs vendir without allowing inherited Git repository-redirection variables to affect that sync. - AC4: Each gate reports drift when regenerated files differ from the caller's Git index within that gate's existing checked paths.
- AC5: Each gate rejects and lists untracked files in its checked payload paths even when personal excludes hide them, while honoring repository
.gitignorerules. - AC6: A failed Git comparison or listing cannot produce a successful gate result.
- AC7: Neither gate stages files or changes the caller's Git index, HEAD, or remotes.
- AC8: Non-functional: the replacement preserves the frozen shell's statuses, separate output streams, and resulting worktree files on Linux, macOS, and Windows.
- AC9: Every existing consumer-facing vendoring-check entry point ends as a thin shell wrapper that probes the Go subcommand and falls back to the frozen shell when that capability is unavailable throughout N-2 compatibility.
Scope and non-goals
The Go-module gate checks go.mod, go.sum, and the whole vendor tree (.devtools/tasks/go.toml:285). The vendir gate compares its two manifest files, mise drop-ins, and the entire devtools payload; its untracked scan covers the drop-ins and payload (.devtools/tasks/vendir.toml:58). Preserve this distinction rather than broadening either gate's scope.
The vendir subprocess excludes GIT_DIR, GIT_COMMON_DIR, GIT_WORK_TREE, GIT_INDEX_FILE, and GIT_OBJECT_DIRECTORY; comparisons retain the caller's environment and therefore its selected index (.devtools/tasks/vendir.toml:29). A staged payload need not match HEAD to pass. Both checks intentionally regenerate worktree content before evaluating drift.
Non-goals: replacing vendir or Go tooling, changing dependency selection, adding checks outside the existing path sets, turning regeneration into a read-only operation, or automatically staging/committing the result. Plain devtools:vendor remains external-tool sequencing (.devtools/tasks/go.toml:268).
Approach
Port both small gates together because they share the same index and untracked-file contract. Establish failing Go behavior tests before replacing dispatch and compare old/new results against real disposable Git indexes and controlled external-tool outcomes. Keep the frozen shell reachable only through the N-2 capability fallback; an operational Go failure must never trigger a second regeneration through shell.
Dependencies
- Port the pins, vendoring, preapproval and APM sync task logic #330 tracks the task family.
- Replace complex shell with tested Go, starting with gates and merging #588 supplies the migration requirements.
- Ship the Go binaries as release assets installed through mise's github backend #333 tracks binary distribution; unchanged N-2 consumers keep the fallback until the Go capability is installed.
Size
S. One PR for the two small drift gates, parity coverage, and compatible dispatch.
Verify plan
Write and observe the named replacement tests fail before changing dispatch or removing shell behavior. Use frozen-shell comparisons as the parity oracle; no live protected action is needed.
- AC1, AC2: Failing tests first for absent, untracked, and tracked vendor manifests; record tidy/vendor order and inject failure at each step.
- AC3: Failing tests first with all five inherited Git-redirection variables; prove vendir receives the scrubbed environment while later comparisons use the caller's index.
- AC4, AC5: Port all assertions from
tests/tasks/vendor.bats:31and payload assertions fromtests/tasks/languages.bats:169. Exercise modified/deleted tracked files, new files in every checked payload tree, a staged update differing from HEAD, global and Git-local excludes, and repository ignores. - AC6, AC7: Failing tests first for comparison/listing errors, including partial valid-looking output. Snapshot the index, HEAD, and remotes before and after successful and failed checks; expect regeneration changes only in the worktree.
- AC8: Compare frozen shell and Go status, stdout, stderr, and worktree results using the same fixtures. Run Go tests on Linux, macOS, and Windows and the required shell parity on Linux and macOS.
- AC9: Failing wrapper tests first for capable, absent, old, and unsupported binaries, consumer-selected version precedence, exact argument forwarding, and no shell rerun after an operational failure. Run focused wiring tests,
mise run lintandmise run test, and relevant payload checks; remove only Bats cases whose behavior has migrated.
Definition of done: D1–D10 apply.
Risks
Comparing against HEAD would reject the very staged update these gates must accept. Honoring personal excludes would hide unreviewed payload. Scrubbing Git variables for the comparisons, rather than only the vendir subprocess, would inspect the wrong index.
Operator authority
None.
Metadata
Metadata
Assignees
Labels
Type
Fields
Priority
Work type
Projects
- StatusShow more project fieldsBacklog
Activity
tbhb-agent commentedon Oct 26, 2026
Refinement: READY — Vendoring drift gates Go migration requirements and verification plan are complete
Model: gemini-4-argon-high
Checked
tbhb-dev/devtools#799(body and0comments) and referenced issues#330,#588, and#333againstorigin/mainata0347a715fab580ece45edfcb3d13509620459a8.devtools:vendor-checkis defined in.devtools/tasks/go.toml:272-295: checksgit ls-files -- vendor/modules.txt(.devtools/tasks/go.toml:277), prints"vendor-check: skipping module without tracked vendor/modules.txt"and exits0when untracked (.devtools/tasks/go.toml:278-281), runsgo mod tidythengo mod vendorunderset -euo pipefail(.devtools/tasks/go.toml:276-283), diffsgo.mod,go.sum, andvendor/against the index (.devtools/tasks/go.toml:285), checks untracked files withgit ls-files --others --exclude-per-directory=.gitignore -- go.mod go.sum vendor/(.devtools/tasks/go.toml:286-290), and writes the failure diagnostic to stderr with exit1(.devtools/tasks/go.toml:291-294).devtools:vendoris external-tool sequencing at.devtools/tasks/go.toml:268-270(run = ["go mod tidy", "go mod vendor"]).devtools:check-vendoredis defined in.devtools/tasks/vendir.toml:50-69: rationale for scrubbingGIT_DIR,GIT_COMMON_DIR,GIT_WORK_TREE,GIT_INDEX_FILE, andGIT_OBJECT_DIRECTORYonvendir syncwhile retaining the caller's environment and index for comparisons is documented at.devtools/tasks/vendir.toml:29-49and implemented at.devtools/tasks/vendir.toml:55-56; index comparison coversvendir.yml,vendir.lock.yml,.config/mise/conf.d, and.devtoolsat.devtools/tasks/vendir.toml:58; untracked scan covers.config/mise/conf.dand.devtoolsat.devtools/tasks/vendir.toml:59-63; drift diagnostic to stderr with exit1and clean confirmation to stdout are at.devtools/tasks/vendir.toml:64-68.tests/tasks/vendor.bats:31-74covers untracked generated files (tests/tasks/vendor.bats:31-38), personal excludes viacore.excludesFileand.git/info/exclude(tests/tasks/vendor.bats:40-53), repository.gitignoreand staged payloads (tests/tasks/vendor.bats:55-65), and skipping modules without trackedvendor/modules.txt(tests/tasks/vendor.bats:67-74). Whole-payload drift and newly added.devtoolsfiles are covered intests/tasks/languages.bats:169-187.AC1–AC9): Every criterion is observable, testable, scoped to a single outcome, and free of prescribed internal package/file/library layout.AC8covers non-functional parity (exit status, separate stdout/stderr streams, worktree files, and Linux/macOS/Windows execution), andAC9covers the thin shell wrapper capability probe and N-2 fallback required bydocs/compatibility.md:3-6,#330, and#588.#330(parent Feature),#588(parent Epic), and#333(release binary distribution paired with N-2 fallback) are real and properly classified.S): Fits one reviewable PR covering two small inline task scripts (14and15source lines indocs/script-inventory.md:235,282), Go unit/integration parity tests, and thin N-2 fallback wrappers.AC1–AC9) has falsifiable test coverage (failing tests first, subprocess order/failure injection, environment scrubbing verification, personal vs repository ignore handling, index/HEAD/remote immutability snapshots, partial/failed Git command handling, cross-platform parity, and wrapper fallback/failure-propagation checks). Risks accurately identify index-vs-HEAD comparison, personal excludes, and environment scrubbing boundaries.Noneis accurate. Neither.devtools/tasks/go.tomlnor.devtools/tasks/vendir.tomlmatchesgolden_paths,constitutional_paths, orowner_pathsin.agents/agent-skills.conf:4-9or special rules in.github/CODEOWNERS:10-13, and wrapping the task bodies with Go capability dispatch plus frozen-shell fallback does not introduce suppressions or remove gate entries underpackages/agents/source/skills/merge-pr/shared/scripts/merge-policy.py:430-471.Gaps
None.
Split
None needed;
Sscope fits a single pull request.Definition of done
The definition of done for #799 (Feature). Tick each item and give its evidence. (Ticked boxes below record planning coverage in the issue's criteria and verification plan, not completed implementation work.)
## Verify planmapsAC1–AC9to concrete test cases and commands (mise run lint,mise run test, focused wiring and parity checks) and statesDefinition of done: D1–D10 apply.## Verify plandeclaresDefinition of done: D1–D10 apply, matching repository merge enforcement in.agents/agent-skills.conf:2-9.## Verify planrequiresmise run lint,mise run test, and Linux/macOS/Windows test passes forAC8–AC9plusDefinition of done: D1–D10 apply;## Operator authorityconfirms no gate loosening or owner-protected path is required (.agents/agent-skills.conf:4-9).check-leaks.shwith the repository's private-strings list, and the leak review of each post. — Planning coverage:## Verify plandeclaresDefinition of done: D1–D10 applyalongsidemise run lint(mise.toml:800,.devtools/scripts/check-leaks.sh:1).## Verify plandeclaresDefinition of done: D1–D10 apply, matching repository commit and merge signing policy (AGENTS.md:53).docs/, CHANGELOG or help text), or the Verification section says "No doc impact" and why. — Planning coverage:## Verify plandeclaresDefinition of done: D1–D10 apply, whileAC8andAC9preserve existing consumer-facing entry points and behavior (docs/compatibility.md:11-20,packages/agents/source/skills/pr/shared/scripts/validate-description.sh:491-492).provenance:agent-assistedlabel. — Planning coverage:## Verify plandeclaresDefinition of done: D1–D10 apply, matching repository trailer and PR validation rules (AGENTS.md:30).## Sizescopes the change toS(one PR for the14- and15-line drift gates at.devtools/tasks/go.toml:272and.devtools/tasks/vendir.toml:50,docs/script-inventory.md:235,282) and## Verify plandeclaresDefinition of done: D1–D10 apply.## Verify plandeclaresDefinition of done: D1–D10 apply, and## Dependencieslinks#330,#588, and#333for the surrounding migration and binary distribution work.Status:comment names the merge commit. — Planning coverage:## Verify plandeclaresDefinition of done: D1–D10 apply.Round: 1 of 3