Skip to content

[formal-spec] intent-attribution-agent-governance.md — Formal model & test suite — 2026-10-21 #70909

Closed as not planned

Description

@github-actions

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

  1. Copy the test file to pkg/intent/.
  2. Replace any // stub helpers with real implementations (the CI drift-escalation logic does not yet exist in the codebase).
  3. Run: go test ./... -run Formal (or run the named Test* functions directly).

Context

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions