agent-alignment-protocol 0.1.8__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. {agent_alignment_protocol-0.1.8 → agent_alignment_protocol-0.3.0}/.gitignore +3 -0
  2. {agent_alignment_protocol-0.1.8 → agent_alignment_protocol-0.3.0}/PKG-INFO +24 -11
  3. {agent_alignment_protocol-0.1.8 → agent_alignment_protocol-0.3.0}/README.md +23 -10
  4. {agent_alignment_protocol-0.1.8 → agent_alignment_protocol-0.3.0}/pyproject.toml +1 -1
  5. {agent_alignment_protocol-0.1.8 → agent_alignment_protocol-0.3.0}/src/aap/__init__.py +27 -5
  6. agent_alignment_protocol-0.3.0/src/aap/compliance.py +56 -0
  7. {agent_alignment_protocol-0.1.8 → agent_alignment_protocol-0.3.0}/src/aap/verification/__init__.py +15 -0
  8. {agent_alignment_protocol-0.1.8 → agent_alignment_protocol-0.3.0}/src/aap/verification/api.py +230 -0
  9. {agent_alignment_protocol-0.1.8 → agent_alignment_protocol-0.3.0}/src/aap/verification/constants.py +9 -0
  10. {agent_alignment_protocol-0.1.8 → agent_alignment_protocol-0.3.0}/src/aap/verification/models.py +105 -0
  11. {agent_alignment_protocol-0.1.8 → agent_alignment_protocol-0.3.0}/LICENSE +0 -0
  12. {agent_alignment_protocol-0.1.8 → agent_alignment_protocol-0.3.0}/schemas/alignment-card.schema.json +0 -0
  13. {agent_alignment_protocol-0.1.8 → agent_alignment_protocol-0.3.0}/schemas/ap-trace.schema.json +0 -0
  14. {agent_alignment_protocol-0.1.8 → agent_alignment_protocol-0.3.0}/schemas/value-coherence.schema.json +0 -0
  15. {agent_alignment_protocol-0.1.8 → agent_alignment_protocol-0.3.0}/src/aap/cli/__init__.py +0 -0
  16. {agent_alignment_protocol-0.1.8 → agent_alignment_protocol-0.3.0}/src/aap/cli/main.py +0 -0
  17. {agent_alignment_protocol-0.1.8 → agent_alignment_protocol-0.3.0}/src/aap/py.typed +0 -0
  18. {agent_alignment_protocol-0.1.8 → agent_alignment_protocol-0.3.0}/src/aap/schemas/__init__.py +0 -0
  19. {agent_alignment_protocol-0.1.8 → agent_alignment_protocol-0.3.0}/src/aap/schemas/alignment_card.py +0 -0
  20. {agent_alignment_protocol-0.1.8 → agent_alignment_protocol-0.3.0}/src/aap/schemas/ap_trace.py +0 -0
  21. {agent_alignment_protocol-0.1.8 → agent_alignment_protocol-0.3.0}/src/aap/schemas/value_coherence.py +0 -0
  22. {agent_alignment_protocol-0.1.8 → agent_alignment_protocol-0.3.0}/src/aap/tracing.py +0 -0
  23. {agent_alignment_protocol-0.1.8 → agent_alignment_protocol-0.3.0}/src/aap/verification/divergence.py +0 -0
  24. {agent_alignment_protocol-0.1.8 → agent_alignment_protocol-0.3.0}/src/aap/verification/features.py +0 -0
  25. {agent_alignment_protocol-0.1.8 → agent_alignment_protocol-0.3.0}/src/aap/verification/ssm.py +0 -0
@@ -68,6 +68,9 @@ architecture/
68
68
  gtm/
69
69
  traces/
70
70
 
71
+ # Node
72
+ node_modules/
73
+
71
74
  # Claude Code
72
75
  .claude/
73
76
  .mcp.json
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-alignment-protocol
3
- Version: 0.1.8
3
+ Version: 0.3.0
4
4
  Summary: Agent Alignment Protocol - The missing alignment layer for the agent protocol stack
5
5
  Project-URL: Homepage, https://github.com/mnemom/aap
6
6
  Project-URL: Documentation, https://github.com/mnemom/aap#readme
@@ -46,7 +46,7 @@ Description-Content-Type: text/markdown
46
46
  [![PyPI](https://img.shields.io/pypi/v/agent-alignment-protocol.svg)](https://pypi.org/project/agent-alignment-protocol/)
47
47
  [![npm](https://img.shields.io/npm/v/@mnemom/agent-alignment-protocol.svg)](https://www.npmjs.com/package/@mnemom/agent-alignment-protocol)
48
48
  [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
49
- [![Spec](https://img.shields.io/badge/spec-v0.1.0-green.svg)](docs/SPEC.md)
49
+ [![Spec](https://img.shields.io/badge/spec-v0.1.0-green.svg)](https://docs.mnemom.ai/protocols/aap/specification)
50
50
 
51
51
  **A transparency protocol for autonomous agents.**
52
52
 
@@ -207,7 +207,7 @@ This matters. Read it.
207
207
 
208
208
  5. **Tested on transformer-based agents.** Other architectures may exhibit behaviors AAP doesn't capture.
209
209
 
210
- For the complete limitations disclosure, see [Section 10 of the Specification](docs/SPEC.md#10-limitations).
210
+ For the complete limitations disclosure, see [Section 10 of the Specification](https://docs.mnemom.ai/protocols/aap/specification#10-limitations).
211
211
 
212
212
  ## Installation
213
213
 
@@ -236,7 +236,7 @@ AAP extends the A2A Agent Card with an `alignment` block:
236
236
  }
237
237
  ```
238
238
 
239
- See [A2A Migration Guide](docs/a2a-migration.md).
239
+ See [A2A Integration Guide](https://docs.mnemom.ai/protocols/aap/a2a-integration).
240
240
 
241
241
  ### With MCP Tools
242
242
 
@@ -250,7 +250,7 @@ def my_tool(params):
250
250
  ...
251
251
  ```
252
252
 
253
- See [MCP Migration Guide](docs/mcp-migration.md).
253
+ See [MCP Migration Guide](https://docs.mnemom.ai/protocols/aap/mcp-migration).
254
254
 
255
255
  ## Verification
256
256
 
@@ -317,18 +317,18 @@ No server required — runs entirely client-side via WebAssembly.
317
317
 
318
318
  | Document | Description |
319
319
  |----------|-------------|
320
- | [**SPEC.md**](docs/SPEC.md) | Full protocol specification (IETF-style) |
321
- | [**QUICKSTART.md**](docs/QUICKSTART.md) | Zero to compliant in 5 minutes |
322
- | [**LIMITS.md**](docs/LIMITS.md) | What AAP guarantees and doesn't |
323
- | [**SECURITY.md**](docs/SECURITY.md) | Threat model and security considerations |
324
- | [**CALIBRATION.md**](docs/CALIBRATION.md) | How verification thresholds were derived |
320
+ | [**Specification**](https://docs.mnemom.ai/protocols/aap/specification) | Full protocol specification (IETF-style) |
321
+ | [**Quick Start**](https://docs.mnemom.ai/protocols/aap/quickstart) | Zero to compliant in 5 minutes |
322
+ | [**Limitations**](https://docs.mnemom.ai/protocols/aap/limitations) | What AAP guarantees and doesn't |
323
+ | [**Security**](https://docs.mnemom.ai/protocols/aap/security) | Threat model and security considerations |
324
+ | [**Calibration**](https://docs.mnemom.ai/protocols/aap/calibration) | How verification thresholds were derived |
325
325
 
326
326
  ## Examples
327
327
 
328
328
  | Example | Description |
329
329
  |---------|-------------|
330
330
  | [`simple-agent/`](examples/simple-agent/) | Minimal AAP implementation |
331
- | [`a2a-integration/`](examples/a2a-integration/) | A2A agent with AAP |
331
+ | [`a2a-integration/`](examples/a2a-integration/) | A2A agent with AAP (Python + TypeScript) |
332
332
  | [`mcp-integration/`](examples/mcp-integration/) | MCP tools with alignment |
333
333
  | [`alignment-failure/`](examples/alignment-failure/) | Deliberate failure for testing |
334
334
 
@@ -374,6 +374,19 @@ from aap import (
374
374
  # aap drift --card CARD --traces TRACES_DIR → Uses SSM analysis
375
375
  ```
376
376
 
377
+ ## Standards & Compliance
378
+
379
+ AAP aligns with and supports compliance for the following international standards and regulatory frameworks:
380
+
381
+ | Standard | Relevance to AAP |
382
+ |----------|-----------------|
383
+ | **[ISO/IEC 42001:2023](https://www.iso.org/standard/42001)** — AI Management Systems | Alignment Card provides the structured AI system documentation required by 42001 management systems |
384
+ | **[ISO/IEC 42005:2025](https://www.iso.org/standard/42005)** — AI System Impact Assessment | AP-Trace and drift detection support ongoing impact assessment and monitoring |
385
+ | **[IEEE 7001-2021](https://standards.ieee.org/ieee/7001/6929/)** — Transparency of Autonomous Systems | AAP's core design goal — making agent decisions observable — directly implements IEEE 7001 transparency requirements |
386
+ | **[IEEE 3152-2024](https://standards.ieee.org/ieee/3152/11718/)** — Transparent Human and Machine Agency Identification | Alignment Card `agent_id`, `principal` block, and relationship types map to IEEE 3152 agency identification |
387
+ | **[Singapore IMDA Model AI Governance Framework for Agentic AI](https://www.imda.gov.sg/-/media/imda/files/about/emerging-tech-and-research/artificial-intelligence/mgf-for-agentic-ai.pdf)** (Jan 2026) | Alignment Card + Value Coherence Handshake address IMDA's agentic AI governance principles for multi-agent coordination |
388
+ | **[EU AI Act Article 50](https://artificialintelligenceact.eu/article/50/)** — Transparency Obligations (enforcement Aug 2026) | Alignment Card `principal` + disclosure fields, AP-Trace structured audit trails, and `audit_commitment.retention_days` support Article 50 compliance. See [EU AI Act Compliance Guide](https://docs.mnemom.ai/guides/eu-compliance) |
389
+
377
390
  ## Contributing
378
391
 
379
392
  We welcome contributions. See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
@@ -6,7 +6,7 @@
6
6
  [![PyPI](https://img.shields.io/pypi/v/agent-alignment-protocol.svg)](https://pypi.org/project/agent-alignment-protocol/)
7
7
  [![npm](https://img.shields.io/npm/v/@mnemom/agent-alignment-protocol.svg)](https://www.npmjs.com/package/@mnemom/agent-alignment-protocol)
8
8
  [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
9
- [![Spec](https://img.shields.io/badge/spec-v0.1.0-green.svg)](docs/SPEC.md)
9
+ [![Spec](https://img.shields.io/badge/spec-v0.1.0-green.svg)](https://docs.mnemom.ai/protocols/aap/specification)
10
10
 
11
11
  **A transparency protocol for autonomous agents.**
12
12
 
@@ -167,7 +167,7 @@ This matters. Read it.
167
167
 
168
168
  5. **Tested on transformer-based agents.** Other architectures may exhibit behaviors AAP doesn't capture.
169
169
 
170
- For the complete limitations disclosure, see [Section 10 of the Specification](docs/SPEC.md#10-limitations).
170
+ For the complete limitations disclosure, see [Section 10 of the Specification](https://docs.mnemom.ai/protocols/aap/specification#10-limitations).
171
171
 
172
172
  ## Installation
173
173
 
@@ -196,7 +196,7 @@ AAP extends the A2A Agent Card with an `alignment` block:
196
196
  }
197
197
  ```
198
198
 
199
- See [A2A Migration Guide](docs/a2a-migration.md).
199
+ See [A2A Integration Guide](https://docs.mnemom.ai/protocols/aap/a2a-integration).
200
200
 
201
201
  ### With MCP Tools
202
202
 
@@ -210,7 +210,7 @@ def my_tool(params):
210
210
  ...
211
211
  ```
212
212
 
213
- See [MCP Migration Guide](docs/mcp-migration.md).
213
+ See [MCP Migration Guide](https://docs.mnemom.ai/protocols/aap/mcp-migration).
214
214
 
215
215
  ## Verification
216
216
 
@@ -277,18 +277,18 @@ No server required — runs entirely client-side via WebAssembly.
277
277
 
278
278
  | Document | Description |
279
279
  |----------|-------------|
280
- | [**SPEC.md**](docs/SPEC.md) | Full protocol specification (IETF-style) |
281
- | [**QUICKSTART.md**](docs/QUICKSTART.md) | Zero to compliant in 5 minutes |
282
- | [**LIMITS.md**](docs/LIMITS.md) | What AAP guarantees and doesn't |
283
- | [**SECURITY.md**](docs/SECURITY.md) | Threat model and security considerations |
284
- | [**CALIBRATION.md**](docs/CALIBRATION.md) | How verification thresholds were derived |
280
+ | [**Specification**](https://docs.mnemom.ai/protocols/aap/specification) | Full protocol specification (IETF-style) |
281
+ | [**Quick Start**](https://docs.mnemom.ai/protocols/aap/quickstart) | Zero to compliant in 5 minutes |
282
+ | [**Limitations**](https://docs.mnemom.ai/protocols/aap/limitations) | What AAP guarantees and doesn't |
283
+ | [**Security**](https://docs.mnemom.ai/protocols/aap/security) | Threat model and security considerations |
284
+ | [**Calibration**](https://docs.mnemom.ai/protocols/aap/calibration) | How verification thresholds were derived |
285
285
 
286
286
  ## Examples
287
287
 
288
288
  | Example | Description |
289
289
  |---------|-------------|
290
290
  | [`simple-agent/`](examples/simple-agent/) | Minimal AAP implementation |
291
- | [`a2a-integration/`](examples/a2a-integration/) | A2A agent with AAP |
291
+ | [`a2a-integration/`](examples/a2a-integration/) | A2A agent with AAP (Python + TypeScript) |
292
292
  | [`mcp-integration/`](examples/mcp-integration/) | MCP tools with alignment |
293
293
  | [`alignment-failure/`](examples/alignment-failure/) | Deliberate failure for testing |
294
294
 
@@ -334,6 +334,19 @@ from aap import (
334
334
  # aap drift --card CARD --traces TRACES_DIR → Uses SSM analysis
335
335
  ```
336
336
 
337
+ ## Standards & Compliance
338
+
339
+ AAP aligns with and supports compliance for the following international standards and regulatory frameworks:
340
+
341
+ | Standard | Relevance to AAP |
342
+ |----------|-----------------|
343
+ | **[ISO/IEC 42001:2023](https://www.iso.org/standard/42001)** — AI Management Systems | Alignment Card provides the structured AI system documentation required by 42001 management systems |
344
+ | **[ISO/IEC 42005:2025](https://www.iso.org/standard/42005)** — AI System Impact Assessment | AP-Trace and drift detection support ongoing impact assessment and monitoring |
345
+ | **[IEEE 7001-2021](https://standards.ieee.org/ieee/7001/6929/)** — Transparency of Autonomous Systems | AAP's core design goal — making agent decisions observable — directly implements IEEE 7001 transparency requirements |
346
+ | **[IEEE 3152-2024](https://standards.ieee.org/ieee/3152/11718/)** — Transparent Human and Machine Agency Identification | Alignment Card `agent_id`, `principal` block, and relationship types map to IEEE 3152 agency identification |
347
+ | **[Singapore IMDA Model AI Governance Framework for Agentic AI](https://www.imda.gov.sg/-/media/imda/files/about/emerging-tech-and-research/artificial-intelligence/mgf-for-agentic-ai.pdf)** (Jan 2026) | Alignment Card + Value Coherence Handshake address IMDA's agentic AI governance principles for multi-agent coordination |
348
+ | **[EU AI Act Article 50](https://artificialintelligenceact.eu/article/50/)** — Transparency Obligations (enforcement Aug 2026) | Alignment Card `principal` + disclosure fields, AP-Trace structured audit trails, and `audit_commitment.retention_days` support Article 50 compliance. See [EU AI Act Compliance Guide](https://docs.mnemom.ai/guides/eu-compliance) |
349
+
337
350
  ## Contributing
338
351
 
339
352
  We welcome contributions. See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "agent-alignment-protocol"
7
- version = "0.1.8"
7
+ version = "0.3.0"
8
8
  description = "Agent Alignment Protocol - The missing alignment layer for the agent protocol stack"
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -36,18 +36,21 @@ Quick Start:
36
36
  See docs/SPEC.md for the full protocol specification.
37
37
  """
38
38
 
39
- __version__ = "0.1.0"
39
+ __version__ = "0.3.0"
40
+
41
+ # EU AI Act compliance presets
42
+ from aap.compliance import (
43
+ EU_COMPLIANCE_AUDIT_COMMITMENT,
44
+ EU_COMPLIANCE_EXTENSIONS,
45
+ EU_COMPLIANCE_VALUES,
46
+ )
40
47
 
41
- # Core verification API
42
48
  # Schema models
43
49
  from aap.schemas import (
44
- # AP-Trace
45
50
  Action,
46
51
  ActionCategory,
47
52
  ActionType,
48
- # Alignment Card
49
53
  AlignmentCard,
50
- # Value Coherence Handshake
51
54
  AlignmentCardRequest,
52
55
  AlignmentCardResponse,
53
56
  Alternative,
@@ -82,20 +85,27 @@ from aap.tracing import (
82
85
 
83
86
  # Verification result models
84
87
  from aap.verification import (
88
+ AgentCoherenceSummary,
85
89
  CoherenceResult,
86
90
  DriftAlert,
87
91
  DriftAnalysis,
88
92
  DriftDirection,
89
93
  DriftIndicator,
94
+ FleetCluster,
95
+ FleetCoherenceResult,
96
+ FleetOutlier,
97
+ PairwiseEntry,
90
98
  Severity,
91
99
  ValueAlignment,
92
100
  ValueConflict,
101
+ ValueDivergence,
93
102
  VerificationMetadata,
94
103
  VerificationResult,
95
104
  Violation,
96
105
  ViolationType,
97
106
  Warning,
98
107
  check_coherence,
108
+ check_fleet_coherence,
99
109
  detect_drift,
100
110
  verify_trace,
101
111
  )
@@ -106,6 +116,7 @@ __all__ = [
106
116
  # Core API
107
117
  "verify_trace",
108
118
  "check_coherence",
119
+ "check_fleet_coherence",
109
120
  "detect_drift",
110
121
  # Tracing Decorators
111
122
  "trace_decision",
@@ -126,6 +137,13 @@ __all__ = [
126
137
  "CoherenceResult",
127
138
  "ValueAlignment",
128
139
  "ValueConflict",
140
+ # Fleet Coherence (E-05)
141
+ "FleetCoherenceResult",
142
+ "PairwiseEntry",
143
+ "FleetOutlier",
144
+ "FleetCluster",
145
+ "ValueDivergence",
146
+ "AgentCoherenceSummary",
129
147
  "DriftAlert",
130
148
  "DriftAnalysis",
131
149
  "DriftDirection",
@@ -155,4 +173,8 @@ __all__ = [
155
173
  "ValueCoherenceCheck",
156
174
  "CoherenceResultMessage",
157
175
  "ProposedCollaboration",
176
+ # EU AI Act Compliance
177
+ "EU_COMPLIANCE_AUDIT_COMMITMENT",
178
+ "EU_COMPLIANCE_EXTENSIONS",
179
+ "EU_COMPLIANCE_VALUES",
158
180
  ]
@@ -0,0 +1,56 @@
1
+ """EU AI Act Article 50 compliance presets for AAP.
2
+
3
+ These presets provide recommended configuration values for deploying
4
+ AAP-instrumented agents in EU jurisdictions subject to AI Act
5
+ transparency obligations. Spread them into your AlignmentCard fields.
6
+
7
+ Usage:
8
+ from aap.compliance import (
9
+ EU_COMPLIANCE_AUDIT_COMMITMENT,
10
+ EU_COMPLIANCE_EXTENSIONS,
11
+ EU_COMPLIANCE_VALUES,
12
+ )
13
+
14
+ card = AlignmentCard(
15
+ ...,
16
+ audit_commitment=AuditCommitment(**EU_COMPLIANCE_AUDIT_COMMITMENT),
17
+ values=Values(declared=EU_COMPLIANCE_VALUES, ...),
18
+ extensions=EU_COMPLIANCE_EXTENSIONS,
19
+ )
20
+
21
+ DISCLAIMER: These presets reflect a technical mapping of AAP features to
22
+ Article 50 requirements. They do not constitute legal advice. Consult
23
+ qualified legal counsel for your specific compliance obligations.
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ # Audit commitment values that satisfy Article 50(4) audit trail requirements.
29
+ EU_COMPLIANCE_AUDIT_COMMITMENT: dict = {
30
+ "retention_days": 90,
31
+ "queryable": True,
32
+ "query_endpoint": "https://audit.example.com/traces",
33
+ "tamper_evidence": "append_only",
34
+ "trace_format": "ap-trace-v1",
35
+ }
36
+
37
+ # Extension block for EU AI Act metadata on the Alignment Card.
38
+ EU_COMPLIANCE_EXTENSIONS: dict = {
39
+ "eu_ai_act": {
40
+ "article_50_compliant": True,
41
+ "ai_system_classification": "general_purpose",
42
+ "disclosure_text": (
43
+ "This system is powered by an AI agent. Its decisions are logged "
44
+ "and auditable. You may request a human review of any decision."
45
+ ),
46
+ "compliance_version": "2026-08",
47
+ },
48
+ }
49
+
50
+ # Recommended declared values for Article 50 transparency obligations.
51
+ EU_COMPLIANCE_VALUES: list[str] = [
52
+ "transparency",
53
+ "honesty",
54
+ "user_control",
55
+ "principal_benefit",
56
+ ]
@@ -36,6 +36,7 @@ See SPEC.md Sections 7, 6.4, and 8 for protocol specification.
36
36
 
37
37
  from aap.verification.api import (
38
38
  check_coherence,
39
+ check_fleet_coherence,
39
40
  detect_drift,
40
41
  verify_trace,
41
42
  )
@@ -57,14 +58,20 @@ from aap.verification.features import (
57
58
  cosine_similarity,
58
59
  )
59
60
  from aap.verification.models import (
61
+ AgentCoherenceSummary,
60
62
  CoherenceResult,
61
63
  DriftAlert,
62
64
  DriftAnalysis,
63
65
  DriftDirection,
64
66
  DriftIndicator,
67
+ FleetCluster,
68
+ FleetCoherenceResult,
69
+ FleetOutlier,
70
+ PairwiseEntry,
65
71
  Severity,
66
72
  ValueAlignment,
67
73
  ValueConflict,
74
+ ValueDivergence,
68
75
  VerificationMetadata,
69
76
  VerificationResult,
70
77
  Violation,
@@ -80,6 +87,7 @@ __all__ = [
80
87
  # Core functions
81
88
  "verify_trace",
82
89
  "check_coherence",
90
+ "check_fleet_coherence",
83
91
  "detect_drift",
84
92
  # SSM and Divergence (Phase 1 Braid extraction)
85
93
  "SSMAnalyzer",
@@ -91,6 +99,13 @@ __all__ = [
91
99
  "compute_centroid",
92
100
  "cosine_similarity",
93
101
  "compute_similarity_with_tfidf",
102
+ # Fleet Coherence (E-05)
103
+ "FleetCoherenceResult",
104
+ "PairwiseEntry",
105
+ "FleetOutlier",
106
+ "FleetCluster",
107
+ "ValueDivergence",
108
+ "AgentCoherenceSummary",
94
109
  # Result models
95
110
  "VerificationResult",
96
111
  "Violation",
@@ -10,8 +10,10 @@ See SPEC.md Sections 7, 6.4, and 8 for protocol specification.
10
10
 
11
11
  from __future__ import annotations
12
12
 
13
+ import math
13
14
  import re
14
15
  import time
16
+ from collections import defaultdict
15
17
  from datetime import datetime
16
18
  from typing import Any
17
19
 
@@ -23,14 +25,21 @@ from aap.verification.constants import (
23
25
  DEFAULT_SUSTAINED_TURNS_THRESHOLD,
24
26
  MIN_COHERENCE_FOR_PROCEED,
25
27
  NEAR_BOUNDARY_THRESHOLD,
28
+ OUTLIER_STD_DEV_THRESHOLD,
26
29
  )
27
30
  from aap.verification.models import (
31
+ AgentCoherenceSummary,
28
32
  CoherenceResult,
29
33
  DriftAlert,
30
34
  DriftDirection,
31
35
  DriftIndicator,
36
+ FleetCluster,
37
+ FleetCoherenceResult,
38
+ FleetOutlier,
39
+ PairwiseEntry,
32
40
  ValueAlignment,
33
41
  ValueConflict,
42
+ ValueDivergence,
34
43
  VerificationMetadata,
35
44
  VerificationResult,
36
45
  Violation,
@@ -334,6 +343,227 @@ def check_coherence(
334
343
  )
335
344
 
336
345
 
346
+ def check_fleet_coherence(
347
+ cards: list[dict[str, Any]],
348
+ task_values: list[str] | None = None,
349
+ ) -> FleetCoherenceResult:
350
+ """Check fleet-level value coherence across N agents.
351
+
352
+ Computes all C(n,2) pairwise coherence scores, then derives:
353
+ - Fleet score: mean of all pairwise scores
354
+ - Outlier detection: agents >1 std dev below fleet mean
355
+ - Cluster analysis: connected components at compatibility threshold
356
+ - Divergence report: values where agents disagree
357
+
358
+ Args:
359
+ cards: List of dicts with "agent_id" and "card" keys
360
+ task_values: Optional list of values required for the task
361
+
362
+ Returns:
363
+ FleetCoherenceResult with full analysis
364
+
365
+ Raises:
366
+ ValueError: If fewer than 2 agents provided
367
+ """
368
+ if len(cards) < 2:
369
+ raise ValueError("Fleet coherence requires at least 2 agents")
370
+
371
+ agent_ids = [c["agent_id"] for c in cards]
372
+
373
+ # Step 1: Compute all pairwise coherence scores
374
+ pairwise_matrix: list[PairwiseEntry] = []
375
+ for i in range(len(cards)):
376
+ for j in range(i + 1, len(cards)):
377
+ result = check_coherence(cards[i]["card"], cards[j]["card"], task_values)
378
+ pairwise_matrix.append(PairwiseEntry(
379
+ agent_a=cards[i]["agent_id"],
380
+ agent_b=cards[j]["agent_id"],
381
+ result=result,
382
+ ))
383
+
384
+ # Step 2: Fleet score (mean of all pairwise scores) + min/max
385
+ all_scores = [p.result.score for p in pairwise_matrix]
386
+ fleet_score = sum(all_scores) / len(all_scores)
387
+ min_pair_score = min(all_scores)
388
+ max_pair_score = max(all_scores)
389
+
390
+ # Step 3: Per-agent summaries
391
+ agent_scores: dict[str, list[float]] = defaultdict(list)
392
+ agent_compatible: dict[str, int] = defaultdict(int)
393
+ agent_conflict: dict[str, int] = defaultdict(int)
394
+
395
+ for pair in pairwise_matrix:
396
+ agent_scores[pair.agent_a].append(pair.result.score)
397
+ agent_scores[pair.agent_b].append(pair.result.score)
398
+ if pair.result.compatible:
399
+ agent_compatible[pair.agent_a] += 1
400
+ agent_compatible[pair.agent_b] += 1
401
+ if len(pair.result.value_alignment.conflicts) > 0:
402
+ agent_conflict[pair.agent_a] += 1
403
+ agent_conflict[pair.agent_b] += 1
404
+
405
+ agent_means: dict[str, float] = {}
406
+ for aid in agent_ids:
407
+ scores = agent_scores[aid]
408
+ agent_means[aid] = sum(scores) / len(scores) if scores else 0.0
409
+
410
+ # Step 4: Outlier detection
411
+ mean_values = list(agent_means.values())
412
+ fleet_mean_of_means = sum(mean_values) / len(mean_values)
413
+ variance = sum((v - fleet_mean_of_means) ** 2 for v in mean_values) / len(mean_values)
414
+ stddev = math.sqrt(variance)
415
+
416
+ outliers: list[FleetOutlier] = []
417
+ if stddev > 0 and len(agent_ids) >= 3:
418
+ for aid in agent_ids:
419
+ agent_mean = agent_means[aid]
420
+ deviation = (fleet_mean_of_means - agent_mean) / stddev
421
+ if deviation >= OUTLIER_STD_DEV_THRESHOLD:
422
+ primary_conflicts: set[str] = set()
423
+ for pair in pairwise_matrix:
424
+ if pair.agent_a == aid or pair.agent_b == aid:
425
+ for conflict in pair.result.value_alignment.conflicts:
426
+ if conflict.initiator_value != "(conflicts_with)":
427
+ primary_conflicts.add(conflict.initiator_value)
428
+ if conflict.responder_value != "(conflicts_with)":
429
+ primary_conflicts.add(conflict.responder_value)
430
+ outliers.append(FleetOutlier(
431
+ agent_id=aid,
432
+ agent_mean_score=round(agent_mean, 4),
433
+ fleet_mean_score=round(fleet_mean_of_means, 4),
434
+ deviation=round(deviation, 4),
435
+ primary_conflicts=sorted(primary_conflicts),
436
+ ))
437
+
438
+ # Step 5: Cluster analysis (connected components at compatibility threshold)
439
+ adjacency: dict[str, set[str]] = {aid: set() for aid in agent_ids}
440
+ for pair in pairwise_matrix:
441
+ if pair.result.compatible:
442
+ adjacency[pair.agent_a].add(pair.agent_b)
443
+ adjacency[pair.agent_b].add(pair.agent_a)
444
+
445
+ visited: set[str] = set()
446
+ clusters: list[FleetCluster] = []
447
+ cluster_id = 0
448
+
449
+ for aid in agent_ids:
450
+ if aid in visited:
451
+ continue
452
+ component: list[str] = []
453
+ queue = [aid]
454
+ visited.add(aid)
455
+ while queue:
456
+ current = queue.pop(0)
457
+ component.append(current)
458
+ for neighbor in adjacency[current]:
459
+ if neighbor not in visited:
460
+ visited.add(neighbor)
461
+ queue.append(neighbor)
462
+
463
+ # Compute internal coherence
464
+ internal_sum = 0.0
465
+ internal_count = 0
466
+ for ci in range(len(component)):
467
+ for cj in range(ci + 1, len(component)):
468
+ for pair in pairwise_matrix:
469
+ if ((pair.agent_a == component[ci] and pair.agent_b == component[cj]) or
470
+ (pair.agent_a == component[cj] and pair.agent_b == component[ci])):
471
+ internal_sum += pair.result.score
472
+ internal_count += 1
473
+ break
474
+ internal_coherence = internal_sum / internal_count if internal_count > 0 else 1.0
475
+
476
+ # Find shared values
477
+ cluster_cards_list = [c for c in cards if c["agent_id"] in component]
478
+ shared: set[str] | None = None
479
+ for entry in cluster_cards_list:
480
+ declared = set(entry["card"].get("values", {}).get("declared", []))
481
+ shared = declared if shared is None else shared & declared
482
+ shared_values = sorted(shared or set())
483
+
484
+ # Find distinguishing values
485
+ other_values: set[str] = set()
486
+ for entry in cards:
487
+ if entry["agent_id"] not in component:
488
+ for v in entry["card"].get("values", {}).get("declared", []):
489
+ other_values.add(v)
490
+ distinguishing = [v for v in shared_values if v not in other_values]
491
+
492
+ clusters.append(FleetCluster(
493
+ cluster_id=cluster_id,
494
+ agent_ids=component,
495
+ internal_coherence=round(internal_coherence, 4),
496
+ shared_values=shared_values,
497
+ distinguishing_values=distinguishing,
498
+ ))
499
+ cluster_id += 1
500
+
501
+ # Step 6: Divergence report
502
+ all_values: set[str] = set()
503
+ agent_value_map: dict[str, set[str]] = {}
504
+ agent_conflict_map: dict[str, set[str]] = {}
505
+
506
+ for entry in cards:
507
+ declared = set(entry["card"].get("values", {}).get("declared", []))
508
+ conflicts_with = set(entry["card"].get("values", {}).get("conflicts_with", []))
509
+ agent_value_map[entry["agent_id"]] = declared
510
+ agent_conflict_map[entry["agent_id"]] = conflicts_with
511
+ all_values |= declared
512
+
513
+ divergence_report: list[ValueDivergence] = []
514
+ for value in all_values:
515
+ declaring = [aid for aid in agent_ids if value in agent_value_map[aid]]
516
+ missing = [aid for aid in agent_ids if value not in agent_value_map[aid]]
517
+ conflicting = [aid for aid in agent_ids if value in agent_conflict_map[aid]]
518
+
519
+ if not missing and not conflicting:
520
+ continue
521
+
522
+ impact = round((len(missing) + len(conflicting)) / len(agent_ids), 4)
523
+ divergence_report.append(ValueDivergence(
524
+ value=value,
525
+ agents_declaring=declaring,
526
+ agents_missing=missing,
527
+ agents_conflicting=conflicting,
528
+ impact_on_fleet_score=impact,
529
+ ))
530
+
531
+ divergence_report.sort(key=lambda d: d.impact_on_fleet_score, reverse=True)
532
+
533
+ # Build agent cluster map
534
+ agent_cluster_map: dict[str, int] = {}
535
+ for cluster in clusters:
536
+ for aid in cluster.agent_ids:
537
+ agent_cluster_map[aid] = cluster.cluster_id
538
+
539
+ outlier_ids = {o.agent_id for o in outliers}
540
+
541
+ agent_summaries = [
542
+ AgentCoherenceSummary(
543
+ agent_id=aid,
544
+ mean_score=round(agent_means[aid], 4),
545
+ compatible_count=agent_compatible[aid],
546
+ conflict_count=agent_conflict[aid],
547
+ cluster_id=agent_cluster_map.get(aid, 0),
548
+ is_outlier=aid in outlier_ids,
549
+ )
550
+ for aid in agent_ids
551
+ ]
552
+
553
+ return FleetCoherenceResult(
554
+ fleet_score=round(fleet_score, 4),
555
+ min_pair_score=round(min_pair_score, 4),
556
+ max_pair_score=round(max_pair_score, 4),
557
+ agent_count=len(cards),
558
+ pair_count=len(pairwise_matrix),
559
+ pairwise_matrix=pairwise_matrix,
560
+ outliers=outliers,
561
+ clusters=clusters,
562
+ divergence_report=divergence_report,
563
+ agent_summaries=agent_summaries,
564
+ )
565
+
566
+
337
567
  def detect_drift(
338
568
  card: dict[str, Any],
339
569
  traces: list[dict[str, Any]],
@@ -38,6 +38,15 @@ MIN_COHERENCE_FOR_PROCEED: float = 0.70
38
38
  CONFLICT_PENALTY_MULTIPLIER: float = 0.50
39
39
 
40
40
 
41
+ # Fleet Coherence
42
+ # ----------------
43
+ # Standard deviations below fleet mean to flag an agent as outlier
44
+ OUTLIER_STD_DEV_THRESHOLD: float = 1.0
45
+
46
+ # Minimum pairwise score to consider agents compatible for cluster analysis
47
+ CLUSTER_COMPATIBILITY_THRESHOLD: float = 0.70
48
+
49
+
41
50
  # Feature Extraction
42
51
  # ------------------
43
52
  # Minimum word length for content features (filters noise)
@@ -258,3 +258,108 @@ class ValueConflict(BaseModel):
258
258
 
259
259
  # Rebuild models with forward references
260
260
  CoherenceResult.model_rebuild()
261
+
262
+
263
+ # --- Fleet Coherence Types (E-05: N-Way Value Coherence) ---
264
+
265
+
266
+ class PairwiseEntry(BaseModel):
267
+ """A single pairwise coherence entry in the fleet matrix."""
268
+
269
+ agent_a: str = Field(..., description="First agent ID")
270
+ agent_b: str = Field(..., description="Second agent ID")
271
+ result: CoherenceResult = Field(..., description="Pairwise coherence result")
272
+
273
+
274
+ class FleetOutlier(BaseModel):
275
+ """An agent flagged as an outlier in fleet coherence."""
276
+
277
+ agent_id: str = Field(..., description="Agent ID")
278
+ agent_mean_score: float = Field(..., description="Agent's mean pairwise score")
279
+ fleet_mean_score: float = Field(..., description="Fleet-wide mean score")
280
+ deviation: float = Field(..., description="Standard deviations below fleet mean")
281
+ primary_conflicts: list[str] = Field(
282
+ default_factory=list, description="Values causing primary conflicts"
283
+ )
284
+
285
+
286
+ class FleetCluster(BaseModel):
287
+ """A cluster of compatible agents."""
288
+
289
+ cluster_id: int = Field(..., description="Cluster identifier")
290
+ agent_ids: list[str] = Field(..., description="Agent IDs in this cluster")
291
+ internal_coherence: float = Field(
292
+ ..., description="Mean coherence score within the cluster"
293
+ )
294
+ shared_values: list[str] = Field(
295
+ default_factory=list,
296
+ description="Values shared by all agents in the cluster",
297
+ )
298
+ distinguishing_values: list[str] = Field(
299
+ default_factory=list,
300
+ description="Values that distinguish this cluster from others",
301
+ )
302
+
303
+
304
+ class ValueDivergence(BaseModel):
305
+ """A value dimension where agents diverge."""
306
+
307
+ value: str = Field(..., description="The value in question")
308
+ agents_declaring: list[str] = Field(
309
+ default_factory=list, description="Agent IDs that declare this value"
310
+ )
311
+ agents_missing: list[str] = Field(
312
+ default_factory=list, description="Agent IDs missing this value"
313
+ )
314
+ agents_conflicting: list[str] = Field(
315
+ default_factory=list,
316
+ description="Agent IDs whose conflicts_with includes this value",
317
+ )
318
+ impact_on_fleet_score: float = Field(
319
+ ..., description="Estimated impact on fleet score if resolved"
320
+ )
321
+
322
+
323
+ class AgentCoherenceSummary(BaseModel):
324
+ """Summary of one agent's position in the fleet."""
325
+
326
+ agent_id: str = Field(..., description="Agent ID")
327
+ mean_score: float = Field(
328
+ ..., description="Mean pairwise score with all other agents"
329
+ )
330
+ compatible_count: int = Field(..., description="Number of compatible pairs")
331
+ conflict_count: int = Field(..., description="Number of conflicting pairs")
332
+ cluster_id: int = Field(..., description="Cluster this agent belongs to")
333
+ is_outlier: bool = Field(
334
+ ..., description="Whether this agent is flagged as an outlier"
335
+ )
336
+
337
+
338
+ class FleetCoherenceResult(BaseModel):
339
+ """Result of N-way fleet coherence analysis."""
340
+
341
+ fleet_score: float = Field(
342
+ ..., description="Mean of all pairwise coherence scores"
343
+ )
344
+ min_pair_score: float = Field(
345
+ ..., description="Minimum pairwise score (weakest link)"
346
+ )
347
+ max_pair_score: float = Field(..., description="Maximum pairwise score")
348
+ agent_count: int = Field(..., description="Number of agents analyzed")
349
+ pair_count: int = Field(..., description="Number of pairwise comparisons")
350
+ pairwise_matrix: list[PairwiseEntry] = Field(
351
+ ..., description="All pairwise coherence results"
352
+ )
353
+ outliers: list[FleetOutlier] = Field(
354
+ default_factory=list, description="Agents flagged as outliers"
355
+ )
356
+ clusters: list[FleetCluster] = Field(
357
+ default_factory=list, description="Clusters of compatible agents"
358
+ )
359
+ divergence_report: list[ValueDivergence] = Field(
360
+ default_factory=list,
361
+ description="Value dimensions where agents diverge",
362
+ )
363
+ agent_summaries: list[AgentCoherenceSummary] = Field(
364
+ default_factory=list, description="Per-agent coherence summaries"
365
+ )