DimitriGilbert / DimitriGilbert/gitsnitch

Test & quality alignment plan

Open
#3 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
HTML
Stars
1
Forks
0
PR merge metrics
No merged PRs in 30d

Description

# Test & Quality Alignment Plan — gitsnitch

_Revised 2026-09-05: CI removed by owner decision — quality gates are local commands run by the owner/agents; no GitHub Actions._

- **Project**: `gitsnitch` (`/home/didi/workspace/gitsnitch`, GH `DimitriGilbert/gitsnitch`, public, default branch `main`) — BTS pnpm+turbo monorepo for `@git-snitch/cli` (TS CLI generating standalone HTML git reports) + TanStack Start marketing site.
- **Date**: 2026-09-05
- **Generated by the fleet test-alignment initiative** (28-repo audit + synthesis).
- **Inputs**: [audit report](../.test-alignment-audit/reports/gitsnitch.md) · [fleet synthesis & decisions D1–D7](../.test-alignment-audit/synthesis-decisions.md)

---

## 1. Adopted decisions (D1–D7 → this stack)

| Decision | Applies here as |
|---|---|
| **D1 — runner & layout** | Vitest **v4 already in place** (`pnpm-workspace.yaml` catalog `vitest: ^4.0.16`) — no runner work, only config work. Gitsnitch has 4 testable packages (core, renderer, cli, web) — **below the ≥6 threshold**, so per-package `vitest.config.ts` files (which the audit delta explicitly asks for), **no** shared `createTestConfig()` factory. Environment policy: `node` default; `jsdom` only where DOM is under test (web always; renderer today via 10 `// @vitest-environment jsdom` docblocks + 54 `render(` calls — consolidate into config, behavior-preserving). Existing `test/` dirs stay (no mass rename). Root headless entry `pnpm test` → `turbo test` already exists. |
| **D2 — coverage** | `@vitest/coverage-v8` (matching the v4 line), reporters `text+json+html`, `include` scoped to `src/**`, exclude tests/`dist`/`routeTree.gen.ts` (bake the generated-file exclusion in from day one). Gitsnitch is a **D2 state-2 repo** (real suite, no thresholds): run coverage once, set `lines` threshold = measured − 5, commit it, ratchet +5; never lower. |
| **D3 — lint & format** | ESLint 9 flat config (root, single `eslint.config.js`) + `typescript-eslint` ^8 type-checked (`recommendedTypeChecked` + projectService) + `eslint-plugin-react-hooks` (React lives in web/renderer/ui) + `import/order` (encodes the repo's own "external imports, blank line, local imports" AGENTS.md rule). `no-floating-promises` and `no-explicit-any` as errors (AGENTS.md already bans `any` by prose). Prettier 3 as formatter, config + scripts now; repo-wide `--write` as an isolated follow-up. Dead root `lint` task (**no package defines `lint`** — `pnpm lint` is a no-op today) gets **implemented at root and the dangling turbo `lint` task deleted**. |
| **D4 — quality metrics** | **knip is required** (gitsnitch publishes 4 packages: `@git-snitch/cli`, `core`, `renderer`, `ui` — export-surface drift is a real risk; `files` fields ship `src` alongside `dist`). jscpd with the launch-mommy canonical config (`minLines: 8`, `minTokens: 80`), **report-only (`exitCode: 0`)**. CRAP requires coverage → optional follow-up after Phase 1. Renovate via org preset one-liner. Mutation testing: **not** nominated for gitsnitch (Stryker's five-core list does not include it). |
| **D5 — no CI by design (owner decision 2026-09-05)** | **No GitHub Actions, no reusable-workflow caller, no local workflow** — the earlier "local workflow in the context-builder donor shape, later swapped to a `DimitriGilbert/.github` `ts-ci.yml` caller" plan is dropped entirely. Enforcement = the root-level headless verification entrypoint (`pnpm verify`: lint → check-types → test → build, composed in Phase 3) run by the owner and by agents; the plan's phase validation gates are run by implementer/validator agents before any phase is declared done. |
| **D6 — shared config** | `@dg/config` adoption is deferred: it is hosted in the same missing org repo, and D6 itself says adopt "when it touches lint/tsconfig/vitest anyway, never as churn". `packages/config` keeps its strict `tsconfig.base.json` (already fleet-grade: `strict`, `noUncheckedIndexedAccess`, `noUnusedLocals/Parameters`, `verbatimModuleSyntax`). Revisit after the org repo exists. |
| **D7 — hooks** | The local gate commands run by the owner/agents are the only authoritative gate. No hooks are required; optional lefthook pre-push (typecheck + affected tests) is listed as an opt-in follow-up, never load-bearing. AGENTS.md must state: "the headless local verification command (`pnpm verify`) is the quality gate, run by the owner/agents; hooks are local convenience." |

### Deviations from the synthesis (reality over synthesis)

1. **`--full-page` is untracked, not tracked.** The audit (§1, §6 P3) calls it a tracked file; `git status` shows `?? --full-page` — it is a stray untracked working-tree artifact. Plan still removes it, by explicit `rm` (never `git clean`).
2. **Version drift is source-side, not test-side.** The audit says the test "expects 0.0.0, package is 0.0.15"; actually `apps/cli/src/index.ts` (lines 26–32) **hardcodes** `version: "0.0.0"` including a literal type, and the test faithfully pins the source. The real bug: the published CLI's `--version` reports `0.0.0` while npm says `0.0.15`. Fix = single-source the version from `apps/cli/package.json` and make the test assert consistency.
3. **jsdom arrives via docblocks, not only the one inline flag.** The audit delta says "one inline `--environment jsdom` flag"; the renderer additionally uses 10 per-file `@vitest-environment jsdom` docblocks. The per-package configs must absorb both without changing which environment any test runs in.
4. **Org host repo missing** (see D5/D6 rows above) — moot for D5 under the no-CI decision; Renovate preset convergence remains for Phase 5.
5. **Sibling package name.** The brief says `/home/didi/workspace/git-snitch` "holds the git-snitch npm package name" — it actually holds **`git-moar`** (v0.0.1, bin `git-moar`). See §6 Risks.
6. **Vitest is already v4** — the D1 "v3 repos upgrade at next touchpoint" clause does not apply.

---

## 2. Current state vs the fleet Definition of Done

| # | DoD item (synthesis §3) | Status in gitsnitch today |
|---|---|---|
| 1 | Root headless test command, documented in AGENTS.md | **Partial** — `pnpm test` → `turbo test` works (27 test files, ~208 cases); AGENTS.md only hedges "when test scripts exist" and carries a stale workdir path |
| 2 | Headless verification entrypoint, green locally, gates recorded by agents | **Missing** — no root aggregate command |
| 3 | Coverage measured + baseline recorded | **Missing** — no `@vitest/coverage-*`, no coverage block; the healthy ~37% test-to-source ratio is unmeasured |
| 4 | Lint installed, zero errors, wired into the headless entrypoint; dead turbo `lint` resolved | **Missing** — zero lint/format tooling; root `lint: turbo lint` targets a task no package defines |
| 5 | AGENTS.md "Testing" section matches reality | **Partial** — testing rules are excellent (`docs/agent/testing.md` is donor-grade) but commands/workdir are stale |
| 6 | Dead scaffold test deps removed or used | **Satisfied** — `@testing-library/*` + `jsdom` in web/renderer are genuinely used (54 `render(` calls); core/cli carry vitest only |
| 7 | Renovate one-liner; no `"latest"` deps | **Missing Renovate**; dependency pinning is fine (catalog + carets, no `latest`) |
| 8 | Quality-report script (knip + jscpd) runnable locally, report-only | **Missing** |
| 9 | No fake passes | **Satisfied** — no `passWithNoTests`, behavioral assertions throughout, docs forbid fake tests; the one drift risk (hardcoded CLI version literal) is fixed in Phase 0 |

---

## 3. Prerequisites

- pnpm 10.10.0 (`packageManager` field), Node ≥ 22 (the documented toolchain), git on PATH (CLI/core tests create temp git repos).
- Run all commands from `/home/didi/workspace/gitsnitch`. Never `git stash`/`reset --hard`/`git clean` — **the tree currently carries uncommitted modifications across ~23 files plus untracked `packages/ui/src/components/tabs.tsx`; every phase must land additively on top.**
- Catalog discipline: add new deps to `pnpm-workspace.yaml` `catalog:` where a version is shared, reference as `"catalog:"`, then `pnpm install`.

## 4. Execution model (per subagent-orchestration skill)

- Each phase is **sequential** (single sub-phase each): orchestrator dispatches **one Implementer** with the complete phase requirements + the NO-SLOP policy (no `any`/`as any`/`: any`, no TODO/FIXME, no unused imports/vars, `import type` for type-only imports, external-then-local import order, no dev servers) → Implementer runs the phase's gatekeeping commands **before** reporting done → orchestrator dispatches **one Validator** (different agent) that must **actually read every changed file** and verify each requirement, then re-run the gates → on FAIL, one **Fixer** with all validator findings at once → re-validate; max 3 fix loops, then halt and report.
- Validators enforce NO-SLOP stringently; running commands alone is not validation.
- Gatekeeping common to every phase: `pnpm run check-types` (and `pnpm run build` for phases marked substantial), `pnpm test`.

---

## Phase 0 — Repo hygiene & version single-sourcing

**Effort**: S · **Type**: Sequential · **Subagent**: Implementer → Validator

**Requirements**:
1. `apps/cli/src/index.ts`: remove the hardcoded `version: "0.0.0"` from `cliPackageMetadata` (and the `"0.0.0"` literal type at line ~26). Source the version from `apps/cli/package.json` (e.g. `import packageJson from "../package.json" with { type: "json" }` — `resolveJsonModule` is already on; TS ^6 supports import attributes; `package.json` is already in the package's `files` list so the relative import resolves identically from `dist/`). Verify `dist/index.js`'s `../package.json` resolution lands on `apps/cli/package.json` after `tsc -p tsconfig.build.json`.
2. `apps/cli/test/index.test.ts`: replace both `0.0.0` literals (the `cliPackageMetadata` toEqual and the `--version` stdout assertion) with assertions of **consistency** — `cliPackageMetadata.version` equals the version read from `apps/cli/package.json`, and `--version` output contains that value. No version literal remains in the test.
3. Delete the stray untracked artifact: `rm -- ./--full-page` (explicit named-file deletion only).
4. `AGENTS.md`: fix the stale workdir line — replace `/home/didi/workspace/Code/git-report/git-snitch` with `/home/didi/workspace/gitsnitch`; drop the now-false "nested repository / legacy files in the parent repo" framing. Do **not** touch the Testing section here (Phase 5 owns it).
5. Leave `example-report.html` untouched (flagged in §6; removal is an owner call).

**Inputs**: `apps/cli/src/index.ts`, `apps/cli/test/index.test.ts`, `apps/cli/package.json`, `AGENTS.md`.
**Outputs**: modified `apps/cli/src/index.ts`, `apps/cli/test/index.test.ts`, `AGENTS.md`; deleted `--full-page`.
**Validation gate** (Validator runs all): `pnpm --filter @git-snitch/cli build` succeeds; `pnpm --filter @git-snitch/cli test` green with no version literal in either file; `pnpm run check-types`; `pnpm test`; `ls --full-page` fails (file gone); AGENTS.md contains no `Code/git-report` path.
**Dependencies**: none.

---

## Phase 1 — Vitest configs + coverage measurement (D1, D2)

**Effort**: M · **Type**: Sequential · **Subagent**: Implementer → Validator

**Requirements**:
1. `pnpm-workspace.yaml` catalog: add `"@vitest/coverage-v8": "^4.0.16"` (same line as `vitest`).
2. Add `"@vitest/coverage-v8": "catalog:"` to devDependencies of `packages/core`, `packages/renderer`, `apps/cli`, `apps/web`; run `pnpm install`.
3. Create four `vitest.config.ts` files (this repo has zero today; tests run on defaults):
- `packages/core/vitest.config.ts` — `test.environment: "node"`; `include: ["test/**/*.test.ts"]`; `coverage` block per step 4.
- `packages/renderer/vitest.config.ts` — keep default `node` environment and the existing per-file `@vitest-environment jsdom` docblocks **as-is**, or consolidate via `environmentMatchGlobs: [["test/**/*.test.tsx", "jsdom"]]` only if every `.tsx` test currently runs jsdom — behavior-preserving is the hard rule; when unsure, keep docblocks. `coverage` block per step 4; exclude `dist/**`.
- `apps/cli/vitest.config.ts` — `node`; coverage per step 4. Keep the package's test script (build-then-test against built deps) unchanged.
- `apps/web/vitest.config.ts` — `environment: "jsdom"` (absorbs the current inline `--environment jsdom` flag); change the web test script to plain `vitest run`; exclude `src/routeTree.gen.ts`; coverage per step 4.
4. Every coverage block: `provider: "v8"`, `reporter: ["text", "json", "html"]`, `include: ["src/**"]`, `exclude` tests, `dist/**`, generated files (`routeTree.gen.ts`), with a `thresholds.lines` placeholder left **unset** until step 5's baseline is measured.
5. Run `pnpm run test:coverage` (below). Read each package's text reporter. Set `thresholds: { lines: }` per package in its `vitest.config.ts`. Record the measured baselines in `AGENTS.md` "Testing And TDD" (one line per package). Ratchet policy (+5 when green, never lower) goes into `docs/agent/testing.md` in Phase 5.
6. Scripts: per tested package add `"test:coverage": "vitest run --coverage"`; root `package.json` add `"test:coverage": "turbo test:coverage"`; `turbo.json` add a `test:coverage` task mirroring the `test` task (`dependsOn: ["^test:coverage"]`, `outputs: ["coverage/**"]`). `coverage/` is already gitignored — no `.gitignore` change.
7. Do not add `passWithNoTests`, `setupFiles`, or a shared factory (repo is below the ≥6-package threshold). Do not rename `test/` dirs.

**Inputs**: `pnpm-workspace.yaml`, all workspace `package.json` files, existing `apps/web/vite.config.ts` + `packages/renderer/vite.config.ts` (stay build-only — add no `test` block to them; configs are separate files).
**Outputs**: create 4 `vitest.config.ts`; modify `pnpm-workspace.yaml`, 4 `package.json` files, root `package.json`, `turbo.json`, `AGENTS.md`; lockfile via `pnpm install`.
**Validation gate**: `pnpm install --frozen-lockfile` succeeds (lockfile committed state); `pnpm test` green with the same per-package case counts as before the change (behavior-preserving — Validator diffs the vitest summary counts); `pnpm run test:coverage` runs all four packages, prints `text` coverage, writes `html`+`json`, and **passes the new thresholds**; `pnpm run check-types`.
**Dependencies**: Phase 0.

---

## Phase 2 — ESLint 9 flat + Prettier 3; revive the dead lint task (D3)

**Effort**: M · **Type**: Sequential · **Subagent**: Implementer → Validator

**Requirements**:
1. Catalog: `eslint: ^9`, `@eslint/js: ^9`, `typescript-eslint: ^8`, `eslint-plugin-react-hooks: ^6` (latest stable major), `eslint-plugin-import: ^2`, `globals: ^16`, `prettier: ^3`. Install at root: `pnpm add -D -w eslint@catalog: @eslint/js@catalog: typescript-eslint@catalog: eslint-plugin-react-hooks@catalog: eslint-plugin-import@catalog: globals@catalog: prettier@catalog:` (exact versions resolved at install; ESLint 9 / ts-eslint ^8 / Prettier 3 are the fleet families).
2. Create root `eslint.config.js` (repo is `"type": "module"`, so ESM works natively): `@eslint/js` recommended + `typescript-eslint` `recommendedTypeChecked` with `parserOptions.projectService: true` and `tsconfigRootDir: import.meta.dirname` (add `allowDefaultProject: ["*.js", "*.mjs"]` so root-level JS config files type-check); `eslint-plugin-react-hooks` recommended applied to `apps/**`, `packages/renderer/**`, `packages/ui/**`; `import/order` with `groups: ["builtin", "external", "parent", "sibling", "index"]` + `"newlines-between": "always"` (encodes the AGENTS.md import convention). Rules as errors: `@typescript-eslint/no-floating-promises`, `@typescript-eslint/no-explicit-any`. `ignores`: `**/dist/**`, `**/coverage/**`, `**/.turbo/**`, `**/node_modules/**`, `**/routeTree.gen.ts`, `**/*.html`, `pnpm-lock.yaml`.
3. Root scripts: `"lint": "eslint ."` (replacing `"lint": "turbo lint"`), `"format": "prettier --write ."`, `"format:check": "prettier --check ."`. **Delete the `lint` task from `turbo.json`** — the dangling task is removed by implementing lint at the root instead (single root config + projectService covers all workspaces; no per-package lint scripts).
4. `.prettierrc.json` with defaults (the codebase is already double-quote/default-style — keep the config empty of overrides unless the implementer hits real churn) and `.prettierignore` (`dist`, `coverage`, `pnpm-lock.yaml`, `**/*.html`, `.turbo`).
5. Run lint and fix **real** findings in source (unused imports, floating promises, misplaced imports). Do not weaken rules to pass; no `eslint-disable` without a written justification comment, and zero of them is the target. Do **not** run the repo-wide `prettier --write` in this phase (churn on top of the dirty tree) — leave `format` as an on-demand script and note it.
6. This phase is substantial: finish with `pnpm run build` as well as the standard gates.

**Outputs**: create `eslint.config.js`, `.prettierrc.json`, `.prettierignore`; modify root `package.json`, `turbo.json`, `pnpm-workspace.yaml`; whatever source files lint legitimately flags.
**Validation gate**: `pnpm run lint` exits 0 with zero errors and zero warnings; `pnpm run check-types`; `pnpm run build`; `pnpm test`; `grep -c '"lint": "turbo lint"' package.json` → 0 and `turbo.json` contains no `lint` task.
**Dependencies**: Phase 1 (so lint gates on a green suite; also both touch shared manifests — order avoids rebase noise).

---

## Phase 3 — Local gate composition (D5)

**Effort**: S · **Type**: Sequential · **Subagent**: Implementer → Validator

**Requirements**:
1. Root `package.json`: add `"verify": "pnpm run lint && pnpm run check-types && pnpm test && pnpm run build"` — the headless verification entrypoint (D5).
2. Coverage reports stay local: the text reporter prints in the console; HTML/JSON go to each package's git-ignored `coverage/` directory. No artifact uploads, no workflow files (D5).
3. `scripts/release.sh` remains the local release procedure — out of scope for this plan.

**Outputs**: modify root `package.json`.
**Validation gate**: `pnpm run verify` exits 0 from the repo root and every sub-command exists in `package.json` scripts; fail-fast proven once (validator introduces a failing assertion in a scratch copy and confirms `verify` exits non-zero at the failing step — never on the real tree); the implementer/validator agents record the green output in the phase report before the phase is declared done (D5); no workflow file was created anywhere.
**Dependencies**: Phases 1 (coverage exists) and 2 (lint exists to gate).

---

## Phase 4 — Quality metrics, report-only: knip + jscpd (D4)

**Effort**: S · **Type**: Sequential · **Subagent**: Implementer → Validator

**Requirements**:
1. `pnpm add -D -w knip@^5 jscpd@^4.2`.
2. Create `knip.json` (`$schema` included): entry `apps/cli/src/index.ts` (the bin), workspace-aware defaults for the published packages (`@git-snitch/cli`, `core`, `renderer`, `ui` — their `exports`/`files` maps ship `src` alongside `dist`, exactly the surface knip must police); tune `ignoreDependencies`/`ignoreExportsUsedInFile` only where findings are false positives. **Report-only — no `--include` exit-code gating.**
3. Create `.jscpd.json` with the launch-mommy canonical config: `min-lines: 8`, `min-tokens: 80`, `reporters: ["consoleFull", "html"]`, exclude `**/test/**`, `**/dist/**`, `**/coverage/**`, `**/*.html`, and `"exitCode": 0` (report-only until a baseline exists — the ideadump lesson: a gate without a baseline just breaks).
4. Root script `"quality:report": "knip && jscpd"`.
5. Run on demand: `quality:report` is executed by the owner or during a periodic agent pass; the jscpd HTML + knip output stay local (git-ignored report dirs). Never part of `verify`, no workflow, no schedule (D4/D5).
6. Fix nothing the reports surface in this phase — collect findings as follow-up issues.

**Outputs**: create `knip.json`, `.jscpd.json`; modify root `package.json`; lockfile.
**Validation gate**: `pnpm run quality:report` exits 0 and produces both reports locally; `pnpm run check-types`; `pnpm test`; `pnpm run lint`; `pnpm run build`.
**Dependencies**: Phase 3 (the verify chain exists, so the report scripts stay out of it).

---

## Phase 5 — Renovate + documentation truth-sync (D6-adjacent, D7, DoD 1/3/5/7)

**Effort**: S · **Type**: Sequential · **Subagent**: Implementer → Validator

**Requirements**:
1. Create `renovate.json`: `{"$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": ["local>DimitriGilbert"]}` — with a note that the org preset repo doesn't exist yet, so this no-ops until `DimitriGilbert/.github` ships its `renovate.json` (fleet-level Wave-1 deliverable). No Dependabot files.
2. `AGENTS.md` sync (full DoD item 1/3/5 compliance):
- Commands section: `Lint: pnpm run lint`, `Test: pnpm test`, add `Test coverage: pnpm run test:coverage`, `Quality report: pnpm run quality:report`; remove the "when lint scripts exist" / "when test scripts exist" hedges.
- Testing And TDD section: state the runner (Vitest 4, per-package `vitest.config.ts`), where tests live, the coverage baselines from Phase 1, the ratchet rule (+5 when green, never lower), and the D7 statement: "the headless local verification command (`pnpm verify`) is the quality gate, run by the owner/agents; hooks are local convenience."
- Add a gate line: `pnpm run verify` is the quality gate.
3. `docs/agent/testing.md`: add a short "Coverage & gate" section (baseline table, ratchet policy, the local gate) — **do not weaken any existing rule**; the doc is donor-grade and stays that way.
4. Optional (only if the owner opts in — D7 says never required): `pnpm add -D -w lefthook@^1` + committed `lefthook.yml` with **pre-push** (not pre-commit) `typecheck` + `turbo test --affected`. Skip by default; absence of hooks is compliant.

**Outputs**: create `renovate.json` (+ `lefthook.yml` only if opted in); modify `AGENTS.md`, `docs/agent/testing.md`.
**Validation gate**: `renovate.json` parses as JSON and `extends` matches the fleet one-liner; AGENTS.md contains zero stale paths (`grep -c "Code/git-report" AGENTS.md` → 0), zero hedged lint/test phrasing, and the coverage baselines match the `vitest.config.ts` thresholds exactly (Validator cross-reads both); `pnpm run check-types`; `pnpm test` still green.
**Dependencies**: Phases 1–4 (documents their outcomes).

---

## 5. Out of scope / follow-ups (not this plan)

- **Browser/`file://` E2E for the renderer** (audit P2: injection safety is the product's top risk and `docs/release-validation.md` admits no browser automation). Real work — a Playwright tier loading generated reports — belongs in its own plan; this initiative's DoD does not include E2E.
- CRAP/complexity reporting (`crap-score` over `coverage-final.json`) — now unblocked once Phase 1 lands; add alongside the local quality report scripts (D4 sequence).
- `@dg/config` adoption (D6) and convergence of `renovate.json` onto the org preset — the latter only if `DimitriGilbert/.github` ships a preset; no CI conversion exists anymore (D5).
- Deleting or relocating the 998 KB tracked `example-report.html` — owner call, flagged only.
- Any `git-snitch` / `git-moar` naming resolution — see §6; **no renames in this plan**.

## 6. Risks & notes specific to this repo

1. **Naming swap (flagged, not fixed here).** Directory `gitsnitch` ↔ root package name `git-snitch` (private) and scoped npm packages `@git-snitch/*` (published, v0.0.15). Sibling directory `/home/didi/workspace/git-snitch` ↔ package **`git-moar`** (v0.0.1) — the brief's claim that the sibling holds the `git-snitch` npm name is inaccurate; it holds `git-moar`. Net effect: both repos' directory names are swapped relative to their package identities, and the unscoped `git-snitch` name is claimed by a *private* manifest here while the sibling's unscoped name is `git-moar`. Repo-hygiene risk: any future unscoped `git-snitch` publish, doc link, or install one-liner can silently target the wrong project. **Per initiative scope: flagged only — no renames, and no publishing step may proceed before the identity question is resolved.** The already-published scoped `@git-snitch/*` packages are unaffected.
2. **Dirty tree.** ~23 modified files + untracked `packages/ui/src/components/tabs.tsx` at planning time. All phases land additively; implementers/fixers must never stash/reset/clean. All gates are local (D5) — no pushes are needed for validation.
3. **Behavior-preserving vitest configs.** Renderer tests run in two environments via docblocks today; a wrong global `environment` flip could mask or break suites. Gate = identical case counts + green runs (Phase 1 validator).
4. **`apps/cli` tests depend on built workspace deps** (`pnpm --filter ... build && vitest run`) and spawn real temp git repos with 120 s timeouts. Machines running the gate need git on PATH; do not "optimize" the build-then-test script away — it is deliberate (tests run against the published shape).
5. **Org repo dependency (Renovate preset only).** `DimitriGilbert/.github` does not exist (verified 2026-09-05) — only the Renovate preset is affected: until it exists, `local>DimitriGilbert` no-ops and dependency updates stay manual here. No CI dependency exists (D5).
6. **Churn control.** Prettier is configured but the repo-wide reformat is deliberately deferred (dirty tree); lint fixes are limited to genuine findings.

## 7. Success criteria

- All six phases pass implementer → validator loops (≤3 fix iterations each).
- Fleet DoD items: 1 ✓ (documented `pnpm test`), 2 ✓ (`pnpm verify` green locally, recorded by agents), 3 ✓ (coverage baselines + thresholds recorded), 4 ✓ (lint zero errors, dead turbo task gone), 5 ✓ (AGENTS.md/testing docs match reality), 6 ✓ (already), 7 ✓ (renovate one-liner), 8 ✓ (knip+jscpd local report script), 9 ✓ (already, version drift closed in Phase 0).
- Final local gates: `pnpm run verify` (and each of its sub-commands) all clean.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with the phase requirements and their named inputs, especially apps/cli/src/index.ts, apps/cli/test/index.test.ts, AGENTS.md, and the package configuration files. Run pnpm test and pnpm run check-types to establish the baseline; the work is done when the planned local quality gates and phase validation commands pass without the documented drift or stale configuration.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
build-system, testing, tooling
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.