feat(templates): explicit cp_write on every kind: script node + audit test (WF-COMP-31d, item 26754227)
cp_write: true -> state-tx (test-validate@1, frozen-fixture-emit@1) and, in
the archived bug-ancestor-auto-advance@1, tag-set + state-tx.
cp_write: false -> every other script node (verdict-gate, policy-pick,
preflight-*, frozen-fixture-emit, parent-link-check).
tests/invariants/test_cp_write_field_set_correctly.py pins the set.
HOLD: do not merge until the CP release that adds WorkflowNode.cp_write.
The current CP schema is extra="forbid" and rejects the new key
(verified: nodes.0.cp_write extra_forbidden), so on the old CP these
template edits are NOT inert.
Claude-Session: https://claude.ai/code/session_01N218bERyNeLhbLmDRDvbWF
This commit is contained in:
@@ -31,6 +31,7 @@ nodes:
|
||||
- id: parent-link-check
|
||||
kind: script
|
||||
cmd: scripts/workflow/parent-link-check
|
||||
cp_write: false
|
||||
on_fail: refuse_dispatch
|
||||
runtime_env:
|
||||
CP_URL: "https://agents.oreillyit.nz/api"
|
||||
@@ -42,6 +43,7 @@ nodes:
|
||||
- id: tag-ai-resolve
|
||||
kind: script
|
||||
cmd: scripts/workflow/tag-set
|
||||
cp_write: true
|
||||
depends_on: [parent-link-check]
|
||||
on_fail: escalate
|
||||
runtime_env:
|
||||
@@ -52,6 +54,7 @@ nodes:
|
||||
- id: state-tx
|
||||
kind: script
|
||||
cmd: scripts/workflow/state-tx
|
||||
cp_write: true
|
||||
depends_on: [tag-ai-resolve]
|
||||
on_fail: escalate
|
||||
runtime_env:
|
||||
|
||||
@@ -23,6 +23,7 @@ nodes:
|
||||
- id: policy-pick
|
||||
kind: script
|
||||
cmd: scripts/workflow/policy-pick
|
||||
cp_write: false
|
||||
on_fail: escalate
|
||||
- id: agent
|
||||
kind: agent
|
||||
|
||||
@@ -18,10 +18,12 @@ nodes:
|
||||
- id: frozen-fixture-emit
|
||||
kind: script
|
||||
cmd: scripts/workflow/frozen-fixture-emit
|
||||
cp_write: false
|
||||
on_fail: refuse_dispatch
|
||||
- id: state-tx
|
||||
kind: script
|
||||
cmd: scripts/workflow/state-tx
|
||||
cp_write: true
|
||||
on_fail: continue
|
||||
runtime_env:
|
||||
CP_URL: "https://agents.oreillyit.nz/api"
|
||||
|
||||
@@ -119,6 +119,7 @@ nodes:
|
||||
- id: judge-gate
|
||||
kind: script
|
||||
cmd: scripts/workflow/verdict-gate
|
||||
cp_write: false
|
||||
depends_on: [judge-haiku]
|
||||
loop:
|
||||
body: [review-opus, review-minimax, improve-sonnet, judge-haiku, judge-gate]
|
||||
|
||||
@@ -129,6 +129,7 @@ nodes:
|
||||
- id: judge-gate
|
||||
kind: script
|
||||
cmd: scripts/workflow/verdict-gate
|
||||
cp_write: false
|
||||
depends_on: [judge-haiku]
|
||||
loop:
|
||||
body: [review-opus, review-minimax, improve-sonnet, judge-haiku, judge-gate]
|
||||
|
||||
@@ -18,18 +18,22 @@ nodes:
|
||||
- id: preflight-test-collection
|
||||
kind: script
|
||||
cmd: scripts/workflow/preflight-test-collection
|
||||
cp_write: false
|
||||
on_fail: refuse_dispatch
|
||||
- id: preflight-fixture-lint
|
||||
kind: script
|
||||
cmd: scripts/workflow/preflight-fixture-lint
|
||||
cp_write: false
|
||||
on_fail: refuse_dispatch
|
||||
- id: preflight-test-fail-mode
|
||||
kind: script
|
||||
cmd: scripts/workflow/preflight-test-fail-mode
|
||||
cp_write: false
|
||||
on_fail: continue
|
||||
- id: state-tx
|
||||
kind: script
|
||||
cmd: scripts/workflow/state-tx
|
||||
cp_write: true
|
||||
on_fail: continue
|
||||
runtime_env:
|
||||
CP_URL: "https://agents.oreillyit.nz/api"
|
||||
|
||||
@@ -61,6 +61,7 @@ nodes:
|
||||
- id: review-gate
|
||||
kind: script
|
||||
cmd: scripts/workflow/verdict-gate
|
||||
cp_write: false
|
||||
depends_on: [review-sonnet]
|
||||
loop:
|
||||
body: [write-minimax, review-sonnet, review-gate]
|
||||
|
||||
87
tests/invariants/test_cp_write_field_set_correctly.py
Normal file
87
tests/invariants/test_cp_write_field_set_correctly.py
Normal file
@@ -0,0 +1,87 @@
|
||||
"""Every shipped kind: script node declares cp_write explicitly (WF-COMP-31d).
|
||||
|
||||
``cp_write: true`` selects the workflow-script-write/v1 composite (AU-55
|
||||
per-step token); ``cp_write: false`` selects workflow-script-nocp/v1 (no CP
|
||||
credential). The declaration must match what the script actually does:
|
||||
state-tx / state-tx-verdict / tag-set write the run's own item (true); every
|
||||
other script, including parent-link-check and decompose-and-queue (whose
|
||||
routes the AU-57 credential cannot serve), is false.
|
||||
|
||||
Archived templates are included: the explicit declaration is the audit pin.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
import yaml
|
||||
|
||||
_DIR = Path(__file__).resolve().parents[2] / "task-templates"
|
||||
|
||||
_CP_WRITE_TRUE = {"state-tx", "state-tx-verdict", "tag-set"}
|
||||
_CP_WRITE_FALSE = {
|
||||
"verdict-gate", "policy-pick", "frozen-fixture-emit",
|
||||
"preflight-test-collection", "preflight-fixture-lint", "preflight-test-fail-mode",
|
||||
"parent-link-check", "decompose-and-queue",
|
||||
}
|
||||
|
||||
|
||||
def _script_nodes() -> list[tuple[str, str, dict]]:
|
||||
out = []
|
||||
for p in sorted(_DIR.rglob("*.yaml")):
|
||||
doc = yaml.safe_load(p.read_text()) or {}
|
||||
if not isinstance(doc, dict):
|
||||
continue
|
||||
for n in doc.get("nodes") or []:
|
||||
if isinstance(n, dict) and n.get("kind") == "script":
|
||||
out.append((str(p.relative_to(_DIR)), n["id"], n))
|
||||
return out
|
||||
|
||||
|
||||
_NODES = _script_nodes()
|
||||
_IDS = [f"{f}::{nid}" for f, nid, _ in _NODES]
|
||||
|
||||
|
||||
def test_script_nodes_discovered():
|
||||
files = {f for f, _, _ in _NODES}
|
||||
assert {
|
||||
"workflow/test-validate@1.yaml",
|
||||
"workflow/frozen-fixture-emit@1.yaml",
|
||||
"workflow/plan-review-loop@1.yaml",
|
||||
"workflow/spec-review-loop@1.yaml",
|
||||
"workflow/test-write-review-loop@1.yaml",
|
||||
"workflow/feature-delivery-loop@1.yaml",
|
||||
"workflow/_archived/bug-ancestor-auto-advance@1.yaml",
|
||||
} <= files
|
||||
|
||||
|
||||
@pytest.mark.parametrize("fname,nid,node", _NODES, ids=_IDS)
|
||||
def test_script_node_declares_cp_write_explicitly_and_correctly(fname, nid, node):
|
||||
assert "cp_write" in node, f"{fname}::{nid} must declare cp_write explicitly (WF-COMP-31d)"
|
||||
assert isinstance(node["cp_write"], bool), f"{fname}::{nid} cp_write must be a bool"
|
||||
script = node["cmd"].rsplit("/", 1)[-1]
|
||||
assert script in _CP_WRITE_TRUE | _CP_WRITE_FALSE, (
|
||||
f"{fname}::{nid} runs unclassified script {script!r}; classify it in "
|
||||
"this test (does it call the CP?) and AU-57 before shipping"
|
||||
)
|
||||
assert node["cp_write"] is (script in _CP_WRITE_TRUE), (
|
||||
f"{fname}::{nid}: cp_write must be {script in _CP_WRITE_TRUE} for {script}"
|
||||
)
|
||||
|
||||
|
||||
def test_wf_comp_31d_cp_write_field_audit_per_framework_template():
|
||||
"""Spec WF-COMP-31d framework-repo test handle: pin the declarations."""
|
||||
got = {(f, nid): n["cp_write"] for f, nid, n in _NODES}
|
||||
assert got[("workflow/test-validate@1.yaml", "state-tx")] is True
|
||||
assert got[("workflow/frozen-fixture-emit@1.yaml", "state-tx")] is True
|
||||
assert got[("workflow/frozen-fixture-emit@1.yaml", "frozen-fixture-emit")] is False
|
||||
for nid in ("preflight-test-collection", "preflight-fixture-lint", "preflight-test-fail-mode"):
|
||||
assert got[("workflow/test-validate@1.yaml", nid)] is False
|
||||
assert got[("workflow/plan-review-loop@1.yaml", "judge-gate")] is False
|
||||
assert got[("workflow/spec-review-loop@1.yaml", "judge-gate")] is False
|
||||
assert got[("workflow/test-write-review-loop@1.yaml", "review-gate")] is False
|
||||
assert got[("workflow/feature-delivery-loop@1.yaml", "policy-pick")] is False
|
||||
arch = "workflow/_archived/bug-ancestor-auto-advance@1.yaml"
|
||||
assert got[(arch, "parent-link-check")] is False
|
||||
assert got[(arch, "tag-ai-resolve")] is True
|
||||
assert got[(arch, "state-tx")] is True
|
||||
Reference in New Issue
Block a user