prizmkit 1.1.107 → 1.1.108
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/bin/create-prizmkit.js +4 -0
- package/bundled/VERSION.json +3 -3
- package/bundled/dev-pipeline/prizmkit_runtime/config.py +81 -14
- package/bundled/dev-pipeline/prizmkit_runtime/heartbeat.py +19 -8
- package/bundled/dev-pipeline/prizmkit_runtime/interoperability.py +0 -1
- package/bundled/dev-pipeline/prizmkit_runtime/launch_profiles.py +18 -0
- package/bundled/dev-pipeline/prizmkit_runtime/runner_bookkeeping.py +22 -2
- package/bundled/dev-pipeline/prizmkit_runtime/runner_recovery.py +3 -1
- package/bundled/dev-pipeline/prizmkit_runtime/runners.py +20 -1
- package/bundled/dev-pipeline/prizmkit_runtime/sessions.py +151 -30
- package/bundled/dev-pipeline/scripts/continuation.py +0 -1
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +6 -46
- package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +7 -34
- package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +40 -33
- package/bundled/dev-pipeline/scripts/utils.py +123 -0
- package/bundled/dev-pipeline/templates/agent-prompts/critic-plan-challenge.md +4 -3
- package/bundled/dev-pipeline/templates/bootstrap-prompt.md +1 -1
- package/bundled/dev-pipeline/templates/bootstrap-tier1.md +8 -7
- package/bundled/dev-pipeline/templates/bootstrap-tier2.md +25 -36
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +16 -31
- package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +4 -16
- package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +3 -15
- package/bundled/dev-pipeline/templates/sections/checkpoint-system.md +14 -48
- package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +7 -13
- package/bundled/dev-pipeline/templates/sections/feature-context.md +0 -4
- package/bundled/dev-pipeline/templates/sections/phase-browser-verification-auto.md +0 -7
- package/bundled/dev-pipeline/templates/sections/phase-browser-verification-opencli.md +0 -7
- package/bundled/dev-pipeline/templates/sections/phase-browser-verification.md +0 -7
- package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +0 -14
- package/bundled/dev-pipeline/templates/sections/phase-commit.md +0 -14
- package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-agent-suffix.md +0 -7
- package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-base.md +0 -2
- package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-lite-suffix.md +0 -7
- package/bundled/dev-pipeline/templates/sections/phase-critic-plan-full.md +6 -8
- package/bundled/dev-pipeline/templates/sections/phase-critic-plan.md +3 -7
- package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +0 -7
- package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +0 -7
- package/bundled/dev-pipeline/templates/sections/phase-implement-lite.md +0 -7
- package/bundled/dev-pipeline/templates/sections/phase-plan-agent.md +2 -9
- package/bundled/dev-pipeline/templates/sections/phase-plan-lite.md +1 -8
- package/bundled/dev-pipeline/templates/sections/phase-prizmkit-test.md +15 -16
- package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +0 -7
- package/bundled/dev-pipeline/templates/sections/phase-review-full.md +0 -7
- package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +2 -9
- package/bundled/dev-pipeline/templates/sections/phase0-init.md +0 -7
- package/bundled/dev-pipeline/templates/sections/phase0-test-baseline.md +2 -15
- package/bundled/dev-pipeline/tests/conftest.py +0 -1
- package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +350 -23
- package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +36 -17
- package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +117 -14
- package/bundled/dev-pipeline/tests/test_python_runner_parity.py +79 -2
- package/bundled/dev-pipeline/tests/test_unified_cli.py +658 -13
- package/bundled/skills/_metadata.json +4 -4
- package/bundled/skills/app-planner/SKILL.md +1 -1
- package/bundled/skills/app-planner/references/architecture-decisions.md +1 -1
- package/bundled/skills/bug-fix-workflow/SKILL.md +174 -128
- package/bundled/skills/bug-planner/SKILL.md +101 -15
- package/bundled/skills/bug-planner/references/severity-rules.md +20 -8
- package/bundled/skills/feature-planner/SKILL.md +87 -8
- package/bundled/skills/feature-planner/assets/planning-guide.md +34 -10
- package/bundled/skills/feature-workflow/SKILL.md +100 -81
- package/bundled/skills/{prizm-kit → prizmkit}/SKILL.md +1 -1
- package/bundled/skills/prizmkit-code-review/SKILL.md +1 -1
- package/bundled/skills/refactor-planner/SKILL.md +88 -7
- package/bundled/skills/refactor-planner/references/fast-path.md +2 -1
- package/bundled/skills/refactor-planner/references/planning-phases.md +29 -11
- package/bundled/skills/refactor-workflow/SKILL.md +116 -57
- package/bundled/templates/project-memory-template.md +1 -1
- package/package.json +1 -1
- package/src/ai-cli-launch.js +194 -0
- package/src/config.js +26 -14
- package/src/index.js +11 -44
- package/src/platforms.js +10 -3
- package/src/prompts.js +60 -2
- package/src/scaffold.js +26 -14
- package/bundled/dev-pipeline/scripts/prizmkit-test-gate.py +0 -446
- package/bundled/dev-pipeline/templates/sections/log-size-awareness.md +0 -20
- package/bundled/dev-pipeline/tests/test_prizmkit_test_gate.py +0 -107
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
### Scoped Feature Test Gate — PrizmKit Test
|
|
2
2
|
|
|
3
|
-
**Goal**: After code review completes, generate and verify tests for this feature's changed scope
|
|
3
|
+
**Goal**: After code review completes, generate and verify tests for this feature's changed scope through the `/prizmkit-test` skill.
|
|
4
4
|
|
|
5
|
-
Create a
|
|
5
|
+
Create a current-run marker immediately before invoking the skill:
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
mkdir -p .prizmkit/specs/{{FEATURE_SLUG}}
|
|
9
|
+
touch .prizmkit/specs/{{FEATURE_SLUG}}/.prizmkit-test-started
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
Run `/prizmkit-test` with the feature artifact directory:
|
|
@@ -23,17 +23,16 @@ Rules:
|
|
|
23
23
|
- If failures are baseline or unrelated to this feature, document them in the report and continue only when no in-scope failure remains unexplained.
|
|
24
24
|
|
|
25
25
|
**Gate Check — Test Report**:
|
|
26
|
-
After `/prizmkit-test` returns,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
```
|
|
26
|
+
After `/prizmkit-test` returns, read `.prizmkit/specs/{{FEATURE_SLUG}}/test-report-path.txt` if it exists; otherwise locate the newest `.prizmkit/test/*/test-report.md` created by the current test run. Accept the report only when it states:
|
|
27
|
+
- `Scope` mode is `this-change`
|
|
28
|
+
- `Artifact Dir` matches `.prizmkit/specs/{{FEATURE_SLUG}}/`
|
|
29
|
+
- `Verdict` is `PASS`
|
|
30
|
+
- `Boundary Matrix` is present
|
|
31
|
+
- `Boundary Completion Gate` is present and reports `Boundary-missing: 0`, `Happy-path-only: 0`, and `Completion gate passed: yes`
|
|
32
|
+
- `Boundary Validation` is present and reports `Validator result: passed`
|
|
34
33
|
|
|
35
34
|
Gate outcomes:
|
|
36
|
-
- `
|
|
37
|
-
- `
|
|
38
|
-
- `
|
|
39
|
-
-
|
|
35
|
+
- `PASS` → ensure `.prizmkit/specs/{{FEATURE_SLUG}}/test-report-path.txt` points to the accepted report, append the report path and a 3-5 bullet summary to `context-snapshot.md` under `## PrizmKit Test Gate`, then proceed.
|
|
36
|
+
- `NEEDS_FIXES` → read the report's `In-Scope Failures`, fix the feature implementation or generated tests within this feature scope, rerun `/prizmkit-test`, and repeat the gate check. Do not proceed to retrospective/commit while the verdict is not `PASS`.
|
|
37
|
+
- `BLOCKED`, wrong mode, wrong artifact dir, unreadable report, stale scope, or boundary failure → write `.prizmkit/specs/{{FEATURE_SLUG}}/failure-log.md` with the scoped test failure and stop for recovery.
|
|
38
|
+
- Missing report → perform one bounded status check: inspect `/prizmkit-test` output and `.prizmkit/test/` for a report directory. If no current-run report exists, write `failure-log.md` and stop for recovery.
|
|
@@ -24,10 +24,3 @@ Read `review-report.md` and check the Verdict:
|
|
|
24
24
|
**CP-3**: Review complete, report written.
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
**Checkpoint update**: Run the update script to set step `prizmkit-code-review` to `"completed"`:
|
|
28
|
-
```bash
|
|
29
|
-
python3 $PIPELINE_DIR/scripts/update-checkpoint.py \
|
|
30
|
-
--checkpoint-path {{CHECKPOINT_PATH}} \
|
|
31
|
-
--step prizmkit-code-review \
|
|
32
|
-
--status completed
|
|
33
|
-
```
|
|
@@ -24,10 +24,3 @@ Read `review-report.md` and check the Verdict:
|
|
|
24
24
|
**CP-3**: Review complete, report written.
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
**Checkpoint update**: Run the update script to set step `prizmkit-code-review` to `"completed"`:
|
|
28
|
-
```bash
|
|
29
|
-
python3 $PIPELINE_DIR/scripts/update-checkpoint.py \
|
|
30
|
-
--checkpoint-path {{CHECKPOINT_PATH}} \
|
|
31
|
-
--step prizmkit-code-review \
|
|
32
|
-
--status completed
|
|
33
|
-
```
|
|
@@ -45,7 +45,7 @@ ls .prizmkit/specs/{{FEATURE_SLUG}}/ 2>/dev/null
|
|
|
45
45
|
ls .prizmkit/specs/{{FEATURE_SLUG}}/spec.md .prizmkit/specs/{{FEATURE_SLUG}}/plan.md 2>/dev/null
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
- spec.md missing: Run `/prizmkit-plan` → generate spec.md. Resolve
|
|
48
|
+
- spec.md missing: Run `/prizmkit-plan` → generate spec.md. Resolve uncertain requirements from the task description, existing code, and conservative existing-project patterns.
|
|
49
49
|
- plan.md missing: Run `/prizmkit-plan` → generate plan.md (change approach, components, interface design, data model, testing strategy, risk assessment, and Tasks section with `[ ]` checkboxes)
|
|
50
50
|
|
|
51
51
|
> All files go under `.prizmkit/specs/{{FEATURE_SLUG}}/`. Confirm each with `ls` after writing.
|
|
@@ -54,16 +54,9 @@ ls .prizmkit/specs/{{FEATURE_SLUG}}/spec.md .prizmkit/specs/{{FEATURE_SLUG}}/pla
|
|
|
54
54
|
Before proceeding past CP-1, verify:
|
|
55
55
|
1. Plan.md Data Model section references existing schema/model files (scan for `*.prisma`, `*.sql`, `migrations/`, `models/`, `*.entity.*` files; read them if not already in context-snapshot)
|
|
56
56
|
2. All new tables/fields follow existing naming conventions, ID strategy, timestamp patterns, and constraint style
|
|
57
|
-
3. No
|
|
57
|
+
3. No unresolved data model uncertainty remains in the Data Model section — resolve by reading existing code and making a conservative choice that matches existing patterns. Document the resolution in plan.md.
|
|
58
58
|
4. If a DB design decision genuinely cannot be resolved from existing code alone, document the assumption made and flag it in the Implementation Log for user review.
|
|
59
59
|
|
|
60
60
|
**CP-1**: Both spec.md and plan.md exist.
|
|
61
61
|
|
|
62
62
|
|
|
63
|
-
**Checkpoint update**: Run the update script to set step `context-snapshot-and-plan` to `"completed"`:
|
|
64
|
-
```bash
|
|
65
|
-
python3 $PIPELINE_DIR/scripts/update-checkpoint.py \
|
|
66
|
-
--checkpoint-path {{CHECKPOINT_PATH}} \
|
|
67
|
-
--step context-snapshot-and-plan \
|
|
68
|
-
--status completed
|
|
69
|
-
```
|
|
@@ -4,10 +4,3 @@
|
|
|
4
4
|
- **CP-0**: Verify `.prizmkit/prizm-docs/root.prizm`, `.prizmkit/config.json` exist
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
**Checkpoint update**: Run the update script to set step `prizmkit-init` to `"completed"`:
|
|
8
|
-
```bash
|
|
9
|
-
python3 $PIPELINE_DIR/scripts/update-checkpoint.py \
|
|
10
|
-
--checkpoint-path {{CHECKPOINT_PATH}} \
|
|
11
|
-
--step prizmkit-init \
|
|
12
|
-
--status completed
|
|
13
|
-
```
|
|
@@ -1,16 +1,3 @@
|
|
|
1
|
-
### Phase 0:
|
|
1
|
+
### Phase 0: Project Already Initialized
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
**Step 2 — Do not run tests yet**: This phase only records the commands that will be used by the post-review PrizmKit Test gate. Do not run baseline, periodic, or full-suite tests here; test execution happens after code review.
|
|
6
|
-
|
|
7
|
-
> **Test Output Rule**: When the post-review gate runs, capture test output to a temp file (`tee /tmp/test-out.txt`). Then grep the file instead of re-running the suite.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
**Checkpoint update**: Run the update script to set step `test-baseline` to `"completed"`:
|
|
11
|
-
```bash
|
|
12
|
-
python3 $PIPELINE_DIR/scripts/update-checkpoint.py \
|
|
13
|
-
--checkpoint-path {{CHECKPOINT_PATH}} \
|
|
14
|
-
--step test-baseline \
|
|
15
|
-
--status completed
|
|
16
|
-
```
|
|
3
|
+
The project is already initialized. Proceed to context loading and planning. Test execution belongs to the post-review `/prizmkit-test` gate.
|
|
@@ -25,5 +25,4 @@ def _load_hyphenated_module(module_name, filename):
|
|
|
25
25
|
_load_hyphenated_module("generate_bootstrap_prompt", "generate-bootstrap-prompt.py")
|
|
26
26
|
_load_hyphenated_module("generate_bugfix_prompt", "generate-bugfix-prompt.py")
|
|
27
27
|
_load_hyphenated_module("generate_refactor_prompt", "generate-refactor-prompt.py")
|
|
28
|
-
_load_hyphenated_module("prizmkit_test_gate", "prizmkit-test-gate.py")
|
|
29
28
|
_load_hyphenated_module("update_feature_status", "update-feature-status.py")
|
|
@@ -23,10 +23,10 @@ from generate_bootstrap_prompt import (
|
|
|
23
23
|
generate_checkpoint_definition,
|
|
24
24
|
merge_checkpoint_state,
|
|
25
25
|
load_active_agent_prompts,
|
|
26
|
-
load_log_size_section,
|
|
27
26
|
main as generate_bootstrap_main,
|
|
28
27
|
)
|
|
29
28
|
from continuation import append_continuation_handoff, checkpoint_cursor
|
|
29
|
+
from utils import resolve_prompt_platform
|
|
30
30
|
|
|
31
31
|
REMOVED_MAX_LOG_ENV = "MAX_" + "LOG_SIZE"
|
|
32
32
|
REMOVED_MAX_LOG_HUMAN = REMOVED_MAX_LOG_ENV + "_HUMAN"
|
|
@@ -443,9 +443,14 @@ class TestScopedFeatureTestGate:
|
|
|
443
443
|
assert names.index("phase-implement") < names.index("phase-review") < names.index("phase-prizmkit-test")
|
|
444
444
|
|
|
445
445
|
rendered = "\n".join(content for _, content in sections)
|
|
446
|
-
assert "prizmkit-test-gate.py" in rendered
|
|
447
|
-
assert "prizmkit-test-
|
|
448
|
-
assert "
|
|
446
|
+
assert "prizmkit-test-gate.py" not in rendered
|
|
447
|
+
assert ".prizmkit-test-started" in rendered
|
|
448
|
+
assert "when present" not in rendered
|
|
449
|
+
assert "Boundary Matrix" in rendered
|
|
450
|
+
assert "Boundary Completion Gate" in rendered
|
|
451
|
+
assert "Boundary-missing: 0" in rendered
|
|
452
|
+
assert "Happy-path-only: 0" in rendered
|
|
453
|
+
assert "Validator result: passed" in rendered
|
|
449
454
|
assert "/prizmkit-test scope=this-change artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/" in rendered
|
|
450
455
|
assert ".prizmkit/bugfix/" in rendered # explicitly forbidden in the gate wording
|
|
451
456
|
assert ".prizmkit/refactor/" in rendered # explicitly forbidden in the gate wording
|
|
@@ -456,6 +461,25 @@ class TestScopedFeatureTestGate:
|
|
|
456
461
|
assert "before code review" not in rendered
|
|
457
462
|
assert "Precondition: the `prizmkit-test` checkpoint is completed" not in rendered
|
|
458
463
|
|
|
464
|
+
def test_standard_sections_include_central_checkpoint_helper(self):
|
|
465
|
+
sections_dir = Path(__file__).resolve().parents[1] / "templates" / "sections"
|
|
466
|
+
sections = assemble_sections(
|
|
467
|
+
"standard",
|
|
468
|
+
str(sections_dir),
|
|
469
|
+
init_done=True,
|
|
470
|
+
is_resume=False,
|
|
471
|
+
critic_enabled=False,
|
|
472
|
+
browser_enabled=False,
|
|
473
|
+
)
|
|
474
|
+
rendered = "\n".join(content for _, content in sections)
|
|
475
|
+
|
|
476
|
+
assert "### Checkpoint Update Helper" in rendered
|
|
477
|
+
assert "python3 .prizmkit/dev-pipeline/scripts/update-checkpoint.py" in rendered
|
|
478
|
+
assert "--checkpoint-path {{CHECKPOINT_PATH}}" in rendered
|
|
479
|
+
assert "--step <step-id-or-skill-name>" in rendered
|
|
480
|
+
assert "Do not hand-edit `workflow-checkpoint.json` directly." in rendered
|
|
481
|
+
assert "pipeline progress mechanism" not in rendered
|
|
482
|
+
|
|
459
483
|
def test_lite_sections_include_review_before_prizmkit_test_and_commit(self):
|
|
460
484
|
sections_dir = Path(__file__).resolve().parents[1] / "templates" / "sections"
|
|
461
485
|
sections = assemble_sections(
|
|
@@ -795,25 +819,32 @@ class TestScopedFeatureTestGate:
|
|
|
795
819
|
# ---------------------------------------------------------------------------
|
|
796
820
|
|
|
797
821
|
class TestHeadlessRecoveryReframing:
|
|
798
|
-
def
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
822
|
+
def test_active_prompt_sources_do_not_reference_deleted_log_size_section(self):
|
|
823
|
+
deleted_section = "log-size-" + "awareness.md"
|
|
824
|
+
loader = "load_" + "log_size_section"
|
|
825
|
+
placeholder = "{{LOG_" + "SIZE_AWARENESS}}"
|
|
826
|
+
deleted_title = "Session " + "Checkpoint Awareness"
|
|
827
|
+
active_paths = [
|
|
828
|
+
Path("dev-pipeline/scripts/generate-bootstrap-prompt.py"),
|
|
829
|
+
Path("dev-pipeline/scripts/generate-bugfix-prompt.py"),
|
|
830
|
+
Path("dev-pipeline/scripts/generate-refactor-prompt.py"),
|
|
831
|
+
Path("dev-pipeline/templates/bootstrap-tier1.md"),
|
|
832
|
+
Path("dev-pipeline/templates/bootstrap-tier2.md"),
|
|
833
|
+
Path("dev-pipeline/templates/bootstrap-tier3.md"),
|
|
834
|
+
Path("dev-pipeline/templates/bugfix-bootstrap-prompt.md"),
|
|
835
|
+
Path("dev-pipeline/templates/refactor-bootstrap-prompt.md"),
|
|
836
|
+
]
|
|
837
|
+
|
|
838
|
+
assert (Path("dev-pipeline/templates/sections") / deleted_section).exists() is False
|
|
839
|
+
for path in active_paths:
|
|
840
|
+
content = path.read_text(encoding="utf-8")
|
|
841
|
+
for forbidden in (deleted_section, loader, placeholder, deleted_title):
|
|
842
|
+
assert forbidden not in content
|
|
814
843
|
|
|
815
844
|
def test_assembled_prompts_do_not_spawn_log_monitor_or_require_compact(self):
|
|
816
845
|
sections_dir = Path("dev-pipeline/templates/sections").resolve()
|
|
846
|
+
deleted_title = "Session " + "Checkpoint Awareness"
|
|
847
|
+
placeholder = "{{LOG_" + "SIZE_AWARENESS}}"
|
|
817
848
|
|
|
818
849
|
for mode in ("lite", "standard", "full"):
|
|
819
850
|
rendered = "\n".join(
|
|
@@ -822,8 +853,8 @@ class TestHeadlessRecoveryReframing:
|
|
|
822
853
|
critic_enabled=False, browser_enabled=False,
|
|
823
854
|
)
|
|
824
855
|
)
|
|
825
|
-
assert
|
|
826
|
-
assert
|
|
856
|
+
assert deleted_title not in rendered
|
|
857
|
+
assert placeholder not in rendered
|
|
827
858
|
assert REMOVED_MAX_LOG_ENV not in rendered
|
|
828
859
|
assert REMOVED_MAX_LOG_HUMAN not in rendered
|
|
829
860
|
assert ("209" + "7152") not in rendered
|
|
@@ -938,7 +969,7 @@ class TestContinuationHandoff:
|
|
|
938
969
|
assert "Treat completed/skipped checkpoint steps as already done." in rendered
|
|
939
970
|
assert "Do not read the previous full `session.log` unless explicitly necessary." in rendered
|
|
940
971
|
assert "prefer synthesized artifacts and summaries over logs" in rendered
|
|
941
|
-
assert "Do not attempt `/compact` as the recovery mechanism." in rendered
|
|
972
|
+
assert "Do not attempt `/compact` as the recovery mechanism." not in rendered
|
|
942
973
|
assert ".prizmkit/specs/123-continuation/workflow-checkpoint.json" in rendered
|
|
943
974
|
assert ".prizmkit/state/features/F-123/sessions/F-123-new/logs/session.log" in rendered
|
|
944
975
|
assert ".prizmkit/state/features/F-123/sessions/F-123-new/logs/progress.json" in rendered
|
|
@@ -960,3 +991,299 @@ class TestContinuationHandoff:
|
|
|
960
991
|
{"id": "S03", "skill": "later", "status": "pending"},
|
|
961
992
|
]}
|
|
962
993
|
assert checkpoint_cursor(checkpoint)["first_cursor"] == "S02 (active)"
|
|
994
|
+
|
|
995
|
+
|
|
996
|
+
# ---------------------------------------------------------------------------
|
|
997
|
+
# F-033 headless prompt cleanup and platform-aware critic paths
|
|
998
|
+
# ---------------------------------------------------------------------------
|
|
999
|
+
|
|
1000
|
+
HEADLESS_FORBIDDEN_PROMPT_STRINGS = [
|
|
1001
|
+
"### Interactive Claude Code Note",
|
|
1002
|
+
"### Project Conventions",
|
|
1003
|
+
"Read CLAUDE.md for project-level coding standards and architecture decisions.",
|
|
1004
|
+
"Scaffold / generated file awareness",
|
|
1005
|
+
"### Resume Behavior",
|
|
1006
|
+
"[NEEDS CLARIFICATION]",
|
|
1007
|
+
"pause for interactive input",
|
|
1008
|
+
"prizmkit-test-gate.py",
|
|
1009
|
+
"### Phase 0: Detect Test Commands",
|
|
1010
|
+
"TEST_CMDS",
|
|
1011
|
+
]
|
|
1012
|
+
|
|
1013
|
+
|
|
1014
|
+
def _write_feature_list(path, feature):
|
|
1015
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
1016
|
+
path.write_text(json.dumps({"features": [feature], "global_context": {"language": "Python"}}), encoding="utf-8")
|
|
1017
|
+
|
|
1018
|
+
|
|
1019
|
+
def _render_feature_prompt(tmp_path, mode="standard", critic=False, template=None, platform="claude"):
|
|
1020
|
+
project = tmp_path / "project"
|
|
1021
|
+
project.mkdir(parents=True)
|
|
1022
|
+
(project / ".prizmkit" / "plans").mkdir(parents=True)
|
|
1023
|
+
(project / ".prizmkit" / "config.json").write_text(
|
|
1024
|
+
json.dumps({"platform": platform, "ai_cli": platform}), encoding="utf-8"
|
|
1025
|
+
)
|
|
1026
|
+
for platform_dir, suffix in ((".claude", ".md"), (".codex", ".toml")):
|
|
1027
|
+
agents_dir = project / platform_dir / "agents"
|
|
1028
|
+
agents_dir.mkdir(parents=True)
|
|
1029
|
+
for name in ("dev", "reviewer", "critic"):
|
|
1030
|
+
(agents_dir / f"prizm-dev-team-{name}{suffix}").write_text("agent\n", encoding="utf-8")
|
|
1031
|
+
feature = {
|
|
1032
|
+
"id": "F-123",
|
|
1033
|
+
"title": "Prompt Cleanup",
|
|
1034
|
+
"description": "Clean prompt text",
|
|
1035
|
+
"estimated_complexity": {"lite": "low", "standard": "medium", "full": "high"}[mode],
|
|
1036
|
+
"acceptance_criteria": ["Prompts are clean"],
|
|
1037
|
+
"critic": critic,
|
|
1038
|
+
}
|
|
1039
|
+
feature_list = project / ".prizmkit" / "plans" / "feature-list.json"
|
|
1040
|
+
_write_feature_list(feature_list, feature)
|
|
1041
|
+
output = project / "prompt.md"
|
|
1042
|
+
args = [
|
|
1043
|
+
"generate-bootstrap-prompt.py",
|
|
1044
|
+
"--feature-list", str(feature_list),
|
|
1045
|
+
"--feature-id", "F-123",
|
|
1046
|
+
"--session-id", "session-1",
|
|
1047
|
+
"--run-id", "run-1",
|
|
1048
|
+
"--retry-count", "0",
|
|
1049
|
+
"--resume-phase", "null",
|
|
1050
|
+
"--state-dir", str(project / ".prizmkit" / "state" / "features"),
|
|
1051
|
+
"--project-root", str(project),
|
|
1052
|
+
"--output", str(output),
|
|
1053
|
+
"--mode", mode,
|
|
1054
|
+
]
|
|
1055
|
+
if critic:
|
|
1056
|
+
args.extend(["--critic", "true"])
|
|
1057
|
+
if template:
|
|
1058
|
+
args.extend(["--template", str(Path("dev-pipeline/templates") / template)])
|
|
1059
|
+
old_argv = os.sys.argv
|
|
1060
|
+
old_platform = os.environ.get("PRIZMKIT_PLATFORM")
|
|
1061
|
+
try:
|
|
1062
|
+
os.sys.argv = args
|
|
1063
|
+
if old_platform is not None:
|
|
1064
|
+
os.environ.pop("PRIZMKIT_PLATFORM")
|
|
1065
|
+
try:
|
|
1066
|
+
generate_bootstrap_main()
|
|
1067
|
+
except SystemExit as exc:
|
|
1068
|
+
if exc.code not in (0, None):
|
|
1069
|
+
raise
|
|
1070
|
+
finally:
|
|
1071
|
+
os.sys.argv = old_argv
|
|
1072
|
+
if old_platform is not None:
|
|
1073
|
+
os.environ["PRIZMKIT_PLATFORM"] = old_platform
|
|
1074
|
+
return output.read_text(encoding="utf-8")
|
|
1075
|
+
|
|
1076
|
+
|
|
1077
|
+
def _ensure_agent_files(project, platforms=("claude", "codex")):
|
|
1078
|
+
for platform in platforms:
|
|
1079
|
+
platform_dir = ".codex" if platform == "codex" else ".claude"
|
|
1080
|
+
suffix = ".toml" if platform == "codex" else ".md"
|
|
1081
|
+
agents_dir = project / platform_dir / "agents"
|
|
1082
|
+
agents_dir.mkdir(parents=True, exist_ok=True)
|
|
1083
|
+
for name in ("dev", "reviewer", "critic"):
|
|
1084
|
+
(agents_dir / f"prizm-dev-team-{name}{suffix}").write_text("agent\n", encoding="utf-8")
|
|
1085
|
+
|
|
1086
|
+
|
|
1087
|
+
def _render_bugfix_prompt(tmp_path, platform="claude", explicit_platform=None):
|
|
1088
|
+
from generate_bugfix_prompt import main as bugfix_main
|
|
1089
|
+
|
|
1090
|
+
project = tmp_path / "bugfix-project"
|
|
1091
|
+
project.mkdir(parents=True)
|
|
1092
|
+
(project / ".prizmkit").mkdir(exist_ok=True)
|
|
1093
|
+
(project / ".prizmkit" / "config.json").write_text(
|
|
1094
|
+
json.dumps({"platform": platform, "ai_cli": platform}), encoding="utf-8"
|
|
1095
|
+
)
|
|
1096
|
+
_ensure_agent_files(project)
|
|
1097
|
+
bug_list = project / ".prizmkit" / "plans" / "bug-fix-list.json"
|
|
1098
|
+
bug_list.parent.mkdir(parents=True)
|
|
1099
|
+
bug_list.write_text(json.dumps({
|
|
1100
|
+
"bugs": [{"id": "B-001", "title": "Broken", "description": "Fix it", "acceptance_criteria": ["Works"]}],
|
|
1101
|
+
"global_context": {"language": "Python"},
|
|
1102
|
+
}), encoding="utf-8")
|
|
1103
|
+
output = project / "bugfix-prompt.md"
|
|
1104
|
+
old_argv = os.sys.argv
|
|
1105
|
+
old_platform = os.environ.get("PRIZMKIT_PLATFORM")
|
|
1106
|
+
try:
|
|
1107
|
+
if explicit_platform is None:
|
|
1108
|
+
os.environ.pop("PRIZMKIT_PLATFORM", None)
|
|
1109
|
+
else:
|
|
1110
|
+
os.environ["PRIZMKIT_PLATFORM"] = explicit_platform
|
|
1111
|
+
os.sys.argv = [
|
|
1112
|
+
"generate-bugfix-prompt.py",
|
|
1113
|
+
"--bug-list", str(bug_list),
|
|
1114
|
+
"--bug-id", "B-001",
|
|
1115
|
+
"--session-id", "session-1",
|
|
1116
|
+
"--run-id", "run-1",
|
|
1117
|
+
"--retry-count", "0",
|
|
1118
|
+
"--resume-phase", "null",
|
|
1119
|
+
"--state-dir", str(project / ".prizmkit" / "state" / "bugfix"),
|
|
1120
|
+
"--project-root", str(project),
|
|
1121
|
+
"--output", str(output),
|
|
1122
|
+
]
|
|
1123
|
+
try:
|
|
1124
|
+
bugfix_main()
|
|
1125
|
+
except SystemExit as exc:
|
|
1126
|
+
if exc.code not in (0, None):
|
|
1127
|
+
raise
|
|
1128
|
+
finally:
|
|
1129
|
+
os.sys.argv = old_argv
|
|
1130
|
+
if old_platform is None:
|
|
1131
|
+
os.environ.pop("PRIZMKIT_PLATFORM", None)
|
|
1132
|
+
else:
|
|
1133
|
+
os.environ["PRIZMKIT_PLATFORM"] = old_platform
|
|
1134
|
+
return output.read_text(encoding="utf-8")
|
|
1135
|
+
|
|
1136
|
+
|
|
1137
|
+
def _render_refactor_prompt(tmp_path, platform="claude", explicit_platform=None):
|
|
1138
|
+
from generate_refactor_prompt import main as refactor_main
|
|
1139
|
+
|
|
1140
|
+
project = tmp_path / "refactor-project"
|
|
1141
|
+
project.mkdir(parents=True)
|
|
1142
|
+
(project / ".prizmkit").mkdir(exist_ok=True)
|
|
1143
|
+
(project / ".prizmkit" / "config.json").write_text(
|
|
1144
|
+
json.dumps({"platform": platform, "ai_cli": platform}), encoding="utf-8"
|
|
1145
|
+
)
|
|
1146
|
+
_ensure_agent_files(project)
|
|
1147
|
+
refactor_list = project / ".prizmkit" / "plans" / "refactor-list.json"
|
|
1148
|
+
refactor_list.parent.mkdir(parents=True)
|
|
1149
|
+
refactor_list.write_text(json.dumps({
|
|
1150
|
+
"refactors": [{
|
|
1151
|
+
"id": "R-001",
|
|
1152
|
+
"title": "Restructure",
|
|
1153
|
+
"description": "Preserve behavior",
|
|
1154
|
+
"acceptance_criteria": ["Behavior preserved"],
|
|
1155
|
+
"scope": {"files": ["src/a.py"], "modules": ["src"]},
|
|
1156
|
+
}],
|
|
1157
|
+
"global_context": {"language": "Python"},
|
|
1158
|
+
}), encoding="utf-8")
|
|
1159
|
+
output = project / "refactor-prompt.md"
|
|
1160
|
+
old_argv = os.sys.argv
|
|
1161
|
+
old_platform = os.environ.get("PRIZMKIT_PLATFORM")
|
|
1162
|
+
try:
|
|
1163
|
+
if explicit_platform is None:
|
|
1164
|
+
os.environ.pop("PRIZMKIT_PLATFORM", None)
|
|
1165
|
+
else:
|
|
1166
|
+
os.environ["PRIZMKIT_PLATFORM"] = explicit_platform
|
|
1167
|
+
os.sys.argv = [
|
|
1168
|
+
"generate-refactor-prompt.py",
|
|
1169
|
+
"--refactor-list", str(refactor_list),
|
|
1170
|
+
"--refactor-id", "R-001",
|
|
1171
|
+
"--session-id", "session-1",
|
|
1172
|
+
"--run-id", "run-1",
|
|
1173
|
+
"--retry-count", "0",
|
|
1174
|
+
"--resume-phase", "null",
|
|
1175
|
+
"--state-dir", str(project / ".prizmkit" / "state" / "refactor"),
|
|
1176
|
+
"--output", str(output),
|
|
1177
|
+
]
|
|
1178
|
+
old_cwd = os.getcwd()
|
|
1179
|
+
os.chdir(project)
|
|
1180
|
+
try:
|
|
1181
|
+
try:
|
|
1182
|
+
refactor_main()
|
|
1183
|
+
except SystemExit as exc:
|
|
1184
|
+
if exc.code not in (0, None):
|
|
1185
|
+
raise
|
|
1186
|
+
finally:
|
|
1187
|
+
os.chdir(old_cwd)
|
|
1188
|
+
finally:
|
|
1189
|
+
os.sys.argv = old_argv
|
|
1190
|
+
if old_platform is None:
|
|
1191
|
+
os.environ.pop("PRIZMKIT_PLATFORM", None)
|
|
1192
|
+
else:
|
|
1193
|
+
os.environ["PRIZMKIT_PLATFORM"] = old_platform
|
|
1194
|
+
return output.read_text(encoding="utf-8")
|
|
1195
|
+
|
|
1196
|
+
|
|
1197
|
+
class TestHeadlessPromptCleanupF033:
|
|
1198
|
+
def test_rendered_feature_bugfix_refactor_prompts_are_clean(self, tmp_path):
|
|
1199
|
+
prompts = []
|
|
1200
|
+
for mode in ("lite", "standard", "full"):
|
|
1201
|
+
prompts.append(_render_feature_prompt(tmp_path / mode, mode=mode, critic=(mode != "lite")))
|
|
1202
|
+
prompts.append(_render_bugfix_prompt(tmp_path))
|
|
1203
|
+
prompts.append(_render_refactor_prompt(tmp_path))
|
|
1204
|
+
|
|
1205
|
+
for prompt in prompts:
|
|
1206
|
+
for forbidden in HEADLESS_FORBIDDEN_PROMPT_STRINGS:
|
|
1207
|
+
assert forbidden not in prompt
|
|
1208
|
+
if "Feature ID" in prompt:
|
|
1209
|
+
assert "/prizmkit-test scope=this-change artifact_dir=.prizmkit/specs/123-prompt-cleanup/" in prompt
|
|
1210
|
+
assert ".prizmkit-test-started" in prompt
|
|
1211
|
+
|
|
1212
|
+
def test_legacy_feature_templates_are_clean_when_rendered(self, tmp_path):
|
|
1213
|
+
for template, mode in (("bootstrap-tier1.md", "lite"), ("bootstrap-tier2.md", "standard"), ("bootstrap-tier3.md", "full")):
|
|
1214
|
+
prompt = _render_feature_prompt(tmp_path / template, mode=mode, critic=(mode != "lite"), template=template)
|
|
1215
|
+
for forbidden in HEADLESS_FORBIDDEN_PROMPT_STRINGS:
|
|
1216
|
+
assert forbidden not in prompt
|
|
1217
|
+
assert "prizmkit-test-gate.py" not in prompt
|
|
1218
|
+
assert ".prizmkit-test-started" in prompt
|
|
1219
|
+
|
|
1220
|
+
def test_claude_config_wins_over_codex_directory_for_critic_path(self, tmp_path, monkeypatch):
|
|
1221
|
+
project = tmp_path / "mixed"
|
|
1222
|
+
(project / ".claude" / "agents").mkdir(parents=True)
|
|
1223
|
+
(project / ".codex" / "agents").mkdir(parents=True)
|
|
1224
|
+
(project / ".prizmkit").mkdir()
|
|
1225
|
+
(project / ".prizmkit" / "config.json").write_text(
|
|
1226
|
+
json.dumps({"platform": "claude", "ai_cli": "claude"}), encoding="utf-8"
|
|
1227
|
+
)
|
|
1228
|
+
monkeypatch.delenv("PRIZMKIT_PLATFORM", raising=False)
|
|
1229
|
+
|
|
1230
|
+
assert resolve_prompt_platform(str(project)) == "claude"
|
|
1231
|
+
prompt = _render_feature_prompt(tmp_path / "rendered-mixed", mode="standard", critic=True, platform="claude")
|
|
1232
|
+
assert ".claude/agents/prizm-dev-team-critic.md" in prompt
|
|
1233
|
+
assert ".codex/agents/prizm-dev-team-critic.toml" not in prompt
|
|
1234
|
+
|
|
1235
|
+
def test_bugfix_refactor_share_claude_platform_resolution(self, tmp_path, monkeypatch):
|
|
1236
|
+
from generate_bugfix_prompt import build_replacements as bugfix_build_replacements
|
|
1237
|
+
|
|
1238
|
+
monkeypatch.delenv("PRIZMKIT_PLATFORM", raising=False)
|
|
1239
|
+
bug_project = tmp_path / "bugfix-replacements"
|
|
1240
|
+
bug_project.mkdir()
|
|
1241
|
+
(bug_project / ".prizmkit").mkdir()
|
|
1242
|
+
(bug_project / ".prizmkit" / "config.json").write_text(
|
|
1243
|
+
json.dumps({"platform": "claude", "ai_cli": "claude"}), encoding="utf-8"
|
|
1244
|
+
)
|
|
1245
|
+
_ensure_agent_files(bug_project)
|
|
1246
|
+
args = Namespace(
|
|
1247
|
+
bug_id="B-001", session_id="session-1", run_id="run-1",
|
|
1248
|
+
retry_count="0", resume_phase="null", state_dir=None,
|
|
1249
|
+
output="out.md", project_root=str(bug_project), template=None,
|
|
1250
|
+
mode=None, critic=None,
|
|
1251
|
+
)
|
|
1252
|
+
replacements = bugfix_build_replacements(
|
|
1253
|
+
args, {"id": "B-001", "title": "Broken"}, {}, str(Path("dev-pipeline/scripts").resolve())
|
|
1254
|
+
)
|
|
1255
|
+
refactor_prompt = _render_refactor_prompt(tmp_path / "refactor-mixed", platform="claude")
|
|
1256
|
+
|
|
1257
|
+
assert replacements["{{REVIEWER_SUBAGENT_PATH}}"].endswith(".claude/agents/prizm-dev-team-reviewer.md")
|
|
1258
|
+
assert ".claude/agents/prizm-dev-team-reviewer.md" in refactor_prompt
|
|
1259
|
+
assert ".codex/agents/prizm-dev-team-reviewer.toml" not in refactor_prompt
|
|
1260
|
+
|
|
1261
|
+
def test_bugfix_refactor_explicit_codex_override(self, tmp_path, monkeypatch):
|
|
1262
|
+
from generate_bugfix_prompt import build_replacements as bugfix_build_replacements
|
|
1263
|
+
|
|
1264
|
+
bug_project = tmp_path / "bugfix-codex-replacements"
|
|
1265
|
+
bug_project.mkdir()
|
|
1266
|
+
_ensure_agent_files(bug_project)
|
|
1267
|
+
monkeypatch.setenv("PRIZMKIT_PLATFORM", "codex")
|
|
1268
|
+
args = Namespace(
|
|
1269
|
+
bug_id="B-001", session_id="session-1", run_id="run-1",
|
|
1270
|
+
retry_count="0", resume_phase="null", state_dir=None,
|
|
1271
|
+
output="out.md", project_root=str(bug_project), template=None,
|
|
1272
|
+
mode=None, critic=None,
|
|
1273
|
+
)
|
|
1274
|
+
replacements = bugfix_build_replacements(
|
|
1275
|
+
args, {"id": "B-001", "title": "Broken"}, {}, str(Path("dev-pipeline/scripts").resolve())
|
|
1276
|
+
)
|
|
1277
|
+
refactor_prompt = _render_refactor_prompt(tmp_path / "refactor-codex", platform="claude", explicit_platform="codex")
|
|
1278
|
+
|
|
1279
|
+
assert replacements["{{REVIEWER_SUBAGENT_PATH}}"].endswith(".codex/agents/prizm-dev-team-reviewer.toml")
|
|
1280
|
+
assert ".codex/agents/prizm-dev-team-reviewer.toml" in refactor_prompt
|
|
1281
|
+
assert ".claude/agents/prizm-dev-team-reviewer.md" not in refactor_prompt
|
|
1282
|
+
|
|
1283
|
+
def test_explicit_codex_env_still_renders_codex_critic_path(self, tmp_path, monkeypatch):
|
|
1284
|
+
project = tmp_path / "codex"
|
|
1285
|
+
(project / ".claude" / "agents").mkdir(parents=True)
|
|
1286
|
+
(project / ".codex" / "agents").mkdir(parents=True)
|
|
1287
|
+
monkeypatch.setenv("PRIZMKIT_PLATFORM", "codex")
|
|
1288
|
+
|
|
1289
|
+
assert resolve_prompt_platform(str(project)) == "codex"
|
|
@@ -12,7 +12,6 @@ from generate_bugfix_prompt import (
|
|
|
12
12
|
format_environment,
|
|
13
13
|
process_conditional_blocks,
|
|
14
14
|
render_template,
|
|
15
|
-
load_log_size_section,
|
|
16
15
|
)
|
|
17
16
|
from continuation import append_continuation_handoff
|
|
18
17
|
|
|
@@ -201,6 +200,9 @@ class TestExplicitProjectRoot:
|
|
|
201
200
|
)
|
|
202
201
|
assert "{{" + REMOVED_MAX_LOG_ENV + "}}" not in replacements
|
|
203
202
|
assert "{{" + REMOVED_MAX_LOG_HUMAN + "}}" not in replacements
|
|
203
|
+
assert "### Checkpoint Update Helper" in replacements["{{CHECKPOINT_SYSTEM}}"]
|
|
204
|
+
assert "python3 .prizmkit/dev-pipeline/scripts/update-checkpoint.py" in replacements["{{CHECKPOINT_SYSTEM}}"]
|
|
205
|
+
assert "pipeline progress mechanism" not in replacements["{{CHECKPOINT_SYSTEM}}"]
|
|
204
206
|
|
|
205
207
|
|
|
206
208
|
# ---------------------------------------------------------------------------
|
|
@@ -226,21 +228,18 @@ class TestSharedHelpers:
|
|
|
226
228
|
# ---------------------------------------------------------------------------
|
|
227
229
|
|
|
228
230
|
class TestHeadlessRecoveryReframing:
|
|
229
|
-
def
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
assert ("
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
assert "background monitoring subagent" not in content
|
|
242
|
-
assert "Execute `/compact`" not in content
|
|
243
|
-
assert "run `/compact`" not in content.lower()
|
|
231
|
+
def test_bugfix_source_has_no_deleted_log_size_injection(self):
|
|
232
|
+
deleted_section = "log-size-" + "awareness.md"
|
|
233
|
+
loader = "load_" + "log_size_section"
|
|
234
|
+
placeholder = "{{LOG_" + "SIZE_AWARENESS}}"
|
|
235
|
+
deleted_title = "Session " + "Checkpoint Awareness"
|
|
236
|
+
source = Path("dev-pipeline/scripts/generate-bugfix-prompt.py").read_text(encoding="utf-8")
|
|
237
|
+
template = Path("dev-pipeline/templates/bugfix-bootstrap-prompt.md").read_text(encoding="utf-8")
|
|
238
|
+
|
|
239
|
+
assert (Path("dev-pipeline/templates/sections") / deleted_section).exists() is False
|
|
240
|
+
for content in (source, template):
|
|
241
|
+
for forbidden in (deleted_section, loader, placeholder, deleted_title):
|
|
242
|
+
assert forbidden not in content
|
|
244
243
|
|
|
245
244
|
def test_bugfix_template_does_not_spawn_monitor_or_require_compact(self):
|
|
246
245
|
content = Path("dev-pipeline/templates/bugfix-bootstrap-prompt.md").read_text(encoding="utf-8")
|
|
@@ -278,8 +277,28 @@ class TestBugfixContinuationHandoff:
|
|
|
278
277
|
|
|
279
278
|
assert prompt.startswith("BUGFIX PROMPT")
|
|
280
279
|
assert "This is an automatic continuation after context overflow." in prompt
|
|
281
|
-
assert "Do not attempt `/compact` as the recovery mechanism." in prompt
|
|
280
|
+
assert "Do not attempt `/compact` as the recovery mechanism." not in prompt
|
|
282
281
|
assert ("Log " + "monitor") not in prompt
|
|
283
282
|
assert ("log-" + "monitor") not in prompt
|
|
284
283
|
assert (tmp_path / ".prizmkit/specs/B-007/continuation-summary.md").exists()
|
|
285
284
|
assert (tmp_path / ".prizmkit/bugfix/B-007/continuation-summary.md").exists()
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
HEADLESS_FORBIDDEN_PROMPT_STRINGS = [
|
|
288
|
+
"### Interactive Claude Code Note",
|
|
289
|
+
"### Project Conventions",
|
|
290
|
+
"Scaffold / generated file awareness",
|
|
291
|
+
"### Resume Behavior",
|
|
292
|
+
"[NEEDS CLARIFICATION]",
|
|
293
|
+
"pause for interactive input",
|
|
294
|
+
"prizmkit-test-gate.py",
|
|
295
|
+
"/compact",
|
|
296
|
+
"Session " + "Checkpoint Awareness",
|
|
297
|
+
"{{LOG_" + "SIZE_AWARENESS}}",
|
|
298
|
+
]
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def test_template_source_is_clean_for_headless_prompt_contract():
|
|
302
|
+
content = Path("dev-pipeline/templates/bugfix-bootstrap-prompt.md").read_text(encoding="utf-8")
|
|
303
|
+
for forbidden in HEADLESS_FORBIDDEN_PROMPT_STRINGS:
|
|
304
|
+
assert forbidden not in content
|