Repository navigation
Add quality gates: enforce lint/type-check before feature_mark_passing - #334
zwanski-start wants to merge 2 commits into
Conversation
AutoForgeAI#96) New quality_gates.py auto-detects ESLint, Biome, ruff, flake8, tsc and mypy from project config files and runs them with a timeout. Node tools only run from the project's node_modules/.bin (never npx), Python tools from the project's venv or PATH. When enabled in .autoforge/config.json (off by default), feature_mark_passing runs the checks first; in strict mode (default) failing checks block marking the feature passing. Results are stored as evidence in a new quality_result column, and failures are tracked via failure_reason/failure_count. New MCP tools: feature_verify_quality and feature_report_failure. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🔍 QA report: ❌ FailedTester: Ada (cubefarm agent, in a fresh session) · Round: 1 · Author: Dennis Quality gates work as described: on a migrated old-schema DB, a real ruff failure blocks feature_mark_passing in strict mode and bumps failure_count, non-strict mode warns, and the fixed code passes. Tests, lint, mypy, build and UI smoke show nothing new versus master. However, the checks run inside the feature MCP server, outside the Bash sandbox and allowlist, from binaries and config files the agent can write, and feature_verify_quality runs even when gates are disabled. A two-line node_modules/.bin/eslint script ran unsandboxed and wrote a file outside the project directory, so security is weakened by default on every project.
🧪 Commands run
🔧 What needs fixing
No browser screenshots were taken in this round. Posted by cubefarm · sent back to the developer for fixes |
…files QA found that checks run inside the feature MCP server, outside the Bash sandbox and allowlist, and that the agent could both write the tooling (node_modules/.bin/eslint) and enable the gates via .autoforge/config.json, or call feature_verify_quality while gates were disabled. - Settings now come only from AUTOFORGE_QUALITY_GATES(_TIMEOUT|_CHECKS) in the AutoForge process environment; client.py forwards them to the MCP server. .autoforge/config.json is no longer read. - feature_verify_quality returns an error and runs nothing when disabled; run_quality_checks also refuses to run while disabled. - Document that enabling gates is a trust decision (unsandboxed project tooling) in quality_gates.py, CLAUDE.md and .env.example. - Clear failure_reason when a feature passes; only store quality_result when the UPDATE actually marked the row passing. - Tests for the env config, the disabled no-op, and a regression test reproducing the QA scenario. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🔍 QA report: ✅ PassedTester: Barbara (cubefarm agent, in a fresh session) · Round: 2 · Author: Dennis Round-2 fixes address every QA finding: quality gates are now enabled only via host env vars (AUTOFORGE_QUALITY_GATES*) forwarded by client.py, project files (.autoforge/config.json, project .env) can no longer turn them on, and feature_verify_quality returns an error and runs nothing while disabled. An end-to-end probe against the real feature MCP server confirmed an agent-planted node_modules/.bin/eslint is never executed without the host switch, while strict/warn behaviour still works with real ruff on a migrated old-schema DB. Tests, ruff, mypy and the UI build show nothing new versus master.
🧪 Commands run
No browser screenshots were taken in this round. Posted by cubefarm · merges automatically once GitHub's checks pass |
Closes #96
What changed
quality_gates.py(new). Finds a project's linters and type checkers from its config files and runs them:eslint.config.*/.eslintrc*/eslintConfig), Biome (biome.json[c]), ruff (ruff.toml/[tool.ruff), flake8 (.flake8/[flake8]). If a project has both ruff and flake8 config, only ruff runs.tsc --noEmit, ortsc --build --noEmitwhentsconfig.jsonusesreferences(Vite-style solution configs, where plaintscchecks nothing). mypy runs when mypy config exists.node_modules/.bin. It never falls back tonpx, so a check can't trigger a package download. Python tools come from the project's.venv/venvfirst, then PATH.Config (trusted, host-side only): environment variables of the AutoForge process, e.g.
~/.autoforge/.env(see.env.example).client.pyforwards them to the feature MCP server. Nothing inside the project directory is read, because the agent can write anything there:AUTOFORGE_QUALITY_GATES=strict # off (default) | strict | warn AUTOFORGE_QUALITY_GATES_TIMEOUT=120 AUTOFORGE_QUALITY_GATES_CHECKS=lint,type_checkfeature_mark_passing. When gates are enabled, the checks run before the DB update and outside any transaction.failure_reason(cleared once the feature passes) and incrementsfailure_count. The feature staysin_progressso the agent can fix the problems and call it again.warnmode, the feature is marked passing and the response includes awarning.New MCP tools:
feature_verify_quality(feature_id)runs the checks on demand and stores the result as evidence. While gates are disabled it returns{"error": "Quality gates are not enabled for this project"}and runs nothing.feature_report_failure(feature_id, reason)records why an attempt failed and incrementsfailure_count. It does not changepassesorin_progress.feature_verify_quality. The prompt templates now describe them.DB: three new
featurescolumns,quality_result(JSON),failure_reason(TEXT) andfailure_count(INTEGER, default 0)._migrate_add_quality_columnsadds them to existing databases, and they are included inFeature.to_dict().Other:
quality_gates.pyis added to the npmfileswhitelist. The CI python job now runstest_quality_gates.py. CLAUDE.md documents the feature.Assumptions / decisions
_on_agent_completealways clearsin_progresswhen a coding agent exits, and on restart it deliberately resumes features leftin_progress. Resetting them after 1 hour would conflict with resuming them, and would need a new timestamp column. I left it out to keep this PR focused.Verification
python -m pytest test_quality_gates.py: 47 passed. These include a regression test for the QA round 1 finding: an agent-written executablenode_modules/.bin/eslintplus.autoforge/config.jsonenabling the gates is never executed without the env switch.ui/(real ESLint plustsc --build --noEmit): both pass in about 4s.ruff check .is clean andtest_security.pypasses.mypy .reports no new errors; its 24 existing errors are the same as on master. The pre-existing failures intest_client.py/test_devserver_security.py(21) are also the same as on master.🤖 Generated with Claude Code