Skip to content

fix(map-plan): add normalize_blueprint repair pass for decomposer drift (#168)#172

Merged
azalio merged 1 commit into
mainfrom
fix/168-normalize-blueprint-topo-sort-coverage-tags
Jun 11, 2026
Merged

fix(map-plan): add normalize_blueprint repair pass for decomposer drift (#168)#172
azalio merged 1 commit into
mainfrom
fix/168-normalize-blueprint-topo-sort-coverage-tags

Conversation

@azalio

@azalio azalio commented Jun 11, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes #168. task-decomposer (Step 5) routinely emits a blueprint.json that fails the framework's own validate_blueprint_contract (Step 5.6), forcing manual JSON surgery before planning can proceed. Two mechanical self-consistency drifts recur:

  1. Forward-dependency ordering — a subtask declared before the dependency it declares. The runtime walker consumes subtasks[] in declaration order (the validator's deadlock guard), so this is rejected even though the dependency DAG is fine; only the array position is wrong.
  2. coverage_map ↔ bracket-tag mismatch — a coverage_map[req] = owner whose owner subtask's validation_criteria does not cite [req].

What this does

Adds a deterministic normalize_blueprint repair pass (runner function + CLI + /map-plan Step 5.55, before validation) so the flow is self-serve — decompose → normalize → validate → proceed — with no hand-editing:

  • Stable topological sort of subtasks[] so every dependency is declared before its dependents. Independent subtasks keep their relative order (minimal diff); a true cycle is left untouched so validate_blueprint_contract still reports it.
  • Bracket-tag injection: for every coverage_map[req] = owner whose owner lacks [req], appends a [req]-tagged validation_criteria entry.

Why a deterministic repair pass rather than loosening the validator or re-prompting the agent: the runtime walker relies on declaration order (loosening would risk a dependent running before its dependency), and a prompt fix is unreliable — the issue notes it fails "routinely" despite the decomposer being prompted with the contract. A topo-sort is safe under either scheduling model.

Conservative by design: never invents coverage_map ownership, never rewrites dependency edges, never touches a soft constraint that relies on tradeoff_rationale. Genuine semantic gaps (a hard constraint missing from coverage_map, an unknown/cyclic dependency) still fail Step 5.6. Idempotentchanged: false and writes nothing on already-normalized input.

python3 .map/scripts/map_step_runner.py normalize_blueprint [<path>] [--check]

Tests

New regression tests in tests/test_map_step_runner.py:

Invariants honored

  • Edited the .jinja single source and re-rendered (make render-templates); all generated trees and the live .map/scripts/ copy stay byte-identical (make check-render).
  • make check green: ruff + mypy + pyright clean, 2291 passed, 3 skipped.

🤖 Generated with Claude Code

…ft (#168)

task-decomposer routinely emits blueprints that fail the framework's own
validate_blueprint_contract (Step 5.6), forcing manual JSON surgery between
decompose and validate. Two mechanical self-consistency drifts recur:

1. Forward-dependency ordering — a subtask declared before the dependency it
   declares. The runtime walker consumes subtasks in declaration order, so the
   validator rejects this (deadlock guard); array position is the only problem.
2. coverage_map <-> bracket-tag mismatch — a coverage_map[req]=owner whose owner
   subtask's validation_criteria does not cite [req].

Add a deterministic normalize_blueprint repair pass (runner function + CLI +
/map-plan Step 5.55) that:
- stably topologically sorts subtasks[] so deps precede dependents (independent
  subtasks keep their relative order; a true cycle is left untouched for the
  validator to reject);
- injects a [req]-tagged validation criterion for every coverage_map entry whose
  owner lacks the tag.

It never invents coverage_map ownership or rewrites dependency edges, so genuine
semantic gaps still fail Step 5.6. Idempotent (changed=false / writes nothing on
already-normalized input). Wired into /map-plan as Step 5.55 (before 5.6).

Regression tests reproduce the exact #168 scenario (both drifts at once) and
prove validate_blueprint_contract flips false->true after normalize, plus
idempotency, stable-order preservation, cycle pass-through, and CLI
--check/in-place paths.

Edited the .jinja single source and re-rendered (make render-templates); all
generated trees + the live .map/scripts copy stay byte-identical (check-render).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@azalio azalio merged commit 1e84e46 into main Jun 11, 2026
6 checks passed
@azalio azalio deleted the fix/168-normalize-blueprint-topo-sort-coverage-tags branch June 11, 2026 15:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

task-decomposer emits blueprints that fail validate_blueprint_contract (forward-dep array order + missing coverage bracket-tags)

1 participant