Skip to content

Phase B: personal/repo-global learned-rules layer + MONITOR-gate fix#153

Merged
azalio merged 8 commits into
mainfrom
corona-mirage
May 30, 2026
Merged

Phase B: personal/repo-global learned-rules layer + MONITOR-gate fix#153
azalio merged 8 commits into
mainfrom
corona-mirage

Conversation

@azalio
Copy link
Copy Markdown
Owner

@azalio azalio commented May 30, 2026

Summary

Two related units of work on one branch.

1. Phase B — personal/repo-global learned-rules layer (ST-001…ST-006)

A gitignored .map/personal/rules/learned/ layer surfaced via the PreToolUse
workflow-context-injector.py hook inside a sanitized, budget-capped
<personal-rules> fence, plus /map-learn personal-vs-public choice +
promotion, .gitignore intent, template-sync, and tests.

  • ST-001 773395b — 3 read-only injector helpers (loader / sanitizer /
    fence-builder): symlink-safe, error-swallowing, (0,"") when absent,
    delimiter-sanitized (INV-6), budget-trimmed well-formed fence (INV-4).
  • ST-002 5af9ad2 — wire personal block into main(): reminder + sep + block, dedup over the full assembled string (INV-7), MAP_INVOKED_BY guard
    stays first (HC-4), total ≤ 10000 (INV-4); byte-for-byte unchanged when no
    personal rules exist (HC-3).
  • ST-003 4ecf0fbmap-learn/SKILL.md: write-time personal-vs-public
    choice (AC-5), promote-existing with the E6 bold-title match key (AC-6),
    D2 limitation note (AC-10).
  • ST-004 232d3c5 — documented .map/personal/ entry in .gitignore (AC-7).
  • ST-005 45ee857make sync-templates → template copies byte-identical (INV-5).
  • ST-006 4066049 — 5 personal-layer subprocess tests + promote-idempotency.

2. Framework fix — MONITOR-phase Edit gate (4360d56)

MAP_MONITOR_HOTFIX now defaults on: Edit/Write/MultiEdit are allowed
during the MONITOR phase by default (Actor routinely lands a test/nit while the
Monitor verdict is captured); MAP_MONITOR_HOTFIX=0 restores strict read-only
MONITOR. Applied to both hook trees (.claude + .codex) and synced to
templates (4-copy parity). docs/improvement-plan.md gains a "Phase B run —
framework gate findings" section recording this fix, the still-open
MAP_STRICT_SCOPE work (#4 ACTOR-diff gate, #6 detect_* receipts) with exact
post-fix test plans, and the deliberately-not-fixed items (#1 state/git
reconcile, #3 idempotency asymmetry, #2 which was a false alarm).

Test plan

  • python3 -m pytest -q1786 passed, 4 skipped
  • python3 scripts/lint-hooks.py → 12/12 hooks conform (recursion guard intact)
  • pytest tests/test_template_sync.py → green; 4-copy gate parity verified
  • Final-verifier (Ralph loop) on Phase B → PASS (all AC/INV/HC satisfied)

Notes

  • The MAP workflow state machine reports COMPLETE for Phase B; the gate fix was
    landed as a follow-up commit on the same branch after explicit user request.

🤖 Generated with Claude Code

azalio and others added 7 commits May 29, 2026 23:54
…-001)

Add three read-only module-level helpers to workflow-context-injector.py
(not yet wired into main() — that is ST-002):
- _load_personal_rules: reads .map/personal/rules/learned/*.md, symlink-safe,
  error-swallowing, returns (0,"") when absent/empty (HC-1/INV-1/E2/E4).
- _sanitize_fence_content: strips case-insensitive <personal-rules> delimiters
  so user content cannot close the fence early (INV-6/E7).
- _build_personal_block: budget-capped, always-well-formed <personal-rules>
  fence with [... trimmed] marker on overflow (INV-4/E3).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…key (ST-002)

Assemble additionalContext = reminder + sep + personal_block on the existing
if-reminder path (SC-1). Reminder-first (capped 700), personal block capped at
10000-len(reminder)-len(sep) with a pre-emit len<=10000 assert (INV-4). Both
dedup sites key on the full assembled string so same-turn personal edits yield
a fresh injection (INV-7). MAP_INVOKED_BY guard stays the first statement of
main() (HC-4/INV-3). No personal rules -> assembled == reminder byte-for-byte
(HC-3); lint green, 73 scoped tests pass, full suite green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Step 3 now documents: (AC-5) a write-time personal vs public layer choice
reusing the same 6-category map and bullet format (personal ->
.map/personal/rules/learned/<category>.md, public -> .claude/rules/learned/);
(AC-6) promote-existing as a MOVE personal->public, idempotent per the E6
exact bold-title match key (same-title -> skip insert, still remove personal
copy); (AC-10) the D2 limitation note that personal rules inject only during
active MAP workflows when step_state.json is present, not on every prompt.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…004)

Explicit .map/personal/ entry adjacent to the .map/* block, immediately
followed by a comment marking it user-local and not shipped. Redundant over
.map/* but kept explicit for intent + defense in depth (AC-7). .gitignore is
not templated, so no src/mapify_cli/templates/ copy is needed (AC-8).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-005)

make sync-templates mirrors the ST-001/ST-002 injector changes and the ST-003
map-learn/SKILL.md changes into src/mapify_cli/templates/. Template copies are
byte-identical to the .claude/ dev copies (INV-5/HC-5); tests/test_template_sync.py
passes (53). .gitignore is intentionally not templated (AC-8).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… (ST-006)

Adds 5 tests to tests/test_workflow_context_injector.py (fresh tmp dir per
subprocess case to dodge per-turn dedup, INV-7):
- test_vc1_personal_present (AC-1): fence + single banner + content
- test_vc2_personal_absent (AC-2): structural absence of fence/banner
- test_vc3_over_budget (AC-3/E3): [... trimmed] + closing tag + total <= 10000
- test_vc4_delimiter_sanitization (AC-9/INV-6/E7): no early fence close
- test_vc5_promote_idempotent (AC-11): E6 bold-title match -> no duplicate, personal copy removed
Full suite green (78 passed across injector + hook patterns).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ICT_SCOPE plan

MAP_MONITOR_HOTFIX now defaults ON: Edit/Write/MultiEdit are permitted during
the MONITOR phase by default (Actor routinely lands a test/nit while the Monitor
verdict is captured). Set MAP_MONITOR_HOTFIX=0 to restore strict read-only
MONITOR. Applied to both hook trees (.claude + .codex), synced to templates.

tests/test_workflow_gate.py:
- test_allows_edit_during_monitor_phase_by_default (new default)
- test_monitor_strict_mode_blocks_edit (MAP_MONITOR_HOTFIX=0 opt-out; deny msg
  documents the opt-out + monitor_failed)
- placeholder "non-editing phase" tests switched MONITOR -> PREDICTOR so each
  still asserts a genuinely-gated phase.

docs/improvement-plan.md: appended "Phase B run - framework gate findings" with
the MONITOR fix, the still-open MAP_STRICT_SCOPE work (#4 ACTOR-diff gate,
#6 detect_* receipts) + exact post-fix test plans, and the not-fixed items
(#1 state/git reconcile, #3 idempotency, #2 false alarm). Original REGISTRY/FOCUS
backlog preserved.

Full suite: 1786 passed. lint-hooks green. 4-copy gate parity intact.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 30, 2026 05:56
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 adds a personal, gitignored learned-rules layer for active MAP workflows and changes the MONITOR-phase gate so edits are allowed by default unless strict mode is explicitly enabled.

Changes:

  • Adds personal-rule injection into workflow-context-injector.py with sanitization, fencing, dedup integration, and budget enforcement.
  • Updates map-learn skill guidance for personal vs public rules and promotion semantics.
  • Changes workflow-gate.py MONITOR behavior across Claude, Codex, and template copies, with corresponding tests and documentation.

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
.claude/hooks/workflow-context-injector.py Loads and injects .map/personal/rules/learned/*.md into hook context.
src/mapify_cli/templates/hooks/workflow-context-injector.py Template copy of the personal-rule injector changes.
.claude/hooks/workflow-gate.py Makes MONITOR edits allowed by default, with MAP_MONITOR_HOTFIX=0 strict mode.
.codex/hooks/workflow-gate.py Codex copy of the MONITOR gate behavior change.
src/mapify_cli/templates/hooks/workflow-gate.py Claude template copy of the MONITOR gate change.
src/mapify_cli/templates/codex/hooks/workflow-gate.py Codex template copy of the MONITOR gate change.
.claude/skills/map-learn/SKILL.md Documents personal/public learned-rule targeting and promotion.
src/mapify_cli/templates/skills/map-learn/SKILL.md Template copy of the updated map-learn skill.
tests/test_workflow_gate.py Updates gate expectations for permissive MONITOR default and strict opt-out.
tests/test_workflow_context_injector.py Adds subprocess coverage for personal-rule injection behavior.
.gitignore Explicitly documents ignoring .map/personal/.
docs/improvement-plan.md Records MONITOR gate findings and remaining strict-scope follow-up work.

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

Comment on lines +1056 to +1057
def _promote(bullet, personal_file, public_file):
if _bullet_present_in_file(bullet, public_file):
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Good catch — addressed in eea4b6f. Added test_vc5_promote_idempotency_rule_documented_in_shipped_skill which pins the exact E6 bold-title idempotency sentence plus the skip-insert / always-remove-personal behaviour markers in BOTH shipped SKILL.md copies (dev + template). Verified the guard fails when the prose is reworded, so prose drift now breaks the suite.

…(Copilot review)

Copilot flagged that test_vc5_promote_idempotent only exercises a helper
defined inside the test body, so it would still pass if map-learn/SKILL.md
dropped or reworded the bold-title idempotency rule it simulates. Add
test_vc5_promote_idempotency_rule_documented_in_shipped_skill, which pins the
exact E6 match-key sentence plus the skip-insert / always-remove-personal
behaviour markers in BOTH shipped copies (dev + template). Verified the guard
fails when the prose is reworded.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@azalio azalio merged commit 3ed7327 into main May 30, 2026
6 checks passed
@azalio azalio deleted the corona-mirage branch May 30, 2026 06:17
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