Repository navigation
[formal-spec] intent-attribution-agent-governance.md — Formal model & test suite — 2026-10-21 #70909
Copy link
Copy link
Closed as not planned
Closed as not planned
Copy link
Description
Summary
The Intent Attribution & Agent Governance spec defines a deterministic layer linking GitHub artifacts to intent (priority, domain, risk) and deriving execution policy. A prior run covered attribution precedence, ambiguity and fail-closed policy (already tested in pkg/intent). This run extends the model to the gaps recorded in repo-memory: the escalation norm (3+ consecutive unaddressed sync warnings => compliance failure), Unknown is not zero (null vs 0 weight), no stale-cache reuse when policy inputs are unresolvable, drift detection symmetry, and artifacts-are-not-objectives counting.
Specification
- File:
specs/intent-attribution-agent-governance.md - Focus area: Safeguards, Sync Notes (escalation norm), Design principles
- Formal notation used: TLA+ (temporal/state) + F* style pre/post contracts + Z3-style constraints (illustrative)
Formal Model
<b>Predicates and invariants (illustrative notation)</b>
\* P1 Escalation (Sync Notes: "3 or more consecutive CI runs ... MUST be escalated")
Escalates(w) == w.consecutive >= 3 /\ ~w.waived /\ ~w.correctivePR
Inv_Escalation == \A w \in Warnings : Escalates(w) => (ci.exit # 0 /\ issue.updated)
\* P2 Below threshold (implied): consecutive < 3 => no escalation
Inv_NoEarlyEscalation == \A w : w.consecutive < 3 => ~Escalates(w)
\* P3 Waiver/corrective PR suppresses escalation ("without a corrective PR or explicit waiver")
Inv_Waiver == \A w : (w.waived \/ w.correctivePR) => ~Escalates(w)
\* P4 Tracking issue content ("affected keys, first-detected date, on-call maintainer as default assignee")
Inv_IssueContent == \A i \in TrackingIssues : i.keys # {} /\ i.firstDetected # NULL /\ i.assignee = onCall
\* P5 Drift symmetry ("Keys present in one source but not the other SHOULD surface")
Drift(A, B) == (A \ B) \cup (B \ A)
Inv_DriftSymmetric == \A A, B : Drift(A, B) = Drift(B, A)
\* P6 Unknown is not zero
Inv_UnknownNotZero == unlinked => weight = NULL /\ weight # 0
\* P7 No stale cache ("MUST NOT silently reuse a stale cached policy decision")
Inv_NoStale == ~inputsResolvable => policy = SafestPolicy /\ policy # cached
\* P8 Fail-closed provenance ("failure reason ... SHOULD be recorded")
Inv_Provenance == ~inputsResolvable => provenance.reason # ""
\* P9 Artifacts are not objectives
Inv_ObjectiveCount == ObjectiveCount(prs) = Cardinality({pr.rootIssue : pr \in prs})Behavioral Coverage Map
| Predicate / Invariant | Test Function | Description |
|---|---|---|
Inv_Escalation / Inv_NoEarlyEscalation |
TestEscalationThreshold |
Threshold of 3 consecutive runs, non-zero exit |
Inv_Waiver |
TestEscalationSuppressedByWaiverOrPR |
Waiver or corrective PR prevents escalation |
Inv_IssueContent |
TestEscalationTrackingIssueContent |
Issue has keys, first-detected date, on-call assignee |
Inv_DriftSymmetric |
TestDriftDetectionSymmetric |
Keys in only one source are reported |
Inv_UnknownNotZero |
TestUnknownIsNotZero |
Unlinked weight is nil, explicit 0 is distinct |
Inv_NoStale / Inv_Provenance |
TestNoStaleCacheReuse |
Unresolvable inputs yield safest policy with reason |
Inv_ObjectiveCount |
TestArtifactsAreNotObjectives |
Many PRs on one issue count as one objective |
Generated Test Suite
<b>📄 `pkg/intent/governance_sync_formal_test.go`</b>
// Formal tests for specs/intent-attribution-agent-governance.md
// Predicates: Inv_Escalation, Inv_NoEarlyEscalation, Inv_Waiver, Inv_IssueContent,
// Inv_DriftSymmetric, Inv_UnknownNotZero, Inv_NoStale, Inv_Provenance, Inv_ObjectiveCount.
package intent_test
import (
"sort"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// stub — replace with real implementation
type syncWarning struct {
Keys []string
FirstSeen string
Consecutive int
Waived bool
CorrectivePR bool
}
// stub — replace with real implementation
type escalation struct {
Escalated bool
ExitCode int
Keys []string
FirstSeen string
Assignee string
}
// stub — replace with real implementation
func evaluateEscalation(w syncWarning, onCall string) escalation {
if w.Consecutive >= 3 && !w.Waived && !w.CorrectivePR {
return escalation{true, 1, w.Keys, w.FirstSeen, onCall}
}
return escalation{}
}
// stub — replace with real implementation
func drift(a, b []string) []string {
in := func(s []string, k string) bool {
for _, x := range s {
if x == k {
return true
}
}
return false
}
var out []string
for _, k := range a {
if !in(b, k) {
out = append(out, k)
}
}
for _, k := range b {
if !in(a, k) {
out = append(out, k)
}
}
sort.Strings(out)
return out
}
// stub — replace with real implementation
type attribution struct {
Status string
Weight *float64
}
// stub — replace with real implementation
type policy struct {
Autonomy string
WriteScope string
HumanApproval bool
AutoMerge bool
MaxAttempts int
Reason string
}
// stub — replace with real implementation
func resolvePolicy(inputsOK bool, cached *policy) policy {
if inputsOK && cached != nil {
return *cached
}
return policy{"propose_only", "none", true, false, 1, "policy inputs unresolved"}
}
// stub — replace with real implementation
func objectiveCount(prRoots []string) int {
seen := map[string]bool{}
for _, r := range prRoots {
seen[r] = true
}
return len(seen)
}
func TestEscalationThreshold(t *testing.T) {
tests := []struct {
name string
runs int
want bool
}{
{"zero runs", 0, false},
{"two runs", 2, false},
{"exactly three runs", 3, true},
{"many runs", 10, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
e := evaluateEscalation(syncWarning{Keys: []string{"p0"}, Consecutive: tt.runs}, "oncall")
assert.Equal(t, tt.want, e.Escalated, "escalation must occur iff 3+ consecutive runs")
if tt.want {
assert.NotEqual(t, 0, e.ExitCode, "escalated check must exit non-zero")
} else {
assert.Equal(t, 0, e.ExitCode, "non-escalated check must exit zero")
}
})
}
}
func TestEscalationSuppressedByWaiverOrPR(t *testing.T) {
for name, w := range map[string]syncWarning{
"waiver": {Keys: []string{"k"}, Consecutive: 5, Waived: true},
"corrective PR": {Keys: []string{"k"}, Consecutive: 5, CorrectivePR: true},
} {
e := evaluateEscalation(w, "oncall")
assert.False(t, e.Escalated, "%s must suppress escalation", name)
}
}
func TestEscalationTrackingIssueContent(t *testing.T) {
e := evaluateEscalation(syncWarning{Keys: []string{"p0", "security"}, FirstSeen: "2026-10-01", Consecutive: 3}, "alice")
require.True(t, e.Escalated, "warning with 3 runs must escalate")
assert.Equal(t, []string{"p0", "security"}, e.Keys, "issue must record affected keys")
assert.Equal(t, "2026-10-01", e.FirstSeen, "issue must record first-detected date")
assert.Equal(t, "alice", e.Assignee, "on-call maintainer must be default assignee")
}
func TestDriftDetectionSymmetric(t *testing.T) {
a := []string{"critical", "p0"}
b := []string{"p0", "docs"}
assert.Equal(t, []string{"critical", "docs"}, drift(a, b), "keys in only one source must be reported")
assert.Equal(t, drift(a, b), drift(b, a), "drift must be symmetric")
assert.Empty(t, drift(a, a), "identical sources must have no drift")
assert.Empty(t, drift(nil, nil), "empty sources must have no drift")
}
func TestUnknownIsNotZero(t *testing.T) {
unlinked := attribution{Status: "unlinked"}
zero := 0.0
explicit := attribution{Status: "mapped", Weight: &zero}
assert.Nil(t, unlinked.Weight, "unlinked weight must be null, not zero")
require.NotNil(t, explicit.Weight, "explicit zero must be a non-nil value")
assert.Equal(t, 0.0, *explicit.Weight, "explicit zero must remain zero")
}
func TestNoStaleCacheReuse(t *testing.T) {
cached := policy{"autonomous", "repo", false, true, 5, ""}
got := resolvePolicy(false, &cached)
assert.NotEqual(t, cached, got, "stale cached policy must not be reused")
assert.Equal(t, "propose_only", got.Autonomy, "autonomy must be propose_only")
assert.Equal(t, "none", got.WriteScope, "write scope must be none")
assert.True(t, got.HumanApproval, "human approval must be required")
assert.False(t, got.AutoMerge, "auto merge must be prohibited")
assert.Equal(t, 1, got.MaxAttempts, "max attempts must be 1")
assert.NotEmpty(t, got.Reason, "failure reason must be recorded in provenance")
}
func TestArtifactsAreNotObjectives(t *testing.T) {
assert.Equal(t, 1, objectiveCount([]string{"#1", "#1", "#1"}), "multiple PRs on one issue are one objective")
assert.Equal(t, 2, objectiveCount([]string{"#1", "#2", "#1"}), "distinct issues are distinct objectives")
assert.Equal(t, 0, objectiveCount(nil), "no PRs means no objectives")
}Usage
- Copy the test file to
pkg/intent/. - Replace any
// stubhelpers with real implementations (the CI drift-escalation logic does not yet exist in the codebase). - Run:
go test ./... -run Formal(or run the namedTest*functions directly).
Context
- Spec processed:
specs/intent-attribution-agent-governance.md - Formal notation: TLA+, F*, Z3-style (illustrative)
- Run: https://github.com/github/gh-aw/actions/runs/39626678183
Generated by 🔬 Daily Formal Spec Verifier · copilot · auto · 21.8 AIC · ⌖ 0.751 AIC · ⊞ 11.2K · ◷
- expires on Oct 28, 2026, 7:39 AM UTC-08:00
Reactions are currently unavailable
Activity