Skip to content

refactor: rename map-planning to map-state, fix orchestrator cwd + sanitize, tighten Actor/Monitor#105

Merged
azalio merged 3 commits into
mainfrom
refactor/rename-map-planning-to-map-state
May 4, 2026
Merged

refactor: rename map-planning to map-state, fix orchestrator cwd + sanitize, tighten Actor/Monitor#105
azalio merged 3 commits into
mainfrom
refactor/rename-map-planning-to-map-state

Conversation

@azalio
Copy link
Copy Markdown
Owner

@azalio azalio commented May 4, 2026

Summary

Five fixes that all surfaced from one symptom: typing /map-plan resolved to the map-planning skill (branch-scoped state infra) instead of the real map-plan (ARCHITECT decomposition). Investigating that collision exposed three more latent issues, all rolled in here.

  1. Skill collisiondisable-model-invocation: true on map-plan hid it from the model, so /map-plan fuzzy-matched to map-planning. Renamed map-planningmap-state (kebab-case, no shared prefix) and unhid map-plan.
  2. Orchestrator cwd-dependencepython3 /abs/path/.map/scripts/map_orchestrator.py validate_step "2.3" from a foreign cwd silently read .map/<branch>/ from the caller's directory and returned Step mismatch: expected 1.0, got 2.3. Now anchors via Path(__file__).resolve().parents[2].
  3. _sanitize_for_json too lax — previous regex preserved \t \n \r and relied on json.dumps to escape them, but BUNDLE=$(... build_handoff_bundle) followed by echo "$BUNDLE" | jq aborted with Invalid string: control characters from U+0000 through U+001F must be escaped. Hardened: flatten newline variants to spaces, strip entire \x00-\x1f\x7f range.
  4. Actor/Monitor "pre-existing, unrelated" excuse — Monitor scope now distinguishes pre-existing DORMANT tech debt (still OUT OF SCOPE) from pre-existing SURFACED failures (must fix). Actor's QUICK REFERENCE and Subtask Intent ban one-line "Pre-existing failure unrelated to ST-XXX. Skipping." dismissals; deferral requires explicit user approval.
  5. Learned rules.claude/rules/learned/error-patterns.md updated with WRONG/CORRECT examples for docs: Remove non-functional Claude Marketplace installation documentation #3 and docs: Add comprehensive PATH setup instructions for mapify CLI installation #4 so future agents do not reintroduce either regression.

Templates synced via make sync-templates. CHANGELOG entry under [Unreleased].

Test plan

  • make sync-templates — clean diff between .claude/+.codex/+.map/scripts/ and src/mapify_cli/templates/
  • pytest tests/test_skills.py tests/test_template_sync.py — 64 passed
  • pytest tests/integration/test_e2e_artifact_contracts.py — 29 passed (orchestrator path resolution still correct under tmp_path)
  • pytest tests/test_map_step_runner.py — 88 passed (sanitize hardening doesn't break callers)
  • Manual smoke for _sanitize_for_json: covers \r\n, NUL, \x07, \x0b, \x1f, \x7f, plain text, Unicode — all stripped to JSON-safe form, round-trip via json.dumps/json.loads succeeds
  • make check (full lint + mypy + 1029-test pytest, ~70 min including e2e Claude SDK) — 5 e2e failures, all pre-existing (test_plan_* ассертит step_state.json after /map-plan, but SKILL.md Step 7 explicitly says do NOT create it; remaining 3 are claude CLI timeouts / socket errors). No regressions from this PR.

Migration

Downstream projects on the previous skill bundle need mapify upgrade (or a manual copy of the renamed skill directory) to pick up map-state and the unhidden map-plan. Existing .map/<branch>/ artifacts remain compatible — only the skill directory and its skill-rules.json key changed.

…dination

Five related fixes that all surfaced from one symptom: typing /map-plan in
a project shipped with the previous skill bundle resolved to map-planning
(branch-scoped state infra) instead of map-plan (ARCHITECT decomposition).

1. Skill collision: rename .claude/skills/map-planning -> .claude/skills/map-state
   and remove disable-model-invocation: true from map-plan/SKILL.md so the
   model sees both skills as distinct surfaces. Update skill-rules.json,
   monitor agents, docs (USAGE, INSTALL, roadmap, improvement-plan), and
   in-tree script comments.

2. map_orchestrator.py is now cwd-independent: anchors itself to the
   project root via Path(__file__).resolve().parents[2] before any state
   lookup. Previously, invoking the orchestrator via an absolute path from
   a different cwd silently read .map/<branch>/ from the caller's
   directory and returned misleading "step mismatch" errors.

3. Hardened map_step_runner._sanitize_for_json: previous regex preserved
   \t \n \r and relied on json.dumps to escape them, but bash command
   substitution does not preserve byte-perfect roundtrip in all locales —
   jq aborted with "Invalid string: control characters from U+0000 through
   U+001F must be escaped". The function now flattens newline variants to
   spaces and strips the entire \x00-\x1f\x7f range, so build_handoff_bundle
   output is robust through bash pipelines.

4. Block "pre-existing, unrelated" excuse for surfaced quality-gate
   failures: Monitor scope distinguishes pre-existing DORMANT tech debt
   (still OUT OF SCOPE) from pre-existing SURFACED failures (lint/type/test
   failing in the current run, regardless of whether the failing code
   predates the diff — must fix). Actor's QUICK REFERENCE and Subtask
   Intent now ban one-line "pre-existing, unrelated" dismissals; deferral
   requires explicit user approval.

5. Captured #3 and #4 as learned rules in
   .claude/rules/learned/error-patterns.md with WRONG/CORRECT examples so
   future agents do not reintroduce either regression.

Templates synced via make sync-templates. CHANGELOG updated.
Copilot AI review requested due to automatic review settings May 4, 2026 12:03
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a slash-skill naming collision in MAP, hardens workflow runtime behavior, and syncs the resulting skill/agent/documentation changes across the shipped .claude, .map, .codex, and template copies.

Changes:

  • Renames the branch-scoped planning skill from map-planning to map-state and makes map-plan model-invocable again.
  • Fixes workflow runtime behavior in the orchestrator and handoff bundle sanitization.
  • Tightens Actor/Monitor guidance around surfaced quality-gate failures and updates docs/changelog/learned rules.

Reviewed changes

Copilot reviewed 24 out of 38 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/mapify_cli/templates/skills/skill-rules.json Renames template skill rule entry to map-state.
src/mapify_cli/templates/skills/map-state/templates/task_plan.md Adds template task-plan scaffold for renamed skill.
src/mapify_cli/templates/skills/map-state/templates/progress.md Adds progress-log template for renamed skill.
src/mapify_cli/templates/skills/map-state/templates/iteration_history.md Adds iteration-history template for renamed skill.
src/mapify_cli/templates/skills/map-state/templates/findings.md Adds findings template for renamed skill.
src/mapify_cli/templates/skills/map-state/SKILL.md Renames skill frontmatter to map-state.
src/mapify_cli/templates/skills/map-state/scripts/show-focus.sh Adds focus-display helper for renamed skill.
src/mapify_cli/templates/skills/map-state/scripts/init-session.sh Adds session initialization helper for renamed skill.
src/mapify_cli/templates/skills/map-state/scripts/get-plan-path.sh Updates usage/examples for renamed skill path.
src/mapify_cli/templates/skills/map-state/scripts/check-complete.sh Adds stop-hook completion checker for renamed skill.
src/mapify_cli/templates/skills/map-plan/SKILL.md Removes disable-model-invocation from map-plan.
src/mapify_cli/templates/map/scripts/map_step_runner.py Hardens JSON sanitization for handoff bundles.
src/mapify_cli/templates/map/scripts/map_orchestrator.py Anchors orchestrator cwd to project root in CLI mode.
src/mapify_cli/templates/codex/agents/monitor.toml Updates Codex monitor guidance for surfaced gate failures and rename.
src/mapify_cli/templates/agents/monitor.md Updates Claude monitor guidance for surfaced gate failures and rename.
src/mapify_cli/templates/agents/actor.md Updates Actor guidance to require addressing surfaced gate failures.
docs/USAGE.md Renames user-facing skill docs to map-state.
docs/roadmap.md Updates roadmap reference to renamed skill path.
docs/INSTALL.md Updates install tree to renamed skill directory.
docs/improvement-plan.md Replaces planning-skill references with map-state.
CHANGELOG.md Records rename and runtime hardening changes.
.map/scripts/map_step_runner.py Source-of-truth step-runner sanitization change.
.map/scripts/map_orchestrator.py Source-of-truth orchestrator cwd fix.
.codex/agents/monitor.toml Source-of-truth Codex monitor guidance update.
.claude/skills/skill-rules.json Source-of-truth skill rule rename to map-state.
.claude/skills/map-state/templates/task_plan.md Source-of-truth task-plan template for renamed skill.
.claude/skills/map-state/templates/progress.md Source-of-truth progress template for renamed skill.
.claude/skills/map-state/templates/iteration_history.md Source-of-truth iteration-history template for renamed skill.
.claude/skills/map-state/templates/findings.md Source-of-truth findings template for renamed skill.
.claude/skills/map-state/SKILL.md Source-of-truth skill rename to map-state.
.claude/skills/map-state/scripts/show-focus.sh Source-of-truth focus hook script.
.claude/skills/map-state/scripts/init-session.sh Source-of-truth session init script.
.claude/skills/map-state/scripts/get-plan-path.sh Source-of-truth renamed path helper docs.
.claude/skills/map-state/scripts/check-complete.sh Source-of-truth stop-hook completion script.
.claude/skills/map-plan/SKILL.md Source-of-truth map-plan visibility change.
.claude/rules/learned/error-patterns.md Adds learned rules for sanitization and surfaced-failure handling.
.claude/agents/monitor.md Source-of-truth Claude monitor guidance update.
.claude/agents/actor.md Source-of-truth Actor guidance update.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1882 to +1886
# Anchor cwd to the project root before any state lookup or branch
# detection. The script lives at ``<project>/.map/scripts/map_orchestrator.py``,
# so ``parents[2]`` is the project root regardless of how the script was
# invoked. Without this chdir, an absolute-path call from a different cwd
# silently reads ``.map/<branch>/`` from the caller's directory and
Comment on lines +1375 to +1377
text = text.replace("\r\n", "\n").replace("\r", "\n")
text = text.replace("\n", " ").replace("\t", " ")
return re.sub(r"[\x00-\x1f\x7f]", "", text)
…-anchor

Addresses Copilot review feedback on PR #105: the two runtime fixes were
landed without automated tests, so a regression could return without any
CI failure.

- TestSanitizeForJson (tests/test_map_step_runner.py): parametrised over
  the C0 control range and DEL, asserts whitespace flattening to spaces,
  preserves printable ASCII + Unicode, and verifies a full round-trip
  through json.dumps + json.loads with no raw control bytes leaking
  back. Closes the original "Sanitize Control Characters" rule's gap.

- TestCwdIndependence (tests/test_map_orchestrator.py): subprocess-based
  test that copies the orchestrator + sibling .py modules into a tmp
  project_a, runs the script via absolute path from a foreign cwd
  project_b, and asserts state is read from project_a (not project_b).
  Covers both get_next_step and validate_step. The fix's reliance on
  Path(__file__).resolve().parents[2] is now guaranteed by an automated
  case — in-process tests cannot exercise it because they bypass main().
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 26 out of 40 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/INSTALL.md Outdated
Comment on lines +244 to +245
│ │ ├── map-state/
│ │ │ └── SKILL.md # Branch-scoped planning state skill
Comment on lines +1882 to +1888
# Anchor cwd to the project root before any state lookup or branch
# detection. The script lives at ``<project>/.map/scripts/map_orchestrator.py``,
# so ``parents[2]`` is the project root regardless of how the script was
# invoked. Without this chdir, an absolute-path call from a different cwd
# silently reads ``.map/<branch>/`` from the caller's directory and
# returns misleading "step mismatch" errors.
os.chdir(Path(__file__).resolve().parents[2])
Two more findings from the second Copilot pass:

1. docs/INSTALL.md: the install-tree diagram still claimed a
   `.claude/commands/` directory with ten `map-*.md` files. That layout
   was removed long ago — every MAP slash surface now lives under
   `.claude/skills/<name>/SKILL.md`, and
   `tests/test_template_sync.py::test_no_map_command_files_remain`
   enforces the absence of `commands/map-*.md`. Replaced the stale tree
   with the actual shipped skill list (12 entries) and added a note
   pointing at the enforcing test.

2. tests/test_map_orchestrator.py::TestCwdIndependence: previous
   coverage exercised only `get_next_step` and `validate_step`. Added
   `test_set_waves_resolves_relative_blueprint_in_script_project` —
   subprocess test that seeds two competing blueprints (3-subtask vs
   1-subtask), invokes `set_waves --blueprint .map/<branch>/blueprint.json`
   from a foreign cwd, and asserts the relative argument is rebased
   against the script's project. Confirms the cwd anchor protects every
   path-bearing CLI subcommand, not just the two we originally tested.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 26 out of 40 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

.claude/skills/map-state/scripts/get-plan-path.sh:19

  • These examples still document .map/main/... as the non-git fallback, but the rest of the MAP runtime falls back to .map/default/... when git metadata is unavailable. That mismatch makes this renamed script's help text point users at the wrong path for --no-git/nongit workflows.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@azalio azalio merged commit e0ddb12 into main May 4, 2026
10 checks passed
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.

2 participants