prizmkit 1.1.153 → 1.1.155
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 +120 -113
- package/bundled/dev-pipeline/assets/skill-subagent-integration.md +1 -1
- package/bundled/dev-pipeline/prizmkit_runtime/checkpoint_state.py +355 -15
- package/bundled/dev-pipeline/prizmkit_runtime/cli.py +189 -110
- package/bundled/dev-pipeline/prizmkit_runtime/commands.py +146 -111
- package/bundled/dev-pipeline/prizmkit_runtime/daemon.py +4 -20
- package/bundled/dev-pipeline/prizmkit_runtime/gitops.py +48 -14
- package/bundled/dev-pipeline/prizmkit_runtime/interoperability.py +0 -1
- package/bundled/dev-pipeline/prizmkit_runtime/paths.py +0 -3
- package/bundled/dev-pipeline/prizmkit_runtime/reset.py +122 -15
- package/bundled/dev-pipeline/prizmkit_runtime/reset_preserve.py +1 -1
- package/bundled/dev-pipeline/prizmkit_runtime/runner_classification.py +50 -2
- package/bundled/dev-pipeline/prizmkit_runtime/runner_models.py +1 -10
- package/bundled/dev-pipeline/prizmkit_runtime/runner_prompts.py +3 -3
- package/bundled/dev-pipeline/prizmkit_runtime/runners.py +139 -74
- package/bundled/dev-pipeline/prizmkit_runtime/runtime_commit.py +482 -0
- package/bundled/dev-pipeline/prizmkit_runtime/status.py +106 -1
- 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/init-bugfix-pipeline.py +2 -2
- package/bundled/dev-pipeline/scripts/prompt_framework.py +36 -41
- package/bundled/dev-pipeline/scripts/update-bug-status.py +197 -71
- package/bundled/dev-pipeline/scripts/update-checkpoint.py +77 -16
- package/bundled/dev-pipeline/scripts/update-feature-status.py +46 -121
- package/bundled/dev-pipeline/scripts/update-refactor-status.py +46 -123
- package/bundled/dev-pipeline/scripts/utils.py +119 -0
- 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/bug-fix-list-schema.json +3 -2
- 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_auto_skip.py +111 -32
- package/bundled/dev-pipeline/tests/test_checkpoint_state.py +617 -30
- package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +262 -194
- 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 +281 -206
- package/bundled/dev-pipeline/tests/test_recovery_workflow.py +322 -0
- package/bundled/dev-pipeline/tests/test_reset_modes.py +935 -0
- package/bundled/dev-pipeline/tests/test_reset_preserve.py +5 -7
- package/bundled/dev-pipeline/tests/test_runtime_commit.py +608 -0
- package/bundled/dev-pipeline/tests/test_unified_cli.py +617 -188
- 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/bug-planner/references/schema-validation.md +1 -1
- package/bundled/skills/bug-planner/scripts/validate-bug-list.py +1 -1
- package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +21 -13
- package/bundled/skills/feature-pipeline-launcher/SKILL.md +22 -14
- 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 +11 -1
- package/bundled/skills/prizmkit-retrospective/SKILL.md +63 -77
- package/bundled/skills/prizmkit-retrospective/references/knowledge-injection-steps.md +3 -3
- package/bundled/skills/prizmkit-retrospective/references/retrospective-result-schema.json +138 -0
- package/bundled/skills/prizmkit-retrospective/references/structural-sync-steps.md +17 -23
- 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 +9 -6
- package/bundled/skills/recovery-workflow/evals/evals.json +2 -2
- package/bundled/skills/recovery-workflow/references/detection.md +7 -6
- package/bundled/skills/recovery-workflow/scripts/detect-recovery-state.py +16 -6
- package/bundled/skills/refactor-pipeline-launcher/SKILL.md +21 -13
- package/bundled/templates/project-memory-template.md +19 -11
- package/package.json +1 -1
- package/src/scaffold.js +33 -22
- package/bundled/dev-pipeline/prizmkit_runtime/runner_recovery.py +0 -228
- package/bundled/dev-pipeline/scripts/generate-recovery-prompt.py +0 -767
- 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
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
### Runtime Commit Handoff
|
|
2
|
+
|
|
3
|
+
The Python runtime, not the AI session, executes the pipeline's local Git commit. This stage contains no prompt-level commit authorization.
|
|
4
|
+
|
|
5
|
+
After Code Review, all configured verification, `TEST_PASS`, family reports/summaries, and retrospective have completed:
|
|
6
|
+
|
|
7
|
+
1. As the session orchestrator, validate every required stage artifact and result first. Atomic Skills do not perform this sequencing check.
|
|
8
|
+
2. Invoke `/prizmkit-committer` with the same artifact root, exact readiness evidence, and request path:
|
|
9
|
+
|
|
10
|
+
```text
|
|
11
|
+
/prizmkit-committer operation=prepare-runtime-commit artifact_dir={{ARTIFACT_DIR}} evidence_paths=<exact validated artifact paths> excluded_paths={{ARTIFACT_DIR}}/workflow-checkpoint.json request_path={{ARTIFACT_DIR}}/runtime-commit-request.json
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
3. The committer validates only the supplied evidence and final diff, then classifies paths before writing the request:
|
|
15
|
+
- all `.prizmkit/**` paths are PrizmKit-internal and stay outside the task commit, including config, plans, Prizm docs, lifecycle Artifacts, Runtime files, and state;
|
|
16
|
+
- `AGENTS.md`, `skills-lock.json`, installed platform directories, and local platform settings are support data and stay outside the task commit;
|
|
17
|
+
- project-specific transient data must already be covered by Git ignore rules;
|
|
18
|
+
- every other Git-visible path must be justified task output and included exactly, otherwise the handoff blocks.
|
|
19
|
+
|
|
20
|
+
It then rejects sensitive/unrelated/unknown paths, generates one Conventional Commit message, and writes this request without staging or committing:
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"schema_version": 1,
|
|
25
|
+
"artifact_dir": "{{ARTIFACT_DIR}}",
|
|
26
|
+
"base_head": "<current HEAD commit hash>",
|
|
27
|
+
"commit_message": "<type>(<scope>): <description>",
|
|
28
|
+
"intended_paths": ["<exact project-relative changed path>"]
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
4. Require the stage-local result `COMMIT_REQUEST_READY`. Then this injected session—not the Skill—marks `prizmkit-committer` `in_progress` with `stage_result=COMMIT_PENDING` through the checkpoint helper. Do not mark it completed or write `COMMITTED`.
|
|
33
|
+
5. Stop normal work after the valid request and checkpoint handoff exist. Do not run `git add`, `git commit`, `git commit --amend`, merge, push, or create additional files.
|
|
34
|
+
|
|
35
|
+
The runtime validates exact task-owned path coverage outside recognized internal/support namespaces, rejects a request that explicitly names one of those namespaces, stages only the requested literal paths, executes and verifies the local commit, finalizes the Runtime-owned checkpoint to `COMMITTED`, and then performs its configured merge/publication behavior. Unknown Git-visible paths are not silently ignored: they produce a mismatch and preserve the task checkout for recovery. A malformed, stale, unsafe, incomplete, or contradictory request also blocks without deleting user data.
|
|
@@ -1,83 +1,66 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
-
"title": "Dev-Pipeline Session Status",
|
|
4
|
-
"description": "Schema for session-status.json written
|
|
3
|
+
"title": "Dev-Pipeline Runtime Session Status",
|
|
4
|
+
"description": "Schema for runner-owned session-status.json written after an AI process exits",
|
|
5
5
|
"type": "object",
|
|
6
|
-
"required": [
|
|
6
|
+
"required": [
|
|
7
|
+
"session_id",
|
|
8
|
+
"task_id",
|
|
9
|
+
"task_type",
|
|
10
|
+
"status",
|
|
11
|
+
"base_branch",
|
|
12
|
+
"active_dev_branch"
|
|
13
|
+
],
|
|
7
14
|
"properties": {
|
|
8
15
|
"session_id": {
|
|
9
16
|
"type": "string",
|
|
10
17
|
"minLength": 1
|
|
11
18
|
},
|
|
12
|
-
"
|
|
19
|
+
"task_id": {
|
|
13
20
|
"type": "string",
|
|
14
|
-
"pattern": "^
|
|
21
|
+
"pattern": "^[FBR]-\\d{3}(?:-[A-Z])?$"
|
|
15
22
|
},
|
|
16
|
-
"
|
|
23
|
+
"task_type": {
|
|
17
24
|
"type": "string",
|
|
18
|
-
"enum": ["
|
|
19
|
-
},
|
|
20
|
-
"completed_phases": {
|
|
21
|
-
"type": "array",
|
|
22
|
-
"items": {
|
|
23
|
-
"type": "integer",
|
|
24
|
-
"minimum": 0,
|
|
25
|
-
"maximum": 7
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
|
-
"current_phase": {
|
|
29
|
-
"type": "integer",
|
|
30
|
-
"minimum": 0,
|
|
31
|
-
"maximum": 7
|
|
25
|
+
"enum": ["feature", "bugfix", "refactor"]
|
|
32
26
|
},
|
|
33
|
-
"
|
|
27
|
+
"status": {
|
|
34
28
|
"type": "string",
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
29
|
+
"enum": [
|
|
30
|
+
"success",
|
|
31
|
+
"failed",
|
|
32
|
+
"crashed",
|
|
33
|
+
"timed_out",
|
|
34
|
+
"infra_error",
|
|
35
|
+
"commit_missing",
|
|
36
|
+
"docs_missing",
|
|
37
|
+
"merge_conflict",
|
|
38
|
+
"context_overflow",
|
|
39
|
+
"stalled_context_continuation",
|
|
40
|
+
"workflow_blocked",
|
|
41
|
+
"workflow_skipped"
|
|
42
|
+
]
|
|
44
43
|
},
|
|
45
|
-
"
|
|
46
|
-
"type": "
|
|
47
|
-
"
|
|
48
|
-
"type": "object",
|
|
49
|
-
"required": ["message"],
|
|
50
|
-
"properties": {
|
|
51
|
-
"phase": { "type": "integer" },
|
|
52
|
-
"type": { "type": "string" },
|
|
53
|
-
"message": { "type": "string" },
|
|
54
|
-
"recoverable": { "type": "boolean" }
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
},
|
|
58
|
-
"can_resume": {
|
|
59
|
-
"type": "boolean"
|
|
44
|
+
"base_branch": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"minLength": 1
|
|
60
47
|
},
|
|
61
|
-
"
|
|
62
|
-
"type": "
|
|
48
|
+
"active_dev_branch": {
|
|
49
|
+
"type": "string",
|
|
50
|
+
"minLength": 1
|
|
63
51
|
},
|
|
64
|
-
"
|
|
65
|
-
"type": "
|
|
52
|
+
"worktree_path": {
|
|
53
|
+
"type": "string"
|
|
66
54
|
},
|
|
67
|
-
"
|
|
68
|
-
"type":
|
|
55
|
+
"reason": {
|
|
56
|
+
"type": "string"
|
|
69
57
|
},
|
|
70
|
-
"
|
|
71
|
-
"type": "
|
|
72
|
-
"properties": {
|
|
73
|
-
"spec_path": { "type": "string" },
|
|
74
|
-
"plan_path": { "type": "string" },
|
|
75
|
-
"context_snapshot_path": { "type": "string" }
|
|
76
|
-
}
|
|
58
|
+
"fatal_error_code": {
|
|
59
|
+
"type": "string"
|
|
77
60
|
},
|
|
78
|
-
"
|
|
79
|
-
"type": "
|
|
80
|
-
"format": "date-time"
|
|
61
|
+
"checkpoint_state": {
|
|
62
|
+
"type": "object"
|
|
81
63
|
}
|
|
82
|
-
}
|
|
64
|
+
},
|
|
65
|
+
"additionalProperties": false
|
|
83
66
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Tests for auto-skip and
|
|
1
|
+
"""Tests for auto-skip and reset_state functionality in update-feature-status.py."""
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import os
|
|
@@ -221,6 +221,76 @@ class TestContextOverflowRetrySemantics:
|
|
|
221
221
|
]:
|
|
222
222
|
assert key not in status
|
|
223
223
|
|
|
224
|
+
def test_start_and_update_persist_effective_retry_budgets_without_charging_workflow_skip(self, tmp_path):
|
|
225
|
+
scripts_dir = Path(__file__).resolve().parents[1] / "scripts"
|
|
226
|
+
|
|
227
|
+
for case in self._script_cases(scripts_dir):
|
|
228
|
+
case_dir = tmp_path / f"budgets-{case['id']}"
|
|
229
|
+
state_dir = case_dir / "state"
|
|
230
|
+
list_path = case_dir / case["list_name"]
|
|
231
|
+
payload = json.loads(json.dumps(case["list_payload"]))
|
|
232
|
+
payload[case["collection"]][0]["status"] = "pending"
|
|
233
|
+
write_json_file(str(list_path), payload)
|
|
234
|
+
|
|
235
|
+
start = subprocess.run(
|
|
236
|
+
[
|
|
237
|
+
"python3",
|
|
238
|
+
str(case["script"]),
|
|
239
|
+
case["list_option"],
|
|
240
|
+
str(list_path),
|
|
241
|
+
"--state-dir",
|
|
242
|
+
str(state_dir),
|
|
243
|
+
case["id_option"],
|
|
244
|
+
case["id"],
|
|
245
|
+
"--action",
|
|
246
|
+
"start",
|
|
247
|
+
"--max-retries",
|
|
248
|
+
"7",
|
|
249
|
+
"--max-infra-retries",
|
|
250
|
+
"4",
|
|
251
|
+
],
|
|
252
|
+
text=True,
|
|
253
|
+
capture_output=True,
|
|
254
|
+
check=True,
|
|
255
|
+
)
|
|
256
|
+
assert json.loads(start.stdout)["new_status"] == "in_progress"
|
|
257
|
+
started = self._runtime_status(state_dir, case["id"])
|
|
258
|
+
assert started["max_retries"] == 7
|
|
259
|
+
assert started["max_infra_retries"] == 4
|
|
260
|
+
|
|
261
|
+
skipped = subprocess.run(
|
|
262
|
+
[
|
|
263
|
+
"python3",
|
|
264
|
+
str(case["script"]),
|
|
265
|
+
case["list_option"],
|
|
266
|
+
str(list_path),
|
|
267
|
+
"--state-dir",
|
|
268
|
+
str(state_dir),
|
|
269
|
+
case["id_option"],
|
|
270
|
+
case["id"],
|
|
271
|
+
"--session-id",
|
|
272
|
+
"sess-skip",
|
|
273
|
+
"--session-status",
|
|
274
|
+
"workflow_skipped",
|
|
275
|
+
"--action",
|
|
276
|
+
"update",
|
|
277
|
+
"--max-retries",
|
|
278
|
+
"5",
|
|
279
|
+
"--max-infra-retries",
|
|
280
|
+
"2",
|
|
281
|
+
],
|
|
282
|
+
text=True,
|
|
283
|
+
capture_output=True,
|
|
284
|
+
check=True,
|
|
285
|
+
)
|
|
286
|
+
summary = json.loads(skipped.stdout)
|
|
287
|
+
runtime = self._runtime_status(state_dir, case["id"])
|
|
288
|
+
assert summary["new_status"] == "skipped"
|
|
289
|
+
assert runtime["max_retries"] == 5
|
|
290
|
+
assert runtime["max_infra_retries"] == 2
|
|
291
|
+
assert runtime["retry_count"] == 0
|
|
292
|
+
assert runtime["infra_error_count"] == 0
|
|
293
|
+
|
|
224
294
|
def test_context_overflow_consumes_retry_and_records_bounded_continuation_metadata(self, tmp_path):
|
|
225
295
|
scripts_dir = Path(__file__).resolve().parents[1] / "scripts"
|
|
226
296
|
|
|
@@ -441,10 +511,10 @@ class TestContextOverflowRetrySemantics:
|
|
|
441
511
|
assert runtime["context_overflow_count"] == 2
|
|
442
512
|
assert runtime["continuation_count"] == 2
|
|
443
513
|
|
|
444
|
-
def
|
|
514
|
+
def test_manual_reset_clean_and_reset_state_clear_all_continuation_state(self, tmp_path):
|
|
445
515
|
scripts_dir = Path(__file__).resolve().parents[1] / "scripts"
|
|
446
516
|
|
|
447
|
-
for action in ["reset", "clean", "
|
|
517
|
+
for action in ["reset", "clean", "reset_state"]:
|
|
448
518
|
for case in self._script_cases(scripts_dir):
|
|
449
519
|
case_dir = tmp_path / f"{action}-{case['id']}"
|
|
450
520
|
state_dir = case_dir / "state"
|
|
@@ -503,7 +573,7 @@ class TestContextOverflowRetrySemantics:
|
|
|
503
573
|
]
|
|
504
574
|
if action in ("reset", "clean"):
|
|
505
575
|
cmd.extend([case["id_option"], case["id"]])
|
|
506
|
-
elif action == "
|
|
576
|
+
elif action == "reset_state":
|
|
507
577
|
cmd.extend([case["id_option"], case["id"]])
|
|
508
578
|
if action == "clean":
|
|
509
579
|
cmd.extend(["--project-root", str(case_dir)])
|
|
@@ -515,7 +585,15 @@ class TestContextOverflowRetrySemantics:
|
|
|
515
585
|
for continuation_file in continuation_files:
|
|
516
586
|
assert not continuation_file.exists()
|
|
517
587
|
runtime = self._runtime_status(state_dir, case["id"])
|
|
518
|
-
|
|
588
|
+
if action == "reset_state":
|
|
589
|
+
assert runtime["active_dev_branch"] == "dev/existing-branch"
|
|
590
|
+
assert runtime["base_branch"] == "main"
|
|
591
|
+
continuation_only = dict(runtime)
|
|
592
|
+
continuation_only.pop("active_dev_branch")
|
|
593
|
+
continuation_only.pop("base_branch")
|
|
594
|
+
self._assert_no_continuation_runtime_state(continuation_only)
|
|
595
|
+
else:
|
|
596
|
+
self._assert_no_continuation_runtime_state(runtime)
|
|
519
597
|
assert runtime["retry_count"] == 0
|
|
520
598
|
assert runtime["infra_error_count"] == 0
|
|
521
599
|
assert runtime["last_infra_error_session_id"] is None
|
|
@@ -601,6 +679,7 @@ class TestContextOverflowRetrySemantics:
|
|
|
601
679
|
"reset",
|
|
602
680
|
case["target"],
|
|
603
681
|
case["item_id"],
|
|
682
|
+
"--fresh-checkout",
|
|
604
683
|
str(prizmkit_dir / "plans" / case["list_name"]),
|
|
605
684
|
],
|
|
606
685
|
cwd=case_dir,
|
|
@@ -758,7 +837,7 @@ def _run_status_snapshot_action(case, list_path, state_dir, action, session_stat
|
|
|
758
837
|
"--action",
|
|
759
838
|
action,
|
|
760
839
|
]
|
|
761
|
-
if action in {"update", "reset", "clean", "
|
|
840
|
+
if action in {"update", "reset", "clean", "reset_state"}:
|
|
762
841
|
cmd.extend([case["id_option"], case["id"]])
|
|
763
842
|
if action == "update":
|
|
764
843
|
cmd.extend([
|
|
@@ -1200,7 +1279,7 @@ class TestAutoSkipEdgeCases:
|
|
|
1200
1279
|
|
|
1201
1280
|
|
|
1202
1281
|
# ---------------------------------------------------------------------------
|
|
1203
|
-
#
|
|
1282
|
+
# action_reset_state — via subprocess (tests the full CLI interface)
|
|
1204
1283
|
# ---------------------------------------------------------------------------
|
|
1205
1284
|
|
|
1206
1285
|
import subprocess
|
|
@@ -1210,12 +1289,12 @@ _SCRIPT = os.path.join(
|
|
|
1210
1289
|
)
|
|
1211
1290
|
|
|
1212
1291
|
|
|
1213
|
-
def
|
|
1292
|
+
def _run_reset_state(fl_path, state_dir, feature_id=None):
|
|
1214
1293
|
cmd = [
|
|
1215
1294
|
"python3", _SCRIPT,
|
|
1216
1295
|
"--feature-list", fl_path,
|
|
1217
1296
|
"--state-dir", state_dir,
|
|
1218
|
-
"--action", "
|
|
1297
|
+
"--action", "reset_state",
|
|
1219
1298
|
]
|
|
1220
1299
|
if feature_id:
|
|
1221
1300
|
cmd += ["--feature-id", feature_id]
|
|
@@ -1344,7 +1423,7 @@ class TestInfraErrorUpdate:
|
|
|
1344
1423
|
assert fs["last_infra_error_session_id"] is None
|
|
1345
1424
|
assert _read_statuses(fl_path)["F-001"] == "pending"
|
|
1346
1425
|
|
|
1347
|
-
def
|
|
1426
|
+
def test_reset_state_clears_infra_retry_counters(self, tmp_path):
|
|
1348
1427
|
features = [_make_feature("F-001", "Root", status="failed")]
|
|
1349
1428
|
fl_path = _write_fl(tmp_path, features)
|
|
1350
1429
|
state_dir = _init_state(tmp_path, ["F-001"])
|
|
@@ -1355,7 +1434,7 @@ class TestInfraErrorUpdate:
|
|
|
1355
1434
|
fs["last_infra_error_session_id"] = "session-infra-final"
|
|
1356
1435
|
write_json_file(status_path, fs)
|
|
1357
1436
|
|
|
1358
|
-
|
|
1437
|
+
_run_reset_state(fl_path, state_dir, "F-001")
|
|
1359
1438
|
|
|
1360
1439
|
fs = load_feature_status(state_dir, "F-001")
|
|
1361
1440
|
assert fs["retry_count"] == 0
|
|
@@ -1363,10 +1442,10 @@ class TestInfraErrorUpdate:
|
|
|
1363
1442
|
assert fs["last_infra_error_session_id"] is None
|
|
1364
1443
|
assert _read_statuses(fl_path)["F-001"] == "pending"
|
|
1365
1444
|
|
|
1366
|
-
class
|
|
1367
|
-
"""
|
|
1445
|
+
class TestResetStateByFeatureId:
|
|
1446
|
+
"""ResetState with --feature-id targets a specific failed feature + downstream."""
|
|
1368
1447
|
|
|
1369
|
-
def
|
|
1448
|
+
def test_reset_state_failed_root_resets_all(self, tmp_path):
|
|
1370
1449
|
features = [
|
|
1371
1450
|
_make_feature("F-001", "Root", status="failed"),
|
|
1372
1451
|
_make_feature("F-002", "Mid", deps=["F-001"], status="auto_skipped"),
|
|
@@ -1375,14 +1454,14 @@ class TestUnskipByFeatureId:
|
|
|
1375
1454
|
fl_path = _write_fl(tmp_path, features)
|
|
1376
1455
|
state_dir = _init_state(tmp_path, ["F-001", "F-002", "F-003"])
|
|
1377
1456
|
|
|
1378
|
-
result =
|
|
1457
|
+
result = _run_reset_state(fl_path, state_dir, "F-001")
|
|
1379
1458
|
|
|
1380
1459
|
assert result["reset_count"] == 3
|
|
1381
1460
|
statuses = _read_statuses(fl_path)
|
|
1382
1461
|
assert all(s == "pending" for s in statuses.values())
|
|
1383
1462
|
|
|
1384
|
-
def
|
|
1385
|
-
"""C2 fix:
|
|
1463
|
+
def test_reset_state_auto_skipped_leaf_resets_upstream(self, tmp_path):
|
|
1464
|
+
"""C2 fix: reset_state F-003 must also find and reset F-001 (failed root)."""
|
|
1386
1465
|
features = [
|
|
1387
1466
|
_make_feature("F-001", "Root", status="failed"),
|
|
1388
1467
|
_make_feature("F-002", "Mid", deps=["F-001"], status="auto_skipped"),
|
|
@@ -1391,14 +1470,14 @@ class TestUnskipByFeatureId:
|
|
|
1391
1470
|
fl_path = _write_fl(tmp_path, features)
|
|
1392
1471
|
state_dir = _init_state(tmp_path, ["F-001", "F-002", "F-003"])
|
|
1393
1472
|
|
|
1394
|
-
result =
|
|
1473
|
+
result = _run_reset_state(fl_path, state_dir, "F-003")
|
|
1395
1474
|
|
|
1396
1475
|
assert result["reset_count"] == 3
|
|
1397
1476
|
reset_ids = {f["feature_id"] for f in result["features"]}
|
|
1398
1477
|
assert "F-001" in reset_ids # transitive upstream reset
|
|
1399
1478
|
assert all(s == "pending" for s in _read_statuses(fl_path).values())
|
|
1400
1479
|
|
|
1401
|
-
def
|
|
1480
|
+
def test_reset_state_preserves_completed_features(self, tmp_path):
|
|
1402
1481
|
features = [
|
|
1403
1482
|
_make_feature("F-001", "Done", status="completed"),
|
|
1404
1483
|
_make_feature("F-002", "Failed", deps=["F-001"], status="failed"),
|
|
@@ -1407,7 +1486,7 @@ class TestUnskipByFeatureId:
|
|
|
1407
1486
|
fl_path = _write_fl(tmp_path, features)
|
|
1408
1487
|
state_dir = _init_state(tmp_path, ["F-001", "F-002", "F-003"])
|
|
1409
1488
|
|
|
1410
|
-
result =
|
|
1489
|
+
result = _run_reset_state(fl_path, state_dir, "F-002")
|
|
1411
1490
|
|
|
1412
1491
|
assert result["reset_count"] == 2
|
|
1413
1492
|
statuses = _read_statuses(fl_path)
|
|
@@ -1415,8 +1494,8 @@ class TestUnskipByFeatureId:
|
|
|
1415
1494
|
assert statuses["F-002"] == "pending"
|
|
1416
1495
|
assert statuses["F-003"] == "pending"
|
|
1417
1496
|
|
|
1418
|
-
def
|
|
1419
|
-
"""
|
|
1497
|
+
def test_reset_state_skipped_feature_resets_downstream(self, tmp_path):
|
|
1498
|
+
"""ResetState a manually-skipped feature should also reset its auto_skipped downstream."""
|
|
1420
1499
|
features = [
|
|
1421
1500
|
_make_feature("F-001", "Skipped", status="skipped"),
|
|
1422
1501
|
_make_feature("F-002", "Child", deps=["F-001"], status="auto_skipped"),
|
|
@@ -1424,7 +1503,7 @@ class TestUnskipByFeatureId:
|
|
|
1424
1503
|
fl_path = _write_fl(tmp_path, features)
|
|
1425
1504
|
state_dir = _init_state(tmp_path, ["F-001", "F-002"])
|
|
1426
1505
|
|
|
1427
|
-
result =
|
|
1506
|
+
result = _run_reset_state(fl_path, state_dir, "F-001")
|
|
1428
1507
|
|
|
1429
1508
|
assert result["reset_count"] == 2
|
|
1430
1509
|
statuses = _read_statuses(fl_path)
|
|
@@ -1432,8 +1511,8 @@ class TestUnskipByFeatureId:
|
|
|
1432
1511
|
assert statuses["F-002"] == "pending"
|
|
1433
1512
|
|
|
1434
1513
|
|
|
1435
|
-
class
|
|
1436
|
-
"""
|
|
1514
|
+
class TestResetStateAll:
|
|
1515
|
+
"""ResetState without --feature-id resets all failed + auto_skipped."""
|
|
1437
1516
|
|
|
1438
1517
|
def test_resets_all_failed_and_auto_skipped(self, tmp_path):
|
|
1439
1518
|
features = [
|
|
@@ -1445,7 +1524,7 @@ class TestUnskipAll:
|
|
|
1445
1524
|
fl_path = _write_fl(tmp_path, features)
|
|
1446
1525
|
state_dir = _init_state(tmp_path, ["F-001", "F-002", "F-003", "F-004"])
|
|
1447
1526
|
|
|
1448
|
-
result =
|
|
1527
|
+
result = _run_reset_state(fl_path, state_dir)
|
|
1449
1528
|
|
|
1450
1529
|
assert result["reset_count"] == 2
|
|
1451
1530
|
statuses = _read_statuses(fl_path)
|
|
@@ -1456,11 +1535,11 @@ class TestUnskipAll:
|
|
|
1456
1535
|
|
|
1457
1536
|
|
|
1458
1537
|
# ---------------------------------------------------------------------------
|
|
1459
|
-
# Integration: auto-skip → get_next →
|
|
1538
|
+
# Integration: auto-skip → get_next → reset_state → get_next
|
|
1460
1539
|
# ---------------------------------------------------------------------------
|
|
1461
1540
|
|
|
1462
1541
|
class TestAutoSkipIntegration:
|
|
1463
|
-
"""Full lifecycle: fail → auto-skip → pipeline complete →
|
|
1542
|
+
"""Full lifecycle: fail → auto-skip → pipeline complete → reset_state → resume."""
|
|
1464
1543
|
|
|
1465
1544
|
def test_full_lifecycle(self, tmp_path):
|
|
1466
1545
|
features = [
|
|
@@ -1477,8 +1556,8 @@ class TestAutoSkipIntegration:
|
|
|
1477
1556
|
# 2. get_next should return PIPELINE_COMPLETE
|
|
1478
1557
|
assert _run_get_next(fl_path, state_dir) == "PIPELINE_COMPLETE"
|
|
1479
1558
|
|
|
1480
|
-
# 3.
|
|
1481
|
-
|
|
1559
|
+
# 3. ResetState recovers everything
|
|
1560
|
+
_run_reset_state(fl_path, state_dir, "F-001")
|
|
1482
1561
|
statuses = _read_statuses(fl_path)
|
|
1483
1562
|
assert statuses["F-001"] == "pending"
|
|
1484
1563
|
assert statuses["F-002"] == "pending"
|
|
@@ -1488,7 +1567,7 @@ class TestAutoSkipIntegration:
|
|
|
1488
1567
|
data = json.loads(output)
|
|
1489
1568
|
assert data["feature_id"] == "F-001"
|
|
1490
1569
|
|
|
1491
|
-
def
|
|
1570
|
+
def test_retry_count_reset_after_reset_state(self, tmp_path):
|
|
1492
1571
|
features = [
|
|
1493
1572
|
_make_feature("F-001", "Root", status="failed"),
|
|
1494
1573
|
]
|
|
@@ -1502,7 +1581,7 @@ class TestAutoSkipIntegration:
|
|
|
1502
1581
|
with open(fs_path, "w") as f:
|
|
1503
1582
|
json.dump(fs, f)
|
|
1504
1583
|
|
|
1505
|
-
|
|
1584
|
+
_run_reset_state(fl_path, state_dir, "F-001")
|
|
1506
1585
|
|
|
1507
1586
|
with open(fs_path) as f:
|
|
1508
1587
|
fs = json.load(f)
|