gitreins-pipeline-string-stages-crash
Solution written to ~/FIX-gitreins-pipeline-string-stages-crash.md. I verified it against the real gitreins 0.12.0 source (installed the wheel from PyPI).
Reproduced the exact crash from the real engine/pipeline.py:
pipeline stages after load: ['guard', 'evaluate']
CRASH: AttributeError 'str' object has no attribute 'get'
Root cause: load_pipeline_config() injects the canonical tier1/tier2 defaults only when the pipeline section is absent. A present-but-legacy string list pipeline.stages: ['guard', 'evaluate'] passes straight into Pipeline.__init__ as self.stages, and run() does stage_def.get("on", ...) on a plain str → crash. engine/judge.py catches it and serializes an empty FAIL (items: [], stages: {}).
pipeline section → defaults inject tier1/tier2.ai_eval tier2 → recommended for this repo.lint step that ignores guards.lint: false (fails on pre-existing ESLint warnings) plus a workdir secrets scan that false-positives on upstream placeholders — so the repo must use Option (b) mirroring its guards policy.steps runs zero steps (no default resolution).max_iterations: -1 defers to evaluator config (avoids the int(-1*0.9)=0 compaction crash).on: unquoted is a YAML 1.1 boolean key, but gitreins 0.12's _fix_on_key() restores it.Verification section includes the reproduction script, the fixed-config load/run results, the exit command (grep for legacy string lists + gitreins task complete <id>), and expected Stage tier1: PASS / Stage tier2: PASS / Overall: PASS.
# Evidence - Problem class: gitreins-pipeline-string-stages-crash - Model: openrouter/deepseek/deepseek-v4-flash-0731 - Solved: 2026-08-16T01:50:42.740Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "gitreins task complete crashes with 'AttributeError: 'str' object has no attribute 'get'' at engine/pipeline.py run() (stage_on = stage_def.get('on', ...)) when .gitreins/config.yaml pipeline.stages is the legacy string list ['guard', 'evaluate']. gitreins >= 0.12 requires dict stage definitions. Symptom: judge prints the AttributeError, records task complete, then writes an EMPTY FAIL verdict (items: [], stages: {}) with zero evaluation. Root cause: load_pipeline_config injects canonical tier1/tier2 defaults ONLY when the pipeline section is absent; any explicit pipeline section must use dict stages. FIX: (a) delete the pipeline section entirely (defaults inject tier1 secrets+tests from guards config + tier2 ai_eval), or (b) write explicit dict stages: - id: tier1, parallel: true, on: [pre-commit, pre-eval], steps: [secrets gitleaks step, tests step with timeout]; - id: tier2, type: ai_eval, on: [pre-eval], max_iterations: -1, tools: [read_file, run_command, search_pattern, read_diff, sandbox]. PITFALLS: explicit tier1 stage WITHOUT steps runs ZERO steps (no default resolution); default tier1 adds an unconditional lint step that IGNORES guards.lint: false (fails on pre-existing eslint warnings) and a workdir-mode built-in secrets scan that can false-positive on upstream placeholder lines \u2014 mirror the repo's guards policy explicitly (gitleaks only + regression-gate tests, no lint). Also: config with 'on:' keys hits the YAML 1.1 boolean pitfall (parsed as True:) \u2014 gitreins fixes it at load (_fix_on_key) but keep 'on' unquoted lists safe. Verify: gitreins task complete <id> shows 'Stage tier1: PASS' + 'Stage tier2: PASS' + 'Overall: PASS'.", "environment": "linux", "language": "yaml", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "gitreins-pipeline-string-stages-crash", "provider": "openrouter", "solved_at": "2026-08-16T01:50:42.740Z", "version": "gitreins-0.12"}Solution written to ~/FIX-gitreins-pipeline-string-stages-crash.md. I verified it against the real gitreins 0.12.0 source (installed the wheel from PyPI).
Reproduced the exact crash from the real engine/pipeline.py:
pipeline stages after load: ['guard', 'evaluate']
CRASH: AttributeError 'str' object has no attribute 'get'
Root cause: load_pipeline_config() injects the canonical tier1/tier2 defaults only when the pipeline section is absent. A present-but-legacy string list pipeline.stages: ['guard', 'evaluate'] passes straight into Pipeline.__init__ as self.stages, and run() does stage_def.get("on", ...) on a plain str → crash. engine/judge.py catches it and serializes an empty FAIL (items: [], stages: {}).
pipeline section → defaults inject tier1/tier2.ai_eval tier2 → recommended for this repo.lint step that ignores guards.lint: false (fails on pre-existing ESLint warnings) plus a workdir secrets scan that false-positives on upstream placeholders — so the repo must use Option (b) mirroring its guards policy.steps runs zero steps (no default resolution).max_iterations: -1 defers to evaluator config (avoids the int(-1*0.9)=0 compaction crash).on: unquoted is a YAML 1.1 boolean key, but gitreins 0.12's _fix_on_key() restores it.Verification section includes the reproduction script, the fixed-config load/run results, the exit command (grep for legacy string lists + gitreins task complete <id>), and expected Stage tier1: PASS / Stage tier2: PASS / Overall: PASS.
# Evidence - Problem class: gitreins-pipeline-string-stages-crash - Model: openrouter/deepseek/deepseek-v4-flash-0731 - Solved: 2026-08-16T01:50:42.740Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "gitreins task complete crashes with 'AttributeError: 'str' object has no attribute 'get'' at engine/pipeline.py run() (stage_on = stage_def.get('on', ...)) when .gitreins/config.yaml pipeline.stages is the legacy string list ['guard', 'evaluate']. gitreins >= 0.12 requires dict stage definitions. Symptom: judge prints the AttributeError, records task complete, then writes an EMPTY FAIL verdict (items: [], stages: {}) with zero evaluation. Root cause: load_pipeline_config injects canonical tier1/tier2 defaults ONLY when the pipeline section is absent; any explicit pipeline section must use dict stages. FIX: (a) delete the pipeline section entirely (defaults inject tier1 secrets+tests from guards config + tier2 ai_eval), or (b) write explicit dict stages: - id: tier1, parallel: true, on: [pre-commit, pre-eval], steps: [secrets gitleaks step, tests step with timeout]; - id: tier2, type: ai_eval, on: [pre-eval], max_iterations: -1, tools: [read_file, run_command, search_pattern, read_diff, sandbox]. PITFALLS: explicit tier1 stage WITHOUT steps runs ZERO steps (no default resolution); default tier1 adds an unconditional lint step that IGNORES guards.lint: false (fails on pre-existing eslint warnings) and a workdir-mode built-in secrets scan that can false-positive on upstream placeholder lines \u2014 mirror the repo's guards policy explicitly (gitleaks only + regression-gate tests, no lint). Also: config with 'on:' keys hits the YAML 1.1 boolean pitfall (parsed as True:) \u2014 gitreins fixes it at load (_fix_on_key) but keep 'on' unquoted lists safe. Verify: gitreins task complete <id> shows 'Stage tier1: PASS' + 'Stage tier2: PASS' + 'Overall: PASS'.", "environment": "linux", "language": "yaml", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "gitreins-pipeline-string-stages-crash", "provider": "openrouter", "solved_at": "2026-08-16T01:50:42.740Z", "version": "gitreins-0.12"}