Fifth field target: n8n's execution-status classification — no defect in n8n. But the pure-reject trap reproduced 5/5 after the 6.1.0 prompt-wording fix, and the study isolated the real trigger: generations reject every branch that maps to a named specialRules entry — because the template and renderer literally commanded it ("REQUIRED reject(reason) cases") for every rule, including rules naming behavioral branches. Full finding: eval/FINDING-n8n-reject-no-write.md.
Changes
- Corpus-classified special rules.
renderSpecialRulesAsRejections(contract, windows)classifies each rule by what the code actually does on its matching windows: all no-op →[REJECTION — must reject]; all change →[BEHAVIORAL — must perform the transition, MUST NOT reject; the name is only the why]; mixed → two-armed instructions split by pre-state, or the per-branch observable-change test when the arms overlap (one absolute would manufacture the inverse trap — caught by adversarial review on the repo's own eval corpus).whenStateidioms (key == 'value',any) normalize before matching; name-only rules render as documentation; canonical (stable) equality throughout. polygen's no-corpus authoring path keeps the must-reject reading. - Auto-regeneration. When the first generation pass hits the reject-as-annotation signature uniformly (every live spec rejected ≥2 windows the code acted on), verify regenerates once with the offending (pre-state, action) windows called out — the correction addendum takes precedence over the base prompt — and reports the second pass with both spec sets kept (
specs/,specs_regen/). findings.md flags the contract-question tension (if the contract deliberately declared those windows no-ops, the first pass was the signal);--no-auto-regenopts out. Tested end-to-end via a generation seam, no live API in tests. - Template/skill: the Special-rules section teaches the observable-change decision test; the skill's contract step and Step-5 triage updated to match.
🤖 Generated with Claude Code