prizmkit 1.1.154 → 1.1.156
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/codex/skill-adapter.js +1 -1
- package/bundled/adapters/pi/skill-adapter.js +2 -1
- package/bundled/dev-pipeline/.env.example +2 -6
- package/bundled/dev-pipeline/README.md +21 -27
- package/bundled/dev-pipeline/prizmkit_runtime/checkpoint_state.py +341 -15
- package/bundled/dev-pipeline/prizmkit_runtime/cli.py +0 -3
- package/bundled/dev-pipeline/prizmkit_runtime/daemon.py +1 -15
- package/bundled/dev-pipeline/prizmkit_runtime/gitops.py +48 -14
- package/bundled/dev-pipeline/prizmkit_runtime/runner_classification.py +50 -2
- package/bundled/dev-pipeline/prizmkit_runtime/runner_models.py +0 -9
- package/bundled/dev-pipeline/prizmkit_runtime/runner_prompts.py +3 -3
- package/bundled/dev-pipeline/prizmkit_runtime/runners.py +120 -22
- package/bundled/dev-pipeline/prizmkit_runtime/runtime_commit.py +482 -0
- package/bundled/dev-pipeline/prizmkit_runtime/test_result.py +64 -11
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +145 -367
- package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +91 -62
- package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +105 -69
- package/bundled/dev-pipeline/scripts/prompt_framework.py +36 -41
- package/bundled/dev-pipeline/scripts/update-bug-status.py +1 -4
- package/bundled/dev-pipeline/scripts/update-checkpoint.py +61 -13
- package/bundled/dev-pipeline/scripts/update-feature-status.py +1 -4
- package/bundled/dev-pipeline/scripts/update-refactor-status.py +1 -4
- package/bundled/dev-pipeline/templates/bootstrap-prompt.md +22 -27
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +71 -104
- package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +59 -111
- package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +37 -72
- package/bundled/dev-pipeline/templates/sections/artifact-manifest.md +39 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-critical-paths.md +3 -1
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-commit-report.md +8 -25
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-diagnose-plan.md +3 -3
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-implement.md +2 -2
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-review.md +3 -3
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-test.md +2 -2
- package/bundled/dev-pipeline/templates/sections/bugfix-reminders.md +4 -4
- package/bundled/dev-pipeline/templates/sections/bugfix-session-context.md +0 -1
- package/bundled/dev-pipeline/templates/sections/checkpoint-system.md +7 -4
- package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +14 -27
- package/bundled/dev-pipeline/templates/sections/feature-completion-summary.md +20 -0
- package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +8 -71
- package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +7 -7
- package/bundled/dev-pipeline/templates/sections/phase-prizmkit-test.md +3 -3
- package/bundled/dev-pipeline/templates/sections/phase-review-full.md +4 -4
- package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +5 -17
- package/bundled/dev-pipeline/templates/sections/refactor-critical-paths.md +3 -1
- package/bundled/dev-pipeline/templates/sections/refactor-phase-commit-report.md +10 -23
- package/bundled/dev-pipeline/templates/sections/refactor-phase-implement.md +2 -2
- package/bundled/dev-pipeline/templates/sections/refactor-phase-plan.md +2 -2
- package/bundled/dev-pipeline/templates/sections/refactor-phase-review.md +3 -3
- package/bundled/dev-pipeline/templates/sections/refactor-phase-test.md +2 -2
- package/bundled/dev-pipeline/templates/sections/refactor-reminders.md +7 -7
- package/bundled/dev-pipeline/templates/sections/refactor-session-context.md +0 -1
- package/bundled/dev-pipeline/templates/sections/retrospective.md +12 -0
- package/bundled/dev-pipeline/templates/sections/runtime-commit-handoff.md +35 -0
- package/bundled/dev-pipeline/templates/session-status-schema.json +45 -62
- package/bundled/dev-pipeline/tests/test_checkpoint_state.py +469 -18
- package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +262 -175
- package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +62 -23
- package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +76 -28
- package/bundled/dev-pipeline/tests/test_python_runner_parity.py +168 -18
- package/bundled/dev-pipeline/tests/test_recovery_workflow.py +111 -0
- package/bundled/dev-pipeline/tests/test_reset_preserve.py +0 -2
- package/bundled/dev-pipeline/tests/test_runtime_commit.py +608 -0
- package/bundled/dev-pipeline/tests/test_unified_cli.py +167 -25
- package/bundled/skills/_metadata.json +9 -9
- package/bundled/skills/app-planner/SKILL.md +3 -3
- package/bundled/skills/app-planner/references/generated-plan-review.md +2 -1
- package/bundled/skills/app-planner/references/rules/backend/derivation-rules.md +56 -64
- package/bundled/skills/app-planner/references/rules/backend/fixed-rules.md +85 -240
- package/bundled/skills/app-planner/references/rules/backend/question-bank.md +25 -25
- package/bundled/skills/app-planner/references/rules/backend/question-manifest.json +16 -7
- package/bundled/skills/app-planner/references/rules/backend/template.md +74 -92
- package/bundled/skills/app-planner/references/rules/database/derivation-rules.md +93 -93
- package/bundled/skills/app-planner/references/rules/database/fixed-rules.md +66 -173
- package/bundled/skills/app-planner/references/rules/database/question-bank.md +31 -26
- package/bundled/skills/app-planner/references/rules/database/question-manifest.json +13 -4
- package/bundled/skills/app-planner/references/rules/database/template.md +76 -98
- package/bundled/skills/app-planner/references/rules/frontend/derivation-rules.md +68 -95
- package/bundled/skills/app-planner/references/rules/frontend/fixed-rules.md +93 -166
- package/bundled/skills/app-planner/references/rules/frontend/question-bank.md +46 -36
- package/bundled/skills/app-planner/references/rules/frontend/question-manifest.json +11 -2
- package/bundled/skills/app-planner/references/rules/frontend/template.md +79 -257
- package/bundled/skills/app-planner/references/rules/mobile/derivation-rules.md +91 -99
- package/bundled/skills/app-planner/references/rules/mobile/fixed-rules.md +73 -246
- package/bundled/skills/app-planner/references/rules/mobile/question-bank.md +17 -17
- package/bundled/skills/app-planner/references/rules/mobile/question-manifest.json +17 -2
- package/bundled/skills/app-planner/references/rules/mobile/template.md +73 -85
- package/bundled/skills/app-planner/references/rules-configuration.md +133 -65
- package/bundled/skills/app-planner/scripts/validate-rules-configuration.py +291 -0
- package/bundled/skills/prizmkit/SKILL.md +17 -18
- package/bundled/skills/prizmkit/references/workflow-state-protocol.md +22 -18
- package/bundled/skills/prizmkit-code-review/SKILL.md +22 -58
- package/bundled/skills/prizmkit-code-review/references/independent-code-review.md +6 -6
- package/bundled/skills/prizmkit-code-review/references/review-report-template.md +2 -2
- package/bundled/skills/prizmkit-committer/SKILL.md +82 -132
- package/bundled/skills/prizmkit-deploy/SKILL.md +27 -11
- package/bundled/skills/prizmkit-deploy/assets/deploy-document-template.md +89 -0
- package/bundled/skills/prizmkit-deploy/references/ci-cd-workflows.md +44 -14
- package/bundled/skills/prizmkit-deploy/references/cloud-platform-deploy.md +19 -3
- package/bundled/skills/prizmkit-deploy/references/database-setup.md +22 -12
- package/bundled/skills/prizmkit-deploy/references/deploy-config-schema.md +3 -1
- package/bundled/skills/prizmkit-deploy/references/deploy-history-schema.md +22 -6
- package/bundled/skills/prizmkit-deploy/references/deploy-metadata-schema.json +49 -0
- package/bundled/skills/prizmkit-deploy/references/live-validation-notes.md +1 -1
- package/bundled/skills/prizmkit-deploy/references/pending-input-schema.json +164 -0
- package/bundled/skills/prizmkit-deploy/references/ssh-adapter-flow.md +9 -8
- package/bundled/skills/prizmkit-deploy/references/ssh-execution-flow.md +6 -6
- package/bundled/skills/prizmkit-implement/SKILL.md +30 -66
- package/bundled/skills/prizmkit-implement/references/implementation-subagent-procedure.md +4 -4
- package/bundled/skills/prizmkit-init/SKILL.md +4 -0
- package/bundled/skills/prizmkit-plan/SKILL.md +21 -64
- package/bundled/skills/prizmkit-plan/references/artifact-identity.md +38 -0
- package/bundled/skills/prizmkit-plan/references/independent-plan-review.md +4 -4
- package/bundled/skills/prizmkit-plan/references/review-plan-spec-loop.md +5 -5
- package/bundled/skills/prizmkit-prizm-docs/SKILL.md +75 -11
- package/bundled/skills/prizmkit-prizm-docs/assets/prizm-docs-format.md +191 -56
- package/bundled/skills/prizmkit-prizm-docs/references/op-init.md +18 -18
- package/bundled/skills/prizmkit-prizm-docs/references/op-rebuild.md +14 -8
- package/bundled/skills/prizmkit-prizm-docs/references/op-status.md +12 -5
- package/bundled/skills/prizmkit-prizm-docs/references/op-update.md +23 -12
- package/bundled/skills/prizmkit-prizm-docs/references/op-validate.md +13 -9
- package/bundled/skills/prizmkit-retrospective/SKILL.md +94 -97
- package/bundled/skills/prizmkit-retrospective/references/knowledge-injection-steps.md +79 -37
- package/bundled/skills/prizmkit-retrospective/references/retrospective-result-schema.json +138 -0
- package/bundled/skills/prizmkit-retrospective/references/structural-sync-steps.md +111 -54
- package/bundled/skills/prizmkit-test/SKILL.md +64 -51
- package/bundled/skills/prizmkit-test/references/boundary-contract-and-test-double-guidance.md +206 -0
- package/bundled/skills/prizmkit-test/references/independent-test-review.md +17 -9
- package/bundled/skills/prizmkit-test/references/test-coverage-model.md +45 -21
- package/bundled/skills/prizmkit-test/references/test-report-template.md +20 -13
- package/bundled/skills/prizmkit-workflow/SKILL.md +35 -37
- package/bundled/skills/prizmkit-workflow/references/artifact-identity.md +34 -0
- package/bundled/skills/prizmkit-workflow/references/workflow-state-protocol.md +22 -18
- package/bundled/skills/recovery-workflow/SKILL.md +2 -1
- package/bundled/skills/recovery-workflow/references/detection.md +4 -3
- package/bundled/skills/recovery-workflow/scripts/detect-recovery-state.py +15 -5
- package/bundled/templates/hooks/validate-prizm-docs.py +124 -12
- package/package.json +1 -1
- package/src/scaffold.js +33 -22
- package/bundled/dev-pipeline/templates/sections/bugfix-artifacts.md +0 -16
- package/bundled/dev-pipeline/templates/sections/bugfix-session-status.md +0 -31
- package/bundled/dev-pipeline/templates/sections/critical-paths-agent.md +0 -7
- package/bundled/dev-pipeline/templates/sections/critical-paths-lite.md +0 -7
- package/bundled/dev-pipeline/templates/sections/directory-convention-agent.md +0 -9
- package/bundled/dev-pipeline/templates/sections/directory-convention-lite.md +0 -6
- package/bundled/dev-pipeline/templates/sections/headless-commit-authorization.md +0 -15
- package/bundled/dev-pipeline/templates/sections/phase-commit.md +0 -61
- package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-agent-suffix.md +0 -24
- package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-lite-suffix.md +0 -12
- package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +0 -44
- package/bundled/dev-pipeline/templates/sections/phase-implement-lite.md +0 -25
- package/bundled/dev-pipeline/templates/sections/phase-plan-agent.md +0 -20
- package/bundled/dev-pipeline/templates/sections/phase-plan-lite.md +0 -20
- package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +0 -20
- package/bundled/dev-pipeline/templates/sections/refactor-artifacts.md +0 -17
- package/bundled/dev-pipeline/templates/sections/refactor-session-status.md +0 -28
- package/bundled/dev-pipeline/templates/sections/test-failure-recovery-agent.md +0 -52
- package/bundled/dev-pipeline/templates/sections/test-failure-recovery-lite.md +0 -52
- package/bundled/skills/prizmkit-code-review/references/workflow-state-protocol.md +0 -174
- package/bundled/skills/prizmkit-committer/references/workflow-state-protocol.md +0 -174
- package/bundled/skills/prizmkit-implement/references/workflow-state-protocol.md +0 -174
- package/bundled/skills/prizmkit-plan/references/workflow-state-protocol.md +0 -174
- package/bundled/skills/prizmkit-retrospective/references/workflow-state-protocol.md +0 -174
- package/bundled/skills/prizmkit-test/references/external-contract-mock-guidance.md +0 -119
|
@@ -76,6 +76,102 @@ def _write_family_plan(paths, kind, items):
|
|
|
76
76
|
return plan_path
|
|
77
77
|
|
|
78
78
|
|
|
79
|
+
@pytest.mark.parametrize(
|
|
80
|
+
("kind", "item_id", "filename", "list_key", "schema", "item"),
|
|
81
|
+
[
|
|
82
|
+
(
|
|
83
|
+
"feature", "F-001", "feature-list.json", "features",
|
|
84
|
+
"dev-pipeline-feature-list-v1",
|
|
85
|
+
{
|
|
86
|
+
"id": "F-001", "title": "Preview Feature", "description": "Preview only",
|
|
87
|
+
"priority": "high", "dependencies": [],
|
|
88
|
+
"acceptance_criteria": ["Prompt validates"], "status": "pending",
|
|
89
|
+
},
|
|
90
|
+
),
|
|
91
|
+
(
|
|
92
|
+
"bugfix", "B-001", "bug-fix-list.json", "bugs",
|
|
93
|
+
"dev-pipeline-bug-fix-list-v1",
|
|
94
|
+
{
|
|
95
|
+
"id": "B-001", "title": "Preview Bug", "description": "Preview only",
|
|
96
|
+
"severity": "high", "priority": "high", "dependencies": [],
|
|
97
|
+
"error_source": {"type": "user_report", "reproduction_steps": ["preview"]},
|
|
98
|
+
"verification_type": "automated",
|
|
99
|
+
"acceptance_criteria": ["Prompt validates"], "status": "pending",
|
|
100
|
+
},
|
|
101
|
+
),
|
|
102
|
+
(
|
|
103
|
+
"refactor", "R-001", "refactor-list.json", "refactors",
|
|
104
|
+
"dev-pipeline-refactor-list-v1",
|
|
105
|
+
{
|
|
106
|
+
"id": "R-001", "title": "Preview Refactor", "description": "Preview only",
|
|
107
|
+
"scope": {"files": ["src/example.js"], "modules": ["example"]},
|
|
108
|
+
"type": "simplify", "priority": "high", "complexity": "low",
|
|
109
|
+
"behavior_preservation": {"strategy": "test-gate", "existing_tests": True},
|
|
110
|
+
"acceptance_criteria": ["Prompt validates"],
|
|
111
|
+
"dependencies": [], "status": "pending",
|
|
112
|
+
},
|
|
113
|
+
),
|
|
114
|
+
],
|
|
115
|
+
)
|
|
116
|
+
def test_actual_dry_run_is_read_only_and_successful(
|
|
117
|
+
tmp_path, kind, item_id, filename, list_key, schema, item,
|
|
118
|
+
):
|
|
119
|
+
from prizmkit_runtime.paths import resolve_runtime_paths
|
|
120
|
+
from prizmkit_runtime.runners import run_pipeline_command
|
|
121
|
+
|
|
122
|
+
project = tmp_path / kind
|
|
123
|
+
plans = project / ".prizmkit" / "plans"
|
|
124
|
+
plans.mkdir(parents=True)
|
|
125
|
+
plan_path = plans / filename
|
|
126
|
+
plan_path.write_text(
|
|
127
|
+
json.dumps({"$schema": schema, "project_name": "Dry Run", list_key: [item]}),
|
|
128
|
+
encoding="utf-8",
|
|
129
|
+
)
|
|
130
|
+
fake_cli = project / "fake-ai.py"
|
|
131
|
+
fake_cli.write_text(
|
|
132
|
+
"#!/usr/bin/env python3\nfrom pathlib import Path\nPath('AI_WAS_LAUNCHED').write_text('bad')\n",
|
|
133
|
+
encoding="utf-8",
|
|
134
|
+
)
|
|
135
|
+
fake_cli.chmod(0o755)
|
|
136
|
+
(project / ".prizmkit" / "config.json").write_text(
|
|
137
|
+
json.dumps({
|
|
138
|
+
"platform": "pi",
|
|
139
|
+
"ai_cli": str(fake_cli),
|
|
140
|
+
"ai_cli_launch": {"profile": "custom", "prompt_arg": "--prompt"},
|
|
141
|
+
}),
|
|
142
|
+
encoding="utf-8",
|
|
143
|
+
)
|
|
144
|
+
subprocess.run(["git", "init", "-b", "main"], cwd=project, check=True, stdout=subprocess.DEVNULL)
|
|
145
|
+
subprocess.run(["git", "config", "user.name", "Dry Run Test"], cwd=project, check=True)
|
|
146
|
+
subprocess.run(["git", "config", "user.email", "dry-run@example.invalid"], cwd=project, check=True)
|
|
147
|
+
subprocess.run(["git", "add", "."], cwd=project, check=True)
|
|
148
|
+
subprocess.run(["git", "commit", "-m", "initial"], cwd=project, check=True, stdout=subprocess.DEVNULL)
|
|
149
|
+
paths = resolve_runtime_paths(pipeline_root=PIPELINE_ROOT, project_root=project)
|
|
150
|
+
branch_before = subprocess.check_output(["git", "branch", "--show-current"], cwd=project, text=True).strip()
|
|
151
|
+
head_before = subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=project, text=True).strip()
|
|
152
|
+
status_before = subprocess.check_output(["git", "status", "--porcelain=v1", "-uall"], cwd=project, text=True)
|
|
153
|
+
|
|
154
|
+
run_args = (
|
|
155
|
+
(str(plan_path), "--dry-run")
|
|
156
|
+
if kind == "feature"
|
|
157
|
+
else (item_id, str(plan_path), "--dry-run")
|
|
158
|
+
)
|
|
159
|
+
result = run_pipeline_command(kind, "run", run_args, paths)
|
|
160
|
+
|
|
161
|
+
assert result.exit_code == 0
|
|
162
|
+
assert "processed=1 completed=False stopped_reason=dry_run" in result.render()
|
|
163
|
+
assert "last_status: dry_run" in result.render()
|
|
164
|
+
assert json.loads(plan_path.read_text(encoding="utf-8"))[list_key][0]["status"] == "pending"
|
|
165
|
+
assert subprocess.check_output(["git", "branch", "--show-current"], cwd=project, text=True).strip() == branch_before
|
|
166
|
+
assert subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=project, text=True).strip() == head_before
|
|
167
|
+
assert subprocess.check_output(["git", "status", "--porcelain=v1", "-uall"], cwd=project, text=True) == status_before
|
|
168
|
+
assert not (project / "AI_WAS_LAUNCHED").exists()
|
|
169
|
+
assert not (project / ".prizmkit" / "state").exists()
|
|
170
|
+
assert not (project / ".prizmkit" / "specs").exists()
|
|
171
|
+
assert not (project / ".prizmkit" / "bugfix").exists()
|
|
172
|
+
assert not (project / ".prizmkit" / "refactor").exists()
|
|
173
|
+
|
|
174
|
+
|
|
79
175
|
def _get_next_result(kind, paths):
|
|
80
176
|
from prizmkit_runtime.runner_models import family_for, parse_invocation
|
|
81
177
|
from prizmkit_runtime.runner_status import get_next
|
|
@@ -97,22 +193,22 @@ def _write_semantic_completion_checkpoint(project_root, artifact_dir, workflow_t
|
|
|
97
193
|
"feature_state",
|
|
98
194
|
[
|
|
99
195
|
"prizmkit-implement", "prizmkit-code-review", "prizmkit-test",
|
|
100
|
-
"
|
|
196
|
+
"completion-summary", "prizmkit-retrospective", "prizmkit-committer",
|
|
101
197
|
],
|
|
102
198
|
),
|
|
103
199
|
"bugfix-pipeline": (
|
|
104
200
|
"bugfix_state",
|
|
105
201
|
[
|
|
106
202
|
"prizmkit-implement", "prizmkit-code-review", "prizmkit-test",
|
|
107
|
-
"
|
|
203
|
+
"bug-report", "prizmkit-retrospective", "prizmkit-committer",
|
|
108
204
|
],
|
|
109
205
|
),
|
|
110
206
|
"refactor-pipeline": (
|
|
111
207
|
"refactor_state",
|
|
112
208
|
[
|
|
113
209
|
"prizmkit-implement", "prizmkit-code-review", "prizmkit-test",
|
|
114
|
-
"
|
|
115
|
-
"
|
|
210
|
+
"refactor-report", "completion-summary", "prizmkit-retrospective",
|
|
211
|
+
"prizmkit-committer",
|
|
116
212
|
],
|
|
117
213
|
),
|
|
118
214
|
}
|
|
@@ -128,6 +224,8 @@ def _write_semantic_completion_checkpoint(project_root, artifact_dir, workflow_t
|
|
|
128
224
|
"required_artifacts": [],
|
|
129
225
|
"depends_on": previous,
|
|
130
226
|
}
|
|
227
|
+
if skill == "prizmkit-implement":
|
|
228
|
+
step["stage_result"] = "IMPLEMENTED"
|
|
131
229
|
if skill == "prizmkit-code-review":
|
|
132
230
|
step["stage_result"] = "REVIEW_PASS"
|
|
133
231
|
if skill == "prizmkit-test":
|
|
@@ -137,6 +235,10 @@ def _write_semantic_completion_checkpoint(project_root, artifact_dir, workflow_t
|
|
|
137
235
|
str(relative_artifact / "test-report.md"),
|
|
138
236
|
str(relative_artifact / "test-result.json"),
|
|
139
237
|
]
|
|
238
|
+
if skill == "prizmkit-retrospective":
|
|
239
|
+
step["stage_result"] = "RETRO_COMPLETE"
|
|
240
|
+
if skill == "prizmkit-committer":
|
|
241
|
+
step["stage_result"] = "COMMITTED"
|
|
140
242
|
steps.append(step)
|
|
141
243
|
previous = step["id"]
|
|
142
244
|
artifact_dir.mkdir(parents=True, exist_ok=True)
|
|
@@ -158,12 +260,31 @@ def _write_semantic_completion_checkpoint(project_root, artifact_dir, workflow_t
|
|
|
158
260
|
},
|
|
159
261
|
"repair_rounds": 0,
|
|
160
262
|
"production_changed": False,
|
|
161
|
-
"review_required": False,
|
|
162
|
-
"review_scope": None,
|
|
163
263
|
"unresolved_items": [],
|
|
164
264
|
}),
|
|
165
265
|
encoding="utf-8",
|
|
166
266
|
)
|
|
267
|
+
runtime_commit_hash = "b" * 40
|
|
268
|
+
runtime_base_head = "a" * 40
|
|
269
|
+
head = subprocess.run(
|
|
270
|
+
["git", "rev-parse", "HEAD"],
|
|
271
|
+
cwd=project_root,
|
|
272
|
+
stdout=subprocess.PIPE,
|
|
273
|
+
stderr=subprocess.DEVNULL,
|
|
274
|
+
text=True,
|
|
275
|
+
check=False,
|
|
276
|
+
)
|
|
277
|
+
parent = subprocess.run(
|
|
278
|
+
["git", "rev-parse", "HEAD^"],
|
|
279
|
+
cwd=project_root,
|
|
280
|
+
stdout=subprocess.PIPE,
|
|
281
|
+
stderr=subprocess.DEVNULL,
|
|
282
|
+
text=True,
|
|
283
|
+
check=False,
|
|
284
|
+
)
|
|
285
|
+
if head.returncode == 0 and parent.returncode == 0:
|
|
286
|
+
runtime_commit_hash = head.stdout.strip()
|
|
287
|
+
runtime_base_head = parent.stdout.strip()
|
|
167
288
|
checkpoint = artifact_dir / "workflow-checkpoint.json"
|
|
168
289
|
checkpoint.write_text(
|
|
169
290
|
json.dumps({
|
|
@@ -173,6 +294,8 @@ def _write_semantic_completion_checkpoint(project_root, artifact_dir, workflow_t
|
|
|
173
294
|
state_key: {
|
|
174
295
|
"repair_round": 0,
|
|
175
296
|
"terminal_status": "WORKFLOW_COMPLETED",
|
|
297
|
+
"runtime_base_head": runtime_base_head,
|
|
298
|
+
"runtime_commit_hash": runtime_commit_hash,
|
|
176
299
|
},
|
|
177
300
|
}),
|
|
178
301
|
encoding="utf-8",
|
|
@@ -403,7 +526,7 @@ def test_runner_models_parse_legacy_args_and_environment(tmp_path):
|
|
|
403
526
|
invocation = parse_invocation(
|
|
404
527
|
family,
|
|
405
528
|
"run",
|
|
406
|
-
("custom-list.json", "F-2", "--features", "F-003:F-001", "--max-retries", "7", "--max-infra-retries=5"
|
|
529
|
+
("custom-list.json", "F-2", "--features", "F-003:F-001", "--max-retries", "7", "--max-infra-retries=5"),
|
|
407
530
|
)
|
|
408
531
|
env = RunnerEnvironment.from_env(
|
|
409
532
|
{
|
|
@@ -422,7 +545,7 @@ def test_runner_models_parse_legacy_args_and_environment(tmp_path):
|
|
|
422
545
|
assert invocation.item_filter == "F-003:F-001"
|
|
423
546
|
assert invocation.max_retries == 7
|
|
424
547
|
assert invocation.max_infra_retries == 5
|
|
425
|
-
assert invocation
|
|
548
|
+
assert not hasattr(invocation, "mode")
|
|
426
549
|
assert env.stop_on_failure is True
|
|
427
550
|
assert env.auto_push is True
|
|
428
551
|
assert env.dev_branch == "dev/custom"
|
|
@@ -1082,7 +1205,6 @@ def test_prompt_generation_result_preserves_per_item_model(monkeypatch, tmp_path
|
|
|
1082
1205
|
"output_path": str(session_paths.prompt_path),
|
|
1083
1206
|
"checkpoint_path": str(paths.project_root / ".prizmkit" / "bugfix" / "B-001" / "workflow-checkpoint.json"),
|
|
1084
1207
|
"model": "per-item-model",
|
|
1085
|
-
"pipeline_mode": "standard",
|
|
1086
1208
|
}
|
|
1087
1209
|
),
|
|
1088
1210
|
stderr="",
|
|
@@ -1130,7 +1252,6 @@ def test_prompt_generation_passes_explicit_execution_root_to_generator(monkeypat
|
|
|
1130
1252
|
"output_path": str(session_paths.prompt_path),
|
|
1131
1253
|
"checkpoint_path": str(execution_root / ".prizmkit" / "specs" / "001-low" / "workflow-checkpoint.json"),
|
|
1132
1254
|
"model": "",
|
|
1133
|
-
"pipeline_mode": "full",
|
|
1134
1255
|
}
|
|
1135
1256
|
),
|
|
1136
1257
|
stderr="",
|
|
@@ -1195,7 +1316,6 @@ def _install_runner_session_fakes(monkeypatch, runners, *, statuses=("success",)
|
|
|
1195
1316
|
return PromptGenerationResult(
|
|
1196
1317
|
output_path=session_paths.prompt_path,
|
|
1197
1318
|
model="per-item-model",
|
|
1198
|
-
pipeline_mode="full",
|
|
1199
1319
|
checkpoint_path=execution_root / ".prizmkit" / "specs" / "001-low" / "workflow-checkpoint.json",
|
|
1200
1320
|
artifact_path=execution_root / ".prizmkit" / "specs" / "001-low",
|
|
1201
1321
|
raw={},
|
|
@@ -1528,7 +1648,6 @@ def test_explicit_worktree_materializes_ignored_support_assets_before_prompt_and
|
|
|
1528
1648
|
return PromptGenerationResult(
|
|
1529
1649
|
output_path=session_paths.prompt_path,
|
|
1530
1650
|
model="",
|
|
1531
|
-
pipeline_mode="full",
|
|
1532
1651
|
checkpoint_path=execution_root / ".prizmkit" / "specs" / "001-support" / "workflow-checkpoint.json",
|
|
1533
1652
|
artifact_path=execution_root / ".prizmkit" / "specs" / "001-support",
|
|
1534
1653
|
raw={},
|
|
@@ -1615,7 +1734,6 @@ def test_has_branch_completion_evidence_requires_task_branch_ahead_of_base(tmp_p
|
|
|
1615
1734
|
subprocess.run(["git", "config", "user.email", "test@example.com"], cwd=tmp_path, check=True)
|
|
1616
1735
|
subprocess.run(["git", "config", "user.name", "Test"], cwd=tmp_path, check=True)
|
|
1617
1736
|
artifact_dir = tmp_path / ".prizmkit" / "specs" / "001-done"
|
|
1618
|
-
_write_semantic_completion_checkpoint(tmp_path, artifact_dir)
|
|
1619
1737
|
(tmp_path / "base.txt").write_text("base", encoding="utf-8")
|
|
1620
1738
|
subprocess.run(["git", "add", "base.txt"], cwd=tmp_path, check=True)
|
|
1621
1739
|
subprocess.run(["git", "commit", "-m", "base"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
@@ -1623,6 +1741,7 @@ def test_has_branch_completion_evidence_requires_task_branch_ahead_of_base(tmp_p
|
|
|
1623
1741
|
(tmp_path / "done.txt").write_text("done", encoding="utf-8")
|
|
1624
1742
|
subprocess.run(["git", "add", "done.txt"], cwd=tmp_path, check=True)
|
|
1625
1743
|
subprocess.run(["git", "commit", "-m", "done"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
1744
|
+
_write_semantic_completion_checkpoint(tmp_path, artifact_dir)
|
|
1626
1745
|
|
|
1627
1746
|
assert has_branch_completion_evidence(tmp_path, "main", "dev/F-001", artifact_dir) is True
|
|
1628
1747
|
|
|
@@ -1994,7 +2113,7 @@ def test_foreground_runner_emits_structured_feature_progress(monkeypatch, tmp_pa
|
|
|
1994
2113
|
assert "Feature: F-001 — Readable output" in captured.err
|
|
1995
2114
|
assert "Code retry: 1 / 3" in captured.err
|
|
1996
2115
|
assert "Preflight: no user-visible changes to preserve before feature task F-001" in captured.err
|
|
1997
|
-
assert "Pipeline mode:
|
|
2116
|
+
assert "Pipeline mode:" not in captured.err
|
|
1998
2117
|
assert "Spawning AI CLI session: F-001-session-1" in captured.err
|
|
1999
2118
|
assert "Session result: success" in captured.err
|
|
2000
2119
|
|
|
@@ -3166,6 +3285,14 @@ def test_classification_accepts_final_success_after_internal_stream_retry(tmp_pa
|
|
|
3166
3285
|
stdout=subprocess.PIPE,
|
|
3167
3286
|
text=True,
|
|
3168
3287
|
).stdout.strip()
|
|
3288
|
+
(tmp_path / "done.txt").write_text("done", encoding="utf-8")
|
|
3289
|
+
subprocess.run(["git", "add", "done.txt"], cwd=tmp_path, check=True)
|
|
3290
|
+
subprocess.run(
|
|
3291
|
+
["git", "commit", "-m", "done"],
|
|
3292
|
+
cwd=tmp_path,
|
|
3293
|
+
check=True,
|
|
3294
|
+
stdout=subprocess.DEVNULL,
|
|
3295
|
+
)
|
|
3169
3296
|
artifact_dir = tmp_path / ".prizmkit" / "bugfix" / "B-004"
|
|
3170
3297
|
checkpoint = _write_semantic_completion_checkpoint(tmp_path, artifact_dir, "bugfix-pipeline")
|
|
3171
3298
|
|
|
@@ -3313,7 +3440,7 @@ def test_classification_keeps_pre_completion_provider_error_as_infra_error(tmp_p
|
|
|
3313
3440
|
assert classification.reason == "ai_runtime_or_provider_error"
|
|
3314
3441
|
|
|
3315
3442
|
|
|
3316
|
-
def
|
|
3443
|
+
def test_classification_rejects_completed_checkpoint_without_runtime_git_receipt(tmp_path):
|
|
3317
3444
|
from prizmkit_runtime.runner_classification import classify_session
|
|
3318
3445
|
from prizmkit_runtime.runner_models import PromptGenerationResult
|
|
3319
3446
|
from prizmkit_runtime.sessions import AISessionCommand, AISessionResult
|
|
@@ -3353,8 +3480,8 @@ def test_classification_accepts_terminal_success_with_completed_checkpoint_witho
|
|
|
3353
3480
|
)
|
|
3354
3481
|
|
|
3355
3482
|
classification = classify_session(raw, project_root=tmp_path, base_head=base_head, prompt=prompt)
|
|
3356
|
-
assert classification.session_status == "
|
|
3357
|
-
assert classification.reason == "
|
|
3483
|
+
assert classification.session_status == "commit_missing"
|
|
3484
|
+
assert classification.reason == "runtime_commit_receipt_mismatch"
|
|
3358
3485
|
|
|
3359
3486
|
|
|
3360
3487
|
def test_classification_preserves_success_before_context_overflow(tmp_path):
|
|
@@ -3915,6 +4042,14 @@ def test_pi_length_stop_does_not_override_completed_checkpoint(tmp_path):
|
|
|
3915
4042
|
from prizmkit_runtime.status import ProgressSummary
|
|
3916
4043
|
|
|
3917
4044
|
base_head = _init_git_repo_for_invalid_checkpoint_test(tmp_path)
|
|
4045
|
+
(tmp_path / "done.txt").write_text("done", encoding="utf-8")
|
|
4046
|
+
subprocess.run(["git", "add", "done.txt"], cwd=tmp_path, check=True)
|
|
4047
|
+
subprocess.run(
|
|
4048
|
+
["git", "commit", "-m", "done"],
|
|
4049
|
+
cwd=tmp_path,
|
|
4050
|
+
check=True,
|
|
4051
|
+
stdout=subprocess.DEVNULL,
|
|
4052
|
+
)
|
|
3918
4053
|
artifact_dir = tmp_path / ".prizmkit" / "specs" / "001-length-complete"
|
|
3919
4054
|
checkpoint = _write_semantic_completion_checkpoint(tmp_path, artifact_dir)
|
|
3920
4055
|
prompt = PromptGenerationResult(
|
|
@@ -4361,6 +4496,21 @@ def test_semantic_completion_classification_has_cross_family_parity(tmp_path, wo
|
|
|
4361
4496
|
(tmp_path / "base.txt").write_text("base", encoding="utf-8")
|
|
4362
4497
|
subprocess.run(["git", "add", "base.txt"], cwd=tmp_path, check=True)
|
|
4363
4498
|
subprocess.run(["git", "commit", "-m", "base"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
4499
|
+
base_head = subprocess.run(
|
|
4500
|
+
["git", "rev-parse", "HEAD"],
|
|
4501
|
+
cwd=tmp_path,
|
|
4502
|
+
check=True,
|
|
4503
|
+
stdout=subprocess.PIPE,
|
|
4504
|
+
text=True,
|
|
4505
|
+
).stdout.strip()
|
|
4506
|
+
(tmp_path / "done.txt").write_text("done", encoding="utf-8")
|
|
4507
|
+
subprocess.run(["git", "add", "done.txt"], cwd=tmp_path, check=True)
|
|
4508
|
+
subprocess.run(
|
|
4509
|
+
["git", "commit", "-m", "done"],
|
|
4510
|
+
cwd=tmp_path,
|
|
4511
|
+
check=True,
|
|
4512
|
+
stdout=subprocess.DEVNULL,
|
|
4513
|
+
)
|
|
4364
4514
|
artifact = tmp_path / ".prizmkit" / "artifacts" / workflow_type
|
|
4365
4515
|
checkpoint = _write_semantic_completion_checkpoint(tmp_path, artifact, workflow_type)
|
|
4366
4516
|
log = tmp_path / f"{workflow_type}.log"
|
|
@@ -4383,7 +4533,7 @@ def test_semantic_completion_classification_has_cross_family_parity(tmp_path, wo
|
|
|
4383
4533
|
classification = classify_session(
|
|
4384
4534
|
raw,
|
|
4385
4535
|
project_root=tmp_path,
|
|
4386
|
-
base_head=
|
|
4536
|
+
base_head=base_head,
|
|
4387
4537
|
prompt=PromptGenerationResult(
|
|
4388
4538
|
output_path=tmp_path / "prompt.md",
|
|
4389
4539
|
checkpoint_path=checkpoint,
|
|
@@ -86,6 +86,25 @@ def _write_checkout(
|
|
|
86
86
|
return checkout
|
|
87
87
|
|
|
88
88
|
|
|
89
|
+
def _write_raw_checkout(
|
|
90
|
+
project: Path,
|
|
91
|
+
family: str,
|
|
92
|
+
directory_id: str,
|
|
93
|
+
payload: dict[str, object],
|
|
94
|
+
) -> Path:
|
|
95
|
+
checkout = (
|
|
96
|
+
project
|
|
97
|
+
/ ".prizmkit"
|
|
98
|
+
/ "state"
|
|
99
|
+
/ STATE_DIRS[family]
|
|
100
|
+
/ directory_id
|
|
101
|
+
/ "checkout.json"
|
|
102
|
+
)
|
|
103
|
+
checkout.parent.mkdir(parents=True, exist_ok=True)
|
|
104
|
+
checkout.write_text(json.dumps(payload) + "\n", encoding="utf-8")
|
|
105
|
+
return checkout
|
|
106
|
+
|
|
107
|
+
|
|
89
108
|
def _repository_snapshot(project: Path) -> tuple[str, str, str]:
|
|
90
109
|
return (
|
|
91
110
|
_git(project, "branch", "--show-current"),
|
|
@@ -209,3 +228,95 @@ def test_zero_candidates_filters_invalid_records_without_history_fallback_or_ses
|
|
|
209
228
|
assert _repository_snapshot(project) == repository_before
|
|
210
229
|
assert _historical_snapshot(historical) == history_before
|
|
211
230
|
assert sorted(path.name for path in historical.parent.iterdir()) == ["historical-only"]
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def test_detector_rejects_malformed_or_mismatched_checkout_identity(tmp_path):
|
|
234
|
+
project = tmp_path / "project"
|
|
235
|
+
_init_repository(project)
|
|
236
|
+
invalid_records = (
|
|
237
|
+
(
|
|
238
|
+
"feature",
|
|
239
|
+
"F-not-an-id",
|
|
240
|
+
"dev/F-not-an-id",
|
|
241
|
+
{
|
|
242
|
+
"task_type": "feature",
|
|
243
|
+
"task_id": "F-not-an-id",
|
|
244
|
+
"state": "active",
|
|
245
|
+
"active_dev_branch": "dev/F-not-an-id",
|
|
246
|
+
"base_branch": "main",
|
|
247
|
+
"checkout_mode": "branch",
|
|
248
|
+
},
|
|
249
|
+
),
|
|
250
|
+
(
|
|
251
|
+
"bugfix",
|
|
252
|
+
"B-004",
|
|
253
|
+
"bugfix/B-004-missing-id",
|
|
254
|
+
{
|
|
255
|
+
"task_type": "bugfix",
|
|
256
|
+
"state": "active",
|
|
257
|
+
"active_dev_branch": "bugfix/B-004-missing-id",
|
|
258
|
+
"base_branch": "main",
|
|
259
|
+
"checkout_mode": "branch",
|
|
260
|
+
},
|
|
261
|
+
),
|
|
262
|
+
(
|
|
263
|
+
"refactor",
|
|
264
|
+
"R-005",
|
|
265
|
+
"refactor/R-005-wrong-type",
|
|
266
|
+
{
|
|
267
|
+
"task_type": "feature",
|
|
268
|
+
"task_id": "R-005",
|
|
269
|
+
"state": "active",
|
|
270
|
+
"active_dev_branch": "refactor/R-005-wrong-type",
|
|
271
|
+
"base_branch": "main",
|
|
272
|
+
"checkout_mode": "branch",
|
|
273
|
+
},
|
|
274
|
+
),
|
|
275
|
+
(
|
|
276
|
+
"feature",
|
|
277
|
+
"F-006",
|
|
278
|
+
"dev/F-006-path-mismatch",
|
|
279
|
+
{
|
|
280
|
+
"task_type": "feature",
|
|
281
|
+
"task_id": "F-007",
|
|
282
|
+
"state": "active",
|
|
283
|
+
"active_dev_branch": "dev/F-006-path-mismatch",
|
|
284
|
+
"base_branch": "main",
|
|
285
|
+
"checkout_mode": "branch",
|
|
286
|
+
},
|
|
287
|
+
),
|
|
288
|
+
)
|
|
289
|
+
for family, directory_id, branch, payload in invalid_records:
|
|
290
|
+
_git(project, "branch", branch)
|
|
291
|
+
_write_raw_checkout(project, family, directory_id, payload)
|
|
292
|
+
|
|
293
|
+
detector = _load_detector("recovery_workflow_invalid_identity")
|
|
294
|
+
|
|
295
|
+
assert detector.detect_candidates(project) == []
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def test_recovery_workflow_metadata_matches_detector_only_contract():
|
|
299
|
+
metadata = json.loads((REPO_ROOT / "core" / "skills" / "_metadata.json").read_text())
|
|
300
|
+
recovery = metadata["skills"]["recovery-workflow"]
|
|
301
|
+
description = recovery["description"].lower()
|
|
302
|
+
|
|
303
|
+
assert recovery["hasScripts"] is True
|
|
304
|
+
assert "active feature, bugfix, or refactor checkout records" in description
|
|
305
|
+
assert "operation-first" in description
|
|
306
|
+
assert "direct requirement" not in description
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def test_canonical_recovery_and_cli_guidance_has_no_retired_contracts():
|
|
310
|
+
env_example = (REPO_ROOT / "dev-pipeline" / ".env.example").read_text(encoding="utf-8")
|
|
311
|
+
readme = (REPO_ROOT / "README.md").read_text(encoding="utf-8")
|
|
312
|
+
readme_en = (REPO_ROOT / "README_EN.md").read_text(encoding="utf-8")
|
|
313
|
+
|
|
314
|
+
assert "cli.py feature run" not in env_example
|
|
315
|
+
assert "cli.py run feature" in env_example
|
|
316
|
+
assert "从断点继续" not in readme
|
|
317
|
+
assert "reset/clean/unskip/complete" not in readme
|
|
318
|
+
assert "reset/clean/reset_state/complete" in readme
|
|
319
|
+
assert "Auto-detect + resume from breakpoint" not in readme_en
|
|
320
|
+
assert "interrupted at Phase 4" not in readme_en
|
|
321
|
+
assert "Resumes from Phase 5" not in readme_en
|
|
322
|
+
assert "Does not execute the command or infer a lifecycle phase" in readme_en
|
|
@@ -110,8 +110,6 @@ def _write_semantic_completion_checkpoint(project_root, artifact_dir, workflow_t
|
|
|
110
110
|
},
|
|
111
111
|
"repair_rounds": 0,
|
|
112
112
|
"production_changed": False,
|
|
113
|
-
"review_required": False,
|
|
114
|
-
"review_scope": None,
|
|
115
113
|
"unresolved_items": [],
|
|
116
114
|
}),
|
|
117
115
|
encoding="utf-8",
|