From 4334f1d6a577b4a0b8d4546b1dd6d4ae6c7c4daa Mon Sep 17 00:00:00 2001 From: Mikhail Petrov Date: Sat, 30 May 2026 11:21:02 +0300 Subject: [PATCH 1/2] feat(map-efficient): emit learning-handoff so deferred /map-learn auto-loads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /map-efficient was the only learning-eligible workflow that never called write_learning_handoff, so `.map//learning-handoff.md` was absent after a run. A deferred zero-argument /map-learn then found no artifact and fell back to reconstructing the workflow summary from in-context memory. Add the write_learning_handoff closeout call to map-efficient Step 3.3, right after write_run_health_report, so the handoff bundle is produced for every run. Empty task_title auto-resolves via read_current_goal. To stay within the 500-line active-body budget (test_skills line cap on HIGH_TRAFFIC_COMPACT_SKILL_REFS), collapse write_run_health_report to its single-line form; the pinned closeout-wiring test is made format-agnostic (accepts single-line and backslash-continued forms) while still catching a hardcoded status regression. Negative-proofed: green->red->green. Codex variant (.agents/skills/map-efficient) intentionally untouched — map-learn is not part of the Codex skill surface. Synced .claude -> templates per repo invariant. make check green (ruff/mypy/pyright 0/0/0, 1787 passed). Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/skills/map-efficient/SKILL.md | 9 ++++---- .../templates/skills/map-efficient/SKILL.md | 9 ++++---- tests/test_skills.py | 22 ++++++++++++------- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/.claude/skills/map-efficient/SKILL.md b/.claude/skills/map-efficient/SKILL.md index 9331d20..b986b52 100644 --- a/.claude/skills/map-efficient/SKILL.md +++ b/.claude/skills/map-efficient/SKILL.md @@ -480,16 +480,15 @@ Set final status from verifier and gates: ```bash RUN_HEALTH_STATUS="${RUN_HEALTH_STATUS:?set from final decision}" -python3 .map/scripts/map_step_runner.py write_run_health_report \ - map-efficient \ - "$RUN_HEALTH_STATUS" +python3 .map/scripts/map_step_runner.py write_run_health_report map-efficient "$RUN_HEALTH_STATUS" +python3 .map/scripts/map_step_runner.py write_learning_handoff map-efficient "" "$RUN_HEALTH_STATUS" "Run /map-learn to preserve patterns, then /map-review" "" ``` -This writes `.map//run_health_report.json`, updates `run_health`, and gives reviewers a machine-readable terminal snapshot. +This writes `run_health_report.json` (machine-readable run snapshot) plus `learning-handoff.md`/`.json`, so a later zero-argument `/map-learn` auto-loads this run instead of reconstructing it from memory. ## Step 4: Summary -Report completed subtasks, files changed, checks run, final status, remaining issues, and next command (`/map-review` or the owning fix workflow). +Report completed subtasks, files changed, checks run, final status, remaining issues, and next command (`/map-review`, the owning fix workflow, or optional `/map-learn` to preserve patterns). ## Examples diff --git a/src/mapify_cli/templates/skills/map-efficient/SKILL.md b/src/mapify_cli/templates/skills/map-efficient/SKILL.md index 9331d20..b986b52 100644 --- a/src/mapify_cli/templates/skills/map-efficient/SKILL.md +++ b/src/mapify_cli/templates/skills/map-efficient/SKILL.md @@ -480,16 +480,15 @@ Set final status from verifier and gates: ```bash RUN_HEALTH_STATUS="${RUN_HEALTH_STATUS:?set from final decision}" -python3 .map/scripts/map_step_runner.py write_run_health_report \ - map-efficient \ - "$RUN_HEALTH_STATUS" +python3 .map/scripts/map_step_runner.py write_run_health_report map-efficient "$RUN_HEALTH_STATUS" +python3 .map/scripts/map_step_runner.py write_learning_handoff map-efficient "" "$RUN_HEALTH_STATUS" "Run /map-learn to preserve patterns, then /map-review" "" ``` -This writes `.map//run_health_report.json`, updates `run_health`, and gives reviewers a machine-readable terminal snapshot. +This writes `run_health_report.json` (machine-readable run snapshot) plus `learning-handoff.md`/`.json`, so a later zero-argument `/map-learn` auto-loads this run instead of reconstructing it from memory. ## Step 4: Summary -Report completed subtasks, files changed, checks run, final status, remaining issues, and next command (`/map-review` or the owning fix workflow). +Report completed subtasks, files changed, checks run, final status, remaining issues, and next command (`/map-review`, the owning fix workflow, or optional `/map-learn` to preserve patterns). ## Examples diff --git a/tests/test_skills.py b/tests/test_skills.py index 30fbecb..bfeb7aa 100644 --- a/tests/test_skills.py +++ b/tests/test_skills.py @@ -1161,14 +1161,20 @@ def test_closeout_prompts_write_run_health_report( content = skill_md.read_text(encoding="utf-8") assert "write_run_health_report" in content - expected_invocation = f'''write_run_health_report \\ - {skill_name} \\ - "$RUN_HEALTH_STATUS"''' - assert expected_invocation in content - hardcoded_complete = f"""write_run_health_report \\ - {skill_name} \\ - complete""" - assert hardcoded_complete not in content + # Accept both single-line and backslash-continued invocations (map-efficient + # is line-budget-gated and uses the compact single-line form), but still + # require the status variable rather than a hardcoded literal in either form. + token_gap = r"\s+\\?\s*" + assert re.search( + "write_run_health_report" + token_gap + re.escape(skill_name) + + token_gap + r'"\$RUN_HEALTH_STATUS"', + content, + ), f"{skill_name} must invoke write_run_health_report with $RUN_HEALTH_STATUS" + assert not re.search( + "write_run_health_report" + token_gap + re.escape(skill_name) + + token_gap + r"(?:complete|pending|blocked|won't_do|superseded)\b", + content, + ), f"{skill_name} must not hardcode a literal status into write_run_health_report" assert "run_health_report.json" in content assert "run_health" in content assert "RUN_HEALTH_STATUS" in content From cedac85942fd899fa850ec82af139eed4c1ccdad Mon Sep 17 00:00:00 2001 From: Mikhail Petrov Date: Sat, 30 May 2026 11:36:28 +0300 Subject: [PATCH 2/2] test(map-efficient): catch quoted hardcoded status in run-health guard Copilot review on PR #154: the hardcoded-status negative guard matched `write_run_health_report complete` but not the quoted shell form `write_run_health_report "complete"`, even though the surrounding examples quote the status argument. Allow an optional leading quote before the literal so the regression test covers both shell forms it claims to reject. Negative-proofed: a quoted `"complete"` hardcode now turns the guard RED; clean state stays GREEN. Co-Authored-By: Claude Opus 4.8 (1M context) --- tests/test_skills.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_skills.py b/tests/test_skills.py index bfeb7aa..44856a0 100644 --- a/tests/test_skills.py +++ b/tests/test_skills.py @@ -1172,7 +1172,7 @@ def test_closeout_prompts_write_run_health_report( ), f"{skill_name} must invoke write_run_health_report with $RUN_HEALTH_STATUS" assert not re.search( "write_run_health_report" + token_gap + re.escape(skill_name) - + token_gap + r"(?:complete|pending|blocked|won't_do|superseded)\b", + + token_gap + r"""["']?(?:complete|pending|blocked|won't_do|superseded)\b""", content, ), f"{skill_name} must not hardcode a literal status into write_run_health_report" assert "run_health_report.json" in content