Repository navigation
Description
Overview
Third instance of one family: a conductor derives a value from prose and ignores the header key the author declared. (1) the Feature Agent's ranker — fixed, #217; (2) the Bug Agent classifying on prose keywords over a declared Type: bug; (3) the Intake Agent persisting its derived Difficulty: over the declared one.
analyse() hand-built the prompt-shaped dict it hands the sizing faculty, omitting the declared_header(text) keys the file-loading path (_sizing.py:369) does fold in. So estimate_difficulty ran with no declared key present, nothing reconciled derived against declared, and the derived level was written into the header — silently replacing what the input asked for. Reported 2026-08-24: raw text declaring Difficulty: medium classified too-large (score 11), unchanged when the full header block was prepended; the header had to be hand-corrected after --apply.
This matters because the derived score weights prompt length, and length is a bad size proxy — a prompt is long when it carries a design and the sibling tasks' traps, not when the work is large. That inversion is already on the record in complete/2026/08/feature-ranker-ignores-header-keys.md ("that is what a declared Difficulty: is for"). A declared key is the documented escape hatch, and on this path it did nothing.
Plan
- Put the precedence rule in the sizing faculty — one place all three conductors already call — instead of re-implementing it per conductor. Rule, stated explicitly: declared wins, and the derived level is reported alongside it when they disagree, which keeps the heuristic honest and visible.
- Give the faculty one definition of "what counts as a declaration": header lines for filed prompts, prose for unheadered conception input; never a fenced block.
- Fix leg (2) in the same pass: a declared
Type: bugoutranks the Bug Agent's prose keywords. - Stop the declaration leaking into intake's derived title and filename.
Detailed implementation plan
Affected Repositories
- PyAutoBrain (primary)
- PyAutoMind (prompt lifecycle only)
Branch
claude/intake-declared-difficulty-icstba (remote web-github session; no task worktree)
Implementation Steps
agents/faculties/sizing/_sizing.pyeffective_difficulty(p) -> (level, score, factors, derived_level)— the single precedence rule, moved here from_feature.py.declared_headeralso readsType:andAutonomy:(it already read Difficulty/Priority/Status/Blocked-by).declared_inline(text) -> (fields, spans)— the same keys read out of unheadered prose, including theideas.mdidiomDifficulty large, supervised.; code fences and inline spans masked first, matchingdeclared_header's rule.strip_declarations(text, spans)— for title derivation only; the prompt body stays verbatim.
agents/conductors/feature/_feature.py— drop the localeffective_difficulty, import the faculty's. No behaviour change.agents/conductors/bug/_bug.py—analyse_bug/select_buggo througheffective_difficulty; the BugDecision gainsdifficulty_declared/difficulty_derived/difficulty_disagreement;re_home_checkreturnsNonefor a prompt that declaresType: bug.agents/conductors/intake/_intake.py— read both declaration sources (header lines win a tie), size througheffective_difficulty, honour a declaredType:over the prose classifier, keep the declaration out of the derived title/slug, and report provenance (difficulty_source,work_type_source,autonomy_source,priority_source).formalise's_derive_fieldstakes the same path.- Docs: the sizing faculty's
AGENTS.md+ module docstring (it now owns the rule), intakeAGENTS.md/INTAKE_TAXONOMY.md,skills/intake/intake.md,BUG_TAXONOMY.md. tests/test_declared_header_precedence.py— the family's lock: rule-level tests plus the reported reproduction, the prepended-header case, the title/slug leak, declaredType:at intake and in the Bug Agent's re-home check, and "no declaration → still derives".
Key Files
agents/faculties/sizing/_sizing.py— the rule and both readersagents/conductors/{intake,bug,feature}/— consumerstests/test_declared_header_precedence.py— new
Validation
pytest tests/ -q→ 491 passedpython3 PyAutoMind/scripts/repos_sync.py --check --only "tenant firewall (organ code)"→ OK
Original Prompt
The authoritative prompt is PyAutoMind active/intake_ignores_declared_difficulty.md (filed on main as c1927d5, advanced draft/ → active/ on issue creation).
Activity
fix: reconcile declared vs derived in the sizing faculty (#274)
[-]fix: intake ignores a difficulty declared in the raw text[/-][+]fix: conductors derive over a declared header key (difficulty, type)[/+]Merge pull request #275 from PyAutoLabs/claude/intake-declared-diffic…
Jammy2211 commentedon Aug 24, 2026
Shipped
979fac5)243a871), lifecycle state onlyThe precedence rule now lives in the sizing faculty, not in each conductor:
effective_difficultyreconciles declared against derived (declared wins; the derived level and score come back alongside so a disagreement is reported),declared_headerreadsType:/Autonomy:as well, anddeclared_inlinereads the same keys out of unheadered conception prose — neither from a fenced block. The Feature Agent's local copy is gone; the Bug Agent and Intake now go through the shared rule.Both legs of the family are closed:
formalise, and no longer leaks into the derived title/slug.Type:over its prose classifier, and the Bug Agent no longer re-homes a prompt declaringType: bugon prose keywords.On the prompt's own file, intake now reports
Work-type: bug (declared)andDifficulty: medium (declared); it previously called itfeatureand re-sized it.CI:
pytest (3.12)andpytest (3.13)green on the merged head (491 tests, 15 new intests/test_declared_header_precedence.py), tenant-firewall leg green. Heart was not reachable from thisweb-githubsession, soship_library's documented fallback — the repo's own suite as the gate — applied.Scope note: the prompt asked for leg (2) in the same pass, so this branch is wider than intake alone. One root cause, one shared rule — splitting would have meant two PRs editing the same function.
Generated by Claude Code