prizmkit 1.1.104 → 1.1.105

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.
@@ -1,8 +1,8 @@
1
1
  ## PrizmKit Directory Convention
2
2
 
3
3
  ```
4
- .prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md ← orchestrator writes Sections 1-4; Dev appends Implementation Log; Reviewer appends Review Notes
4
+ .prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md ← orchestrator writes Sections 1-4 + Implementation Log; Reviewer appends Review Notes
5
5
  .prizmkit/specs/{{FEATURE_SLUG}}/plan.md ← includes Tasks section
6
6
  ```
7
7
 
8
- **`context-snapshot.md`** is the shared knowledge base. Orchestrator writes Sections 1-4; Dev appends Implementation Log; Reviewer appends Review Notes. Append-only after initial creation.
8
+ **`context-snapshot.md`** is the shared knowledge base. Orchestrator writes Sections 1-4 and the Implementation Log; Reviewer appends Review Notes. Append-only after initial creation.
@@ -1,9 +1,9 @@
1
1
  ## PrizmKit Directory Convention
2
2
 
3
3
  ```
4
- .prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md ← orchestrator writes Sections 1-4; Dev appends Implementation Log; Reviewer appends Review Notes
4
+ .prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md ← orchestrator writes Sections 1-4 + Implementation Log; Reviewer appends Review Notes
5
5
  .prizmkit/specs/{{FEATURE_SLUG}}/spec.md
6
6
  .prizmkit/specs/{{FEATURE_SLUG}}/plan.md ← includes Tasks section
7
7
  ```
8
8
 
9
- **`context-snapshot.md`** is the shared knowledge base. Orchestrator writes Sections 1-4; Dev appends Implementation Log; Reviewer appends Review Notes. This eliminates redundant I/O across all agents.
9
+ **`context-snapshot.md`** is the shared knowledge base. Orchestrator writes Sections 1-4 and the Implementation Log; Reviewer appends Review Notes. This eliminates redundant I/O across review and orchestration phases.
@@ -22,6 +22,7 @@ grep -c '^\- \[ \]' .prizmkit/specs/{{FEATURE_SLUG}}/plan.md 2>/dev/null || true
22
22
  - Implements task-by-task, marking each `[x]` immediately
23
23
  - Creates/updates L2 `.prizm` docs when creating new modules
24
24
  - Defers scoped/full test execution until after the code-review loop completes
25
+ - Preserves Reviewer/Critic behavior; only the top-level implementation Dev handoff is removed
25
26
  - If plan.md has >5 tasks: update checkpoints after every 3 tasks
26
27
 
27
28
  **3c. Focused checks only (no test gate here)**:
@@ -23,6 +23,7 @@ Save pre-existing failing tests as `BASELINE_FAILURES`.
23
23
  - Implements task-by-task, marking each `[x]` immediately
24
24
  - Creates/updates L2 `.prizm` docs when creating new modules
25
25
  - Defers scoped/full test execution until after the code-review loop completes
26
+ - Preserves Reviewer/Critic behavior; only the top-level implementation Dev handoff is removed
26
27
  - If plan.md has >5 tasks: update checkpoints after every 3 tasks
27
28
 
28
29
  **3c. Focused checks only (no test gate here)**:
@@ -8,6 +8,7 @@ from argparse import Namespace
8
8
  from pathlib import Path
9
9
 
10
10
  from generate_bootstrap_prompt import (
11
+ ACTIVE_AGENT_PROMPTS,
11
12
  compute_feature_slug,
12
13
  find_feature,
13
14
  format_acceptance_criteria,
@@ -21,6 +22,7 @@ from generate_bootstrap_prompt import (
21
22
  build_replacements,
22
23
  generate_checkpoint_definition,
23
24
  merge_checkpoint_state,
25
+ load_active_agent_prompts,
24
26
  load_log_size_section,
25
27
  main as generate_bootstrap_main,
26
28
  )
@@ -809,6 +811,50 @@ class TestHeadlessRecoveryReframing:
809
811
  assert "run `/compact` after" not in rendered
810
812
 
811
813
 
814
+ class TestDirectOrchestratorImplementationPrompts:
815
+ def test_active_agent_prompt_loader_excludes_retired_dev_implement_prompt(self):
816
+ templates_dir = Path("dev-pipeline/templates").resolve()
817
+
818
+ replacements = load_active_agent_prompts(str(templates_dir))
819
+
820
+ assert "dev-implement.md" not in ACTIVE_AGENT_PROMPTS
821
+ assert "{{AGENT_PROMPT_DEV_IMPLEMENT}}" not in replacements
822
+ assert "{{AGENT_PROMPT_CRITIC_PLAN_CHALLENGE}}" in replacements
823
+ assert (templates_dir / "agent-prompts" / "dev-implement.md").exists() is False
824
+
825
+ def test_sections_all_modes_use_direct_orchestrator_implementation(self):
826
+ sections_dir = Path("dev-pipeline/templates/sections").resolve()
827
+
828
+ for mode in ("lite", "standard", "full"):
829
+ rendered = "\n".join(
830
+ section for _name, section in assemble_sections(
831
+ mode, str(sections_dir), init_done=True, is_resume=False,
832
+ critic_enabled=(mode == "full"), browser_enabled=False,
833
+ )
834
+ )
835
+
836
+ assert "/prizmkit-implement" in rendered
837
+ assert "orchestrator) execute" in rendered or "Run `/prizmkit-implement`" in rendered
838
+ assert "Spawn Dev subagent" not in rendered
839
+ assert "Spawn Dev agent" not in rendered
840
+ assert "Implement — Dev" not in rendered
841
+ assert "{{AGENT_PROMPT_DEV_IMPLEMENT}}" not in rendered
842
+ assert "dev-implement.md" not in rendered
843
+ assert "Reviewer Agent → filter → Dev Agent fix" in rendered
844
+
845
+ def test_legacy_tier_templates_use_direct_orchestrator_implementation(self):
846
+ for template_name in ("bootstrap-tier2.md", "bootstrap-tier3.md"):
847
+ rendered = (Path("dev-pipeline/templates") / template_name).read_text(encoding="utf-8")
848
+
849
+ assert "/prizmkit-implement" in rendered
850
+ assert "Implement — Orchestrator Direct" in rendered
851
+ assert "Spawn Dev subagent" not in rendered
852
+ assert "Spawn Dev agent" not in rendered
853
+ assert "Implement — Dev" not in rendered
854
+ assert "{{AGENT_PROMPT_DEV_IMPLEMENT}}" not in rendered
855
+ assert "dev-implement.md" not in rendered
856
+
857
+
812
858
  # ---------------------------------------------------------------------------
813
859
  # continuation handoff
814
860
  # ---------------------------------------------------------------------------
@@ -864,6 +864,98 @@ def test_default_no_worktree_preserves_main_worktree_branch_launch(monkeypatch,
864
864
  assert "branch_merge" in plan_names
865
865
 
866
866
 
867
+ def test_no_worktree_runner_ignores_recovery_side_effect_branch(monkeypatch, tmp_path):
868
+ from prizmkit_runtime import runners
869
+ from prizmkit_runtime.runner_models import family_for, parse_invocation
870
+
871
+ monkeypatch.delenv("DEV_BRANCH", raising=False)
872
+ paths = _make_paths(tmp_path)
873
+ family = family_for("feature", paths)
874
+ invocation = parse_invocation(family, "run", ())
875
+ invocation = invocation.__class__(**{**invocation.__dict__, "list_path": paths.feature_plan})
876
+ observed = _install_runner_session_fakes(monkeypatch, runners)
877
+ branch_names = []
878
+
879
+ monkeypatch.setenv("DEV_BRANCH", "dev/F-001-recovery-20260707")
880
+ monkeypatch.setattr(runners, "current_branch", lambda _root: "dev/F-001-recovery-20260707")
881
+
882
+ def fake_run_git_plan(project_root, plan):
883
+ if plan.name == "branch_create":
884
+ branch_names.append(plan.commands[1].args[2])
885
+ return SimpleNamespace(ok=True, plan=plan, results=())
886
+
887
+ monkeypatch.setattr(runners, "run_git_plan", fake_run_git_plan)
888
+
889
+ status = runners._process_item(family, invocation, "F-001", paths, initial_metadata={})
890
+
891
+ assert status == "completed"
892
+ assert branch_names and branch_names[0].startswith("dev/F-001-")
893
+ assert "recovery" not in branch_names[0]
894
+ assert observed.updates[-1][2]["active_dev_branch"] == branch_names[0]
895
+ assert observed.updates[-1][2]["base_branch"] == "main"
896
+
897
+
898
+ def test_foreground_runner_emits_structured_feature_progress(monkeypatch, tmp_path, capsys):
899
+ from prizmkit_runtime import runners
900
+ from prizmkit_runtime.runner_models import family_for, parse_invocation
901
+
902
+ monkeypatch.setenv("DEV_BRANCH", "dev/F-001-output")
903
+ paths = _make_paths(tmp_path)
904
+ family = family_for("feature", paths)
905
+ invocation = parse_invocation(family, "run", ())
906
+ invocation = invocation.__class__(**{**invocation.__dict__, "list_path": paths.feature_plan})
907
+ _install_runner_session_fakes(monkeypatch, runners)
908
+ monkeypatch.setattr(runners, "run_git_plan", lambda project_root, plan: SimpleNamespace(ok=True, plan=plan, results=()))
909
+
910
+ status = runners._process_item(
911
+ family,
912
+ invocation,
913
+ "F-001",
914
+ paths,
915
+ initial_metadata={"title": "Readable output", "retry_count": 1, "infra_error_count": 2},
916
+ )
917
+
918
+ captured = capsys.readouterr()
919
+ assert status == "completed"
920
+ assert "────────────────────────────────────────────────────" in captured.err
921
+ assert "Feature: F-001 — Readable output" in captured.err
922
+ assert "Code retry: 1 / 3" in captured.err
923
+ assert "Infrastructure retry: 2 / 3" in captured.err
924
+ assert "Pipeline mode: lite (Tier 1 — Single Agent)" in captured.err
925
+ assert "Agents: 1 (critic: disabled)" in captured.err
926
+ assert "Spawning AI CLI session: F-001-session-1" in captured.err
927
+ assert "Session result: success" in captured.err
928
+
929
+
930
+ def test_no_worktree_interrupt_saves_wip_and_returns_to_base(monkeypatch, tmp_path):
931
+ from prizmkit_runtime import runners
932
+ from prizmkit_runtime.runner_models import family_for, parse_invocation
933
+
934
+ monkeypatch.setenv("DEV_BRANCH", "dev/F-001-interrupt")
935
+ paths = _make_paths(tmp_path)
936
+ family = family_for("feature", paths)
937
+ invocation = parse_invocation(family, "run", ())
938
+ invocation = invocation.__class__(**{**invocation.__dict__, "list_path": paths.feature_plan})
939
+ _install_runner_session_fakes(monkeypatch, runners)
940
+ ensure_calls = []
941
+ monkeypatch.setattr(runners, "run_git_plan", lambda project_root, plan: SimpleNamespace(ok=True, plan=plan, results=()))
942
+ monkeypatch.setattr(runners, "branch_ensure_return", lambda project_root, base, branch: ensure_calls.append((base, branch)))
943
+
944
+ class InterruptingLauncher:
945
+ def __init__(self, config):
946
+ self.config = config
947
+
948
+ def run(self):
949
+ raise KeyboardInterrupt
950
+
951
+ monkeypatch.setattr(runners, "AISessionLauncher", InterruptingLauncher)
952
+
953
+ with pytest.raises(KeyboardInterrupt):
954
+ runners._process_item(family, invocation, "F-001", paths, initial_metadata={})
955
+
956
+ assert ensure_calls == [("main", "dev/F-001-interrupt")]
957
+
958
+
867
959
  def test_context_overflow_reuses_worktree_and_skips_cleanup_until_terminal_outcome(monkeypatch, tmp_path):
868
960
  from prizmkit_runtime import runners
869
961
  from prizmkit_runtime.runner_models import family_for, parse_invocation
@@ -964,6 +1056,14 @@ def test_classification_stalls_after_repeated_no_progress_context_overflow(tmp_p
964
1056
  assert classification.no_progress_count == 2
965
1057
 
966
1058
 
1059
+ def test_recovery_prompt_keeps_existing_branch_instead_of_recovery_suffix():
1060
+ text = (PIPELINE_ROOT / "scripts" / "generate-recovery-prompt.py").read_text(encoding="utf-8")
1061
+
1062
+ assert "fix/{bug_id}-recovery" not in text
1063
+ assert "do not create an additional" in text
1064
+ assert "last-resort fallback" in text
1065
+
1066
+
967
1067
  def test_recovery_detector_resolver_prefers_installed_platform_asset(tmp_path):
968
1068
  from prizmkit_runtime.paths import resolve_runtime_paths
969
1069
  from prizmkit_runtime.runner_recovery import RecoveryDetectorResolver
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.1.104",
2
+ "version": "1.1.105",
3
3
  "skills": {
4
4
  "prizm-kit": {
5
5
  "description": "Full-lifecycle dev toolkit. Covers spec-driven development, Prizm context docs, code quality, debugging, deployment, and knowledge management.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prizmkit",
3
- "version": "1.1.104",
3
+ "version": "1.1.105",
4
4
  "description": "Create a new PrizmKit-powered project with clean initialization — no framework dev files, just what you need.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,71 +0,0 @@
1
- "<!-- DEPRECATED (P0-6): This prompt was injected into a Dev subagent spawn.
2
- The orchestrator now implements directly (see phase-implement-agent.md / phase-implement-full.md).
3
- This file is retained only so load_agent_prompts() does not break; it is no longer referenced
4
- by any phase section. Do not add new rules here — add them to the phase-implement-* sections instead.
5
- The rules below are the legacy Dev-subagent version, kept for reference only. -->
6
-
7
- Read {{DEV_SUBAGENT_PATH}}. Implement feature {{FEATURE_ID}} (slug: {{FEATURE_SLUG}}).
8
-
9
- ## Task Summary Card
10
-
11
- **Objective**: Implement {{FEATURE_TITLE}}.
12
-
13
- **Primary files** (see context-snapshot.md Section 4 for full manifest):
14
- - Review plan.md Tasks section for the complete task-to-file mapping.
15
- - Each task's `— file:` suffix identifies the target file.
16
-
17
- **Test command**: `{{TEST_CMD}}`
18
-
19
- **Known baseline failures**: `{{BASELINE_FAILURES}}`
20
-
21
- **DO NOT**:
22
- - Re-read source files already listed in context-snapshot.md Section 4 File Manifest
23
- - Create new files unless a plan.md task explicitly requires it
24
- - Run git commands
25
- - Use mock success data or fake rows in UI/tests
26
-
27
- ## Required Inputs
28
-
29
- 1. Read `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` first.
30
- 2. Use Section 4 File Manifest for targeted reads.
31
- 3. Do not expand scope beyond the Task Contract and Verification Gates.
32
- 4. Do not re-read source files already listed in Section 4 unless implementation details are missing from the manifest.
33
-
34
- ## Work
35
-
36
- Run `/prizmkit-implement` to execute `plan.md`.
37
-
38
- Test command:
39
- `{{TEST_CMD}}`
40
-
41
- Known baseline failures:
42
- `{{BASELINE_FAILURES}}`
43
-
44
- If plan.md has more than 5 tasks, update durable checkpoints/artifacts after every 3 tasks, minimize output, and rely on runner continuation if context overflow occurs. In an interactive Claude Code session operated manually outside the headless pipeline, `/compact` may be used as an optional convenience only.
45
-
46
- ## Required Outputs
47
-
48
- Before returning, append `## Implementation Log` to `context-snapshot.md` with:
49
- - files changed/created
50
- - key decisions
51
- - deviations from plan
52
- - test results
53
- - Verification Gate status
54
- - unresolved blockers, if any
55
-
56
- ## Protocol References
57
-
58
- - Follow the global Context Budget Rules.
59
- - Carry forward the Dev-isolated subset: skip scaffold/generated files listed in `context-snapshot.md`; verify dependency versions before install/build commands that resolve dependencies; after build/compile commands, ensure outputs are ignored and never commit generated artifacts.
60
- - If tests fail, follow this Test Failure Recovery subset: classify failures as baseline, new regression, brittle test, or environment/tooling; fix new regressions and brittle tests while progress is being made; document baseline failures; write `failure-log.md` for blockers.
61
- - Do not run git commands; staging and commit are handled by the orchestrator.
62
- - **Edit safety**: If an Edit fails with 'String to replace not found', grep for the target text before retrying. Never guess file offsets — verify them with a Read or grep first.
63
- - **Read safety**: If 3 consecutive Reads to the same file return 'shorter than offset' or 'Wasted call', STOP and report BLOCKED.
64
- - **Test gate placement**: Do not run mandatory periodic or full-suite tests here. The scoped/full test gate runs after code review; only use tiny targeted checks when needed for local debugging.
65
-
66
- Do not return success unless:
67
- 1. implementation tasks are complete;
68
- 2. `## Implementation Log` exists;
69
- 3. every Verification Gate is verified.
70
-
71
- If any Verification Gate is blocked, write `failure-log.md` and return a blocked/incomplete result instead of success."