Scope rule: every finding from the 2026-06-12 audit with criterion improvement or missing-feature (any severity), plus the medium-severity idiomatic-go / best-practices refactor items not eligible for Plan 1. Low/info defects are in Plan 2.
Ordering rationale: phases are ordered by estimated effort, ascending β quick wins first, spec-requiring framework features last. Effort scale: XS < 1 h Β· S β half a day Β· M 1β2 days Β· L multi-day, spec required. Each phase is one package (or one tightly-related group), one MR.
Phase 1 β docs accuracy quick wins β XS
| ID |
Sev |
Fix |
stale-testing-doc-api-example |
low |
Update testing.md's NewReaderContainer example to the post-functional-options API (make it compile). |
stale-builtin-command-inventory |
low |
Add DoctorCmd/ChangelogCmd to docs/index.md + CLAUDE.md; consider generating the inventory from props.DefaultFeatures. |
machine-id-irreversibility-claim-overstated |
low |
Soften "anonymous/cannot be reversed" to pseudonymous; note cross-tool correlatability (or add a per-tool salt β then it's an S). |
Phase 2 β pkg/cmd root conveniences β XSβS
| ID |
Sev |
Fix |
no-root-version-flag |
low |
rootCmd.Version = props.Version.GetVersion() β --version works in every GTB tool. |
collector-invariant-not-upheld-for-init |
low |
Default Props.Collector to a noop at construction (uphold the documented invariant); drop the six nil-guards. |
init-detection-by-use-string |
low |
Replace cmd.Use == "init" comparisons with typed Feature/annotations. |
flag-setup-creates-config-dir-side-effect |
low |
Make GetDefaultConfigDir pure; create the dir lazily at first write. (Coordinate with Plan 2 Phase 1's error-return change β same function.) |
completion-command-ungated-undocumented |
low |
Add a CompletionCmd feature flag + a how-to page. |
Review decisions (2026-06-15): Per maintainer review, three of the five Phase 2 items are implemented β collector-invariant-not-upheld-for-init, init-detection-by-use-string, and flag-setup-creates-config-dir-side-effect. The remaining two are rejected by design and will not be implemented:
no-root-version-flag β rejected: GTB deliberately exposes a version command, not a --version flag. Adding the flag would duplicate the existing surface.
completion-command-ungated-undocumented β rejected: cobra provides the completion command automatically; gating it behind a feature flag would diverge from upstream cobra behaviour for no benefit.
Phase 3 β pkg/controls small wiring β S
| ID |
Sev |
Fix |
valid-error-func-never-used |
Med |
Add WithValidError option and consult it in the restart supervisor (exempt e.g. http.ErrServerClosed) β or // Deprecated: the dead API. Decide alongside Plan 1 Phase 10's restart-semantics spec. |
register-after-start-unguarded |
low |
Reject/warn Register when controller state β Unknown (mirror RegisterHealthCheck). |
healthcheck-cancel-field-dead |
info |
Call entry.cancel on deregistration/shutdown, or remove the field. |
Phase 4 β pkg/setup + pkg/workspace hygiene β S
| ID |
Sev |
Fix |
sealregistry-never-called |
low |
Call SealRegistry alongside setup.Seal() β activate the inert guard. |
predictable-temp-file-no-cleanup |
low |
Randomised temp suffix + O_EXCL + defer Remove + chmod-before-rename in the install path. |
direct-token-skips-credential-precedence |
low |
Route the direct provider through vcs.ResolveToken (env-ref/keychain chain). |
workspace-range-loop-discarded-var |
low |
Fix the discarded loop var; make maxDepth <= 0 include the start dir. |
Phase 5 β CI gate β S
| ID |
Sev |
Fix |
api-stability-gate-not-enforced-in-ci |
Med |
Add a just apidiff target (compare against the latest tag) and a blocking MR job. Documentation already mandates it; this is enforcement only β no spec. |
| ID |
Sev |
Fix |
duplicate-isinteractive-semantics |
low |
One IsInteractive with explicit stream parameter; gate spinner/progress/status on the stream they write to (stderr). |
writer-ignores-non-json-formats |
low |
Make Writer.Write honour YAML/CSV or return a clear unsupported-format error β not silent text. |
utils-grab-bag-package |
low |
Move tool-specific install constants out of the framework; unexport/freeze the mutable Instructions map. |
Phase 7 β pkg/telemetry hygiene batch β SβM
| ID |
Sev |
Fix |
track-methods-duplicated-event-construction |
low |
Extract a shared record(); this duplication is how the spill inconsistency survived (pairs with Plan 1 Phase 6). |
otel-endpoint-parse-lacks-validation |
low |
Validate scheme/host in ParseEndpoint (fail fast like chat.ValidateBaseURL). |
at-least-once-defeated-by-error-swallowing-backends |
low |
Return transport errors from Send (or re-document DeliveryAtLeastOnce honestly). |
observability-setup-leaks-providers-on-partial-failure |
low |
Run collected shutdowns on the error path; don't strand installed global providers. |
backendinfo-unsynchronized-despite-concurrency-contract |
low |
Mutex/atomic for BackendInfo/SetBackendInfo. |
Phase 8 β signing chain hygiene (pkg/openpgpkey, pkg/signing, internal/trustkeys) β SβM
| ID |
Sev |
Fix |
wkd-hash-encoder-duplicated |
low |
Single shared z-base-32/WKD-hash implementation (pkg/openpgpkey), consumed by pkg/setup β wire-format-critical code must not drift. |
manifest-duplicate-entry-last-wins |
low |
Reject duplicate manifest filenames. |
kms-signer-ignores-pss-opts |
low |
Return an explicit error when *rsa.PSSOptions is requested (don't silently sign PKCS#1 v1.5). |
trustkeys-doc-drift-and-swallowed-walk-error |
low |
Fix the "ships empty" package doc; propagate the WalkDir error (trust anchors must fail loud). |
detachsign-buffering-and-inverted-flag-name |
info |
Tidy per the report note. |
no-signer-fingerprint-on-success |
info |
Log the verifying key fingerprint on successful verification (audit trail). |
Phase 9 β pkg/chat provider polish β M
| ID |
Sev |
Fix |
tool-handler-panic-not-recovered |
Med |
recover() in executeTool and the parallel path; convert panics to tool-error strings per the documented error-as-content behaviour. |
settools-accumulates-stale-handlers |
low |
Replace (don't merge) the handler map in SetTools; align the Claude-only ResponseSchema reset. |
claude-stream-empty-tool-args-invalid-json |
low |
Normalise empty argBuf to {}. |
claude-system-prompt-as-user-message |
low |
Use the System field, not a user turn. |
openai-hardcoded-seed-zero |
low |
Make seed configurable (omit by default). |
no-usage-or-cost-observability |
low |
Surface token usage from all three providers (return on response struct + optional telemetry event). |
Phase 10 β transport + gateway polish β M
| ID |
Sev |
Fix |
missing-security-headers-middleware |
Med |
Add SecurityHeadersMiddleware (nosniff, frame-ancestors, referrer-policy, optional HSTS/CSP); apply to the docs/openapi handlers by default. |
gateway-register-no-http-option-passthrough |
low |
Pass HTTP server options through gateway.Register. |
response-logger-missing-unwrap |
low |
Add Unwrap() for http.ResponseController compatibility. |
openapi-path-options-unvalidated |
low |
Validate spec/docs paths (ServeMux panics on invalid patterns). |
Phase 11 β internal/generator + internal/cmd refactors β M
| ID |
Sev |
Fix |
manifest-io-duplication |
low |
Extract shared manifest read/encode helpers (4 sites). |
skeleton-data-struct-duplicated-inline |
low |
Use the named skeletonTemplateData everywhere. |
unused-escape-helpers-doc-mismatch |
low |
Wire escapeShellArg/escapeMarkdownCodeBlock at their documented sites or correct the docs. |
single-dir-tool-discards-exec-error |
low |
Surface missing-binary exec errors instead of empty "lint issues found". |
run-vs-rune-fatal-inconsistency |
low |
Standardise on RunE across internal commands. |
org-validation-silently-skipped-two-segment-repo |
info |
Validate org on two-segment repo paths too. |
Phase 12 β pkg/credentials wizard consolidation β M
| ID |
Sev |
Fix |
setup-credential-wizard-duplication |
Med |
Hoist isCI() (Γ3), keychainOpTimeout (Γ4), validateEnvVarName (Γ4), storage-mode option builders (Γ2) into pkg/credentials. Security-relevant: the CI-literal-refusal logic currently lives in 4β5 drifting copies. |
ci-check-duplicated-across-wizards |
low |
Subsumed by the hoist above. |
fieldschema-children-dead-api |
low |
Make FieldSchema.Children reachable or remove it. |
loadenv-wrong-warn-and-nil-logger |
low |
Fix the copy-pasted warning and the nil-logger panic. |
loadembed-overrides-caller-format |
low |
Honour the caller's format instead of forcing YAML. |
credtest-install-parallel-unsafe |
info |
Document the no-t.Parallel constraint. |
Phase 13 β pkg/setup mocking-hook removal + error-funnel consistency β M (API-stability care)
| ID |
Sev |
Fix |
exported-mocking-hooks-update-cmd |
Med |
Replace ExportNewUpdater/ExportNewOfflineUpdater with an UpdateOption (mirror WithExecCommand); // Deprecated: the vars for β₯1 minor release per the stability policy. |
logger-fatalf-bypasses-errorhandler |
Med |
Convert setup ai/bitbucket/github init subcommands to RunE (or ErrorHandler.Fatal) so hints, ExitFunc, and the telemetry flush apply. |
Phase 14 β pkg/vcs repo-layer evolution β MβL (small spec)
| ID |
Sev |
Fix |
repo-auth-hardcoded-to-github |
Med |
Provider-aware clone/push auth via vcs.ResolveToken; missing auth non-fatal. Small spec β public API surface. |
uninitialised-repo-methods-panic |
low |
Sentinel guards on all RepoLike methods (match WithRepo/WithTree). |
getsshkey-fragile-passphrase-detection-and-tui-prompt |
low |
Use typed *ssh.PassphraseMissingError; move the huh prompt out of library code into the CLI layer. |
(deferred from Plan 2) repolike-kitchen-sink-weak-typing β interface split |
low |
Role-interface split of the 22-method RepoLike (the controls precedent) β fold into the same spec as a v2-direction note. |
Phase 15 β pkg/props provider-interface adoption β L
| ID |
Sev |
Fix |
props-provider-interfaces-unused |
Med |
Decide once: adopt the nine narrow provider interfaces in leaf-package signatures (backward-compatible β *Props satisfies them), or amend the architecture docs to call them downstream-convenience-only. If adopting: mechanical but wide; do it package-by-package behind the apidiff gate (Phase 5). |
Phase 16 β framework execution-model features β L (spec each)
The three remaining framework features change documented behaviour for every downstream tool β each needs its own /gtb-spec.
| ID |
Sev |
Fix |
no-signal-aware-execution-context |
Med |
signal.NotifyContext + ExecuteContext; flows Ctrl-C through cmd.Context(), the telemetry flush, and update-temp cleanup. Update the skeleton main template (generator regeneration check). |
child-persistentprerune-silently-disables-framework-setup |
Med |
Set cobra.EnableTraverseRunHooks = true (assess side-effects) or move bootstrap into Execute/outermost middleware; warn when a downstream hook would shadow bootstrap. |
flag-to-config-binding-unimplemented |
Med |
Implement the documented flags layer: a WithBoundFlags binding facility applied during config load; reconcile the two contradictory precedence docs. |
| ID |
Sev |
Fix |
no-downstream-test-fixture-helper |
low |
Ship a public propstest fixture helper (wired Props with noop logger/fs/collector). Natural companion to the signal/context work since downstream tests need the new execution model. |
Coverage
All Β§3.5 improvement and Β§3.6 missing-feature findings, plus the four medium refactor-class items excluded from Plan 1 by criterion (exported-mocking-hooks-update-cmd, props-provider-interfaces-unused, logger-fatalf-bypasses-errorhandler, tool-handler-panic-not-recovered) and the medium missing-features (valid-error-func-never-used, repo-auth-hardcoded-to-github, missing-security-headers-middleware, child-persistentprerune-silently-disables-framework-setup, no-signal-aware-execution-context, api-stability-gate-not-enforced-in-ci, flag-to-config-binding-unimplemented), are assigned above. Phases 1β8 are independent quick wins; 9β14 are package refactors; 15β16 are the long-pole framework decisions.