mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-25 17:45:53 +01:00
test(runner): reconcile phase 5 status fixtures
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
164e44ef4e
commit
1daa51d9eb
3 files changed
+33
-8
No files matched your search
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema": "paperclip.status-authority-conformance.v1",
|
||||
"corpusRevision": 1,
|
||||
"corpusRevision": 2,
|
||||
"policyVersion": "status-authority-v1",
|
||||
"fixtures": [
|
||||
{
|
||||
@@ -143,7 +143,7 @@
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": ["SD-11"], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["required_review"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "needs_review", "nativeFinalization": "present", "completionState": "intentional_human_judgment", "trigger": "attention_candidate" },
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "needs_review", "nativeFinalization": "present", "completionState": "intentional_human_judgment", "reviewGate": "completion", "trigger": "attention_candidate" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "in_review", "reasonCode": "attention_requires_human_authority", "requiredEffects": ["create_interaction", "notify_owner"], "forbiddenEffects": ["bind_blocker"], "livePathKind": "interaction", "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 1, "maxNotificationCount": 1 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
@@ -153,8 +153,8 @@
|
||||
"covers": { "decisionRows": ["SD-12"], "terminalRows": [], "attentionRows": ["ATT-02", "ATT-03"], "livenessRows": [], "reconciliationRows": ["REC-02"], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["repeated_question", "excessive_human_request", "deterministic_replay"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "yielded", "nativeFinalization": "present", "completionState": "equivalent_attention_family", "trigger": "attention_candidate" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "preserve", "reasonCode": "attention_duplicate_suppressed", "requiredEffects": ["link_canonical_request"], "forbiddenEffects": ["create_interaction", "notify_owner", "enqueue_continuation"], "livePathKind": null, "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 6, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "preserve", "reasonCode": "attention_duplicate_suppressed", "requiredEffects": ["link_canonical_request"], "forbiddenEffects": ["create_interaction", "notify_owner", "enqueue_continuation"], "livePathKind": null, "preserveClaim": true, "nativeRecords": true, "decisionCount": 0, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 6, "sameDecisionDigest": true, "maxSemanticDecisions": 0, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "attention-budget-exhausted",
|
||||
|
||||
@@ -4915,6 +4915,7 @@ interface StatusAuthorityConformanceFixtureV1 {
|
||||
reportedWorkDisposition: ReportedWorkDisposition | null;
|
||||
nativeFinalization: "present" | "missing" | "invalid" | "not_applicable";
|
||||
completionState: string;
|
||||
reviewGate?: "completion" | "mid_work";
|
||||
trigger: string;
|
||||
fault?: string;
|
||||
};
|
||||
@@ -4943,6 +4944,14 @@ interface StatusAuthorityConformanceFixtureV1 {
|
||||
}
|
||||
```
|
||||
|
||||
`reviewGate` disambiguates an intentional human-judgment interaction that gates
|
||||
completion from one raised while productive work remains. A completion gate may
|
||||
resolve to `in_review` under SD-11; a mid-work interaction still requires the
|
||||
response-wake or preserve branches from that row. `decisionCount` counts status
|
||||
decisions newly persisted for the fixture stimulus. Linking an equivalent
|
||||
request to a pre-existing canonical family does not count that family's earlier
|
||||
decision.
|
||||
|
||||
Fixture assertions are database assertions, not only response assertions. Every
|
||||
case records the terminal turn/run facts, original result/evidence retention,
|
||||
issue `status` and `status_version`, contract/policy version, assessment and
|
||||
|
||||
@@ -121,6 +121,9 @@ check("fixture IDs and required fields are valid", () => {
|
||||
if (!fixture.given || requiredGiven.some((key) => !(key in fixture.given))) {
|
||||
throw new Error(`${fixture.id}: incomplete given facts`);
|
||||
}
|
||||
if (fixture.given.reviewGate !== undefined && !["completion", "mid_work"].includes(fixture.given.reviewGate)) {
|
||||
throw new Error(`${fixture.id}: invalid reviewGate`);
|
||||
}
|
||||
if (!fixture.expected || requiredExpected.some((key) => !(key in fixture.expected))) {
|
||||
throw new Error(`${fixture.id}: incomplete expected facts`);
|
||||
}
|
||||
@@ -208,16 +211,29 @@ check("non-terminal status fixtures carry an atomic liveness path", () => {
|
||||
return "in_review, blocked, and in_progress paths validated";
|
||||
});
|
||||
|
||||
check("duplicate attention cannot create an unbounded loop", () => {
|
||||
check("duplicate attention creates no status decision or unbounded loop", () => {
|
||||
const duplicates = corpus.fixtures.filter((fixture) => fixture.expected.reasonCode === "attention_duplicate_suppressed");
|
||||
if (duplicates.length === 0) throw new Error("no duplicate-attention fixture");
|
||||
const unsafe = duplicates.filter((fixture) =>
|
||||
fixture.expected.decisionCount !== 0 ||
|
||||
fixture.expected.maxWakeCount !== 0 ||
|
||||
fixture.expected.maxNotificationCount !== 0 ||
|
||||
fixture.replay.maxSemanticDecisions > 1 ||
|
||||
fixture.replay.maxSemanticDecisions !== 0 ||
|
||||
fixture.replay.maxDomainEffectsPerKey > 1);
|
||||
if (unsafe.length) throw new Error(`unbounded duplicate fixture(s): ${unsafe.map((fixture) => fixture.id).join(", ")}`);
|
||||
return `${duplicates.length} duplicate fixture(s) bounded at zero wakes/notifications`;
|
||||
if (unsafe.length) throw new Error(`unsafe duplicate fixture(s): ${unsafe.map((fixture) => fixture.id).join(", ")}`);
|
||||
return `${duplicates.length} duplicate fixture(s) bounded at zero decisions/wakes/notifications`;
|
||||
});
|
||||
|
||||
check("completion-gating human judgment is explicit", () => {
|
||||
const fixture = corpus.fixtures.find((candidate) => candidate.id === "human-authority-required");
|
||||
if (!fixture) throw new Error("missing human-authority-required fixture");
|
||||
if (!fixture.covers.decisionRows.includes("SD-11") ||
|
||||
fixture.given.completionState !== "intentional_human_judgment" ||
|
||||
fixture.given.reviewGate !== "completion" ||
|
||||
fixture.expected.statusAction !== "in_review") {
|
||||
throw new Error("human-authority-required does not pin the SD-11 completion-review branch");
|
||||
}
|
||||
return "human-authority-required pins reviewGate=completion";
|
||||
});
|
||||
|
||||
check("replay effects are at-most-once per semantic key", () => {
|
||||
|
||||
Reference in new issue
Block a user