Harness/brownfield adoption - #2
Conversation
The harness gated the whole codebase, not the change, so a large existing repo was red on day one and got deleted rather than adopted. Two mechanisms now split by whether a finding has a natural count: findings without one are diff-scoped to changed lines; findings with one get a floor that starts where the repo already is. Verified by adopting into scratch clones of two real repos: fusion OK 11 passed 62k lines, no pyproject.toml doghouse OK 11 passed 208k lines Django, config-only pyproject Runner (python/harness.py): - line-level diff scoping via ruff/basedpyright JSON mapped to changed hunks; --whole-file opts out. I001 deliberately excluded from WHOLE_FILE_CODES: fix cannot resort an import block without touching untouched lines, so including it deadlocks the gate. - fix reverts any file whose edits reached outside the changed ranges. Weaker guarantee than lint by design: never rewrites a line you did not touch, rather than always fixing what it could. - five ratcheted floors (coverage, complexity, CRAP, deadcode, suppressions). --update-baseline is all-or-nothing and fails loudly rather than recording a floor it could not measure. - _tool() resolver so the runner works without uv; TEST_COMMAND so a pytest repo needs a one-line edit, not two rewritten functions. - ci/pre-push are actually read-only now: four hardcoded `uv run` sites created a .venv mid-gate. A source-grep test prevents a fifth. - sync-agents-md refuses to clobber symlinks and case-variant filenames. It destroyed 277 lines of a real repo's agents.md before this. Docs (skills/harness/, skills/ratchet/): - adoption manifest rewritten by executing it until both repos went green, not by reasoning about it. The previous version was written from a code read and had 17 defects when followed literally. - keep the adopter's ruff config: overwriting doghouse's yields 19,581 findings, keeping it yields 390. - new /ratchet skill: raises one floor per run, writing only tests and .harness-baseline. Known limitation: `test` is the one gate with no adoption ramp. Neither repo's suite runs out of the box. Note: the working tree already contained uncommitted changes to bun/, go/, rust/, monorepo/, .github/, scripts/ and others from before this work. They are included here because they overlap the same files and could not be cleanly separated.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 507e9b650c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| - name: Run each template's CI gate | ||
| run: make ci |
There was a problem hiding this comment.
Install template dependencies before running CI
On a fresh GitHub runner, this invokes every template's CI without first running uv sync in python/ or bun install --frozen-lockfile in bun/, although the individual template workflows perform those steps. Consequently the Bun architecture gate tries to execute the absent ./node_modules/.bin/depcruise and fails, while Python's _audit_gate_or_warn sees no .venv and silently skips the dependency audit; install both templates' dependencies before dispatching make ci.
AGENTS.md reference: AGENTS.md:L75-L77
Useful? React with 👍 / 👎.
| if ranges and _in_ranges(*_diagnostic_row_span(diagnostic), ranges): | ||
| kept.append(diagnostic) |
There was a problem hiding this comment.
Compare type diagnostics against the base result
When a changed declaration causes basedpyright to report the resulting error on an unchanged consumer, this filter drops the newly introduced diagnostic. For example, changing a function's return annotation can make an untouched assignment incompatible, but because basedpyright locates the error at that assignment rather than the edited declaration, both check and ci pass; determine whether diagnostics are new relative to the base revision instead of using diagnostic-line overlap alone.
Useful? React with 👍 / 👎.
| arch_config_ok = _check_arch_config_guard(include_pre_push_stdin=True) | ||
| gates = [ | ||
| gherkin_ok = _check_gherkin_guard(include_pre_push_stdin=True) |
There was a problem hiding this comment.
Read the pre-push ref stream only once
When the pushed-ref stream is the only usable change source—for example, an orphan branch or a checkout where none of the configured/fallback base refs resolves—the arch-config guard consumes sys.stdin here and the immediately following Gherkin guard reads EOF, sees no production changes, and passes. The same ordering exists in the Bun, Go, and Rust pre-push paths; cache the ref stream or collect changed paths once and share them between both guards.
AGENTS.md reference: python/AGENTS.md:L20-L20
Useful? React with 👍 / 👎.
| // `.feature` file anywhere under root. | ||
| func hasAnyFeatureFiles() bool { | ||
| found := false | ||
| _ = filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error { |
There was a problem hiding this comment.
Restrict feature discovery to the acceptance directory
In a brownfield Go repository containing an unrelated .feature file under vendor/, generated output, or another tooling directory, walking the entire repository marks the acceptance suite as adopted even when features/ is empty. The acceptance command then skips, but the Gherkin guard becomes active and blocks every production change; search only the features/ tree that the Godog acceptance gate actually executes.
AGENTS.md reference: go/AGENTS.md:L12-L12
Useful? React with 👍 / 👎.
No description provided.