prizmkit 1.1.127 → 1.1.129
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.
- package/bundled/VERSION.json +3 -3
- package/bundled/adapters/claude/command-adapter.js +2 -75
- package/bundled/dev-pipeline/assets/skill-subagent-integration.md +14 -11
- package/bundled/dev-pipeline/prizmkit_runtime/gitops.py +88 -58
- package/bundled/dev-pipeline/prizmkit_runtime/reset.py +4 -3
- package/bundled/dev-pipeline/prizmkit_runtime/runner_bookkeeping.py +53 -1
- package/bundled/dev-pipeline/prizmkit_runtime/runners.py +33 -17
- package/bundled/dev-pipeline/prizmkit_runtime/runtime_helper.py +0 -1
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +28 -26
- package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +1 -1
- package/bundled/dev-pipeline/scripts/generate-recovery-prompt.py +4 -3
- package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +1 -1
- package/bundled/dev-pipeline/scripts/parse-stream-progress.py +3 -3
- package/bundled/dev-pipeline/templates/bootstrap-prompt.md +2 -2
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +22 -21
- package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +4 -4
- package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +5 -5
- package/bundled/dev-pipeline/templates/sections/bugfix-mission.md +1 -1
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-review.md +11 -4
- package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +1 -1
- package/bundled/dev-pipeline/templates/sections/directory-convention-agent.md +3 -2
- package/bundled/dev-pipeline/templates/sections/directory-convention-full.md +3 -2
- package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +1 -1
- package/bundled/dev-pipeline/templates/sections/phase-commit.md +1 -1
- package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +1 -1
- package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +1 -1
- package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +12 -5
- package/bundled/dev-pipeline/templates/sections/phase-review-full.md +12 -5
- package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +1 -1
- package/bundled/dev-pipeline/templates/sections/phase0-init.md +1 -1
- package/bundled/dev-pipeline/templates/sections/refactor-mission.md +1 -1
- package/bundled/dev-pipeline/templates/sections/refactor-phase-review.md +13 -6
- package/bundled/dev-pipeline/templates/sections/refactor-reminders.md +1 -1
- package/bundled/dev-pipeline/templates/sections/subagent-timeout-recovery.md +6 -4
- package/bundled/dev-pipeline/templates/sections/test-failure-recovery-agent.md +1 -1
- package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +106 -7
- package/bundled/dev-pipeline/tests/test_python_runner_parity.py +139 -11
- package/bundled/dev-pipeline/tests/test_runtime_helper.py +9 -3
- package/bundled/dev-pipeline/tests/test_unified_cli.py +225 -24
- package/bundled/skills/_metadata.json +3 -3
- package/bundled/skills/feature-planner/SKILL.md +2 -2
- package/bundled/skills/prizmkit/SKILL.md +1 -1
- package/bundled/skills/prizmkit-code-review/SKILL.md +63 -122
- package/bundled/skills/prizmkit-code-review/references/review-report-template.md +9 -36
- package/bundled/skills/prizmkit-code-review/scripts/render_review_report.py +21 -111
- package/package.json +1 -1
- package/src/manifest.js +8 -3
- package/src/scaffold.js +5 -16
- package/bundled/skills/prizmkit-code-review/assets/reviewer-role.json +0 -19
- package/bundled/skills/prizmkit-code-review/references/reviewer-agent-prompt.md +0 -120
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import os
|
|
5
|
+
import re
|
|
5
6
|
import shutil
|
|
6
7
|
import subprocess
|
|
7
8
|
import sys
|
|
@@ -811,7 +812,7 @@ def test_session_preamble_writes_redacted_start_command_for_all_launch_profiles(
|
|
|
811
812
|
assert str(prompt) not in "\n".join(lines[:6])
|
|
812
813
|
|
|
813
814
|
|
|
814
|
-
def
|
|
815
|
+
def test_headless_review_guidance_uses_main_agent_review_loop():
|
|
815
816
|
headless_guidance_files = [
|
|
816
817
|
REPO_ROOT / "dev-pipeline" / "templates" / "sections" / "phase-review-full.md",
|
|
817
818
|
REPO_ROOT / "dev-pipeline" / "templates" / "bootstrap-tier3.md",
|
|
@@ -827,32 +828,28 @@ def test_headless_review_guidance_uses_risk_routed_dual_layer_loop():
|
|
|
827
828
|
|
|
828
829
|
for path in headless_guidance_files:
|
|
829
830
|
text = path.read_text(encoding="utf-8")
|
|
830
|
-
assert "Main-Agent
|
|
831
|
-
assert "
|
|
832
|
-
assert "Reviewer 3 is forbidden" in text, path
|
|
831
|
+
assert "Main-Agent review loop" in text, path
|
|
832
|
+
assert "up to ten completed rounds" in text, path
|
|
833
833
|
assert "text final-verdict" in text, path
|
|
834
|
-
assert "
|
|
835
|
-
assert "
|
|
836
|
-
assert "
|
|
837
|
-
assert "
|
|
838
|
-
assert "
|
|
839
|
-
assert "USE_WORKTREE" not in text, path
|
|
834
|
+
assert "The current Main Agent is the only Code Review executor" in text, path
|
|
835
|
+
assert "Do not invoke another review skill or review workflow" in text, path
|
|
836
|
+
assert "low=0" not in text and "Reviewer 3" not in text, path
|
|
837
|
+
assert "REVIEW_BLOCKED" not in text, path
|
|
838
|
+
assert "forced-worktree changed-content fallback" not in text, path
|
|
840
839
|
assert "isolation:" not in text, path
|
|
841
840
|
|
|
842
841
|
skill_text = skill_path.read_text(encoding="utf-8")
|
|
843
842
|
assert "staged and unstaged tracked changes" in skill_text
|
|
844
843
|
assert "untracked files" in skill_text
|
|
845
844
|
assert "accepted = 0" in skill_text
|
|
846
|
-
assert "
|
|
847
|
-
assert "accepted high-severity finding" in skill_text
|
|
848
|
-
assert "Do not launch Reviewer 3" in skill_text
|
|
845
|
+
assert "ten completed review rounds" in skill_text
|
|
849
846
|
assert "## Final Result" in skill_text
|
|
850
|
-
assert "
|
|
851
|
-
assert "
|
|
847
|
+
assert "PASS | NEEDS_FIXES" in skill_text
|
|
848
|
+
assert "BLOCKED" not in skill_text
|
|
849
|
+
assert "Reviewer 2" not in skill_text
|
|
852
850
|
assert "reviewer-workspace-protocol.md" not in skill_text
|
|
853
851
|
assert "reviewer-execution-protocol.md" not in skill_text
|
|
854
852
|
assert "WORKSPACE_MISMATCH" not in skill_text
|
|
855
|
-
assert "REVIEW_INFRASTRUCTURE_BLOCKED" not in skill_text
|
|
856
853
|
|
|
857
854
|
|
|
858
855
|
def test_progress_parser_adds_required_metadata(tmp_path):
|
|
@@ -952,10 +949,11 @@ def test_progress_parser_normalizes_codebuddy_agent_tools_with_deduplication():
|
|
|
952
949
|
|
|
953
950
|
assert data["cb_session_id"] == "cb-session"
|
|
954
951
|
assert data["subagent_provider"] == "codebuddy"
|
|
955
|
-
assert data["subagent_spawn_count"] ==
|
|
956
|
-
assert data["active_subagent_count"] ==
|
|
952
|
+
assert data["subagent_spawn_count"] == 1
|
|
953
|
+
assert data["active_subagent_count"] == 1
|
|
957
954
|
assert {item["status"] for item in data["subagent_states"]} == {"running"}
|
|
958
|
-
assert len(data["subagent_statistics"]["records"]) ==
|
|
955
|
+
assert len(data["subagent_statistics"]["records"]) == 1
|
|
956
|
+
assert data["subagent_statistics"]["records"][0]["metadata"]["tool"] == "Agent"
|
|
959
957
|
|
|
960
958
|
|
|
961
959
|
def test_progress_parser_normalizes_codex_collab_metadata_with_missing_fields():
|
|
@@ -1832,14 +1830,18 @@ def test_git_branch_worktree_plans_preserve_shell_invariants(tmp_path):
|
|
|
1832
1830
|
|
|
1833
1831
|
assert create.name == "branch_create"
|
|
1834
1832
|
assert any(command.args[:2] == ("checkout", "-b") for command in create.commands)
|
|
1835
|
-
assert any(command.args[
|
|
1833
|
+
assert not any(command.args and command.args[0] == "stash" for command in merge.commands)
|
|
1834
|
+
assert any(command.args[:2] == ("status", "--porcelain") for command in merge.commands)
|
|
1836
1835
|
assert any(command.args[:2] == ("merge", "--ff-only") for command in merge.commands)
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
assert
|
|
1836
|
+
push_index = next(index for index, command in enumerate(merge.commands) if command.args == ("push",))
|
|
1837
|
+
merge_index = next(index for index, command in enumerate(merge.commands) if command.args[:2] == ("merge", "--ff-only"))
|
|
1838
|
+
assert merge_index < push_index
|
|
1839
|
+
assert save_wip.never_fails is False
|
|
1840
|
+
assert ensure.never_fails is False
|
|
1840
1841
|
assert any(command.args[:2] == ("rebase", "--abort") for command in ensure.commands)
|
|
1841
1842
|
assert any(command.args[:2] == ("add", "-A") for command in ensure.commands)
|
|
1842
|
-
assert not any(command.args[
|
|
1843
|
+
assert not any(command.args and command.args[0] == "stash" for command in ensure.commands)
|
|
1844
|
+
assert ensure.never_fails is False
|
|
1843
1845
|
assert any(".*/worktrees/**" in " ".join(command.args) for command in save_wip.commands)
|
|
1844
1846
|
assert worktree.commands[0].args[:2] == ("worktree", "add")
|
|
1845
1847
|
|
|
@@ -1867,6 +1869,205 @@ def test_git_branch_worktree_plans_preserve_shell_invariants(tmp_path):
|
|
|
1867
1869
|
assert skipped_wip.results == ()
|
|
1868
1870
|
|
|
1869
1871
|
|
|
1872
|
+
def test_runtime_source_constructs_no_git_stash_commands():
|
|
1873
|
+
runtime = Path("dev-pipeline/prizmkit_runtime")
|
|
1874
|
+
matches = []
|
|
1875
|
+
for path in runtime.glob("*.py"):
|
|
1876
|
+
text = path.read_text(encoding="utf-8")
|
|
1877
|
+
if re.search(r'["\']stash["\']', text):
|
|
1878
|
+
matches.append(path.as_posix())
|
|
1879
|
+
|
|
1880
|
+
assert matches == []
|
|
1881
|
+
|
|
1882
|
+
|
|
1883
|
+
def _init_merge_repo(project_root):
|
|
1884
|
+
subprocess.run(["git", "init", "-b", "main"], cwd=project_root, check=True, stdout=subprocess.DEVNULL)
|
|
1885
|
+
subprocess.run(["git", "config", "user.email", "test@example.com"], cwd=project_root, check=True)
|
|
1886
|
+
subprocess.run(["git", "config", "user.name", "Test"], cwd=project_root, check=True)
|
|
1887
|
+
manifest = project_root / ".prizmkit" / "manifest.json"
|
|
1888
|
+
manifest.parent.mkdir(parents=True)
|
|
1889
|
+
manifest.write_text('{"version":"current"}\n', encoding="utf-8")
|
|
1890
|
+
(project_root / "app.txt").write_text("base\n", encoding="utf-8")
|
|
1891
|
+
subprocess.run(["git", "add", "."], cwd=project_root, check=True)
|
|
1892
|
+
subprocess.run(["git", "commit", "-m", "base"], cwd=project_root, check=True, stdout=subprocess.DEVNULL)
|
|
1893
|
+
|
|
1894
|
+
|
|
1895
|
+
def _stash_oids(project_root):
|
|
1896
|
+
output = subprocess.run(
|
|
1897
|
+
["git", "stash", "list", "--format=%H"],
|
|
1898
|
+
cwd=project_root,
|
|
1899
|
+
check=True,
|
|
1900
|
+
stdout=subprocess.PIPE,
|
|
1901
|
+
text=True,
|
|
1902
|
+
).stdout
|
|
1903
|
+
return tuple(line for line in output.splitlines() if line)
|
|
1904
|
+
|
|
1905
|
+
|
|
1906
|
+
def test_branch_merge_preserves_preexisting_stash_when_workspace_is_clean(tmp_path):
|
|
1907
|
+
from prizmkit_runtime.gitops import BranchContext, branch_merge_plan, run_git_plan
|
|
1908
|
+
|
|
1909
|
+
_init_merge_repo(tmp_path)
|
|
1910
|
+
manifest = tmp_path / ".prizmkit" / "manifest.json"
|
|
1911
|
+
manifest.write_text('{"version":"stale"}\n', encoding="utf-8")
|
|
1912
|
+
subprocess.run(["git", "stash", "push", "-m", "stale-install", "--", ".prizmkit/manifest.json"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
1913
|
+
stale_stashes = _stash_oids(tmp_path)
|
|
1914
|
+
subprocess.run(["git", "checkout", "-b", "dev/example"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
1915
|
+
(tmp_path / "feature.txt").write_text("done\n", encoding="utf-8")
|
|
1916
|
+
subprocess.run(["git", "add", "feature.txt"], cwd=tmp_path, check=True)
|
|
1917
|
+
subprocess.run(["git", "commit", "-m", "feature"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
1918
|
+
|
|
1919
|
+
result = run_git_plan(
|
|
1920
|
+
tmp_path,
|
|
1921
|
+
branch_merge_plan(BranchContext("main", "dev/example", tmp_path)),
|
|
1922
|
+
)
|
|
1923
|
+
|
|
1924
|
+
assert result.ok is True
|
|
1925
|
+
assert _stash_oids(tmp_path) == stale_stashes
|
|
1926
|
+
assert json.loads(manifest.read_text(encoding="utf-8"))["version"] == "current"
|
|
1927
|
+
assert (tmp_path / "feature.txt").read_text(encoding="utf-8") == "done\n"
|
|
1928
|
+
|
|
1929
|
+
|
|
1930
|
+
def test_branch_merge_rejects_dirty_task_checkout_without_touching_stashes(tmp_path):
|
|
1931
|
+
from prizmkit_runtime.gitops import BranchContext, branch_merge_plan, run_git_plan
|
|
1932
|
+
|
|
1933
|
+
_init_merge_repo(tmp_path)
|
|
1934
|
+
manifest = tmp_path / ".prizmkit" / "manifest.json"
|
|
1935
|
+
manifest.write_text('{"version":"stale"}\n', encoding="utf-8")
|
|
1936
|
+
subprocess.run(["git", "stash", "push", "-m", "user-stash", "--", ".prizmkit/manifest.json"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
1937
|
+
stale_stashes = _stash_oids(tmp_path)
|
|
1938
|
+
subprocess.run(["git", "checkout", "-b", "dev/example"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
1939
|
+
(tmp_path / "feature.txt").write_text("done\n", encoding="utf-8")
|
|
1940
|
+
subprocess.run(["git", "add", "feature.txt"], cwd=tmp_path, check=True)
|
|
1941
|
+
subprocess.run(["git", "commit", "-m", "feature"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
1942
|
+
(tmp_path / "app.txt").write_text("local visible change\n", encoding="utf-8")
|
|
1943
|
+
|
|
1944
|
+
result = run_git_plan(
|
|
1945
|
+
tmp_path,
|
|
1946
|
+
branch_merge_plan(BranchContext("main", "dev/example", tmp_path)),
|
|
1947
|
+
)
|
|
1948
|
+
|
|
1949
|
+
assert result.ok is False
|
|
1950
|
+
assert _stash_oids(tmp_path) == stale_stashes
|
|
1951
|
+
assert (tmp_path / "app.txt").read_text(encoding="utf-8") == "local visible change\n"
|
|
1952
|
+
assert json.loads(manifest.read_text(encoding="utf-8"))["version"] == "current"
|
|
1953
|
+
assert subprocess.run(
|
|
1954
|
+
["git", "branch", "--show-current"],
|
|
1955
|
+
cwd=tmp_path,
|
|
1956
|
+
check=True,
|
|
1957
|
+
stdout=subprocess.PIPE,
|
|
1958
|
+
text=True,
|
|
1959
|
+
).stdout.strip() == "dev/example"
|
|
1960
|
+
|
|
1961
|
+
|
|
1962
|
+
def test_branch_merge_rebases_committed_task_without_stash_restore_conflict(tmp_path):
|
|
1963
|
+
from prizmkit_runtime.gitops import BranchContext, branch_merge_plan, run_git_plan
|
|
1964
|
+
|
|
1965
|
+
_init_merge_repo(tmp_path)
|
|
1966
|
+
subprocess.run(["git", "checkout", "-b", "dev/example"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
1967
|
+
(tmp_path / "feature.txt").write_text("done\n", encoding="utf-8")
|
|
1968
|
+
subprocess.run(["git", "add", "feature.txt"], cwd=tmp_path, check=True)
|
|
1969
|
+
subprocess.run(["git", "commit", "-m", "feature"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
1970
|
+
subprocess.run(["git", "checkout", "main"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
1971
|
+
(tmp_path / "app.txt").write_text("main changed\n", encoding="utf-8")
|
|
1972
|
+
subprocess.run(["git", "commit", "-am", "advance main"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
1973
|
+
subprocess.run(["git", "checkout", "dev/example"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
1974
|
+
|
|
1975
|
+
result = run_git_plan(
|
|
1976
|
+
tmp_path,
|
|
1977
|
+
branch_merge_plan(BranchContext("main", "dev/example", tmp_path)),
|
|
1978
|
+
)
|
|
1979
|
+
|
|
1980
|
+
assert result.ok is True
|
|
1981
|
+
assert _stash_oids(tmp_path) == ()
|
|
1982
|
+
assert (tmp_path / "app.txt").read_text(encoding="utf-8") == "main changed\n"
|
|
1983
|
+
assert subprocess.run(
|
|
1984
|
+
["git", "branch", "--show-current"],
|
|
1985
|
+
cwd=tmp_path,
|
|
1986
|
+
check=True,
|
|
1987
|
+
stdout=subprocess.PIPE,
|
|
1988
|
+
text=True,
|
|
1989
|
+
).stdout.strip() == "main"
|
|
1990
|
+
|
|
1991
|
+
|
|
1992
|
+
def test_branch_return_commits_wip_without_touching_user_stashes(tmp_path):
|
|
1993
|
+
from prizmkit_runtime.gitops import branch_ensure_return
|
|
1994
|
+
|
|
1995
|
+
_init_merge_repo(tmp_path)
|
|
1996
|
+
manifest = tmp_path / ".prizmkit" / "manifest.json"
|
|
1997
|
+
manifest.write_text('{"version":"stale"}\n', encoding="utf-8")
|
|
1998
|
+
subprocess.run(["git", "stash", "push", "-m", "user-stash", "--", ".prizmkit/manifest.json"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
1999
|
+
user_stashes = _stash_oids(tmp_path)
|
|
2000
|
+
subprocess.run(["git", "checkout", "-b", "dev/interrupted"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
2001
|
+
(tmp_path / "app.txt").write_text("interrupted work\n", encoding="utf-8")
|
|
2002
|
+
|
|
2003
|
+
result = branch_ensure_return(tmp_path, "main", "dev/interrupted")
|
|
2004
|
+
|
|
2005
|
+
assert result.ok is True
|
|
2006
|
+
assert _stash_oids(tmp_path) == user_stashes
|
|
2007
|
+
assert subprocess.run(
|
|
2008
|
+
["git", "branch", "--show-current"], cwd=tmp_path, check=True, stdout=subprocess.PIPE, text=True,
|
|
2009
|
+
).stdout.strip() == "main"
|
|
2010
|
+
assert subprocess.run(
|
|
2011
|
+
["git", "show", "dev/interrupted:app.txt"], cwd=tmp_path, check=True, stdout=subprocess.PIPE, text=True,
|
|
2012
|
+
).stdout == "interrupted work\n"
|
|
2013
|
+
|
|
2014
|
+
|
|
2015
|
+
def test_branch_return_commit_failure_does_not_checkout_base(monkeypatch, tmp_path):
|
|
2016
|
+
from prizmkit_runtime import gitops
|
|
2017
|
+
|
|
2018
|
+
calls = []
|
|
2019
|
+
|
|
2020
|
+
def fake_run(_root, args):
|
|
2021
|
+
args = tuple(args)
|
|
2022
|
+
calls.append(args)
|
|
2023
|
+
if args[:3] == ("rev-parse", "--abbrev-ref", "HEAD"):
|
|
2024
|
+
return gitops.GitCommandResult(args, 0, "dev/interrupted\n", "")
|
|
2025
|
+
if args and args[0] == "commit":
|
|
2026
|
+
return gitops.GitCommandResult(args, 1, "", "commit failed")
|
|
2027
|
+
if args[:2] == ("status", "--porcelain"):
|
|
2028
|
+
return gitops.GitCommandResult(args, 0, " M app.txt\n", "")
|
|
2029
|
+
return gitops.GitCommandResult(args, 0, "", "")
|
|
2030
|
+
|
|
2031
|
+
monkeypatch.setattr(gitops, "run_git_command", fake_run)
|
|
2032
|
+
|
|
2033
|
+
result = gitops.branch_ensure_return(tmp_path, "main", "dev/interrupted")
|
|
2034
|
+
|
|
2035
|
+
assert result.ok is False
|
|
2036
|
+
assert not any(args[:2] == ("checkout", "main") for args in calls)
|
|
2037
|
+
assert not any(args and args[0] == "stash" for args in calls)
|
|
2038
|
+
|
|
2039
|
+
|
|
2040
|
+
def test_non_current_reset_preserves_dirty_workspace_and_user_stashes(tmp_path):
|
|
2041
|
+
from prizmkit_runtime.gitops import reset_cleanup_branch
|
|
2042
|
+
|
|
2043
|
+
_init_merge_repo(tmp_path)
|
|
2044
|
+
subprocess.run(["git", "branch", "dev/other"], cwd=tmp_path, check=True)
|
|
2045
|
+
manifest = tmp_path / ".prizmkit" / "manifest.json"
|
|
2046
|
+
manifest.write_text('{"version":"stale"}\n', encoding="utf-8")
|
|
2047
|
+
subprocess.run(["git", "stash", "push", "-m", "user-stash", "--", ".prizmkit/manifest.json"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
2048
|
+
user_stashes = _stash_oids(tmp_path)
|
|
2049
|
+
(tmp_path / "app.txt").write_text("unstaged\n", encoding="utf-8")
|
|
2050
|
+
(tmp_path / "staged.txt").write_text("staged\n", encoding="utf-8")
|
|
2051
|
+
subprocess.run(["git", "add", "staged.txt"], cwd=tmp_path, check=True)
|
|
2052
|
+
(tmp_path / "untracked.txt").write_text("untracked\n", encoding="utf-8")
|
|
2053
|
+
before = subprocess.run(["git", "status", "--porcelain"], cwd=tmp_path, check=True, stdout=subprocess.PIPE, text=True).stdout
|
|
2054
|
+
|
|
2055
|
+
reset_result = reset_cleanup_branch(tmp_path, "dev/other", return_branch="main", delete=False)
|
|
2056
|
+
|
|
2057
|
+
assert reset_result.branch_preserved is True
|
|
2058
|
+
assert reset_result.checkout_discarded is False
|
|
2059
|
+
assert subprocess.run(["git", "branch", "--show-current"], cwd=tmp_path, check=True, stdout=subprocess.PIPE, text=True).stdout.strip() == "main"
|
|
2060
|
+
assert subprocess.run(["git", "status", "--porcelain"], cwd=tmp_path, check=True, stdout=subprocess.PIPE, text=True).stdout == before
|
|
2061
|
+
assert _stash_oids(tmp_path) == user_stashes
|
|
2062
|
+
assert subprocess.run(["git", "show-ref", "--verify", "refs/heads/dev/other"], cwd=tmp_path, check=False).returncode == 0
|
|
2063
|
+
|
|
2064
|
+
clean_result = reset_cleanup_branch(tmp_path, "dev/other", return_branch="main", delete=True)
|
|
2065
|
+
|
|
2066
|
+
assert clean_result.deleted is True
|
|
2067
|
+
assert subprocess.run(["git", "status", "--porcelain"], cwd=tmp_path, check=True, stdout=subprocess.PIPE, text=True).stdout == before
|
|
2068
|
+
assert _stash_oids(tmp_path) == user_stashes
|
|
2069
|
+
|
|
2070
|
+
|
|
1870
2071
|
def test_worktree_runtime_context_uses_safe_deterministic_path(tmp_path):
|
|
1871
2072
|
from prizmkit_runtime.gitops import BranchContext, WorktreePolicy, worktree_runtime_context
|
|
1872
2073
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.1.
|
|
2
|
+
"version": "1.1.129",
|
|
3
3
|
"skills": {
|
|
4
4
|
"prizmkit": {
|
|
5
5
|
"description": "Full-lifecycle dev toolkit. Covers spec-driven development, Prizm context docs, code quality, debugging, deployment, and knowledge management.",
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
"hasScripts": false
|
|
31
31
|
},
|
|
32
32
|
"prizmkit-code-review": {
|
|
33
|
-
"description": "
|
|
33
|
+
"description": "Bounded Main-Agent code review with evidence-based finding adjudication, direct repairs, verification, and append-only progress reporting.",
|
|
34
34
|
"tier": "1",
|
|
35
35
|
"category": "prizmkit-skill",
|
|
36
|
-
"hasAssets":
|
|
36
|
+
"hasAssets": false,
|
|
37
37
|
"hasScripts": true
|
|
38
38
|
},
|
|
39
39
|
"prizmkit-committer": {
|
|
@@ -361,8 +361,8 @@ Key requirements:
|
|
|
361
361
|
- descriptions: minimum 15 words (error), recommended minimum 30/50/80/100+ for low/medium/high/critical (warning). No upper limit — more detail prevents AI guessing
|
|
362
362
|
- `estimated_complexity` determines pipeline execution tier:
|
|
363
363
|
- `low` / `medium` → **lite** (single agent, no subagents)
|
|
364
|
-
- `high` → **standard** (
|
|
365
|
-
- `critical` → **full** (strongest
|
|
364
|
+
- `high` → **standard** (Main-Agent review guardrails, 3-agent compatibility metadata)
|
|
365
|
+
- `critical` → **full** (strongest Main-Agent review guardrails). Use for: architectural changes touching 10+ files, cross-module refactoring with API surface changes, or safety/security/data-loss risk
|
|
366
366
|
|
|
367
367
|
**IMPORTANT: Do NOT hand-write the final JSON file.** Instead:
|
|
368
368
|
1. Write a draft JSON to a temporary path (e.g., `.prizmkit/plans/feature-list.draft.json`)
|
|
@@ -110,7 +110,7 @@ PrizmKit supports any development scenario through the same skill chain. `/prizm
|
|
|
110
110
|
| `/prizmkit-plan` | First implementation planning step: run ahead of `/prizmkit-implement` to turn natural language into `spec.md` + `plan.md` with executable tasks. | "specify", "plan", "new task", "architect", "break it down" |
|
|
111
111
|
| `/prizmkit-implement` | Implementation step: use after `/prizmkit-plan` to execute `plan.md` tasks with TDD where applicable, task order, and checkpoints. | "implement", "build", "code it", "start coding" |
|
|
112
112
|
| `/prizmkit-test` | Risk-triggered quality gate: run after implementation when behavior, interfaces, data, security, or deploy risk requires tests and boundary coverage. | "test", "run tests", "verify", "quality check", "boundary tests" |
|
|
113
|
-
| `/prizmkit-code-review` | Full path quality gate:
|
|
113
|
+
| `/prizmkit-code-review` | Full path quality gate: the current Main Agent reviews and repairs the complete change in the active checkout without direct or indirect review delegation. | "review", "check code", "code review", "is it ready to commit" |
|
|
114
114
|
| `/prizmkit-retrospective` | Docs maintenance step: run after review/implementation when structure, interfaces, dependencies, behavior, or durable knowledge changed. | "retrospective", "retro", "update docs", "sync docs", "wrap up" |
|
|
115
115
|
| `/prizmkit-committer` | Final lifecycle commit step: use after required gates are satisfied; safely stages and creates a Conventional Commit without changing changelog by default. | "commit", "submit", "finish", "done" |
|
|
116
116
|
| `/prizmkit-prizm-docs` | Documentation system entry point: use for init/status/rebuild/validate/migrate or out-of-band repair, not normal development sync. | "initialize docs", "check docs", "rebuild docs", "validate docs", "docs drifted" |
|
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "prizmkit-code-review"
|
|
3
|
-
description: "
|
|
3
|
+
description: "Review the complete current change in a bounded Main-Agent loop. Adjudicate findings with evidence, directly repair accepted findings, verify repairs, and append progress until the review converges to PASS or stops with unresolved findings as NEEDS_FIXES. (project)"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# PrizmKit Code Review
|
|
7
7
|
|
|
8
|
-
Use
|
|
8
|
+
Use one Main-Agent review loop. The current Main Agent is the only Code Review executor: it performs the complete review, filters candidate findings, repairs accepted findings, verifies the repairs, and decides the final result.
|
|
9
|
+
|
|
10
|
+
## Execution Boundary
|
|
11
|
+
|
|
12
|
+
- Do not delegate any part of Code Review directly or indirectly.
|
|
13
|
+
- Do not invoke another review skill or review workflow from inside this skill.
|
|
14
|
+
- Do not launch review work through a general-purpose execution unit or relabel it as a finder, verifier, audit, compatibility review, verification, or gap sweep.
|
|
15
|
+
- These restrictions apply for the entire review phase, including candidate discovery, evidence checks, repair verification, and final gap analysis.
|
|
16
|
+
- The Main Agent may directly use non-delegating read, search, edit, and test capabilities in the active workspace.
|
|
17
|
+
- `{artifact_dir}/review-report.md` is the only persisted review artifact. Do not append separate Review Notes to `context-snapshot.md`.
|
|
9
18
|
|
|
10
19
|
## When to Use
|
|
11
20
|
|
|
12
21
|
- After `/prizmkit-implement` as the Full path quality gate
|
|
13
|
-
- For Fast path when behavior,
|
|
22
|
+
- For Fast path when behavior, impact, or the user warrants review
|
|
14
23
|
- When the user asks to validate implementation, find defects, assess regressions, or decide commit readiness
|
|
15
24
|
|
|
16
25
|
## Input
|
|
@@ -19,167 +28,101 @@ Use a dual-layer review loop: the Main Agent owns iterative review and repair, w
|
|
|
19
28
|
|---|---|---|
|
|
20
29
|
| `artifact_dir` | No | Directory containing `spec.md` and `plan.md`. Reuse a caller-provided directory; otherwise locate the current completed change artifact. |
|
|
21
30
|
|
|
22
|
-
## Required
|
|
31
|
+
## Required Asset
|
|
23
32
|
|
|
24
|
-
- `${SKILL_DIR}/references/reviewer-agent-prompt.md`: independent Reviewer input and output contract
|
|
25
33
|
- `${SKILL_DIR}/references/review-report-template.md`: report lifecycle and append contract
|
|
26
|
-
- `${SKILL_DIR}/assets/reviewer-role.json`: semantic read-only and non-delegating Reviewer boundary
|
|
27
|
-
|
|
28
|
-
Do not weaken or summarize the Reviewer prompt. The protocol specifies semantic capabilities rather than platform-specific tool names.
|
|
29
34
|
|
|
30
35
|
## Phase 0: Initialize Report and Collect Context
|
|
31
36
|
|
|
32
37
|
1. Resolve `{artifact_dir}` and `{artifact_dir}/review-report.md`.
|
|
33
|
-
2. replace any prior report with a new execution header using the report template. The new report begins with `## Status: IN_PROGRESS` and contains no prior Final Result.
|
|
38
|
+
2. At the start of every execution, replace any prior report with a new execution header using the report template. The new report begins with `## Status: IN_PROGRESS` and contains no prior Final Result.
|
|
34
39
|
3. Read `spec.md`, `plan.md`, relevant `/prizmkit-test` evidence, `.prizmkit/prizm-docs/root.prizm`, applicable progressive docs, and project rules.
|
|
35
|
-
4. Inspect
|
|
40
|
+
4. Inspect the complete current Git change:
|
|
36
41
|
- staged and unstaged tracked changes;
|
|
37
42
|
- untracked files;
|
|
38
43
|
- deleted and renamed files;
|
|
39
44
|
- relevant unchanged callers, dependents, contracts, and tests.
|
|
40
|
-
5.
|
|
41
|
-
6. If no changes exist, append
|
|
42
|
-
|
|
43
|
-
### Checkout Access
|
|
44
|
-
|
|
45
|
-
Prefer direct access to the active checkout. If the platform forces an isolated worktree, provide the same staged and unstaged diffs, untracked file contents, and changed-path states; use the worktree only for baseline and surrounding-context reads. Do not require workspace-equivalence proof.
|
|
46
|
-
|
|
47
|
-
## Phase 1: Semantic Risk Assessment
|
|
48
|
-
|
|
49
|
-
Classify the current change from behavior and failure impact, not changed-file count or a fixed path allowlist:
|
|
50
|
-
|
|
51
|
-
- `low: 0` independent Reviewers — documentation, test text, mechanical change, local low-impact configuration, or trivially verifiable behavior.
|
|
52
|
-
- `medium: 1` independent Reviewer — general business behavior, internal interface changes, or non-critical data processing with user-visible regression potential.
|
|
53
|
-
- `high: 2` independent Reviewers maximum — payments, financial ledgers, authentication, authorization, security, migration, concurrent transactions, irreversible data operations, or public contracts.
|
|
54
|
-
|
|
55
|
-
Mixed risks use the highest applicable level. A large mechanical diff is not automatically high; a small money or authorization change is high.
|
|
45
|
+
5. Review in the active workspace so dirty and untracked content is authoritative.
|
|
46
|
+
6. If no changes exist, append final verification and exactly one final result with `PASS`, then finish.
|
|
56
47
|
|
|
57
|
-
|
|
48
|
+
## Phase 1: Main-Agent Review Loop
|
|
58
49
|
|
|
59
|
-
|
|
50
|
+
The Main Agent reviews and repairs in the current context. The fixed limit is ten completed review rounds.
|
|
60
51
|
|
|
61
|
-
|
|
52
|
+
Track cumulative counts:
|
|
62
53
|
|
|
63
54
|
```yaml
|
|
64
55
|
main_review_rounds: 0
|
|
65
|
-
|
|
66
|
-
|
|
56
|
+
accepted_findings: 0
|
|
57
|
+
fixed_findings: 0
|
|
58
|
+
rejected_findings: 0
|
|
59
|
+
unresolved_findings: 0
|
|
67
60
|
```
|
|
68
61
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
### Main-Agent Self-Review Loop
|
|
62
|
+
### Review One Round
|
|
72
63
|
|
|
73
64
|
Each round examines the complete current change against goals, contracts, rules, callers, dependents, regression risks, and test evidence.
|
|
74
65
|
|
|
75
|
-
1. Identify concrete candidate findings.
|
|
76
|
-
2. Classify each as:
|
|
77
|
-
- `accepted`: evidence supports the failure scenario;
|
|
78
|
-
- `rejected`: code or governing evidence disproves
|
|
79
|
-
|
|
80
|
-
|
|
66
|
+
1. Identify concrete candidate findings. A finding must describe a reproducible failure scenario, affected behavior, and supporting evidence.
|
|
67
|
+
2. Classify each candidate as exactly one of:
|
|
68
|
+
- `accepted`: concrete evidence supports the failure scenario and an in-scope repair is required;
|
|
69
|
+
- `rejected`: code, tests, contracts, or governing evidence disproves the failure scenario;
|
|
70
|
+
- `unresolved`: correctness cannot be established or repaired safely with the available evidence or environment.
|
|
71
|
+
3. Treat Missing tools, permissions, environment, or required evidence as an unresolved finding when they prevent required verification. Do not treat missing evidence as success.
|
|
72
|
+
4. Append `## Main Review Round N` with findings, accepted, rejected, unresolved, and the next action.
|
|
73
|
+
5. Apply these rules:
|
|
81
74
|
|
|
82
75
|
```text
|
|
83
|
-
accepted = 0
|
|
84
|
-
accepted > 0 and round < 10
|
|
85
|
-
accepted > 0 at ten completed
|
|
86
|
-
|
|
87
|
-
|
|
76
|
+
accepted = 0 and unresolved = 0 -> review converged
|
|
77
|
+
accepted > 0 and round < 10 -> Main Agent directly repairs, verifies, and continues
|
|
78
|
+
accepted > 0 at ten completed review rounds -> NEEDS_FIXES
|
|
79
|
+
unresolved > 0 -> NEEDS_FIXES
|
|
80
|
+
repair cannot be completed safely -> unresolved finding -> NEEDS_FIXES
|
|
81
|
+
required verification fails or cannot be performed -> unresolved finding -> NEEDS_FIXES
|
|
88
82
|
```
|
|
89
83
|
|
|
90
|
-
When all findings are rejected, `accepted = 0` and
|
|
91
|
-
|
|
92
|
-
After each repair batch, append `## Repair Verification` with fixed findings, verification evidence, and next phase.
|
|
93
|
-
|
|
94
|
-
## Phase 3: Independent Reviewer 1
|
|
95
|
-
|
|
96
|
-
After Main-Agent self-review and required tests converge:
|
|
84
|
+
When all candidate findings are rejected, `accepted = 0` and `unresolved = 0`, so the review converges. Rejected findings do not cause another round.
|
|
97
85
|
|
|
98
|
-
|
|
99
|
-
- medium or high risk: launch Reviewer 1.
|
|
86
|
+
## Phase 2: Repair and Verification
|
|
100
87
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
```markdown
|
|
104
|
-
## Independent Reviewer 1
|
|
105
|
-
|
|
106
|
-
- Status: RUNNING
|
|
107
|
-
- Risk Trigger: <medium|high>
|
|
108
|
-
```
|
|
88
|
+
When a round has accepted findings and fewer than ten rounds have completed:
|
|
109
89
|
|
|
110
|
-
|
|
90
|
+
1. Main Agent directly repairs every accepted in-scope finding in the active workspace.
|
|
91
|
+
2. Run targeted tests, static checks, or other verification appropriate to each repaired behavior.
|
|
92
|
+
3. Inspect resulting changes and ensure the repair did not introduce a new regression.
|
|
93
|
+
4. Append `## Repair Verification` with fixed findings, verification evidence, and the next round.
|
|
94
|
+
5. Start the next complete review round.
|
|
111
95
|
|
|
112
|
-
|
|
96
|
+
If a repair is unsafe, incomplete, or cannot receive required verification, record the affected finding as unresolved and finish with `NEEDS_FIXES`.
|
|
113
97
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
1. append the observable failure;
|
|
117
|
-
2. count the failed launch attempt against the semantic-risk Reviewer limit;
|
|
118
|
-
3. allow at most one infrastructure retry at this same Reviewer position only when the risk limit still has an unused launch;
|
|
119
|
-
4. append a new RUNNING retry section before retrying and increment the Reviewer launch counter;
|
|
120
|
-
5. if the retry fails or the risk limit is exhausted, append Final Result `BLOCKED` and stop;
|
|
121
|
-
6. do not convert infrastructure failure into a code finding;
|
|
122
|
-
7. Do not substitute Main-Agent self-review for a required independent result.
|
|
123
|
-
|
|
124
|
-
### Finding Adjudication
|
|
125
|
-
|
|
126
|
-
For a usable Reviewer result, append `## Independent Reviewer 1 Result`, then classify every finding as accepted or rejected with evidence.
|
|
127
|
-
|
|
128
|
-
```text
|
|
129
|
-
accepted = 0 -> Reviewer 1 converged
|
|
130
|
-
accepted > 0 -> Main Agent repairs, verifies, and reruns its self-review loop
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
Accepted findings do not automatically trigger another independent Reviewer.
|
|
134
|
-
|
|
135
|
-
## Phase 4: Reviewer 2 Eligibility
|
|
136
|
-
|
|
137
|
-
Reviewer 2 is allowed only when every condition is true:
|
|
138
|
-
|
|
139
|
-
- risk is `high`;
|
|
140
|
-
- Reviewer 1 contained at least one accepted high-severity finding;
|
|
141
|
-
- all accepted high findings were repaired;
|
|
142
|
-
- targeted verification passed;
|
|
143
|
-
- Main-Agent self-review reconverged.
|
|
144
|
-
|
|
145
|
-
Accepted medium or low findings alone never trigger Reviewer 2. Medium risk never starts Reviewer 2.
|
|
146
|
-
|
|
147
|
-
When eligible, append a RUNNING section and launch one fresh Reviewer 2 with the unchanged complete-review prompt and current change input.
|
|
148
|
-
|
|
149
|
-
After Reviewer 2:
|
|
150
|
-
|
|
151
|
-
- accepted = 0: proceed to final verification;
|
|
152
|
-
- accepted > 0: Main Agent repairs, verifies, and runs its final self-review loop;
|
|
153
|
-
- unresolved repair: `NEEDS_FIXES`;
|
|
154
|
-
- Do not launch Reviewer 3 under any condition.
|
|
155
|
-
|
|
156
|
-
## Phase 5: Append-Only Reporting
|
|
98
|
+
## Phase 3: Append-Only Reporting
|
|
157
99
|
|
|
158
100
|
`{artifact_dir}/review-report.md` is the only required persisted review artifact.
|
|
159
101
|
|
|
160
102
|
Within one execution, append new sections only. Do not rewrite an earlier progress section. Append after:
|
|
161
103
|
|
|
162
|
-
- risk assessment;
|
|
163
104
|
- every Main-Agent review round;
|
|
164
105
|
- every repair and verification batch;
|
|
165
|
-
-
|
|
166
|
-
-
|
|
167
|
-
|
|
168
|
-
|
|
106
|
+
- final verification;
|
|
107
|
+
- the final result.
|
|
108
|
+
|
|
109
|
+
An interrupted execution remains `IN_PROGRESS` and shows its latest completed phase. It has no terminal verdict.
|
|
169
110
|
|
|
170
|
-
|
|
111
|
+
## Phase 4: Final Verification and Result
|
|
171
112
|
|
|
172
|
-
|
|
113
|
+
Before completing:
|
|
173
114
|
|
|
174
|
-
|
|
115
|
+
1. Confirm the final workspace still represents the complete reviewed change.
|
|
116
|
+
2. Confirm required tests and checks have credible evidence.
|
|
117
|
+
3. Confirm no accepted or unresolved finding remains for `PASS`.
|
|
118
|
+
4. Append `## Final Verification`.
|
|
119
|
+
5. Append exactly one final result:
|
|
175
120
|
|
|
176
121
|
```markdown
|
|
177
122
|
## Final Result
|
|
178
123
|
|
|
179
|
-
- Verdict: PASS | NEEDS_FIXES
|
|
180
|
-
- Risk: low | medium | high
|
|
124
|
+
- Verdict: PASS | NEEDS_FIXES
|
|
181
125
|
- Main Review Rounds: <count>
|
|
182
|
-
- Independent Reviewers Started: <count>
|
|
183
126
|
- Accepted Findings: <count>
|
|
184
127
|
- Fixed Findings: <count>
|
|
185
128
|
- Rejected Findings: <count>
|
|
@@ -189,9 +132,8 @@ Append exactly one final result:
|
|
|
189
132
|
|
|
190
133
|
Final outcomes:
|
|
191
134
|
|
|
192
|
-
- `PASS`:
|
|
193
|
-
- `NEEDS_FIXES`:
|
|
194
|
-
- `BLOCKED`: a required independent Reviewer position failed and either its one permitted retry failed or the semantic-risk launch limit left no retry capacity; essential independent-review context is unavailable.
|
|
135
|
+
- `PASS`: review converged with `accepted = 0`, `unresolved = 0`, and required verification evidence is complete.
|
|
136
|
+
- `NEEDS_FIXES`: round ten still has accepted findings, any finding remains unresolved, a repair cannot be completed safely, or required verification is unavailable or failed.
|
|
195
137
|
|
|
196
138
|
Exactly one final result is allowed. Do not append progress after Final Result.
|
|
197
139
|
|
|
@@ -199,4 +141,3 @@ Completion handoff:
|
|
|
199
141
|
|
|
200
142
|
- `PASS`: run `/prizmkit-retrospective` when structural docs or durable knowledge changed; otherwise proceed to `/prizmkit-committer`.
|
|
201
143
|
- `NEEDS_FIXES`: report unresolved findings and stop.
|
|
202
|
-
- `BLOCKED`: report infrastructure evidence and permit recovery.
|