mapify-cli 3.31.3__py3-none-any.whl → 3.32.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. mapify_cli/__init__.py +1 -1
  2. mapify_cli/templates/codex/hooks/context-meter.py +3 -3
  3. mapify_cli/templates/codex/hooks/detect-clarification-triggers.py +3 -3
  4. mapify_cli/templates/codex/hooks/map-memory-capture.py +3 -3
  5. mapify_cli/templates/codex/hooks/map-memory-endmark.py +3 -3
  6. mapify_cli/templates/codex/hooks/map-memory-recall.py +3 -3
  7. mapify_cli/templates/codex/hooks/map-memory-session.py +3 -3
  8. mapify_cli/templates/codex/hooks/map-stop.py +3 -3
  9. mapify_cli/templates/codex/hooks/map-token-meter.py +3 -3
  10. mapify_cli/templates/codex/hooks/post-compact-context.py +3 -3
  11. mapify_cli/templates/codex/hooks/pre-compact-save-transcript.py +3 -3
  12. mapify_cli/templates/codex/hooks/ralph-context-pruner.py +3 -3
  13. mapify_cli/templates/codex/hooks/ralph-iteration-logger.py +3 -3
  14. mapify_cli/templates/codex/hooks/safety-guardrails.py +3 -3
  15. mapify_cli/templates/codex/hooks/scrub-internal-ids.py +27 -17
  16. mapify_cli/templates/codex/hooks/workflow-context-injector.py +3 -3
  17. mapify_cli/templates/codex/hooks/workflow-gate.py +3 -3
  18. mapify_cli/templates/codex/skills/map-efficient/SKILL.md +1 -1
  19. mapify_cli/templates/codex/skills/map-efficient/efficient-reference.md +7 -19
  20. mapify_cli/templates/codex/skills/map-plan/SKILL.md +13 -6
  21. mapify_cli/templates/codex/skills/map-release/SKILL.md +23 -30
  22. mapify_cli/templates/codex/skills/map-release/release-reference.md +145 -44
  23. mapify_cli/templates/codex/skills/map-review/SKILL.md +543 -256
  24. mapify_cli/templates/codex/skills/map-review/adversarial-reference.md +87 -128
  25. mapify_cli/templates/codex/skills/map-review/review-reference.md +239 -337
  26. mapify_cli/templates/codex/skills/map-task/SKILL.md +1 -1
  27. mapify_cli/templates/codex/skills/map-wayfind/SKILL.md +20 -8
  28. mapify_cli/templates/codex/skills/map-wayfind/wayfind-reference.md +131 -3
  29. mapify_cli/templates/hooks/context-meter.py +3 -3
  30. mapify_cli/templates/hooks/detect-clarification-triggers.py +3 -3
  31. mapify_cli/templates/hooks/map-memory-capture.py +3 -3
  32. mapify_cli/templates/hooks/map-memory-endmark.py +3 -3
  33. mapify_cli/templates/hooks/map-memory-finalize.py +3 -3
  34. mapify_cli/templates/hooks/map-memory-recall.py +3 -3
  35. mapify_cli/templates/hooks/map-statusline.py +3 -3
  36. mapify_cli/templates/hooks/map-token-meter.py +3 -3
  37. mapify_cli/templates/hooks/post-compact-context.py +3 -3
  38. mapify_cli/templates/hooks/pre-compact-save-transcript.py +3 -3
  39. mapify_cli/templates/hooks/ralph-context-pruner.py +3 -3
  40. mapify_cli/templates/hooks/ralph-iteration-logger.py +3 -3
  41. mapify_cli/templates/hooks/safety-guardrails.py +3 -3
  42. mapify_cli/templates/hooks/scrub-internal-ids.py +27 -17
  43. mapify_cli/templates/hooks/workflow-context-injector.py +3 -3
  44. mapify_cli/templates/hooks/workflow-gate.py +3 -3
  45. mapify_cli/templates/map/scripts/map_orchestrator.py +3 -3
  46. mapify_cli/templates/map/scripts/map_step_runner.py +289 -66
  47. mapify_cli/templates/map/scripts/scrub_internal_ids.py +23 -9
  48. mapify_cli/templates/map/scripts/validate_spec_citations.py +3 -3
  49. mapify_cli/templates/map/scripts/wayfind_runner.py +575 -4
  50. mapify_cli/templates/skills/map-efficient/SKILL.md +1 -1
  51. mapify_cli/templates/skills/map-efficient/efficient-reference.md +7 -19
  52. mapify_cli/templates/skills/map-plan/SKILL.md +4 -7
  53. mapify_cli/templates/skills/map-release/SKILL.md +23 -30
  54. mapify_cli/templates/skills/map-release/release-reference.md +147 -43
  55. mapify_cli/templates/skills/map-review/SKILL.md +62 -63
  56. mapify_cli/templates/skills/map-review/adversarial-reference.md +39 -41
  57. mapify_cli/templates/skills/map-review/review-reference.md +32 -22
  58. mapify_cli/templates/skills/map-task/SKILL.md +1 -1
  59. mapify_cli/templates/skills/map-wayfind/SKILL.md +19 -7
  60. mapify_cli/templates/skills/map-wayfind/wayfind-reference.md +131 -3
  61. mapify_cli/templates_src/_partials/python-version-guard.py.jinja +3 -3
  62. mapify_cli/templates_src/codex/skills/map-auto/auto-reference.md.jinja +1 -78
  63. mapify_cli/templates_src/codex/skills/map-efficient/SKILL.md.jinja +1 -1
  64. mapify_cli/templates_src/codex/skills/map-efficient/efficient-reference.md.jinja +7 -19
  65. mapify_cli/templates_src/codex/skills/map-plan/SKILL.md.jinja +13 -6
  66. mapify_cli/templates_src/codex/skills/map-release/SKILL.md.jinja +1 -177
  67. mapify_cli/templates_src/codex/skills/map-release/release-reference.md.jinja +1 -456
  68. mapify_cli/templates_src/codex/skills/map-review/SKILL.md.jinja +1 -412
  69. mapify_cli/templates_src/codex/skills/map-review/adversarial-reference.md.jinja +1 -224
  70. mapify_cli/templates_src/codex/skills/map-review/review-reference.md.jinja +1 -477
  71. mapify_cli/templates_src/codex/skills/map-task/SKILL.md.jinja +1 -1
  72. mapify_cli/templates_src/codex/skills/map-wayfind/SKILL.md.jinja +1 -129
  73. mapify_cli/templates_src/codex/skills/map-wayfind/wayfind-reference.md.jinja +1 -134
  74. mapify_cli/templates_src/hooks/scrub-internal-ids.py.jinja +24 -14
  75. mapify_cli/templates_src/map/scripts/map_step_runner.py.jinja +286 -63
  76. mapify_cli/templates_src/map/scripts/scrub_internal_ids.py.jinja +23 -9
  77. mapify_cli/templates_src/map/scripts/wayfind_runner.py.jinja +575 -4
  78. mapify_cli/templates_src/skills/map-auto/auto-reference.md.jinja +9 -8
  79. mapify_cli/templates_src/skills/map-efficient/SKILL.md.jinja +1 -1
  80. mapify_cli/templates_src/skills/map-efficient/efficient-reference.md.jinja +7 -19
  81. mapify_cli/templates_src/skills/map-plan/SKILL.md.jinja +4 -7
  82. mapify_cli/templates_src/skills/map-release/SKILL.md.jinja +34 -34
  83. mapify_cli/templates_src/skills/map-release/release-reference.md.jinja +163 -47
  84. mapify_cli/templates_src/skills/map-review/SKILL.md.jinja +115 -65
  85. mapify_cli/templates_src/skills/map-review/adversarial-reference.md.jinja +62 -41
  86. mapify_cli/templates_src/skills/map-review/review-reference.md.jinja +39 -28
  87. mapify_cli/templates_src/skills/map-task/SKILL.md.jinja +1 -1
  88. mapify_cli/templates_src/skills/map-wayfind/SKILL.md.jinja +36 -21
  89. mapify_cli/templates_src/skills/map-wayfind/wayfind-reference.md.jinja +148 -14
  90. mapify_cli/tools/validate_dependencies.py +57 -32
  91. {mapify_cli-3.31.3.dist-info → mapify_cli-3.32.0.dist-info}/METADATA +3 -3
  92. {mapify_cli-3.31.3.dist-info → mapify_cli-3.32.0.dist-info}/RECORD +95 -95
  93. {mapify_cli-3.31.3.dist-info → mapify_cli-3.32.0.dist-info}/WHEEL +0 -0
  94. {mapify_cli-3.31.3.dist-info → mapify_cli-3.32.0.dist-info}/entry_points.txt +0 -0
  95. {mapify_cli-3.31.3.dist-info → mapify_cli-3.32.0.dist-info}/licenses/LICENSE +0 -0
mapify_cli/__init__.py CHANGED
@@ -23,7 +23,7 @@ Or install globally:
23
23
  mapify check
24
24
  """
25
25
 
26
- __version__ = "3.31.3"
26
+ __version__ = "3.32.0"
27
27
 
28
28
  # MUST stay the first import: it turns "this interpreter is older than 3.11" into
29
29
  # a message that says so, instead of the ImportError raised by `from datetime
@@ -36,13 +36,13 @@ import sys
36
36
  # evaluated annotations) fails with a message that never mentions the version.
37
37
  # Name the real cause instead. Kept in sync with
38
38
  # mapify_cli/python_runtime.MINIMUM_PYTHON.
39
- # UP036 is suppressed on purpose: the project targets 3.11, but the interpreter
40
- # executing this shipped file is the user's `python3`, not the project's.
39
+ # Compare the runtime tuple: the executing interpreter is the user's `python3`,
40
+ # not necessarily the Python version targeted by the project's static checker.
41
41
  #
42
42
  # FAIL-OPEN mode. Exit 1 is a non-blocking hook error for Claude Code (only
43
43
  # exit 2, or a JSON deny, blocks a tool call), so the reason reaches the user
44
44
  # and the session continues -- a broken interpreter is not a policy decision.
45
- if sys.version_info < (3, 11): # noqa: UP036
45
+ if tuple(sys.version_info) < (3, 11):
46
46
  _MAP_PYTHON_PROBLEM = (
47
47
  f"MAP requires Python 3.11 or newer, but {sys.executable} is "
48
48
  f"Python {sys.version_info[0]}.{sys.version_info[1]}.\n"
@@ -37,13 +37,13 @@ import sys
37
37
  # evaluated annotations) fails with a message that never mentions the version.
38
38
  # Name the real cause instead. Kept in sync with
39
39
  # mapify_cli/python_runtime.MINIMUM_PYTHON.
40
- # UP036 is suppressed on purpose: the project targets 3.11, but the interpreter
41
- # executing this shipped file is the user's `python3`, not the project's.
40
+ # Compare the runtime tuple: the executing interpreter is the user's `python3`,
41
+ # not necessarily the Python version targeted by the project's static checker.
42
42
  #
43
43
  # FAIL-OPEN mode. Exit 1 is a non-blocking hook error for Claude Code (only
44
44
  # exit 2, or a JSON deny, blocks a tool call), so the reason reaches the user
45
45
  # and the session continues -- a broken interpreter is not a policy decision.
46
- if sys.version_info < (3, 11): # noqa: UP036
46
+ if tuple(sys.version_info) < (3, 11):
47
47
  _MAP_PYTHON_PROBLEM = (
48
48
  f"MAP requires Python 3.11 or newer, but {sys.executable} is "
49
49
  f"Python {sys.version_info[0]}.{sys.version_info[1]}.\n"
@@ -10,13 +10,13 @@ import sys
10
10
  # evaluated annotations) fails with a message that never mentions the version.
11
11
  # Name the real cause instead. Kept in sync with
12
12
  # mapify_cli/python_runtime.MINIMUM_PYTHON.
13
- # UP036 is suppressed on purpose: the project targets 3.11, but the interpreter
14
- # executing this shipped file is the user's `python3`, not the project's.
13
+ # Compare the runtime tuple: the executing interpreter is the user's `python3`,
14
+ # not necessarily the Python version targeted by the project's static checker.
15
15
  #
16
16
  # FAIL-OPEN mode. Exit 1 is a non-blocking hook error for Claude Code (only
17
17
  # exit 2, or a JSON deny, blocks a tool call), so the reason reaches the user
18
18
  # and the session continues -- a broken interpreter is not a policy decision.
19
- if sys.version_info < (3, 11): # noqa: UP036
19
+ if tuple(sys.version_info) < (3, 11):
20
20
  _MAP_PYTHON_PROBLEM = (
21
21
  f"MAP requires Python 3.11 or newer, but {sys.executable} is "
22
22
  f"Python {sys.version_info[0]}.{sys.version_info[1]}.\n"
@@ -10,13 +10,13 @@ import sys
10
10
  # evaluated annotations) fails with a message that never mentions the version.
11
11
  # Name the real cause instead. Kept in sync with
12
12
  # mapify_cli/python_runtime.MINIMUM_PYTHON.
13
- # UP036 is suppressed on purpose: the project targets 3.11, but the interpreter
14
- # executing this shipped file is the user's `python3`, not the project's.
13
+ # Compare the runtime tuple: the executing interpreter is the user's `python3`,
14
+ # not necessarily the Python version targeted by the project's static checker.
15
15
  #
16
16
  # FAIL-OPEN mode. Exit 1 is a non-blocking hook error for Claude Code (only
17
17
  # exit 2, or a JSON deny, blocks a tool call), so the reason reaches the user
18
18
  # and the session continues -- a broken interpreter is not a policy decision.
19
- if sys.version_info < (3, 11): # noqa: UP036
19
+ if tuple(sys.version_info) < (3, 11):
20
20
  _MAP_PYTHON_PROBLEM = (
21
21
  f"MAP requires Python 3.11 or newer, but {sys.executable} is "
22
22
  f"Python {sys.version_info[0]}.{sys.version_info[1]}.\n"
@@ -10,13 +10,13 @@ import sys
10
10
  # evaluated annotations) fails with a message that never mentions the version.
11
11
  # Name the real cause instead. Kept in sync with
12
12
  # mapify_cli/python_runtime.MINIMUM_PYTHON.
13
- # UP036 is suppressed on purpose: the project targets 3.11, but the interpreter
14
- # executing this shipped file is the user's `python3`, not the project's.
13
+ # Compare the runtime tuple: the executing interpreter is the user's `python3`,
14
+ # not necessarily the Python version targeted by the project's static checker.
15
15
  #
16
16
  # FAIL-OPEN mode. Exit 1 is a non-blocking hook error for Claude Code (only
17
17
  # exit 2, or a JSON deny, blocks a tool call), so the reason reaches the user
18
18
  # and the session continues -- a broken interpreter is not a policy decision.
19
- if sys.version_info < (3, 11): # noqa: UP036
19
+ if tuple(sys.version_info) < (3, 11):
20
20
  _MAP_PYTHON_PROBLEM = (
21
21
  f"MAP requires Python 3.11 or newer, but {sys.executable} is "
22
22
  f"Python {sys.version_info[0]}.{sys.version_info[1]}.\n"
@@ -10,13 +10,13 @@ import sys
10
10
  # evaluated annotations) fails with a message that never mentions the version.
11
11
  # Name the real cause instead. Kept in sync with
12
12
  # mapify_cli/python_runtime.MINIMUM_PYTHON.
13
- # UP036 is suppressed on purpose: the project targets 3.11, but the interpreter
14
- # executing this shipped file is the user's `python3`, not the project's.
13
+ # Compare the runtime tuple: the executing interpreter is the user's `python3`,
14
+ # not necessarily the Python version targeted by the project's static checker.
15
15
  #
16
16
  # FAIL-OPEN mode. Exit 1 is a non-blocking hook error for Claude Code (only
17
17
  # exit 2, or a JSON deny, blocks a tool call), so the reason reaches the user
18
18
  # and the session continues -- a broken interpreter is not a policy decision.
19
- if sys.version_info < (3, 11): # noqa: UP036
19
+ if tuple(sys.version_info) < (3, 11):
20
20
  _MAP_PYTHON_PROBLEM = (
21
21
  f"MAP requires Python 3.11 or newer, but {sys.executable} is "
22
22
  f"Python {sys.version_info[0]}.{sys.version_info[1]}.\n"
@@ -10,13 +10,13 @@ import sys
10
10
  # evaluated annotations) fails with a message that never mentions the version.
11
11
  # Name the real cause instead. Kept in sync with
12
12
  # mapify_cli/python_runtime.MINIMUM_PYTHON.
13
- # UP036 is suppressed on purpose: the project targets 3.11, but the interpreter
14
- # executing this shipped file is the user's `python3`, not the project's.
13
+ # Compare the runtime tuple: the executing interpreter is the user's `python3`,
14
+ # not necessarily the Python version targeted by the project's static checker.
15
15
  #
16
16
  # FAIL-OPEN mode. Exit 1 is a non-blocking hook error for Claude Code (only
17
17
  # exit 2, or a JSON deny, blocks a tool call), so the reason reaches the user
18
18
  # and the session continues -- a broken interpreter is not a policy decision.
19
- if sys.version_info < (3, 11): # noqa: UP036
19
+ if tuple(sys.version_info) < (3, 11):
20
20
  _MAP_PYTHON_PROBLEM = (
21
21
  f"MAP requires Python 3.11 or newer, but {sys.executable} is "
22
22
  f"Python {sys.version_info[0]}.{sys.version_info[1]}.\n"
@@ -41,13 +41,13 @@ import sys
41
41
  # evaluated annotations) fails with a message that never mentions the version.
42
42
  # Name the real cause instead. Kept in sync with
43
43
  # mapify_cli/python_runtime.MINIMUM_PYTHON.
44
- # UP036 is suppressed on purpose: the project targets 3.11, but the interpreter
45
- # executing this shipped file is the user's `python3`, not the project's.
44
+ # Compare the runtime tuple: the executing interpreter is the user's `python3`,
45
+ # not necessarily the Python version targeted by the project's static checker.
46
46
  #
47
47
  # FAIL-OPEN mode. Exit 1 is a non-blocking hook error for Claude Code (only
48
48
  # exit 2, or a JSON deny, blocks a tool call), so the reason reaches the user
49
49
  # and the session continues -- a broken interpreter is not a policy decision.
50
- if sys.version_info < (3, 11): # noqa: UP036
50
+ if tuple(sys.version_info) < (3, 11):
51
51
  _MAP_PYTHON_PROBLEM = (
52
52
  f"MAP requires Python 3.11 or newer, but {sys.executable} is "
53
53
  f"Python {sys.version_info[0]}.{sys.version_info[1]}.\n"
@@ -20,13 +20,13 @@ import sys
20
20
  # evaluated annotations) fails with a message that never mentions the version.
21
21
  # Name the real cause instead. Kept in sync with
22
22
  # mapify_cli/python_runtime.MINIMUM_PYTHON.
23
- # UP036 is suppressed on purpose: the project targets 3.11, but the interpreter
24
- # executing this shipped file is the user's `python3`, not the project's.
23
+ # Compare the runtime tuple: the executing interpreter is the user's `python3`,
24
+ # not necessarily the Python version targeted by the project's static checker.
25
25
  #
26
26
  # FAIL-OPEN mode. Exit 1 is a non-blocking hook error for Claude Code (only
27
27
  # exit 2, or a JSON deny, blocks a tool call), so the reason reaches the user
28
28
  # and the session continues -- a broken interpreter is not a policy decision.
29
- if sys.version_info < (3, 11): # noqa: UP036
29
+ if tuple(sys.version_info) < (3, 11):
30
30
  _MAP_PYTHON_PROBLEM = (
31
31
  f"MAP requires Python 3.11 or newer, but {sys.executable} is "
32
32
  f"Python {sys.version_info[0]}.{sys.version_info[1]}.\n"
@@ -20,13 +20,13 @@ import sys
20
20
  # evaluated annotations) fails with a message that never mentions the version.
21
21
  # Name the real cause instead. Kept in sync with
22
22
  # mapify_cli/python_runtime.MINIMUM_PYTHON.
23
- # UP036 is suppressed on purpose: the project targets 3.11, but the interpreter
24
- # executing this shipped file is the user's `python3`, not the project's.
23
+ # Compare the runtime tuple: the executing interpreter is the user's `python3`,
24
+ # not necessarily the Python version targeted by the project's static checker.
25
25
  #
26
26
  # FAIL-OPEN mode. Exit 1 is a non-blocking hook error for Claude Code (only
27
27
  # exit 2, or a JSON deny, blocks a tool call), so the reason reaches the user
28
28
  # and the session continues -- a broken interpreter is not a policy decision.
29
- if sys.version_info < (3, 11): # noqa: UP036
29
+ if tuple(sys.version_info) < (3, 11):
30
30
  _MAP_PYTHON_PROBLEM = (
31
31
  f"MAP requires Python 3.11 or newer, but {sys.executable} is "
32
32
  f"Python {sys.version_info[0]}.{sys.version_info[1]}.\n"
@@ -25,13 +25,13 @@ import sys
25
25
  # evaluated annotations) fails with a message that never mentions the version.
26
26
  # Name the real cause instead. Kept in sync with
27
27
  # mapify_cli/python_runtime.MINIMUM_PYTHON.
28
- # UP036 is suppressed on purpose: the project targets 3.11, but the interpreter
29
- # executing this shipped file is the user's `python3`, not the project's.
28
+ # Compare the runtime tuple: the executing interpreter is the user's `python3`,
29
+ # not necessarily the Python version targeted by the project's static checker.
30
30
  #
31
31
  # FAIL-OPEN mode. Exit 1 is a non-blocking hook error for Claude Code (only
32
32
  # exit 2, or a JSON deny, blocks a tool call), so the reason reaches the user
33
33
  # and the session continues -- a broken interpreter is not a policy decision.
34
- if sys.version_info < (3, 11): # noqa: UP036
34
+ if tuple(sys.version_info) < (3, 11):
35
35
  _MAP_PYTHON_PROBLEM = (
36
36
  f"MAP requires Python 3.11 or newer, but {sys.executable} is "
37
37
  f"Python {sys.version_info[0]}.{sys.version_info[1]}.\n"
@@ -19,13 +19,13 @@ import sys
19
19
  # evaluated annotations) fails with a message that never mentions the version.
20
20
  # Name the real cause instead. Kept in sync with
21
21
  # mapify_cli/python_runtime.MINIMUM_PYTHON.
22
- # UP036 is suppressed on purpose: the project targets 3.11, but the interpreter
23
- # executing this shipped file is the user's `python3`, not the project's.
22
+ # Compare the runtime tuple: the executing interpreter is the user's `python3`,
23
+ # not necessarily the Python version targeted by the project's static checker.
24
24
  #
25
25
  # FAIL-OPEN mode. Exit 1 is a non-blocking hook error for Claude Code (only
26
26
  # exit 2, or a JSON deny, blocks a tool call), so the reason reaches the user
27
27
  # and the session continues -- a broken interpreter is not a policy decision.
28
- if sys.version_info < (3, 11): # noqa: UP036
28
+ if tuple(sys.version_info) < (3, 11):
29
29
  _MAP_PYTHON_PROBLEM = (
30
30
  f"MAP requires Python 3.11 or newer, but {sys.executable} is "
31
31
  f"Python {sys.version_info[0]}.{sys.version_info[1]}.\n"
@@ -24,8 +24,8 @@ import sys
24
24
  # evaluated annotations) fails with a message that never mentions the version.
25
25
  # Name the real cause instead. Kept in sync with
26
26
  # mapify_cli/python_runtime.MINIMUM_PYTHON.
27
- # UP036 is suppressed on purpose: the project targets 3.11, but the interpreter
28
- # executing this shipped file is the user's `python3`, not the project's.
27
+ # Compare the runtime tuple: the executing interpreter is the user's `python3`,
28
+ # not necessarily the Python version targeted by the project's static checker.
29
29
  #
30
30
  # FAIL-CLOSED mode. This file is a blocking PreToolUse gate whose only job is to
31
31
  # refuse unsafe tool calls, so an interpreter it cannot run on must not degrade
@@ -34,7 +34,7 @@ import sys
34
34
  # how a PreToolUse hook blocks), so the call stops and the reason -- version,
35
35
  # interpreter, fix -- reaches the operator. Fix python3 in another terminal;
36
36
  # tool calls stay blocked until `python3 --version` reports 3.11+.
37
- if sys.version_info < (3, 11): # noqa: UP036
37
+ if tuple(sys.version_info) < (3, 11):
38
38
  _MAP_PYTHON_PROBLEM = (
39
39
  f"MAP requires Python 3.11 or newer, but {sys.executable} is "
40
40
  f"Python {sys.version_info[0]}.{sys.version_info[1]}.\n"
@@ -14,12 +14,16 @@ Gating (no-op in ~all turns):
14
14
  1. ``MAP_INVOKED_BY`` set -> exit (don't run inside a sub-agent).
15
15
  2. no ``.map/<branch>/step_state.json`` OR ``workflow_status`` is not
16
16
  ``WORKFLOW_COMPLETE`` -> exit (run not finished).
17
- 3. marker ``.map/<branch>/.scrub_done`` present -> exit (already ran once).
18
- 4. ``scrub_internal_ids: false`` in ``.map/config.yaml`` -> exit (opt-out).
17
+ 3. no ``.map/<branch>/run_health_report.json`` -> exit (final verification
18
+ not yet complete; ``workflow_status`` transitions to ``WORKFLOW_COMPLETE``
19
+ before the final-verifier step, so we gate on the health report instead).
20
+ 4. marker ``.map/<branch>/.scrub_done`` present -> exit (already ran once).
21
+ 5. ``scrub_internal_ids: false`` in ``.map/config.yaml`` -> exit (opt-out).
19
22
 
20
- When it does run: calls the engine in ``clean`` mode, commits the resulting
21
- working-tree changes as a dedicated ``chore(map): strip internal workflow IDs``
22
- commit (never amends), and writes the marker so it fires exactly once.
23
+ When it does run: calls the engine in ``clean`` mode, leaves any cleaned files
24
+ unstaged, prints a short ``stderr`` reminder to the operator, and writes the
25
+ marker so it fires exactly once. The operator decides how and whether to commit
26
+ the changes (preserving the host repository's commit conventions).
23
27
 
24
28
  Synchronous by design (justified exception to the async-hook rule): the scrub
25
29
  must finish and commit before the run is considered done; a detached run would
@@ -39,13 +43,13 @@ import sys
39
43
  # evaluated annotations) fails with a message that never mentions the version.
40
44
  # Name the real cause instead. Kept in sync with
41
45
  # mapify_cli/python_runtime.MINIMUM_PYTHON.
42
- # UP036 is suppressed on purpose: the project targets 3.11, but the interpreter
43
- # executing this shipped file is the user's `python3`, not the project's.
46
+ # Compare the runtime tuple: the executing interpreter is the user's `python3`,
47
+ # not necessarily the Python version targeted by the project's static checker.
44
48
  #
45
49
  # FAIL-OPEN mode. Exit 1 is a non-blocking hook error for Claude Code (only
46
50
  # exit 2, or a JSON deny, blocks a tool call), so the reason reaches the user
47
51
  # and the session continues -- a broken interpreter is not a policy decision.
48
- if sys.version_info < (3, 11): # noqa: UP036
52
+ if tuple(sys.version_info) < (3, 11):
49
53
  _MAP_PYTHON_PROBLEM = (
50
54
  f"MAP requires Python 3.11 or newer, but {sys.executable} is "
51
55
  f"Python {sys.version_info[0]}.{sys.version_info[1]}.\n"
@@ -135,6 +139,13 @@ def main() -> None:
135
139
  if status != "WORKFLOW_COMPLETE":
136
140
  _silent()
137
141
 
142
+ # Gate on run_health_report.json: written after the final-verifier step.
143
+ # workflow_status becomes WORKFLOW_COMPLETE before final verification, so
144
+ # we wait for the health report to avoid scrubbing while the verifier is
145
+ # reading HEAD.
146
+ if not (branch_dir / "run_health_report.json").exists():
147
+ _silent()
148
+
138
149
  marker = branch_dir / ".scrub_done"
139
150
  if marker.exists():
140
151
  _silent()
@@ -162,17 +173,16 @@ def main() -> None:
162
173
  report = {}
163
174
 
164
175
  modified = report.get("files_modified") or []
176
+ # Leave cleaned files unstaged so the operator can review and commit them
177
+ # using the host repository's conventions (ticket ID, sign-off, etc.).
178
+ # Never auto-commit with a fixed message.
165
179
  if modified:
166
- try:
167
- subprocess.run(["git", "add", "--", *modified], cwd=PROJECT_DIR,
168
- env=env, capture_output=True, text=True, timeout=15, check=False)
169
- subprocess.run(
170
- ["git", "commit", "-m", "chore(map): strip internal workflow IDs"],
171
- cwd=PROJECT_DIR, env=env, capture_output=True, text=True, timeout=30,
172
- check=False,
180
+ sys.stderr.write(
181
+ "[scrub-internal-ids] cleaned {} file(s) — review and commit with "
182
+ "your project's conventions:\n git add -- {}\n".format(
183
+ len(modified), " ".join(modified)
173
184
  )
174
- except (OSError, subprocess.SubprocessError):
175
- pass # leave the cleaned working tree in place; never block
185
+ )
176
186
 
177
187
  # Mark done so the scrub fires exactly once for this completed run.
178
188
  try:
@@ -25,13 +25,13 @@ import sys
25
25
  # evaluated annotations) fails with a message that never mentions the version.
26
26
  # Name the real cause instead. Kept in sync with
27
27
  # mapify_cli/python_runtime.MINIMUM_PYTHON.
28
- # UP036 is suppressed on purpose: the project targets 3.11, but the interpreter
29
- # executing this shipped file is the user's `python3`, not the project's.
28
+ # Compare the runtime tuple: the executing interpreter is the user's `python3`,
29
+ # not necessarily the Python version targeted by the project's static checker.
30
30
  #
31
31
  # FAIL-OPEN mode. Exit 1 is a non-blocking hook error for Claude Code (only
32
32
  # exit 2, or a JSON deny, blocks a tool call), so the reason reaches the user
33
33
  # and the session continues -- a broken interpreter is not a policy decision.
34
- if sys.version_info < (3, 11): # noqa: UP036
34
+ if tuple(sys.version_info) < (3, 11):
35
35
  _MAP_PYTHON_PROBLEM = (
36
36
  f"MAP requires Python 3.11 or newer, but {sys.executable} is "
37
37
  f"Python {sys.version_info[0]}.{sys.version_info[1]}.\n"
@@ -45,8 +45,8 @@ import sys
45
45
  # evaluated annotations) fails with a message that never mentions the version.
46
46
  # Name the real cause instead. Kept in sync with
47
47
  # mapify_cli/python_runtime.MINIMUM_PYTHON.
48
- # UP036 is suppressed on purpose: the project targets 3.11, but the interpreter
49
- # executing this shipped file is the user's `python3`, not the project's.
48
+ # Compare the runtime tuple: the executing interpreter is the user's `python3`,
49
+ # not necessarily the Python version targeted by the project's static checker.
50
50
  #
51
51
  # FAIL-CLOSED mode. This file is a blocking PreToolUse gate whose only job is to
52
52
  # refuse unsafe tool calls, so an interpreter it cannot run on must not degrade
@@ -55,7 +55,7 @@ import sys
55
55
  # how a PreToolUse hook blocks), so the call stops and the reason -- version,
56
56
  # interpreter, fix -- reaches the operator. Fix python3 in another terminal;
57
57
  # tool calls stay blocked until `python3 --version` reports 3.11+.
58
- if sys.version_info < (3, 11): # noqa: UP036
58
+ if tuple(sys.version_info) < (3, 11):
59
59
  _MAP_PYTHON_PROBLEM = (
60
60
  f"MAP requires Python 3.11 or newer, but {sys.executable} is "
61
61
  f"Python {sys.version_info[0]}.{sys.version_info[1]}.\n"
@@ -96,7 +96,7 @@ Resolve pending approval holds before `resume_from_plan` initializes any executi
96
96
  python3 .map/scripts/map_step_runner.py list_approval_holds --state pending
97
97
  ```
98
98
 
99
- A pending `plan_approval` requires an explicit operator approve/deny, recorded via `decide_approval_hold <hold-id> <approved|denied> --note "<operator note>"`: approved continues into Step 0, denied STOPS here — revise the plan and re-run `$map-plan` (no staleness re-check); an autonomous chain never reaches this ask because its pre-phase `auto_decide_holds` poll approves `plan_approval` first. A pending `dangerous_action`/`safety_guardrail` hold refuses to proceed instead — surface the hold's `reason` and stop.
99
+ A ready plan needs no approval. A pending `plan_approval` (left by an older `$map-plan`) is not a gate: do not ask — close it via `decide_approval_hold <hold-id> approved --note "plan_approval no longer gates execution"` and continue into Step 0. A pending `dangerous_action`/`safety_guardrail` hold refuses to proceed instead — surface the hold's `reason` and stop.
100
100
 
101
101
  ## Step 0: Resume Existing State Or Plan
102
102
 
@@ -6,9 +6,8 @@ Load only the section needed by the active phase.
6
6
  ## Approval-Hold Preflight
7
7
 
8
8
  Resolve any pending approval hold BEFORE Step 0's `resume_from_plan`
9
- bootstraps execution state — a hold left pending means execution has not
10
- been explicitly authorized, and a denied plan must stop before any
11
- `step_state.json` exists.
9
+ bootstraps execution state. A ready plan itself needs no approval —
10
+ `$map-plan` no longer opens a hold.
12
11
 
13
12
  ```bash
14
13
  python3 .map/scripts/map_step_runner.py list_approval_holds --state pending
@@ -16,31 +15,20 @@ python3 .map/scripts/map_step_runner.py list_approval_holds --state pending
16
15
 
17
16
  Each pending hold's `kind` decides the branch:
18
17
 
19
- - **`plan_approval`** — the operator must explicitly approve or deny before
20
- execution starts:
18
+ - **`plan_approval`** (left by an older `$map-plan`) — not a gate. Do not
19
+ ask the operator; close it and continue:
21
20
  ```bash
22
21
  python3 .map/scripts/map_step_runner.py decide_approval_hold \
23
- <hold-id> approved --note "approved by operator; proceeding with plan"
24
- # or:
25
- python3 .map/scripts/map_step_runner.py decide_approval_hold \
26
- <hold-id> denied --note "<why the plan was denied>"
22
+ <hold-id> approved --note "plan_approval no longer gates execution"
27
23
  ```
28
- - **Approved** — continue into the pre-flight test baseline below.
29
- - **Denied** — STOP. Tell the operator to revise the plan and re-run
30
- `$map-plan`; there is no staleness re-check against the denied blueprint
31
- — the operator who denied it is the same operator re-running
32
- `$map-efficient`.
33
24
  - **`dangerous_action` / `safety_guardrail`** (hard stops) — never decide
34
25
  these from inside the preflight. Refuse to proceed: surface the hold's
35
26
  `reason` and `request_summary`, and stop. The operator resolves the
36
27
  underlying issue out of band and decides the hold via `decide_approval_hold`
37
28
  before retrying.
38
29
 
39
- An autonomous chain never reaches the interactive ask above: its pre-phase
40
- `auto_decide_holds` poll auto-approves `plan_approval` before `$map-efficient`
41
- starts, so the preflight here finds nothing pending. If the operator
42
- already decided the hold manually (CLI) before starting `$map-efficient`, the
43
- preflight likewise finds nothing pending and proceeds without asking.
30
+ If the operator already decided a hold manually (CLI) before starting
31
+ `$map-efficient`, the preflight finds nothing pending and proceeds.
44
32
 
45
33
  ## Pre-Monitor Gates
46
34
 
@@ -130,6 +130,18 @@ that the PRD became ready.
130
130
 
131
131
  ---
132
132
 
133
+ ## Pre-flight: Wayfinding Handoff (optional)
134
+
135
+ A handoff seeds a fresh plan ONLY after Resume Detection returns `no_plan` (or after operator-confirmed archival resolves `goal_mismatch`). On `resume`, existing spec/task-plan wins and the handoff is NOT re-consumed; never overwrite an in-progress plan by re-seeding.
136
+
137
+ - For explicit `--wayfind <slug>`, select `.map/wayfind/<slug>/handoff.json` (repo-level).
138
+ - Otherwise run `python3 .map/scripts/wayfind_runner.py list_handoffs`; exactly one completed handoff may be offered, but consume only on an explicit user yes. Never guess a match; zero/multiple handoffs means skip.
139
+ - For BOTH explicit and user-accepted offered handoffs, run `python3 .map/scripts/wayfind_runner.py validate_wayfind_handoff <slug>` immediately before seeding. Non-success → STOP: stale, tampered, missing or actively corrected managed evidence is not settled input. Success with `evidence_status: legacy_unrecorded` → surface the provenance warning, never call it verified. Validation is read-only and proves integrity, not truth; do not repair or migrate the map on read.
140
+
141
+ When a handoff is used, pre-seed the spec: `decisions[]` → **Decisions Made** (settled; do not re-ask), `out_of_scope[]` → **Out of Scope**, `remaining_risks[]` → **Open Questions**. Unresolved research and corrections in risks are not decisions. Continue for anything the handoff did not settle; never modify the wayfinding map.
142
+
143
+ ---
144
+
133
145
  ## Pre-flight: Workflow-Fit Gate
134
146
 
135
147
  Assess whether MAP planning is warranted. Evaluate these signals:
@@ -773,13 +785,9 @@ Record artifacts in the manifest:
773
785
  ```
774
786
  exec_command:
775
787
  cmd: |
776
- PLAN_ARTIFACTS_RESULT=$(python3 .map/scripts/map_step_runner.py record_plan_artifacts)
777
- printf '%s\n' "$PLAN_ARTIFACTS_RESULT"
778
- PLAN_APPROVAL_HOLD_ID=$(printf '%s' "$PLAN_ARTIFACTS_RESULT" | jq -r '.plan_approval_hold_id // empty')
788
+ python3 .map/scripts/map_step_runner.py record_plan_artifacts
779
789
  ```
780
790
 
781
- `record_plan_artifacts` also opens a `plan_approval` hold at the plan-ready boundary and returns it as `plan_approval_hold_id` (idempotent — re-running finds the same pending hold instead of spamming a new one). Capture `PLAN_APPROVAL_HOLD_ID` for the Step 8 checkpoint. This hold does **not** block `$map-plan` itself: planning artifacts are written and Step 8 prints its checkpoint regardless of whether the hold is still pending. The decision (`decide_approval_hold <hold-id> approved|denied`) happens later, at the `$map-efficient` approval-hold preflight — or automatically via an autonomous chain's `auto_decide_holds` poll. If the result instead carries `plan_approval_hold_error: true`, the hold store failed — say so in the Step 8 checkpoint and have the operator create/decide the hold manually (`create_approval_hold --kind plan_approval ...`).
782
-
783
791
  ---
784
792
 
785
793
  ## Step 8: Output Checkpoint
@@ -804,7 +812,6 @@ exec_command:
804
812
  echo "[ok] Plan written to .map/${BRANCH}/task_plan_${BRANCH}.md"
805
813
  echo "[ok] artifact_manifest.json updated"
806
814
  echo "[ok] Mode: [standard | light | deep]"
807
- echo "[ok] Plan approval hold: ${PLAN_APPROVAL_HOLD_ID:-none} — decide via decide_approval_hold <hold-id> <approved|denied> --note \"<operator note>\" before \$map-efficient will proceed"
808
815
  echo ""
809
816
  echo "Next steps:"
810
817
  echo " 1. Review .map/${BRANCH}/task_plan_${BRANCH}.md"
@@ -73,7 +73,7 @@ Execute all 12 gates. Read the full gate scripts in [release-reference.md § Pha
73
73
  - **Gates 5–6:** Build + twine check
74
74
  - **Gate 7:** Security audit (`pip-audit`)
75
75
  - **Gates 8–10:** Git state — main branch, clean working directory, up-to-date with origin
76
- - **Gate 11:** Latest CI run on main must have `conclusion: "success"`
76
+ - **Gate 11:** CI run for `git merge-base HEAD origin/main` must have `conclusion: "success"`; unpushed commits may touch only release metadata
77
77
  - **Gate 12:** CHANGELOG.md completeness (Unreleased section exists and has content; commit/entry gap check)
78
78
 
79
79
  **If any gate fails:** ABORT. Fix issues, re-run Phase 1.
@@ -81,27 +81,21 @@ Execute all 12 gates. Read the full gate scripts in [release-reference.md § Pha
81
81
  ## Phase 2: Version Determination
82
82
 
83
83
  Read CHANGELOG.md `[Unreleased]` section to determine bump type (MAJOR/MINOR/PATCH/EXPLICIT).
84
- Get current version from `pyproject.toml`. Ask the user directly for the bump type.
84
+ Get current version from `pyproject.toml`.
85
85
 
86
- See [release-reference.md § Phase 2](release-reference.md#phase-2-version-determination) for the full question/option block.
87
-
88
- ## Phase 3: Execute Version Bump Script
86
+ Ask the user directly for PATCH / MINOR / MAJOR / EXPLICIT, and wait for their answer.
89
87
 
90
- Run `./scripts/bump-version.sh --yes "$BUMP_TYPE"`, then verify:
88
+ For EXPLICIT, ask separately for the exact version. Carry only the user's approved
89
+ `BUMP_TYPE` and exact `NEW_VERSION` into Phase 3; each command runs in a fresh shell.
91
90
 
92
- ```bash
93
- # Verify tag points to HEAD
94
- TAG_COMMIT=$(git rev-list -n 1 "$LAST_TAG")
95
- HEAD_COMMIT=$(git rev-parse HEAD)
96
- [[ "$TAG_COMMIT" != "$HEAD_COMMIT" ]] && echo "❌ Tag mismatch" && exit 1
91
+ See [release-reference.md § Phase 2](release-reference.md#phase-2-version-determination) for the full question/option block.
97
92
 
98
- # 🚨 CRITICAL: Verify __version__ in __init__.py (bump-version.sh known bug)
99
- INIT_VERSION=$(grep -m1 -E '^__version__ = ' src/mapify_cli/__init__.py | sed -E 's/__version__ = "(.*)"/\1/')
100
- TAG_VERSION="${LAST_TAG#v}"
101
- [[ "$INIT_VERSION" != "$TAG_VERSION" ]] && echo "❌ __version__ mismatch — fix manually, see reference" && exit 1
93
+ ## Phase 3: Execute Version Bump Script
102
94
 
103
- echo "✅ Version bump successful: all version fields match"
104
- ```
95
+ Show the exact approved version and bump type, then execute the Phase 3 reference
96
+ blocks with those values explicitly supplied in each invocation. Never rely on
97
+ variables left by a previous shell. Verify the version-derived `vX.Y.Z` tag points
98
+ to HEAD and both version fields match it using the Phase 3.3 reference block.
105
99
 
106
100
  If `__version__` mismatches, follow the fix procedure in [release-reference.md § Phase 3 workaround](release-reference.md#phase-3-execute-version-bump-script).
107
101
 
@@ -109,25 +103,24 @@ If `__version__` mismatches, follow the fix procedure in [release-reference.md
109
103
 
110
104
  **⚠️ CRITICAL PHASE:** Once the tag is pushed the release workflow triggers and publishes to PyPI.
111
105
 
112
- Re-verify: on main branch, CI passed, tag does not already exist on remote. Then ask the user directly for **explicit confirmation** (YES / NO / REVIEW options). See [release-reference.md § Phase 4](release-reference.md#phase-4-push-commit-and-tag-irreversible) for the full confirmation block.
106
+ Re-verify: on main branch, exact merge-base CI completed successfully with matching
107
+ `headSha`, only the three allowed metadata files changed, version-derived tag
108
+ points to HEAD and does not already exist on remote. Then request **explicit user
109
+ confirmation** (YES / NO / REVIEW options).
113
110
 
114
- ```bash
115
- git push origin main
116
- git push origin "$LAST_TAG"
117
- ```
111
+ Ask the user directly and wait; only an unambiguous YES authorizes pushing.
112
+
113
+ Read [release-reference.md § Phase 4](release-reference.md#phase-4-push-commit-and-tag-irreversible)
114
+ for the confirmation and push blocks. Recompute the tag in the push invocation;
115
+ consent for an earlier version or commit does not authorize a changed release.
118
116
 
119
117
  If user aborts: stop workflow, exit gracefully. Tag remains local only.
120
118
 
121
119
  ## Phase 5: CI/CD Monitoring
122
120
 
123
- Wait for the release workflow to start, then watch it to completion:
124
-
125
- ```bash
126
- gh run list --workflow=release.yml --limit 1 --json databaseId,status,conclusion,createdAt
127
- gh run watch "$RUN_ID"
128
- FINAL_STATUS=$(gh run view "$RUN_ID" --json conclusion --jq '.conclusion')
129
- [[ "$FINAL_STATUS" != "success" ]] && echo "❌ Release workflow failed — see reference for rollback" && exit 1
130
- ```
121
+ Use the Phase 5 reference block: recompute the version-derived tag and release
122
+ commit, select `release.yml` for that exact commit (not latest-main), derive
123
+ `RUN_ID` in the same shell, then watch and validate the final status and `headSha`.
131
124
 
132
125
  The GitHub Release is created automatically by the workflow (no manual step).
133
126