mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-25 17:45:53 +01:00
docs(runner): add status authority phase 5 conformance
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
56606e1d16
commit
9349db8438
5 files changed
+1069
-45
No files matched your search
@@ -42,6 +42,7 @@
|
||||
"check:token-gates": "node scripts/check-token-gates.mjs",
|
||||
"check:no-git-push": "node scripts/check-no-git-push.mjs",
|
||||
"check:runner-phase4-spec": "node scripts/check-runner-phase4-spec.mjs",
|
||||
"check:runner-phase5-spec": "node scripts/check-runner-phase5-spec.mjs",
|
||||
"test:check-no-git-push": "node --test scripts/check-no-git-push.test.mjs",
|
||||
"test:install-sh-docker": "./scripts/test-install-sh-docker.sh",
|
||||
"test:hermes-gateway-smoke": "node --test scripts/smoke/hermes-gateway-smoke.test.mjs",
|
||||
|
||||
@@ -0,0 +1,475 @@
|
||||
{
|
||||
"schema": "paperclip.status-authority-conformance.v1",
|
||||
"corpusRevision": 1,
|
||||
"policyVersion": "status-authority-v1",
|
||||
"fixtures": [
|
||||
{
|
||||
"id": "native-mechanical-completion",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": ["SD-01"], "terminalRows": ["TC-01"], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["deterministic_replay"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "done", "nativeFinalization": "present", "completionState": "mechanically_satisfied", "trigger": "runner_finalizer" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "done", "reasonCode": "completion_contract_satisfied", "requiredEffects": ["release_checkout"], "forbiddenEffects": ["bind_reviewer", "bind_blocker"], "livePathKind": null, "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "native-low-risk-policy-claim",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": ["SD-02"], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["native_legacy_distinction"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "done", "nativeFinalization": "present", "completionState": "low_risk_policy_claim", "trigger": "runner_finalizer" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "done", "reasonCode": "completion_claim_policy_accepted", "requiredEffects": ["release_checkout"], "forbiddenEffects": ["create_interaction"], "livePathKind": null, "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "premature-done-missing-evidence",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": ["SD-03"], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["premature_done_claim", "incomplete_evidence", "partial_progress", "atomic_liveness"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "done", "nativeFinalization": "present", "completionState": "missing_required_test", "trigger": "runner_finalizer" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "in_progress", "reasonCode": "completion_evidence_incomplete", "requiredEffects": ["enqueue_continuation"], "forbiddenEffects": ["release_checkout_as_done"], "livePathKind": "continuation", "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 1, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "incomplete-evidence-no-live-path",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": ["SD-03"], "terminalRows": [], "attentionRows": [], "livenessRows": ["LIVE-06"], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["incomplete_evidence", "atomic_liveness"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "done", "nativeFinalization": "present", "completionState": "missing_required_test", "trigger": "runner_finalizer", "fault": "continuation_insert_failure" },
|
||||
"expected": { "runStatus": "failed", "statusAction": "preserve", "reasonCode": "side_effect_planning_failed", "requiredEffects": ["record_finalization_error"], "forbiddenEffects": ["enqueue_continuation", "status_version_increment"], "livePathKind": null, "preserveClaim": true, "nativeRecords": true, "decisionCount": 0, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "prior-status-preserved-without-live-path",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["atomic_liveness", "reconciliation"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "yielded", "nativeFinalization": "present", "completionState": "no_durable_continuation", "trigger": "runner_finalizer" },
|
||||
"expected": { "runStatus": "failed", "statusAction": "preserve", "reasonCode": "prior_status_preserved_no_live_path", "requiredEffects": ["record_finalization_error"], "forbiddenEffects": ["set_issue_status", "enqueue_continuation", "bind_blocker", "bind_reviewer"], "livePathKind": "recovery", "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 1, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "required-subjective-review",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": ["SD-04"], "terminalRows": [], "attentionRows": [], "livenessRows": ["LIVE-01"], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["required_review", "atomic_liveness"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "needs_review", "nativeFinalization": "present", "completionState": "named_reviewer_required", "trigger": "runner_finalizer" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "in_review", "reasonCode": "completion_review_required", "requiredEffects": ["bind_reviewer", "notify_owner"], "forbiddenEffects": ["bind_blocker"], "livePathKind": "review", "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 1, "maxNotificationCount": 1 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "required-governed-review",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": ["SD-04"], "terminalRows": [], "attentionRows": ["ATT-08"], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["required_review", "excessive_human_request"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "needs_review", "nativeFinalization": "present", "completionState": "governed_gate_pending", "trigger": "runner_finalizer" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "in_review", "reasonCode": "governed_gate_pending", "requiredEffects": ["create_interaction", "notify_owner"], "forbiddenEffects": ["attention_routed_to_agent"], "livePathKind": "interaction", "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 1, "maxNotificationCount": 1 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "review-side-effect-rollback",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": [], "livenessRows": ["LIVE-02"], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["required_review", "atomic_liveness"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "needs_review", "nativeFinalization": "present", "completionState": "review_required", "trigger": "runner_finalizer", "fault": "reviewer_insert_failure" },
|
||||
"expected": { "runStatus": "failed", "statusAction": "preserve", "reasonCode": "side_effect_planning_failed", "requiredEffects": ["record_finalization_error"], "forbiddenEffects": ["bind_reviewer", "notify_owner", "status_version_increment"], "livePathKind": null, "preserveClaim": true, "nativeRecords": true, "decisionCount": 0, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "invalid-native-result",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": ["SD-05"], "terminalRows": ["TC-08"], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": ["COMP-02"], "migrationRows": [] },
|
||||
"tags": ["native_legacy_distinction", "reconciliation"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": null, "nativeFinalization": "invalid", "completionState": "safe_partial_parse", "trigger": "runner_finalizer" },
|
||||
"expected": { "runStatus": "failed", "statusAction": "preserve", "reasonCode": "native_finalization_invalid", "requiredEffects": ["record_finalization_error"], "forbiddenEffects": ["legacy_finalizer", "bind_blocker", "bind_reviewer"], "livePathKind": "recovery", "preserveClaim": true, "nativeRecords": true, "decisionCount": 0, "maxWakeCount": 1, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "valid-yielded-continuation",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": ["SD-06"], "terminalRows": ["TC-05"], "attentionRows": [], "livenessRows": ["LIVE-05"], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["continuation", "partial_progress", "atomic_liveness"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "interrupted", "runTerminalState": "succeeded", "reportedWorkDisposition": "yielded", "nativeFinalization": "present", "completionState": "valid_continuation", "trigger": "runner_finalizer" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "in_progress", "reasonCode": "live_continuation_registered", "requiredEffects": ["enqueue_continuation"], "forbiddenEffects": ["bind_blocker"], "livePathKind": "continuation", "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 1, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 3, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "false-task-wide-blocker",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": ["SD-07"], "terminalRows": [], "attentionRows": ["ATT-05"], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["false_blocker", "excessive_human_request", "continuation"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "blocked", "nativeFinalization": "present", "completionState": "alternate_track_runnable", "trigger": "runner_finalizer" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "in_progress", "reasonCode": "turn_waiting_other_track_live", "requiredEffects": ["enqueue_continuation"], "forbiddenEffects": ["bind_blocker", "create_interaction"], "livePathKind": "continuation", "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 1, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "real-task-wide-blocker",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": ["SD-08"], "terminalRows": [], "attentionRows": [], "livenessRows": ["LIVE-03"], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["real_blocker", "atomic_liveness"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "blocked", "nativeFinalization": "present", "completionState": "task_wide_owner_action_bound", "trigger": "runner_finalizer" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "blocked", "reasonCode": "task_wide_blocker_bound", "requiredEffects": ["bind_blocker", "notify_owner"], "forbiddenEffects": ["enqueue_continuation"], "livePathKind": "blocker", "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 1, "maxNotificationCount": 1 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "blocker-side-effect-rollback",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": [], "livenessRows": ["LIVE-04"], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["real_blocker", "atomic_liveness"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "blocked", "nativeFinalization": "present", "completionState": "task_wide_owner_action_bound", "trigger": "runner_finalizer", "fault": "blocker_insert_failure" },
|
||||
"expected": { "runStatus": "failed", "statusAction": "preserve", "reasonCode": "side_effect_planning_failed", "requiredEffects": ["record_finalization_error"], "forbiddenEffects": ["bind_blocker", "notify_owner", "status_version_increment"], "livePathKind": null, "preserveClaim": true, "nativeRecords": true, "decisionCount": 0, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "question-resolved-from-context",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": ["SD-09"], "terminalRows": [], "attentionRows": ["ATT-01"], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["excessive_human_request", "repeated_question"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "yielded", "nativeFinalization": "present", "completionState": "context_answer_current", "trigger": "attention_response" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "in_progress", "reasonCode": "attention_resolved_from_context", "requiredEffects": ["enqueue_continuation"], "forbiddenEffects": ["create_interaction", "notify_owner"], "livePathKind": "continuation", "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 1, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "human-request-routed-to-agent",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": ["SD-10"], "terminalRows": [], "attentionRows": ["ATT-04"], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["excessive_human_request"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "yielded", "nativeFinalization": "present", "completionState": "ordinary_domain_expertise", "trigger": "attention_candidate" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "in_progress", "reasonCode": "attention_routed_to_agent", "requiredEffects": ["create_delegated_issue", "enqueue_continuation"], "forbiddenEffects": ["create_interaction"], "livePathKind": "delegated_issue", "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 1, "maxNotificationCount": 1 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "human-authority-required",
|
||||
"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" },
|
||||
"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 }
|
||||
},
|
||||
{
|
||||
"id": "duplicate-and-fresh-key-question",
|
||||
"mode": "native",
|
||||
"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 }
|
||||
},
|
||||
{
|
||||
"id": "attention-budget-exhausted",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": ["SD-13"], "terminalRows": [], "attentionRows": ["ATT-07", "ATT-12"], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["excessive_human_request", "repeated_question", "reconciliation"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "yielded", "nativeFinalization": "present", "completionState": "resolver_budget_exhausted", "trigger": "attention_candidate" },
|
||||
"expected": { "runStatus": "failed", "statusAction": "preserve", "reasonCode": "attention_budget_exhausted", "requiredEffects": ["record_finalization_error"], "forbiddenEffects": ["create_interaction", "bind_blocker", "bind_reviewer"], "livePathKind": "recovery", "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 1, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 8, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "failed-run-partial-evidence",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": ["SD-14"], "terminalRows": ["TC-02"], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["partial_progress", "partial_evidence_before_failure"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "failed", "runTerminalState": "failed", "reportedWorkDisposition": "yielded", "nativeFinalization": "present", "completionState": "partial_evidence_persisted", "trigger": "runner_finalizer" },
|
||||
"expected": { "runStatus": "failed", "statusAction": "preserve", "reasonCode": "run_failed_partial_evidence_preserved", "requiredEffects": ["schedule_retry"], "forbiddenEffects": ["release_checkout_as_done"], "livePathKind": "retry", "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 1, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "completion-report-finalization-failure",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": ["SD-15"], "terminalRows": ["TC-03"], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["finalization_failure", "partial_evidence_before_failure", "reconciliation"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "failed", "reportedWorkDisposition": "done", "nativeFinalization": "present", "completionState": "claim_before_workspace_failure", "trigger": "runner_finalizer", "fault": "workspace_finalize_failure" },
|
||||
"expected": { "runStatus": "failed", "statusAction": "preserve", "reasonCode": "finalization_failed_claim_preserved", "requiredEffects": ["record_finalization_error"], "forbiddenEffects": ["release_checkout_as_done"], "livePathKind": "recovery", "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 1, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "turn-only-cancellation",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": ["SD-16"], "terminalRows": ["TC-06"], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["cancellation_scope"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "cancelled", "runTerminalState": "active", "reportedWorkDisposition": null, "nativeFinalization": "present", "completionState": "turn_scope", "trigger": "authorized_agent" },
|
||||
"expected": { "runStatus": "running", "statusAction": "preserve", "reasonCode": "cancellation_turn_only", "requiredEffects": ["accept_replacement_turn"], "forbiddenEffects": ["cancel_issue", "release_run_resources"], "livePathKind": "continuation", "preserveClaim": false, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "run-only-cancellation",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": ["SD-17"], "terminalRows": ["TC-06"], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["cancellation_scope"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "cancelled", "runTerminalState": "cancelled", "reportedWorkDisposition": null, "nativeFinalization": "present", "completionState": "run_scope", "trigger": "authorized_agent" },
|
||||
"expected": { "runStatus": "cancelled", "statusAction": "preserve", "reasonCode": "cancellation_run_only", "requiredEffects": ["release_run_resources"], "forbiddenEffects": ["cancel_issue"], "livePathKind": null, "preserveClaim": false, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "issue-cancellation-authorized",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": ["SD-18"], "terminalRows": ["TC-07"], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["cancellation_scope"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "cancelled", "runTerminalState": "cancelled", "reportedWorkDisposition": null, "nativeFinalization": "present", "completionState": "issue_scope_authorized", "trigger": "board_user" },
|
||||
"expected": { "runStatus": "cancelled", "statusAction": "cancelled", "reasonCode": "cancellation_issue_authorized", "requiredEffects": ["release_checkout", "cancel_continuations"], "forbiddenEffects": ["authorized_resume"], "livePathKind": null, "preserveClaim": false, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 0, "maxNotificationCount": 1 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "new-evidence-supersedes-decision",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": ["SD-19"], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": ["REC-07"], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["supersession", "deterministic_replay", "reconciliation"],
|
||||
"given": { "priorIssueStatus": "in_review", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "done", "nativeFinalization": "present", "completionState": "new_evidence_satisfies_contract", "trigger": "interaction" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "done", "reasonCode": "decision_superseded_by_new_evidence", "requiredEffects": ["release_checkout"], "forbiddenEffects": ["replay_superseded_effect"], "livePathKind": null, "preserveClaim": true, "nativeRecords": true, "decisionCount": 2, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 3, "sameDecisionDigest": false, "maxSemanticDecisions": 2, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "dependency-resolution-supersession",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": ["SD-19"], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["supersession", "continuation"],
|
||||
"given": { "priorIssueStatus": "blocked", "turnTerminalState": null, "runTerminalState": null, "reportedWorkDisposition": "blocked", "nativeFinalization": "present", "completionState": "dependency_now_done", "trigger": "dependency" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "in_progress", "reasonCode": "dependency_resolved", "requiredEffects": ["enqueue_continuation"], "forbiddenEffects": ["duplicate_dependency_wake"], "livePathKind": "continuation", "preserveClaim": true, "nativeRecords": true, "decisionCount": 2, "maxWakeCount": 1, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 3, "sameDecisionDigest": false, "maxSemanticDecisions": 2, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "authorized-resume-terminal-issue",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": ["SD-19"], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": ["COMP-05"], "migrationRows": [] },
|
||||
"tags": ["authorized_resume", "supersession", "existing_issue_state"],
|
||||
"given": { "priorIssueStatus": "done", "turnTerminalState": null, "runTerminalState": null, "reportedWorkDisposition": null, "nativeFinalization": "present", "completionState": "explicit_resume_capability", "trigger": "board_user" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "in_progress", "reasonCode": "authorized_resume", "requiredEffects": ["enqueue_continuation"], "forbiddenEffects": ["late_result_reopen"], "livePathKind": "continuation", "preserveClaim": false, "nativeRecords": true, "decisionCount": 2, "maxWakeCount": 1, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": false, "maxSemanticDecisions": 2, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "interrupted-active-run",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": [], "terminalRows": ["TC-04"], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["continuation"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "interrupted", "runTerminalState": "active", "reportedWorkDisposition": null, "nativeFinalization": "present", "completionState": "replacement_turn_accepted", "trigger": "runner_finalizer" },
|
||||
"expected": { "runStatus": "running", "statusAction": "preserve", "reasonCode": null, "requiredEffects": ["accept_replacement_turn"], "forbiddenEffects": ["finalize_run", "set_issue_status"], "livePathKind": "continuation", "preserveClaim": false, "nativeRecords": true, "decisionCount": 0, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 0, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "retry-succeeds-before-escalation",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": ["ATT-06"], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["excessive_human_request"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "yielded", "nativeFinalization": "present", "completionState": "transient_retry_then_success", "trigger": "attention_candidate" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "in_progress", "reasonCode": "attention_resolved_from_context", "requiredEffects": ["enqueue_continuation"], "forbiddenEffects": ["create_delegated_issue", "create_interaction"], "livePathKind": "continuation", "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 1, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "cross-company-attention-rejected",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": ["ATT-09"], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["excessive_human_request"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "yielded", "nativeFinalization": "present", "completionState": "cross_company_target", "trigger": "attention_candidate" },
|
||||
"expected": { "runStatus": "failed", "statusAction": "preserve", "reasonCode": "result_schema_rejected", "requiredEffects": ["record_finalization_error"], "forbiddenEffects": ["create_interaction", "notify_owner", "enqueue_continuation"], "livePathKind": null, "preserveClaim": true, "nativeRecords": true, "decisionCount": 0, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 0, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "stale-attention-response",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": ["ATT-10"], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["supersession", "repeated_question"],
|
||||
"given": { "priorIssueStatus": "in_review", "turnTerminalState": null, "runTerminalState": null, "reportedWorkDisposition": null, "nativeFinalization": "present", "completionState": "response_after_supersession", "trigger": "interaction" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "preserve", "reasonCode": "attention_duplicate_suppressed", "requiredEffects": ["record_stale_response"], "forbiddenEffects": ["enqueue_continuation", "set_issue_status"], "livePathKind": null, "preserveClaim": false, "nativeRecords": true, "decisionCount": 0, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 3, "sameDecisionDigest": true, "maxSemanticDecisions": 0, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "expired-human-interaction",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": ["ATT-11"], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["repeated_question", "excessive_human_request"],
|
||||
"given": { "priorIssueStatus": "in_review", "turnTerminalState": null, "runTerminalState": null, "reportedWorkDisposition": null, "nativeFinalization": "present", "completionState": "interaction_expired", "trigger": "monitor" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "preserve", "reasonCode": "attention_budget_exhausted", "requiredEffects": ["record_expiry"], "forbiddenEffects": ["recreate_equivalent_interaction"], "livePathKind": "recovery", "preserveClaim": false, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 1, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 3, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "identical-result-replay",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": ["REC-01"], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["deterministic_replay"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "done", "nativeFinalization": "present", "completionState": "identical_result_before_ack", "trigger": "runner_finalizer" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "done", "reasonCode": "completion_contract_satisfied", "requiredEffects": ["release_checkout"], "forbiddenEffects": ["duplicate_decision", "duplicate_effect"], "livePathKind": null, "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 3, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "caller-id-mutation-conflict",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": ["REC-03"], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["deterministic_replay"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "done", "nativeFinalization": "present", "completionState": "reused_id_changed_material", "trigger": "runner_finalizer" },
|
||||
"expected": { "runStatus": "failed", "statusAction": "preserve", "reasonCode": "structured_result_replay_conflict", "requiredEffects": ["record_finalization_error"], "forbiddenEffects": ["set_issue_status", "notify_owner", "enqueue_continuation"], "livePathKind": null, "preserveClaim": true, "nativeRecords": true, "decisionCount": 0, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 0, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "crash-before-workspace-finalization",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": ["REC-04"], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["reconciliation", "deterministic_replay", "finalization_failure"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "done", "nativeFinalization": "present", "completionState": "result_preserved", "trigger": "runner_finalizer", "fault": "crash_before_workspace_finalize" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "done", "reasonCode": "completion_contract_satisfied", "requiredEffects": ["resume_workspace_operation", "release_checkout"], "forbiddenEffects": ["duplicate_workspace_finalize"], "livePathKind": null, "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 3, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "crash-after-decision-commit",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": ["REC-05"], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["reconciliation", "deterministic_replay"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "yielded", "nativeFinalization": "present", "completionState": "decision_committed_delivery_pending", "trigger": "runner_finalizer", "fault": "crash_before_outbox_ack" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "in_progress", "reasonCode": "live_continuation_registered", "requiredEffects": ["enqueue_continuation", "dispatch_pending_effect"], "forbiddenEffects": ["re_arbitrate", "duplicate_continuation"], "livePathKind": "continuation", "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 1, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 3, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "board-wins-finalizer-race",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": ["REC-06"], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["supersession", "reconciliation"],
|
||||
"given": { "priorIssueStatus": "cancelled", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "done", "nativeFinalization": "present", "completionState": "board_cancelled_before_cas", "trigger": "runner_finalizer" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "preserve", "reasonCode": "prior_status_terminal_preserved", "requiredEffects": ["append_superseding_assessment"], "forbiddenEffects": ["reopen_issue", "release_checkout_as_done"], "livePathKind": null, "preserveClaim": true, "nativeRecords": true, "decisionCount": 2, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": false, "maxSemanticDecisions": 2, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "policy-version-changes-before-replay",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": ["REC-08"], "compatibilityRows": [], "migrationRows": [] },
|
||||
"tags": ["supersession", "reconciliation", "deterministic_replay"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "done", "nativeFinalization": "present", "completionState": "new_policy_requires_review", "trigger": "authorized_agent" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "in_review", "reasonCode": "completion_review_required", "requiredEffects": ["bind_reviewer", "append_superseding_assessment"], "forbiddenEffects": ["mutate_old_decision"], "livePathKind": "review", "preserveClaim": true, "nativeRecords": true, "decisionCount": 2, "maxWakeCount": 1, "maxNotificationCount": 1 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": false, "maxSemanticDecisions": 2, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "legacy-adapter-unchanged",
|
||||
"mode": "legacy",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": ["COMP-01", "COMP-07"], "migrationRows": [] },
|
||||
"tags": ["native_legacy_distinction"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": null, "runTerminalState": null, "reportedWorkDisposition": null, "nativeFinalization": "not_applicable", "completionState": "legacy_exit_zero", "trigger": "legacy_finalizer" },
|
||||
"expected": { "runStatus": "legacy_derived", "statusAction": "legacy_finalizer", "reasonCode": null, "requiredEffects": ["legacy_existing_behavior"], "forbiddenEffects": ["create_completion_contract", "create_work_assessment", "create_status_decision"], "livePathKind": null, "preserveClaim": false, "nativeRecords": false, "decisionCount": 0, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 0, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "model-authored-native-field-ignored",
|
||||
"mode": "legacy",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": ["COMP-03"], "migrationRows": [] },
|
||||
"tags": ["native_legacy_distinction"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": null, "runTerminalState": null, "reportedWorkDisposition": null, "nativeFinalization": "not_applicable", "completionState": "native_field_only_in_result_json", "trigger": "legacy_finalizer" },
|
||||
"expected": { "runStatus": "legacy_derived", "statusAction": "legacy_finalizer", "reasonCode": null, "requiredEffects": ["legacy_existing_behavior"], "forbiddenEffects": ["select_native_mode", "create_work_assessment"], "livePathKind": null, "preserveClaim": false, "nativeRecords": false, "decisionCount": 0, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 0, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "existing-open-issues-expand-only",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": ["COMP-04"], "migrationRows": [] },
|
||||
"tags": ["existing_issue_state"],
|
||||
"given": { "priorIssueStatus": "in_review", "turnTerminalState": null, "runTerminalState": null, "reportedWorkDisposition": null, "nativeFinalization": "missing", "completionState": "preexisting_open_issue", "trigger": "migration" },
|
||||
"expected": { "runStatus": "running", "statusAction": "preserve", "reasonCode": null, "requiredEffects": ["initialize_status_version_zero"], "forbiddenEffects": ["synthesize_contract", "synthesize_decision", "change_liveness_path"], "livePathKind": "review", "preserveClaim": false, "nativeRecords": false, "decisionCount": 0, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 0, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "shadow-records-remain-unapplied",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": ["COMP-06"], "migrationRows": [] },
|
||||
"tags": ["native_legacy_distinction", "rollback"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "done", "nativeFinalization": "present", "completionState": "shadow_application_disabled", "trigger": "runner_finalizer" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "preserve", "reasonCode": "completion_contract_satisfied", "requiredEffects": ["record_shadow_decision"], "forbiddenEffects": ["set_issue_status", "dispatch_effect"], "livePathKind": null, "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "mixed-ledger-native-legacy",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": ["COMP-07"], "migrationRows": [] },
|
||||
"tags": ["native_legacy_distinction"],
|
||||
"given": { "priorIssueStatus": "done", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "done", "nativeFinalization": "present", "completionState": "mixed_ledger", "trigger": "read_model" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "preserve", "reasonCode": "completion_contract_satisfied", "requiredEffects": ["render_four_layers"], "forbiddenEffects": ["decorate_legacy_row", "aggregate_modes"], "livePathKind": null, "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "authorized-writer-version-race",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": ["COMP-08"], "migrationRows": [] },
|
||||
"tags": ["existing_issue_state", "reconciliation"],
|
||||
"given": { "priorIssueStatus": "in_review", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "done", "nativeFinalization": "present", "completionState": "authorized_writer_incremented_version", "trigger": "board_user" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "preserve", "reasonCode": "arbitration_conflict_reloaded", "requiredEffects": ["increment_status_version", "schedule_reconciliation"], "forbiddenEffects": ["apply_stale_decision"], "livePathKind": "recovery", "preserveClaim": true, "nativeRecords": true, "decisionCount": 2, "maxWakeCount": 1, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": false, "maxSemanticDecisions": 2, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "migration-expand-schema",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": ["MIG-01"] },
|
||||
"tags": ["existing_issue_state", "rollback"],
|
||||
"given": { "priorIssueStatus": "todo", "turnTerminalState": null, "runTerminalState": null, "reportedWorkDisposition": null, "nativeFinalization": "missing", "completionState": "production_shaped_upgrade", "trigger": "migration" },
|
||||
"expected": { "runStatus": "running", "statusAction": "preserve", "reasonCode": null, "requiredEffects": ["expand_schema", "status_version_default_zero"], "forbiddenEffects": ["rewrite_issue", "synthesize_history"], "livePathKind": null, "preserveClaim": false, "nativeRecords": false, "decisionCount": 0, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 0, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "migration-version-all-writers",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": ["MIG-02"] },
|
||||
"tags": ["existing_issue_state"],
|
||||
"given": { "priorIssueStatus": "todo", "turnTerminalState": null, "runTerminalState": null, "reportedWorkDisposition": null, "nativeFinalization": "missing", "completionState": "authorized_status_write", "trigger": "board_user" },
|
||||
"expected": { "runStatus": "running", "statusAction": "in_review", "reasonCode": null, "requiredEffects": ["increment_status_version_once", "bind_reviewer"], "forbiddenEffects": ["double_increment"], "livePathKind": "review", "preserveClaim": false, "nativeRecords": false, "decisionCount": 0, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 1, "sameDecisionDigest": true, "maxSemanticDecisions": 0, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "migration-read-only-compatibility",
|
||||
"mode": "legacy",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": ["MIG-03"] },
|
||||
"tags": ["native_legacy_distinction"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": null, "runTerminalState": null, "reportedWorkDisposition": null, "nativeFinalization": "not_applicable", "completionState": "no_native_rows", "trigger": "read_model" },
|
||||
"expected": { "runStatus": "legacy_derived", "statusAction": "legacy_finalizer", "reasonCode": null, "requiredEffects": ["return_native_false"], "forbiddenEffects": ["read_error", "native_ui_decoration"], "livePathKind": null, "preserveClaim": false, "nativeRecords": false, "decisionCount": 0, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 0, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "migration-shadow-materialization",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": ["MIG-04"] },
|
||||
"tags": ["native_legacy_distinction", "deterministic_replay"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "done", "nativeFinalization": "present", "completionState": "shadow_compute", "trigger": "runner_finalizer" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "preserve", "reasonCode": "completion_contract_satisfied", "requiredEffects": ["materialize_contract", "record_shadow_decision"], "forbiddenEffects": ["set_issue_status", "dispatch_effect"], "livePathKind": null, "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "migration-shadow-comparison",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": ["MIG-05"] },
|
||||
"tags": ["native_legacy_distinction", "deterministic_replay"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "done", "nativeFinalization": "present", "completionState": "classified_native_legacy_divergence", "trigger": "shadow_comparator" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "preserve", "reasonCode": "completion_evidence_incomplete", "requiredEffects": ["record_mode_labeled_divergence"], "forbiddenEffects": ["apply_shadow_decision", "aggregate_modes"], "livePathKind": null, "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "migration-internal-canary",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": ["MIG-06"] },
|
||||
"tags": ["atomic_liveness", "native_legacy_distinction"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "yielded", "nativeFinalization": "present", "completionState": "allowlisted_company_adapter_policy", "trigger": "runner_finalizer" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "in_progress", "reasonCode": "live_continuation_registered", "requiredEffects": ["enqueue_continuation", "record_mode_native"], "forbiddenEffects": ["mode_switch_mid_run"], "livePathKind": "continuation", "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 1, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "migration-cohort-rollout",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": ["MIG-07"] },
|
||||
"tags": ["reconciliation", "native_legacy_distinction"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "done", "nativeFinalization": "present", "completionState": "cohort_policy_pinned", "trigger": "runner_finalizer" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "done", "reasonCode": "completion_contract_satisfied", "requiredEffects": ["record_mode_native", "record_policy_version"], "forbiddenEffects": ["latest_policy_rebind"], "livePathKind": null, "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "migration-kill-switch-rollback",
|
||||
"mode": "native",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": ["MIG-08"] },
|
||||
"tags": ["rollback", "native_legacy_distinction", "reconciliation"],
|
||||
"given": { "priorIssueStatus": "in_progress", "turnTerminalState": "completed", "runTerminalState": "succeeded", "reportedWorkDisposition": "yielded", "nativeFinalization": "present", "completionState": "kill_switch_during_active_native_run", "trigger": "runner_finalizer" },
|
||||
"expected": { "runStatus": "succeeded", "statusAction": "in_progress", "reasonCode": "live_continuation_registered", "requiredEffects": ["enqueue_continuation", "finish_as_native", "stop_new_native_dispatch"], "forbiddenEffects": ["convert_active_run_to_legacy", "drop_coordinator"], "livePathKind": "continuation", "preserveClaim": true, "nativeRecords": true, "decisionCount": 1, "maxWakeCount": 1, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 3, "sameDecisionDigest": true, "maxSemanticDecisions": 1, "maxDomainEffectsPerKey": 1 }
|
||||
},
|
||||
{
|
||||
"id": "migration-explicit-contract-migration",
|
||||
"mode": "legacy",
|
||||
"covers": { "decisionRows": [], "terminalRows": [], "attentionRows": [], "livenessRows": [], "reconciliationRows": [], "compatibilityRows": [], "migrationRows": ["MIG-09"] },
|
||||
"tags": ["native_legacy_distinction", "existing_issue_state", "rollback"],
|
||||
"given": { "priorIssueStatus": "done", "turnTerminalState": null, "runTerminalState": null, "reportedWorkDisposition": null, "nativeFinalization": "not_applicable", "completionState": "no_reviewed_adapter_contract_migration", "trigger": "migration" },
|
||||
"expected": { "runStatus": "legacy_derived", "statusAction": "legacy_finalizer", "reasonCode": null, "requiredEffects": ["retain_legacy_mode", "retain_audit_lineage"], "forbiddenEffects": ["infer_contract_from_exit_code", "delete_history"], "livePathKind": null, "preserveClaim": false, "nativeRecords": false, "decisionCount": 0, "maxWakeCount": 0, "maxNotificationCount": 0 },
|
||||
"replay": { "attempts": 2, "sameDecisionDigest": true, "maxSemanticDecisions": 0, "maxDomainEffectsPerKey": 1 }
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -511,6 +511,9 @@ server/src/services/environment-run-orchestrator.ts
|
||||
- terminal conversion to `AdapterExecutionResult`;
|
||||
- typed `nativeFinalization` validation and complete terminal/arbitration handling;
|
||||
- server-owned status arbiter for completion, blocker, review, attention, and continuation signals;
|
||||
- the shared Section 18.13 status-authority corpus consumed without changing
|
||||
fixture expectations by arbiter, database, finalizer, migration, legacy, and
|
||||
UI tests;
|
||||
- native interaction bridge binding, materialization, continuation projection,
|
||||
and response-delivery integration;
|
||||
- native finalizer conformance tests for run status, issue status, continuation/review effects, and cancellation scope;
|
||||
@@ -524,6 +527,8 @@ server/src/services/environment-run-orchestrator.ts
|
||||
- a missing or invalid native finalization discriminator fails closed instead of using the legacy success heuristic;
|
||||
- an agent signal cannot move an issue to `blocked` or `in_review` without the required blocker or review path;
|
||||
- human-needed requests persist and wake the correct owner without requiring an invalid issue status;
|
||||
- `pnpm check:runner-phase5-spec` passes and implementation output reports a
|
||||
result for every `SD`, `TC`, `ATT`, `LIVE`, `REC`, `COMP`, and `MIG` fixture;
|
||||
- a blocking semantic interaction yields only after durable materialization and
|
||||
resumes with a typed response without model-visible Paperclip credentials;
|
||||
- legacy integration tests are unchanged;
|
||||
|
||||
@@ -3497,27 +3497,27 @@ result_schema_rejected
|
||||
|
||||
The complete arbitration table is normative. “Preserve” means that the current issue status remains unchanged.
|
||||
|
||||
| Case | Authority and required inputs | Authoritative decision | Required atomic side effects and liveness | Reason code |
|
||||
|---|---|---|---|---|
|
||||
| Run succeeded; contract mechanically satisfied | Arbiter; accepted current-revision evidence, required artifacts, no missing criteria, no pending gate, no remaining completion work | `done` | Persist assessment/decision, compact handoff, release checkout | `completion_contract_satisfied` |
|
||||
| Run succeeded; low-risk agent claims done under explicit policy | Arbiter; current claim, policy permits agent authority, no contradictory evidence or pending gate | `done` | Persist policy basis and evidence classifications, release checkout | `completion_claim_policy_accepted` |
|
||||
| Run succeeded; agent claims done but required evidence or criteria are incomplete | Arbiter; completion claim plus missing/rejected/unverifiable requirements | `in_progress` only when a live path is created; otherwise preserve | Register continuation/retry/delegated verification; if none can be created, record finalization error and preserve status | `completion_evidence_incomplete` |
|
||||
| Run succeeded; completion requires subjective, Security, QA, CTO, board, or governed review | Arbiter; contract gate or risk policy and a real review target | `in_review` | Atomically bind reviewer, approval, interaction, delegated review issue, or monitor that wakes the assignee | `completion_review_required` or `governed_gate_pending` |
|
||||
| Structured result is invalid, stale, cross-boundary, or remains uncorrected after the bounded correction policy | Runner/finalizer + arbiter; rejected result, binding/schema failure, runtime facts, safely parsed evidence | Preserve | Persist the rejected input and reason, terminalize the run from runtime facts, and atomically create a bounded correction/recovery path when policy permits; never infer `in_review`, `blocked`, or `done` from rejection | `result_schema_rejected` |
|
||||
| Run succeeded; agent reports yielded and continuation is valid | Arbiter; declared continuation with valid target/idempotency and policy budget | `in_progress` | Atomically enqueue continuation, retry, delegated issue, response wake, or monitor | `live_continuation_registered` |
|
||||
| Current turn waits for an answer, but another productive track exists | Attention resolver + arbiter; `scope: current_turn` or `current_track`, alternate track and continuation | `in_progress` | Persist/rout attention and enqueue alternate productive track; do not create task-wide blocker | `turn_waiting_other_track_live` |
|
||||
| A task-wide blocker prevents all productive progress | Arbiter; blocker `scope: task_wide`, concrete owner, unblock action, evidence, no alternate live track | `blocked` | Atomically bind blocker issue or named owner/action and wake/notify route | `task_wide_blocker_bound` |
|
||||
| Agent asks a question answerable from durable context or policy | Attention resolver; context hit bound to request and current revision | `in_progress` only when a response wake is registered; otherwise preserve | Record answer, resolve request, wake current turn/assignee as requested | `attention_resolved_from_context` |
|
||||
| Agent asks for expertise another in-company agent can supply | Attention resolver; capability match, company scope, delegation policy | `in_progress` only when delegation creates a live response path; otherwise preserve | Route request or create delegated issue with response binding and wake path | `attention_routed_to_agent` |
|
||||
| Agent asks for human help and only human/board authority or intentional judgment can resolve it | Attention resolver + arbiter; authority match, company scope, dedupe/budget checks | `in_review` only for contract review; otherwise `in_progress` only with a response wake; otherwise preserve | Create board interaction/approval and required wake atomically; `scope: current_turn` alone does not set status | `attention_requires_human_authority` |
|
||||
| Duplicate or repeated attention request has no new evidence | Attention resolver; same dedupe key or superseded request, no material evidence delta | Preserve | Link duplicate to canonical request; do not notify or create another interaction | `attention_duplicate_suppressed` |
|
||||
| Attention retry/escalation budget is exhausted with no valid resolver | Arbiter; attempt history and failed capability routing | Preserve | Record finalization error and named recovery owner/action; never manufacture `blocked` or `in_review` | `attention_budget_exhausted` |
|
||||
| Run fails after producing partial work or evidence | Runner/finalizer + arbiter; failed run facts and safely persisted result/evidence | Preserve | Persist claims/evidence, apply retry/recovery policy, schedule live path when allowed | `run_failed_partial_evidence_preserved` |
|
||||
| Model reports completion but transport, workspace, or finalization later fails | Runner/finalizer + arbiter; accepted completion claim plus finalization failure | Preserve | Persist claim and evidence, mark run failed, open/schedule reconciliation; never mark done | `finalization_failed_claim_preserved` |
|
||||
| Cancellation targets only the active turn | Cancellation authority; authenticated command with `scope: turn` | Preserve | Terminalize turn `cancelled`; continue or await replacement turn according to run policy | `cancellation_turn_only` |
|
||||
| Cancellation targets the run, not the issue | Cancellation authority; authenticated command with `scope: run` | Preserve | Terminalize run `cancelled`, release runtime resources, keep issue available for resume | `cancellation_run_only` |
|
||||
| Cancellation explicitly targets the issue | Board or otherwise authorized issue-status actor; authenticated command with `scope: issue` | `cancelled` | Cancel active turn/run, record issue transition, release checkout and continuations | `cancellation_issue_authorized` |
|
||||
| Later evidence, dependency resolution, interaction response, or authorized resume changes the facts | Arbiter; new assessment, prior decision, authorized trigger | Re-evaluate to any legal status | Append superseding assessment/decision and create the required new liveness path | `decision_superseded_by_new_evidence`, `dependency_resolved`, or `authorized_resume` |
|
||||
| ID | Case | Authority and required inputs | Authoritative decision | Required atomic side effects and liveness | Reason code |
|
||||
|---|---|---|---|---|---|
|
||||
| SD-01 | Run succeeded; contract mechanically satisfied | Arbiter; accepted current-revision evidence, required artifacts, no missing criteria, no pending gate, no remaining completion work | `done` | Persist assessment/decision, compact handoff, release checkout | `completion_contract_satisfied` |
|
||||
| SD-02 | Run succeeded; low-risk agent claims done under explicit policy | Arbiter; current claim, policy permits agent authority, no contradictory evidence or pending gate | `done` | Persist policy basis and evidence classifications, release checkout | `completion_claim_policy_accepted` |
|
||||
| SD-03 | Run succeeded; agent claims done but required evidence or criteria are incomplete | Arbiter; completion claim plus missing/rejected/unverifiable requirements | `in_progress` only when a live path is created; otherwise preserve | Register continuation/retry/delegated verification; if none can be created, record finalization error and preserve status | `completion_evidence_incomplete` |
|
||||
| SD-04 | Run succeeded; completion requires subjective, Security, QA, CTO, board, or governed review | Arbiter; contract gate or risk policy and a real review target | `in_review` | Atomically bind reviewer, approval, interaction, delegated review issue, or monitor that wakes the assignee | `completion_review_required` or `governed_gate_pending` |
|
||||
| SD-05 | Structured result is invalid, stale, cross-boundary, or remains uncorrected after the bounded correction policy | Runner/finalizer + arbiter; rejected result, binding/schema failure, runtime facts, safely parsed evidence | Preserve | Persist the rejected input and reason, terminalize the run from runtime facts, and atomically create a bounded correction/recovery path when policy permits; never infer `in_review`, `blocked`, or `done` from rejection | `result_schema_rejected` |
|
||||
| SD-06 | Run succeeded; agent reports yielded and continuation is valid | Arbiter; declared continuation with valid target/idempotency and policy budget | `in_progress` | Atomically enqueue continuation, retry, delegated issue, response wake, or monitor | `live_continuation_registered` |
|
||||
| SD-07 | Current turn waits for an answer, but another productive track exists | Attention resolver + arbiter; `scope: current_turn` or `current_track`, alternate track and continuation | `in_progress` | Persist/route attention and enqueue alternate productive track; do not create task-wide blocker | `turn_waiting_other_track_live` |
|
||||
| SD-08 | A task-wide blocker prevents all productive progress | Arbiter; blocker `scope: task_wide`, concrete owner, unblock action, evidence, no alternate live track | `blocked` | Atomically bind blocker issue or named owner/action and wake/notify route | `task_wide_blocker_bound` |
|
||||
| SD-09 | Agent asks a question answerable from durable context or policy | Attention resolver; context hit bound to request and current revision | `in_progress` only when a response wake is registered; otherwise preserve | Record answer, resolve request, wake current turn/assignee as requested | `attention_resolved_from_context` |
|
||||
| SD-10 | Agent asks for expertise another in-company agent can supply | Attention resolver; capability match, company scope, delegation policy | `in_progress` only when delegation creates a live response path; otherwise preserve | Route request or create delegated issue with response binding and wake path | `attention_routed_to_agent` |
|
||||
| SD-11 | Agent asks for human help and only human/board authority or intentional judgment can resolve it | Attention resolver + arbiter; authority match, company scope, dedupe/budget checks | `in_review` only for contract review; otherwise `in_progress` only with a response wake; otherwise preserve | Create board interaction/approval and required wake atomically; `scope: current_turn` alone does not set status | `attention_requires_human_authority` |
|
||||
| SD-12 | Duplicate or repeated attention request has no new evidence | Attention resolver; same dedupe key or superseded request, no material evidence delta | Preserve | Link duplicate to canonical request; do not notify or create another interaction | `attention_duplicate_suppressed` |
|
||||
| SD-13 | Attention retry/escalation budget is exhausted with no valid resolver | Arbiter; attempt history and failed capability routing | Preserve | Record finalization error and named recovery owner/action; never manufacture `blocked` or `in_review` | `attention_budget_exhausted` |
|
||||
| SD-14 | Run fails after producing partial work or evidence | Runner/finalizer + arbiter; failed run facts and safely persisted result/evidence | Preserve | Persist claims/evidence, apply retry/recovery policy, schedule live path when allowed | `run_failed_partial_evidence_preserved` |
|
||||
| SD-15 | Model reports completion but transport, workspace, or finalization later fails | Runner/finalizer + arbiter; accepted completion claim plus finalization failure | Preserve | Persist claim and evidence, mark run failed, open/schedule reconciliation; never mark done | `finalization_failed_claim_preserved` |
|
||||
| SD-16 | Cancellation targets only the active turn | Cancellation authority; authenticated command with `scope: turn` | Preserve | Terminalize turn `cancelled`; continue or await replacement turn according to run policy | `cancellation_turn_only` |
|
||||
| SD-17 | Cancellation targets the run, not the issue | Cancellation authority; authenticated command with `scope: run` | Preserve | Terminalize run `cancelled`, release runtime resources, keep issue available for resume | `cancellation_run_only` |
|
||||
| SD-18 | Cancellation explicitly targets the issue | Board or otherwise authorized issue-status actor; authenticated command with `scope: issue` | `cancelled` | Cancel active turn/run, record issue transition, release checkout and continuations | `cancellation_issue_authorized` |
|
||||
| SD-19 | Later evidence, dependency resolution, interaction response, or authorized resume changes the facts | Arbiter; new assessment, prior decision, authorized trigger | Re-evaluate to any legal status | Append superseding assessment/decision and create the required new liveness path | `decision_superseded_by_new_evidence`, `dependency_resolved`, or `authorized_resume` |
|
||||
|
||||
Every decision records the arbiter authority, exact input assessment, reason code, side effects, and policy version. An issue transition and its liveness side effects commit in one transaction. A failed side effect means the transition is not applied.
|
||||
|
||||
@@ -3744,20 +3744,20 @@ The transaction rolls back if any required liveness side effect cannot be create
|
||||
|
||||
This matrix is the required Phase 3 design verification. Each row has a bounded terminal routing outcome and no infinite wake edge.
|
||||
|
||||
| Scenario | Expected resolver outcome | Status/liveness assertion |
|
||||
|---|---|---|
|
||||
| Agent asks a question already answered in the current document revision | Context response with versioned source refs | No human route; one response wake at most. |
|
||||
| Agent repeats the same question with the same key | Return canonical request | No new attempt, notification, status decision, or wake. |
|
||||
| Agent paraphrases the same question with fresh IDs | Match equivalence family and consume the shared budget | Duplicate suppressed; fresh keys cannot reset escalation. |
|
||||
| Agent requests a human for ordinary domain expertise | Reclassify to `expertise`; match an in-company agent | No human wait by default; delegation has a bound response path. |
|
||||
| Agent claims `task_wide` while an independent acceptance track is runnable | Narrow to `current_turn` or `current_track` and queue the alternate track | Issue remains truthfully `in_progress`; waiting track remains durable. |
|
||||
| Retry-safe tool call fails transiently, then succeeds | One bounded idempotent retry resolves it | No delegation or human route. |
|
||||
| Retry-safe failure exhausts two retries | Advance once to qualified agent/recovery or truthful fallback | No retry loop and no automatic human escalation without human authority. |
|
||||
| Agent labels a governed action as `requiredAuthority: none` | Policy derives the governed minimum authority | Exact approval route; expertise cannot downgrade it. |
|
||||
| Candidate names an agent, user, resource, or integration in another company | Generic side-effect-free rejection | No target disclosure, route, notification, or wake. |
|
||||
| Selected resolver changes or replies after supersession/expiry | Record stale response only | No issue transition, execution, or wake. |
|
||||
| Human interaction expires unanswered | Resolve expiry once; use policy fallback only with a durable new state or authorized resume | At most one fallback wake; no equivalent interaction recreation loop. |
|
||||
| No eligible agent, human authority, integration, or safe retry exists | Mark request exhausted and record finalization error/recovery alert | Preserve prior issue status; do not manufacture `blocked` or `in_review`. |
|
||||
| ID | Scenario | Expected resolver outcome | Status/liveness assertion |
|
||||
|---|---|---|---|
|
||||
| ATT-01 | Agent asks a question already answered in the current document revision | Context response with versioned source refs | No human route; one response wake at most. |
|
||||
| ATT-02 | Agent repeats the same question with the same key | Return canonical request | No new attempt, notification, status decision, or wake. |
|
||||
| ATT-03 | Agent paraphrases the same question with fresh IDs | Match equivalence family and consume the shared budget | Duplicate suppressed; fresh keys cannot reset escalation. |
|
||||
| ATT-04 | Agent requests a human for ordinary domain expertise | Reclassify to `expertise`; match an in-company agent | No human wait by default; delegation has a bound response path. |
|
||||
| ATT-05 | Agent claims `task_wide` while an independent acceptance track is runnable | Narrow to `current_turn` or `current_track` and queue the alternate track | Issue remains truthfully `in_progress`; waiting track remains durable. |
|
||||
| ATT-06 | Retry-safe tool call fails transiently, then succeeds | One bounded idempotent retry resolves it | No delegation or human route. |
|
||||
| ATT-07 | Retry-safe failure exhausts two retries | Advance once to qualified agent/recovery or truthful fallback | No retry loop and no automatic human escalation without human authority. |
|
||||
| ATT-08 | Agent labels a governed action as `requiredAuthority: none` | Policy derives the governed minimum authority | Exact approval route; expertise cannot downgrade it. |
|
||||
| ATT-09 | Candidate names an agent, user, resource, or integration in another company | Generic side-effect-free rejection | No target disclosure, route, notification, or wake. |
|
||||
| ATT-10 | Selected resolver changes or replies after supersession/expiry | Record stale response only | No issue transition, execution, or wake. |
|
||||
| ATT-11 | Human interaction expires unanswered | Resolve expiry once; use policy fallback only with a durable new state or authorized resume | At most one fallback wake; no equivalent interaction recreation loop. |
|
||||
| ATT-12 | No eligible agent, human authority, integration, or safe retry exists | Mark request exhausted and record finalization error/recovery alert | Preserve prior issue status; do not manufacture `blocked` or `in_review`. |
|
||||
|
||||
The implementation test plan must turn every row into a deterministic fixture that asserts canonical/equivalence identity, counters, selected route, effective scope, status decision reason, side effects, wake count, and stale-response behavior.
|
||||
|
||||
@@ -3830,16 +3830,16 @@ interface AdapterExecutionResult {
|
||||
|
||||
Native adapters must set `nativeFinalization`. The heartbeat finalizer validates it against `resultJson` and persisted terminal events, derives the heartbeat run status from `runTerminalState`, and then submits a `WorkAssessment` to the arbiter. Compatibility fields are process diagnostics only.
|
||||
|
||||
| Native facts | Compatibility fields | Required native behavior |
|
||||
|---|---|---|
|
||||
| Turn `completed`; run `succeeded`; reported disposition present | Usually `exitCode: 0`, `timedOut: false`; result in `resultJson` | Persist succeeded run and assess the report. No reported disposition maps directly to issue status. |
|
||||
| Turn `failed`; run `failed`; partial result/evidence may exist | Nonzero exit when available; error metadata populated | Persist failed run, preserve partial claims/evidence, apply retry/recovery, preserve issue status unless a separate authorized decision applies. |
|
||||
| Turn `completed`; run `failed` because workspace/transport/finalization failed after a report | Exit code may still be zero; finalization error identifies failure | Persist failed run and preserve the completion claim for reconciliation. Never mark the issue done. |
|
||||
| Turn `interrupted`; run remains active or a replacement turn is accepted | No terminal adapter result yet | Terminalize only the turn; continue the same run/session. |
|
||||
| Turn `interrupted`; run `succeeded` with valid `yielded` report and continuation | Usually `exitCode: 0` | Assess yielded work and atomically register continuation; interruption alone grants no issue transition. |
|
||||
| Turn `cancelled`; run `cancelled`; scope `turn` or `run` | `exitCode: null`; cancellation diagnostics optional | Preserve issue status. Turn scope may permit replacement work; run scope releases run resources. |
|
||||
| Turn/run `cancelled`; scope `issue` and actor is authorized | `exitCode: null`; cancellation command reference persisted | Arbiter applies issue `cancelled` and cancels continuations atomically. |
|
||||
| Native finalization missing, inconsistent, stale, or invalid | Any compatibility values | Fail closed as `native_finalization_missing` or `native_finalization_invalid`; never use the legacy heuristic. Preserve safe evidence and create recovery. |
|
||||
| ID | Native facts | Compatibility fields | Required native behavior |
|
||||
|---|---|---|---|
|
||||
| TC-01 | Turn `completed`; run `succeeded`; reported disposition present | Usually `exitCode: 0`, `timedOut: false`; result in `resultJson` | Persist succeeded run and assess the report. No reported disposition maps directly to issue status. |
|
||||
| TC-02 | Turn `failed`; run `failed`; partial result/evidence may exist | Nonzero exit when available; error metadata populated | Persist failed run, preserve partial claims/evidence, apply retry/recovery, preserve issue status unless a separate authorized decision applies. |
|
||||
| TC-03 | Turn `completed`; run `failed` because workspace/transport/finalization failed after a report | Exit code may still be zero; finalization error identifies failure | Persist failed run and preserve the completion claim for reconciliation. Never mark the issue done. |
|
||||
| TC-04 | Turn `interrupted`; run remains active or a replacement turn is accepted | No terminal adapter result yet | Terminalize only the turn; continue the same run/session. |
|
||||
| TC-05 | Turn `interrupted`; run `succeeded` with valid `yielded` report and continuation | Usually `exitCode: 0` | Assess yielded work and atomically register continuation; interruption alone grants no issue transition. |
|
||||
| TC-06 | Turn `cancelled`; run `cancelled`; scope `turn` or `run` | `exitCode: null`; cancellation diagnostics optional | Preserve issue status. Turn scope may permit replacement work; run scope releases run resources. |
|
||||
| TC-07 | Turn/run `cancelled`; scope `issue` and actor is authorized | `exitCode: null`; cancellation command reference persisted | Arbiter applies issue `cancelled` and cancels continuations atomically. |
|
||||
| TC-08 | Native finalization missing, inconsistent, stale, or invalid | Any compatibility values | Fail closed as `native_finalization_missing` or `native_finalization_invalid`; never use the legacy heuristic. Preserve safe evidence and create recovery. |
|
||||
|
||||
All compatibility results set `signal: null` unless the harness reported a real signal. They preserve usage, cost, session, provider, model, billing, and runtime-service fields without changing their meaning. `resultJson` contains the original structured result when one exists, plus references to the assessment and status decision after arbitration.
|
||||
|
||||
@@ -4870,6 +4870,234 @@ affordance matrix, duplicate suppression, finalization error truthfulness,
|
||||
unknown reason code fallback, clock-skew countdown, legacy fallback, and
|
||||
keyboard operation of the response control.
|
||||
|
||||
### 18.13 Phase 5 conformance, migration, and rollback contract
|
||||
|
||||
Phase 5 turns the authority, resolver, finalizer, and operator contracts into an
|
||||
independently executable scenario matrix. The checked-in source of truth is
|
||||
[`fixtures/status-authority-phase5.json`](./fixtures/status-authority-phase5.json),
|
||||
and `pnpm check:runner-phase5-spec` is the standing spec-level conformance gate.
|
||||
The corpus is language-neutral: TypeScript server tests, Rust protocol tests,
|
||||
the deterministic driver, migration tests, and QA harnesses consume the same
|
||||
fixture IDs and expected facts. An implementation may add transport-specific
|
||||
setup, but it must not rewrite an expected status, reason code, effect, count,
|
||||
or compatibility mode.
|
||||
|
||||
Each fixture names the exact normative rows it covers:
|
||||
|
||||
- `SD-01`–`SD-19`: every row of the section 18.3 status-decision table;
|
||||
- `TC-01`–`TC-08`: every row of the section 18.5 terminal conversion table;
|
||||
- `ATT-01`–`ATT-12`: every row of the section 18.3.7 adversarial-attention table;
|
||||
- `LIVE-01`–`LIVE-06`: atomic liveness success and rollback paths below;
|
||||
- `REC-01`–`REC-08`: deterministic replay and reconciliation paths below;
|
||||
- `COMP-01`–`COMP-08`: native/legacy and existing-state compatibility below;
|
||||
- `MIG-01`–`MIG-09`: rollout, migration, rollback, and reconciliation stages below.
|
||||
|
||||
The fixture schema separates input facts from assertions:
|
||||
|
||||
```ts
|
||||
interface StatusAuthorityConformanceFixtureV1 {
|
||||
id: string;
|
||||
mode: "native" | "legacy";
|
||||
covers: {
|
||||
decisionRows: string[];
|
||||
terminalRows: string[];
|
||||
attentionRows: string[];
|
||||
livenessRows: string[];
|
||||
reconciliationRows: string[];
|
||||
compatibilityRows: string[];
|
||||
migrationRows: string[];
|
||||
};
|
||||
tags: string[];
|
||||
given: {
|
||||
priorIssueStatus: AuthoritativeIssueStatus;
|
||||
turnTerminalState: TurnTerminalState | "active" | null;
|
||||
runTerminalState: RunTerminalState | "active" | null;
|
||||
reportedWorkDisposition: ReportedWorkDisposition | null;
|
||||
nativeFinalization: "present" | "missing" | "invalid" | "not_applicable";
|
||||
completionState: string;
|
||||
trigger: string;
|
||||
fault?: string;
|
||||
};
|
||||
expected: {
|
||||
runStatus: "succeeded" | "failed" | "cancelled" | "running" | "legacy_derived";
|
||||
statusAction:
|
||||
| AuthoritativeIssueStatus
|
||||
| "preserve"
|
||||
| "legacy_finalizer";
|
||||
reasonCode: StatusDecisionReasonCode | string | null;
|
||||
requiredEffects: string[];
|
||||
forbiddenEffects: string[];
|
||||
livePathKind: LivePathView["kind"] | null;
|
||||
preserveClaim: boolean;
|
||||
nativeRecords: boolean;
|
||||
decisionCount: number;
|
||||
maxWakeCount: number;
|
||||
maxNotificationCount: number;
|
||||
};
|
||||
replay: {
|
||||
attempts: number;
|
||||
sameDecisionDigest: boolean;
|
||||
maxSemanticDecisions: number;
|
||||
maxDomainEffectsPerKey: number;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
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
|
||||
decision lineage, effect-ledger rows, domain liveness rows, outbox counts,
|
||||
notifications, wakes, activity, and the coordinator phase. A failure response
|
||||
with a leaked row or a correct row with an extra wake both fail conformance.
|
||||
Timestamps and allocated UUIDs may differ; canonical input and decision digests,
|
||||
ordered effect kinds, reason codes, and semantic counts may not.
|
||||
|
||||
#### 18.13.1 Required adversarial scenario inventory
|
||||
|
||||
The corpus must keep at least one fixture carrying each tag below. Tags are
|
||||
stable QA selectors; renaming or removing one is a protocol change.
|
||||
|
||||
| Tag | Required behavior |
|
||||
|---|---|
|
||||
| `premature_done_claim` | A `done` claim with missing proof cannot set `done`; accepted claim/evidence remains inspectable. |
|
||||
| `incomplete_evidence` | Missing, rejected, and unverifiable evidence stay distinct and choose continuation or truthful preservation. |
|
||||
| `required_review` | Subjective/governed completion reaches `in_review` only with the matching reviewer/approval path. |
|
||||
| `continuation` | A valid yielded result creates one canonical continuation and keeps the issue `in_progress`. |
|
||||
| `partial_progress` | Useful partial work survives a non-terminal result and remains attached to the next run. |
|
||||
| `real_blocker` | Only a task-wide stop with an owner/action and no alternate track can set `blocked`. |
|
||||
| `excessive_human_request` | Agent-resolvable requests route through context, retry, or another agent before a human route. |
|
||||
| `repeated_question` | Same-key and fresh-key equivalents share one canonical family and bounded counters. |
|
||||
| `false_blocker` | Claimed task-wide scope is narrowed while another productive track is queued. |
|
||||
| `partial_evidence_before_failure` | Failed execution preserves safely parsed evidence and never upgrades the issue from that evidence alone. |
|
||||
| `finalization_failure` | A completion claim followed by workspace/transport/finalizer failure remains preserved but unapplied. |
|
||||
| `cancellation_scope` | Turn, run, and issue cancellation have three intentionally different issue effects. |
|
||||
| `authorized_resume` | Only an authorized trigger can supersede a terminal/waiting decision and it creates a new liveness path. |
|
||||
| `supersession` | New evidence produces append-only assessment/decision lineage; stale effects do not replay. |
|
||||
| `native_legacy_distinction` | Native rows use contracts/assessments/decisions; legacy rows remain on the existing finalizer and create none. |
|
||||
| `existing_issue_state` | Upgrade does not synthesize history or silently rewrite open or terminal issue status. |
|
||||
| `atomic_liveness` | A non-terminal status and its durable next-action path commit or roll back together. |
|
||||
| `deterministic_replay` | Same canonical input/policy returns one digest and at-most-one semantic effect. |
|
||||
| `reconciliation` | Crash/race recovery resumes from durable phase and appends supersession when facts changed. |
|
||||
| `rollback` | Disabling native application stops new native dispatch without converting an active native run to legacy. |
|
||||
|
||||
#### 18.13.2 Atomic liveness fixtures
|
||||
|
||||
| ID | Injection | Required result |
|
||||
|---|---|---|
|
||||
| LIVE-01 | Valid completion-review target | `in_review`, reviewer/approval/interaction domain row, return owner, and wake outbox commit in one transaction. |
|
||||
| LIVE-02 | Reviewer/interaction insert fails | Prior status/version preserved; no reviewer, notification, or wake leaks; `side_effect_planning_failed` recovery is recorded. |
|
||||
| LIVE-03 | Valid task-wide blocker | `blocked`, company-scoped blocker relation or unblock descriptor, owner notification intent, and dependency wake identity commit together. |
|
||||
| LIVE-04 | Blocker relation/owner binding fails | Prior status/version preserved; no `blocked` projection or owner notification leaks. |
|
||||
| LIVE-05 | Valid continuation | Continued `in_progress`, cleared completed-run lock, one canonical queued continuation/response wake/monitor, and attempt budget increment commit together. |
|
||||
| LIVE-06 | Continuation/outbox insert fails | Prior status/version preserved; no orphan continuation, wake, or `in_progress` transition; recovery names an owner. |
|
||||
|
||||
The failpoint is after validation but before transaction commit. Each failure is
|
||||
replayed after the failpoint is removed to prove that rollback did not consume
|
||||
the canonical idempotency key. A post-commit websocket or external-notification
|
||||
failure is different: the authoritative transition stays committed and only
|
||||
the existing effect-ledger row is retried.
|
||||
|
||||
#### 18.13.3 Deterministic replay and reconciliation fixtures
|
||||
|
||||
| ID | Scenario | Required result |
|
||||
|---|---|---|
|
||||
| REC-01 | Identical result is ingested twice before acknowledgement | One result fingerprint, assessment, decision digest, status transition, and domain effect per idempotency key. |
|
||||
| REC-02 | Equivalent material arrives with fresh caller IDs/dedupe keys | Resolve to the canonical result and shared attention budget; caller keys cannot mint another semantic action. |
|
||||
| REC-03 | Caller reuses an ID with changed material | `structured_result_replay_conflict`; no decision, status change, route, notification, or wake. |
|
||||
| REC-04 | Finalizer crashes after result preservation and before workspace finalization | Reconciler resumes the existing workspace operation, then assesses once. |
|
||||
| REC-05 | Finalizer crashes after decision commit and before outbox acknowledgement | Replay dispatches only pending effect rows; it does not re-arbitrate or duplicate a domain row. |
|
||||
| REC-06 | Board update wins the status-row race | Finalizer reloads and appends a superseding assessment; stale effects remain cancelled/preserved and cannot reopen a terminal issue. |
|
||||
| REC-07 | Dependency or interaction response wins the race | Superseding assessment includes the resolved fact and emits at most one newly legal continuation. |
|
||||
| REC-08 | Contract or policy version changes before replay | Old inputs remain bound to their immutable versions; a new assessment uses the new versions and links, rather than mutating, the old decision. |
|
||||
|
||||
Every replay fixture runs once in original order, once with duplicate delivery,
|
||||
and once after a simulated control-plane restart. The final database projection
|
||||
and ordered semantic-effect identities must be equal. When the authoritative
|
||||
facts intentionally change, only the append-only supersession chain may differ.
|
||||
|
||||
#### 18.13.4 Native, legacy, and existing-state compatibility
|
||||
|
||||
| ID | Starting condition | Compatibility behavior |
|
||||
|---|---|---|
|
||||
| COMP-01 | Existing adapter omits `nativeFinalization` | Select the legacy finalizer exactly as before; create no contract, result, coordinator, assessment, decision, or attention row. |
|
||||
| COMP-02 | Persisted run profile is native and the discriminator is missing/invalid | Fail closed with native finalization failure and recovery; never select the legacy heuristic. |
|
||||
| COMP-03 | Adapter result contains a native-looking model-authored field only inside `resultJson` | Ignore it for mode selection; the persisted run profile plus typed adapter boundary are authoritative. |
|
||||
| COMP-04 | Existing issue upgraded in `todo`, `in_progress`, `in_review`, or `blocked` | Initialize `status_version = 0` without changing status, owner, blocker, review path, monitor, checkout, or timestamps; create no synthetic history. |
|
||||
| COMP-05 | Existing issue upgraded in `done` or `cancelled` | Preserve terminal status/timestamps; late native evidence is audit-only unless an authorized resume/cancellation capability permits a legal new decision. |
|
||||
| COMP-06 | Native application flag disabled after shadow records exist | Shadow rows remain inspectable and unapplied; legacy runs keep existing behavior; no shadow decision may dispatch an effect. |
|
||||
| COMP-07 | One ledger contains native and legacy runs | Native rows expose four authority layers and decision lineage; legacy rows render the byte-identical pre-change path with `native: false`. |
|
||||
| COMP-08 | Existing authorized status route races or runs during rollout | It increments `status_version` in every mode and triggers native reconciliation only when a native coordinator is active. |
|
||||
|
||||
There is no implicit “upgrade legacy history” job. A later migration that wants
|
||||
native contracts for a legacy adapter must define how the contract is sourced,
|
||||
how historical evidence is classified, and who authorizes semantic backfill.
|
||||
Until then, native and legacy metrics, UI summaries, audit exports, and QA
|
||||
reports carry an explicit `mode` dimension and are never aggregated as though
|
||||
their completion semantics were identical.
|
||||
|
||||
#### 18.13.5 Rollout and migration sequence
|
||||
|
||||
| ID | Stage | Entry gate | Action and exit evidence |
|
||||
|---|---|---|---|
|
||||
| MIG-01 | Expand schema | Migration dry-run and rollback rehearsal pass on production-shaped data | Add nullable references/new tables plus `status_version default 0`; no behavior or issue-state change. |
|
||||
| MIG-02 | Version all writers | Every issue-status mutation test asserts one `status_version` increment | Deploy writer compatibility before any native arbiter can apply decisions. |
|
||||
| MIG-03 | Read-only compatibility | Legacy UI/API snapshots and cross-company read tests pass | Ship read types/routes behind flags; missing native rows are an intentional `native: false`/`404`, not an error. |
|
||||
| MIG-04 | Shadow materialization | Contract/result redaction, digest, and storage tests pass | Materialize native contracts/results and compute assessments/decisions with effect dispatch disabled. |
|
||||
| MIG-05 | Shadow comparison | Complete Phase 5 corpus passes and divergence dashboard labels expected legacy/native differences | Compare proposed native decisions with existing behavior; reconcile or classify every unexplained divergence. |
|
||||
| MIG-06 | Internal canary | QA accepts the complete matrix; Security/CTO gates remain satisfied | Enable application for allowlisted company + adapter profile + policy version; keep per-run mode immutable. |
|
||||
| MIG-07 | Cohort rollout | Canary has no unreconciled coordinator, liveness-integrity, cross-company, or duplicate-effect failures | Increase cohorts by company/adapter profile; pin policy/algorithm versions for in-flight runs. |
|
||||
| MIG-08 | Disable/rollback | Kill-switch drill and active-run inventory are available | Stop new native dispatch/application, retain read visibility, let active native runs finish/reconcile as native, and send later attempts to legacy only when their profile is newly selected as legacy. |
|
||||
| MIG-09 | Contract migration or cleanup | Explicit reviewed migration exists for each adapter family | Only then migrate a legacy adapter or remove compatibility columns/flags; never infer contracts from exit codes or delete audit lineage. |
|
||||
|
||||
Schema rollback is expand/contract, never destructive in the incident window.
|
||||
The application can roll back while the expanded schema remains. New binaries
|
||||
must tolerate old rows with no native references, and the immediately previous
|
||||
binary must tolerate the added nullable columns/tables. A destructive contract
|
||||
phase is forbidden until retention, export, audit, and downgrade compatibility
|
||||
are reviewed separately.
|
||||
|
||||
Policy compatibility is exact-version, not “latest wins.” A run binds the
|
||||
immutable completion-contract, resolver-policy, and arbiter-algorithm versions
|
||||
at envelope creation. Replay uses those versions. A policy rollout affects new
|
||||
runs and explicit authorized re-assessments only. Emergency policy revocation
|
||||
may prevent an undelivered effect from executing, but it records a new
|
||||
superseding assessment/reason; it never silently edits the committed decision.
|
||||
Unknown contract, fixture, result, or policy schema versions fail closed and
|
||||
remain recoverable/readable as preserved input.
|
||||
|
||||
Rollback reconciliation is complete only when every native coordinator is in
|
||||
`committed` or `terminal_failure` with a named recovery owner, every committed
|
||||
effect is delivered or durably retryable, no active native run was converted
|
||||
mid-session, and the native/legacy/shadow counts reconcile to the dispatch
|
||||
ledger. Re-enablement resumes from coordinator state; it does not bulk replay
|
||||
all historical reports.
|
||||
|
||||
#### 18.13.6 Independent QA acceptance package
|
||||
|
||||
QA receives the fixture corpus, this specification, the Phase 4 operator
|
||||
contract, the conformance command output, implementation test output grouped by
|
||||
fixture ID, migration rehearsal output, and a failure-injection ledger. The
|
||||
matrix is accepted only when:
|
||||
|
||||
1. every `SD`, `TC`, `ATT`, `LIVE`, `REC`, `COMP`, and `MIG` ID has at least one
|
||||
passing implementation result;
|
||||
2. every required adversarial tag has a passing fixture and no unclassified
|
||||
divergence;
|
||||
3. native and legacy results are reported in separate columns and the legacy
|
||||
baseline snapshot is unchanged;
|
||||
4. duplicate/replay runs prove bounded wakes, notifications, decisions, and
|
||||
domain effects;
|
||||
5. the three non-terminal status families pass both success and transaction
|
||||
rollback failpoints;
|
||||
6. a production-shaped upgrade, kill-switch rollback, and re-enable rehearsal
|
||||
reconcile without status loss, synthetic history, or mode conversion; and
|
||||
7. Phase 4 rendering fixtures consume the same decision/attention outcomes and
|
||||
preserve OPX-1–OPX-10.
|
||||
|
||||
QA records acceptance against the corpus schema version and git revision.
|
||||
Changing an expected semantic assertion after acceptance requires a new corpus
|
||||
schema or fixture revision and a fresh independent acceptance run.
|
||||
|
||||
---
|
||||
|
||||
## 19. Sandbox and provider integration
|
||||
@@ -6216,6 +6444,30 @@ and interaction, run, and issue statuses remain server-only fields. Neither a
|
||||
model hint, runner lease, response payload, continuation intent, nor replay/ACK
|
||||
can bypass those invariants.
|
||||
|
||||
### 27.10 Status-authority Phase 5 conformance
|
||||
|
||||
Section 18.13 and
|
||||
[`fixtures/status-authority-phase5.json`](./fixtures/status-authority-phase5.json)
|
||||
are the sole scenario inventory for status-authority implementation and QA.
|
||||
`pnpm check:runner-phase5-spec` must pass before a runtime suite starts. Runtime
|
||||
suites then execute the same fixture IDs at these layers:
|
||||
|
||||
| Consumer | Required assertions |
|
||||
|---|---|
|
||||
| Shared/validator | Input schema, enum, contract/policy version, server-owned field rejection, and safe error code. |
|
||||
| Status arbiter | Pure decision digest, status/no-op, reason code, ordered effect plan, and supersession lineage. |
|
||||
| Server/database | Transactional status version, domain liveness rows, coordinator phase, effect ledger, activity, notification, and wake counts. |
|
||||
| Runner/finalizer | Turn/run terminal conversion, claim/evidence preservation, workspace-finalization order, and native discriminator fail-closed behavior. |
|
||||
| Legacy regression | Existing finalizer behavior and byte-identical legacy read/UI snapshots with zero native history rows. |
|
||||
| Migration harness | Production-shaped expand migration, writer versioning, shadow comparison, canary, kill-switch rollback, reconciliation, and re-enable. |
|
||||
| Phase 4 UI | Four authority layers, decision/attention truthfulness, liveness owner, finalization recovery, and native/legacy distinction from the same outcomes. |
|
||||
|
||||
Each test result is emitted as `{ corpusRevision, gitRevision, fixtureId,
|
||||
consumer, outcome, observedDigests, semanticCounts }`. QA rejects aggregate
|
||||
“suite passed” evidence that cannot be joined back to every required fixture
|
||||
ID. Failure injection runs record the failpoint and pre/post database counts;
|
||||
replay runs record all attempt IDs and the one canonical semantic identity.
|
||||
|
||||
---
|
||||
|
||||
## 28. Rollout and compatibility
|
||||
@@ -6268,6 +6520,13 @@ them to collapse into one public endpoint.
|
||||
10. Five-kind interaction bridge, response replay, and resumed-run gates.
|
||||
11. Additional drivers.
|
||||
|
||||
Native status application additionally follows the ordered `MIG-01`–`MIG-09`
|
||||
sequence in section 18.13.5. The generic runner gates above cannot skip shadow
|
||||
comparison, complete Phase 5 fixture acceptance, internal canary, or the
|
||||
kill-switch reconciliation drill. A driver may reach a later runner gate while
|
||||
its status application remains shadow-only; mode is persisted per run and never
|
||||
changes mid-session.
|
||||
|
||||
### 28.4 Kill switch
|
||||
|
||||
The control plane can:
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
#!/usr/bin/env node
|
||||
// Structural conformance gate for the 18.3 Phase 5 status-authority corpus.
|
||||
//
|
||||
// Usage: pnpm check:runner-phase5-spec
|
||||
//
|
||||
// This validates the language-neutral fixture matrix before runtime
|
||||
// implementations exist. Runtime suites consume the same fixture IDs and add
|
||||
// database/transport setup without changing the expected semantics.
|
||||
|
||||
import { readFileSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const root = join(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const specPath = join(root, "packages", "paperclip-runner", "spec", "paperclip-native-runner-spike-spec.md");
|
||||
const fixturePath = join(root, "packages", "paperclip-runner", "spec", "fixtures", "status-authority-phase5.json");
|
||||
const spec = readFileSync(specPath, "utf8");
|
||||
const corpus = JSON.parse(readFileSync(fixturePath, "utf8"));
|
||||
|
||||
const failures = [];
|
||||
const checks = [];
|
||||
|
||||
function check(name, fn) {
|
||||
try {
|
||||
const detail = fn();
|
||||
checks.push(`PASS ${name}${detail ? ` — ${detail}` : ""}`);
|
||||
} catch (error) {
|
||||
failures.push(`FAIL ${name} — ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
function section(source, heading) {
|
||||
const start = source.indexOf(heading);
|
||||
if (start === -1) throw new Error(`missing heading: ${heading}`);
|
||||
const level = heading.match(/^#+/)[0].length;
|
||||
const rest = source.slice(start + heading.length);
|
||||
const next = rest.search(new RegExp(`\\n#{1,${level}} `));
|
||||
return next === -1 ? rest : rest.slice(0, next);
|
||||
}
|
||||
|
||||
function tableIds(source, prefix) {
|
||||
return [...source.matchAll(new RegExp(`^\\| (${prefix}-\\d+) \\|`, "gm"))].map((match) => match[1]);
|
||||
}
|
||||
|
||||
function assertExactCoverage(label, definedIds, coverKey) {
|
||||
const covered = new Set(corpus.fixtures.flatMap((fixture) => fixture.covers[coverKey]));
|
||||
const missing = definedIds.filter((id) => !covered.has(id));
|
||||
const unknown = [...covered].filter((id) => !definedIds.includes(id));
|
||||
if (missing.length || unknown.length) {
|
||||
throw new Error([
|
||||
missing.length ? `missing ${missing.join(", ")}` : null,
|
||||
unknown.length ? `unknown ${unknown.join(", ")}` : null,
|
||||
].filter(Boolean).join("; "));
|
||||
}
|
||||
return `${definedIds.length} ${label} rows covered`;
|
||||
}
|
||||
|
||||
const decisionSection = section(spec, "### 18.3 Status authority and human-needed signaling");
|
||||
const attentionSection = section(spec, "#### 18.3.7 Weak-agent and adversarial scenario check");
|
||||
const terminalSection = section(spec, "### 18.5 Complete terminal conversion contract");
|
||||
const phase5 = section(spec, "### 18.13 Phase 5 conformance, migration, and rollback contract");
|
||||
|
||||
check("corpus header is versioned", () => {
|
||||
if (corpus.schema !== "paperclip.status-authority-conformance.v1") {
|
||||
throw new Error(`unexpected schema ${corpus.schema}`);
|
||||
}
|
||||
if (!Number.isInteger(corpus.corpusRevision) || corpus.corpusRevision < 1) {
|
||||
throw new Error("corpusRevision must be a positive integer");
|
||||
}
|
||||
if (typeof corpus.policyVersion !== "string" || corpus.policyVersion.length === 0) {
|
||||
throw new Error("policyVersion is required");
|
||||
}
|
||||
if (!Array.isArray(corpus.fixtures) || corpus.fixtures.length < 35) {
|
||||
throw new Error(`fixture corpus looks truncated (${corpus.fixtures?.length ?? 0})`);
|
||||
}
|
||||
return `revision ${corpus.corpusRevision}, ${corpus.fixtures.length} fixtures`;
|
||||
});
|
||||
|
||||
check("fixture IDs and required fields are valid", () => {
|
||||
const ids = new Set();
|
||||
const coverKeys = [
|
||||
"decisionRows",
|
||||
"terminalRows",
|
||||
"attentionRows",
|
||||
"livenessRows",
|
||||
"reconciliationRows",
|
||||
"compatibilityRows",
|
||||
"migrationRows",
|
||||
];
|
||||
const requiredGiven = [
|
||||
"priorIssueStatus",
|
||||
"turnTerminalState",
|
||||
"runTerminalState",
|
||||
"reportedWorkDisposition",
|
||||
"nativeFinalization",
|
||||
"completionState",
|
||||
"trigger",
|
||||
];
|
||||
const requiredExpected = [
|
||||
"runStatus",
|
||||
"statusAction",
|
||||
"reasonCode",
|
||||
"requiredEffects",
|
||||
"forbiddenEffects",
|
||||
"livePathKind",
|
||||
"preserveClaim",
|
||||
"nativeRecords",
|
||||
"decisionCount",
|
||||
"maxWakeCount",
|
||||
"maxNotificationCount",
|
||||
];
|
||||
for (const fixture of corpus.fixtures) {
|
||||
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(fixture.id)) throw new Error(`invalid fixture id ${fixture.id}`);
|
||||
if (ids.has(fixture.id)) throw new Error(`duplicate fixture id ${fixture.id}`);
|
||||
ids.add(fixture.id);
|
||||
if (!["native", "legacy"].includes(fixture.mode)) throw new Error(`${fixture.id}: invalid mode`);
|
||||
if (!fixture.covers || coverKeys.some((key) => !Array.isArray(fixture.covers[key]))) {
|
||||
throw new Error(`${fixture.id}: incomplete covers object`);
|
||||
}
|
||||
if (!Array.isArray(fixture.tags)) throw new Error(`${fixture.id}: tags must be an array`);
|
||||
if (!fixture.given || requiredGiven.some((key) => !(key in fixture.given))) {
|
||||
throw new Error(`${fixture.id}: incomplete given facts`);
|
||||
}
|
||||
if (!fixture.expected || requiredExpected.some((key) => !(key in fixture.expected))) {
|
||||
throw new Error(`${fixture.id}: incomplete expected facts`);
|
||||
}
|
||||
if (!fixture.replay || !Number.isInteger(fixture.replay.attempts) || fixture.replay.attempts < 1) {
|
||||
throw new Error(`${fixture.id}: invalid replay contract`);
|
||||
}
|
||||
}
|
||||
return `${ids.size} unique IDs`;
|
||||
});
|
||||
|
||||
check("every status-decision row has a fixture", () =>
|
||||
assertExactCoverage("decision", tableIds(decisionSection, "SD"), "decisionRows"));
|
||||
|
||||
check("every terminal-conversion row has a fixture", () =>
|
||||
assertExactCoverage("terminal", tableIds(terminalSection, "TC"), "terminalRows"));
|
||||
|
||||
check("every adversarial-attention row has a fixture", () =>
|
||||
assertExactCoverage("attention", tableIds(attentionSection, "ATT"), "attentionRows"));
|
||||
|
||||
for (const [label, heading, prefix, coverKey] of [
|
||||
["atomic liveness", "#### 18.13.2 Atomic liveness fixtures", "LIVE", "livenessRows"],
|
||||
["reconciliation", "#### 18.13.3 Deterministic replay and reconciliation fixtures", "REC", "reconciliationRows"],
|
||||
["compatibility", "#### 18.13.4 Native, legacy, and existing-state compatibility", "COMP", "compatibilityRows"],
|
||||
["migration", "#### 18.13.5 Rollout and migration sequence", "MIG", "migrationRows"],
|
||||
]) {
|
||||
check(`every ${label} row has a fixture`, () =>
|
||||
assertExactCoverage(label, tableIds(section(spec, heading), prefix), coverKey));
|
||||
}
|
||||
|
||||
check("all stable decision reason codes are exercised", () => {
|
||||
const enumBlock = spec.match(/`StatusDecisionReasonCode` is a stable protocol enum[\s\S]*?```text\n([\s\S]*?)```/);
|
||||
if (!enumBlock) throw new Error("could not locate StatusDecisionReasonCode enum");
|
||||
const defined = enumBlock[1].trim().split("\n").map((line) => line.trim()).filter(Boolean);
|
||||
const exercised = new Set(corpus.fixtures.map((fixture) => fixture.expected.reasonCode).filter(Boolean));
|
||||
const missing = defined.filter((code) => !exercised.has(code));
|
||||
if (missing.length) throw new Error(`unexercised reason code(s): ${missing.join(", ")}`);
|
||||
return `${defined.length} reason codes exercised`;
|
||||
});
|
||||
|
||||
check("required adversarial tags are all selectable", () => {
|
||||
const required = [
|
||||
"premature_done_claim",
|
||||
"incomplete_evidence",
|
||||
"required_review",
|
||||
"continuation",
|
||||
"partial_progress",
|
||||
"real_blocker",
|
||||
"excessive_human_request",
|
||||
"repeated_question",
|
||||
"false_blocker",
|
||||
"partial_evidence_before_failure",
|
||||
"finalization_failure",
|
||||
"cancellation_scope",
|
||||
"authorized_resume",
|
||||
"supersession",
|
||||
"native_legacy_distinction",
|
||||
"existing_issue_state",
|
||||
"atomic_liveness",
|
||||
"deterministic_replay",
|
||||
"reconciliation",
|
||||
"rollback",
|
||||
];
|
||||
const tags = new Set(corpus.fixtures.flatMap((fixture) => fixture.tags));
|
||||
const missing = required.filter((tag) => !tags.has(tag));
|
||||
if (missing.length) throw new Error(`missing tag(s): ${missing.join(", ")}`);
|
||||
return `${required.length} required tags present`;
|
||||
});
|
||||
|
||||
check("non-terminal status fixtures carry an atomic liveness path", () => {
|
||||
const acceptedEffects = {
|
||||
in_review: new Set(["bind_reviewer", "create_interaction"]),
|
||||
blocked: new Set(["bind_blocker"]),
|
||||
in_progress: new Set(["enqueue_continuation", "schedule_retry", "create_delegated_issue"]),
|
||||
};
|
||||
const violations = [];
|
||||
for (const fixture of corpus.fixtures) {
|
||||
const expected = fixture.expected;
|
||||
const allowed = acceptedEffects[expected.statusAction];
|
||||
if (!allowed) continue;
|
||||
if (expected.livePathKind === null || !expected.requiredEffects.some((effect) => allowed.has(effect))) {
|
||||
violations.push(fixture.id);
|
||||
}
|
||||
}
|
||||
if (violations.length) throw new Error(`missing atomic path/effect: ${violations.join(", ")}`);
|
||||
return "in_review, blocked, and in_progress paths validated";
|
||||
});
|
||||
|
||||
check("duplicate attention cannot create an 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.maxWakeCount !== 0 ||
|
||||
fixture.expected.maxNotificationCount !== 0 ||
|
||||
fixture.replay.maxSemanticDecisions > 1 ||
|
||||
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`;
|
||||
});
|
||||
|
||||
check("replay effects are at-most-once per semantic key", () => {
|
||||
const unsafe = corpus.fixtures.filter((fixture) =>
|
||||
fixture.replay.maxDomainEffectsPerKey !== 1 ||
|
||||
fixture.replay.maxSemanticDecisions > fixture.expected.decisionCount + 1);
|
||||
if (unsafe.length) throw new Error(`unsafe replay bounds: ${unsafe.map((fixture) => fixture.id).join(", ")}`);
|
||||
const replayed = corpus.fixtures.filter((fixture) => fixture.replay.attempts > 1);
|
||||
if (replayed.length < 30) throw new Error(`too few replayed fixtures (${replayed.length})`);
|
||||
return `${replayed.length} fixtures replayed with one effect per key`;
|
||||
});
|
||||
|
||||
check("native and legacy expectations remain intentionally distinct", () => {
|
||||
const legacy = corpus.fixtures.filter((fixture) => fixture.mode === "legacy");
|
||||
const native = corpus.fixtures.filter((fixture) => fixture.mode === "native");
|
||||
if (!legacy.length || !native.length) throw new Error("both modes are required");
|
||||
const badLegacy = legacy.filter((fixture) =>
|
||||
fixture.expected.nativeRecords || fixture.expected.decisionCount !== 0 || fixture.expected.statusAction !== "legacy_finalizer");
|
||||
const badNative = native.filter((fixture) => fixture.expected.statusAction === "legacy_finalizer");
|
||||
if (badLegacy.length || badNative.length) {
|
||||
throw new Error(`mode leakage in: ${[...badLegacy, ...badNative].map((fixture) => fixture.id).join(", ")}`);
|
||||
}
|
||||
return `${native.length} native / ${legacy.length} legacy fixtures`;
|
||||
});
|
||||
|
||||
check("rollback fixture forbids active-run mode conversion", () => {
|
||||
const rollback = corpus.fixtures.find((fixture) => fixture.covers.migrationRows.includes("MIG-08"));
|
||||
if (!rollback) throw new Error("missing MIG-08 fixture");
|
||||
if (!rollback.expected.requiredEffects.includes("stop_new_native_dispatch") ||
|
||||
!rollback.expected.forbiddenEffects.includes("convert_active_run_to_legacy")) {
|
||||
throw new Error("MIG-08 does not prove dispatch stop plus immutable active-run mode");
|
||||
}
|
||||
return rollback.id;
|
||||
});
|
||||
|
||||
check("Phase 5 markdown tables are rectangular", () => {
|
||||
const lines = phase5.split("\n");
|
||||
let inFence = false;
|
||||
let expectedColumns = null;
|
||||
let tables = 0;
|
||||
lines.forEach((line, index) => {
|
||||
if (line.trimStart().startsWith("```")) inFence = !inFence;
|
||||
if (inFence) return;
|
||||
const isRow = line.trimStart().startsWith("|") && line.trimEnd().endsWith("|");
|
||||
if (!isRow) {
|
||||
expectedColumns = null;
|
||||
return;
|
||||
}
|
||||
const columns = line.trim().slice(1, -1).split(/(?<!\\)\|/).length;
|
||||
if (expectedColumns === null) {
|
||||
expectedColumns = columns;
|
||||
tables += 1;
|
||||
} else if (columns !== expectedColumns) {
|
||||
throw new Error(`ragged table at Phase 5 offset line ${index + 1}: ${columns} vs ${expectedColumns}`);
|
||||
}
|
||||
});
|
||||
if (inFence) throw new Error("unbalanced code fence in section 18.13");
|
||||
return `${tables} tables`;
|
||||
});
|
||||
|
||||
for (const line of checks) console.log(line);
|
||||
for (const line of failures) console.error(line);
|
||||
console.log(`\n${checks.length} passed, ${failures.length} failed`);
|
||||
process.exit(failures.length ? 1 : 0);
|
||||
Reference in new issue
Block a user