agent-alignment-protocol 0.5.0__tar.gz → 2.0.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.5.0 → agent_alignment_protocol-2.0.0}/.gitignore +2 -0
  2. {agent_alignment_protocol-0.5.0 → agent_alignment_protocol-2.0.0}/PKG-INFO +23 -8
  3. {agent_alignment_protocol-0.5.0 → agent_alignment_protocol-2.0.0}/README.md +22 -7
  4. {agent_alignment_protocol-0.5.0 → agent_alignment_protocol-2.0.0}/pyproject.toml +8 -1
  5. {agent_alignment_protocol-0.5.0 → agent_alignment_protocol-2.0.0}/schemas/alignment-card.schema.json +62 -83
  6. {agent_alignment_protocol-0.5.0 → agent_alignment_protocol-2.0.0}/src/aap/__init__.py +16 -8
  7. {agent_alignment_protocol-0.5.0 → agent_alignment_protocol-2.0.0}/src/aap/cli/main.py +23 -9
  8. {agent_alignment_protocol-0.5.0 → agent_alignment_protocol-2.0.0}/src/aap/compliance.py +4 -3
  9. {agent_alignment_protocol-0.5.0 → agent_alignment_protocol-2.0.0}/src/aap/schemas/__init__.py +18 -14
  10. {agent_alignment_protocol-0.5.0 → agent_alignment_protocol-2.0.0}/src/aap/schemas/alignment_card.py +126 -53
  11. {agent_alignment_protocol-0.5.0 → agent_alignment_protocol-2.0.0}/src/aap/schemas/ap_trace.py +28 -1
  12. {agent_alignment_protocol-0.5.0 → agent_alignment_protocol-2.0.0}/src/aap/verification/api.py +24 -4
  13. {agent_alignment_protocol-0.5.0 → agent_alignment_protocol-2.0.0}/src/aap/verification/features.py +5 -4
  14. {agent_alignment_protocol-0.5.0 → agent_alignment_protocol-2.0.0}/LICENSE +0 -0
  15. {agent_alignment_protocol-0.5.0 → agent_alignment_protocol-2.0.0}/schemas/ap-trace.schema.json +0 -0
  16. {agent_alignment_protocol-0.5.0 → agent_alignment_protocol-2.0.0}/schemas/value-coherence.schema.json +0 -0
  17. {agent_alignment_protocol-0.5.0 → agent_alignment_protocol-2.0.0}/src/aap/cli/__init__.py +0 -0
  18. {agent_alignment_protocol-0.5.0 → agent_alignment_protocol-2.0.0}/src/aap/py.typed +0 -0
  19. {agent_alignment_protocol-0.5.0 → agent_alignment_protocol-2.0.0}/src/aap/schemas/value_coherence.py +0 -0
  20. {agent_alignment_protocol-0.5.0 → agent_alignment_protocol-2.0.0}/src/aap/tracing.py +0 -0
  21. {agent_alignment_protocol-0.5.0 → agent_alignment_protocol-2.0.0}/src/aap/verification/__init__.py +0 -0
  22. {agent_alignment_protocol-0.5.0 → agent_alignment_protocol-2.0.0}/src/aap/verification/constants.py +0 -0
  23. {agent_alignment_protocol-0.5.0 → agent_alignment_protocol-2.0.0}/src/aap/verification/divergence.py +0 -0
  24. {agent_alignment_protocol-0.5.0 → agent_alignment_protocol-2.0.0}/src/aap/verification/models.py +0 -0
  25. {agent_alignment_protocol-0.5.0 → agent_alignment_protocol-2.0.0}/src/aap/verification/ssm.py +0 -0
@@ -40,6 +40,8 @@ env/
40
40
  .coverage
41
41
  .coverage.*
42
42
  htmlcov/
43
+ coverage/
44
+ coverage.xml
43
45
  .pytest_cache/
44
46
  .hypothesis/
45
47
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-alignment-protocol
3
- Version: 0.5.0
3
+ Version: 2.0.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.4.0-green.svg)](https://docs.mnemom.ai/protocols/aap/specification)
49
+ [![Spec](https://img.shields.io/badge/spec-v1.0.0-green.svg)](https://docs.mnemom.ai/protocols/aap/specification)
50
50
 
51
51
  **A transparency protocol for autonomous agents.**
52
52
 
@@ -111,21 +111,27 @@ As agent capabilities become symmetric—equal access to information, equal reas
111
111
 
112
112
  ### Alignment Card
113
113
 
114
- A structured declaration of an agent's alignment posture:
114
+ A structured declaration of an agent's alignment posture, in the unified /
115
+ ADR-039 shape accepted by `mnemom card validate` and the Mnemom platform:
115
116
 
116
117
  ```json
117
118
  {
118
- "aap_version": "0.1.0",
119
+ "card_version": "unified/2026-04-26",
120
+ "card_id": "ac-my-agent-001",
119
121
  "agent_id": "did:web:my-agent.example.com",
122
+ "issued_at": "2026-04-26T00:00:00Z",
123
+ "autonomy_mode": "enforce",
124
+ "integrity_mode": "enforce",
120
125
  "principal": {
121
126
  "type": "human",
127
+ "identifier": "did:web:user.example.com",
122
128
  "relationship": "delegated_authority"
123
129
  },
124
130
  "values": {
125
131
  "declared": ["principal_benefit", "transparency", "minimal_data"],
126
132
  "conflicts_with": ["deceptive_marketing", "hidden_fees"]
127
133
  },
128
- "autonomy_envelope": {
134
+ "autonomy": {
129
135
  "bounded_actions": ["search", "compare", "recommend"],
130
136
  "escalation_triggers": [
131
137
  {
@@ -136,14 +142,23 @@ A structured declaration of an agent's alignment posture:
136
142
  ],
137
143
  "forbidden_actions": ["share_credentials", "subscribe_to_services"]
138
144
  },
139
- "audit_commitment": {
145
+ "audit": {
140
146
  "trace_format": "ap-trace-v1",
141
147
  "retention_days": 90,
142
- "queryable": true
148
+ "queryable": true,
149
+ "query_endpoint": "https://my-agent.example.com/api/traces"
143
150
  }
144
151
  }
145
152
  ```
146
153
 
154
+ > **Migration note (v2.0.0):** earlier releases used the AAP 0.5.0 card shape
155
+ > (`aap_version`, `autonomy_envelope`, `audit_commitment`). The card has moved
156
+ > to the unified / ADR-039 shape above: `autonomy_envelope` → `autonomy`,
157
+ > `audit_commitment` → `audit`, `aap_version` → `card_version`, plus the
158
+ > top-level `autonomy_mode` / `integrity_mode` master switches and a required
159
+ > `principal.identifier` when `principal.type != "unspecified"`. See the
160
+ > [Alignment Card Schema](https://docs.mnemom.ai/specifications/alignment-card-schema).
161
+
147
162
  ### AP-Trace
148
163
 
149
164
  An audit log entry recording each decision:
@@ -385,7 +400,7 @@ AAP aligns with and supports compliance for the following international standard
385
400
  | **[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
401
  | **[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
402
  | **[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) |
403
+ | **[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.retention_days` support Article 50 compliance. See [EU AI Act Compliance Guide](https://docs.mnemom.ai/guides/eu-compliance) |
389
404
 
390
405
  ## Contributing
391
406
 
@@ -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.4.0-green.svg)](https://docs.mnemom.ai/protocols/aap/specification)
9
+ [![Spec](https://img.shields.io/badge/spec-v1.0.0-green.svg)](https://docs.mnemom.ai/protocols/aap/specification)
10
10
 
11
11
  **A transparency protocol for autonomous agents.**
12
12
 
@@ -71,21 +71,27 @@ As agent capabilities become symmetric—equal access to information, equal reas
71
71
 
72
72
  ### Alignment Card
73
73
 
74
- A structured declaration of an agent's alignment posture:
74
+ A structured declaration of an agent's alignment posture, in the unified /
75
+ ADR-039 shape accepted by `mnemom card validate` and the Mnemom platform:
75
76
 
76
77
  ```json
77
78
  {
78
- "aap_version": "0.1.0",
79
+ "card_version": "unified/2026-04-26",
80
+ "card_id": "ac-my-agent-001",
79
81
  "agent_id": "did:web:my-agent.example.com",
82
+ "issued_at": "2026-04-26T00:00:00Z",
83
+ "autonomy_mode": "enforce",
84
+ "integrity_mode": "enforce",
80
85
  "principal": {
81
86
  "type": "human",
87
+ "identifier": "did:web:user.example.com",
82
88
  "relationship": "delegated_authority"
83
89
  },
84
90
  "values": {
85
91
  "declared": ["principal_benefit", "transparency", "minimal_data"],
86
92
  "conflicts_with": ["deceptive_marketing", "hidden_fees"]
87
93
  },
88
- "autonomy_envelope": {
94
+ "autonomy": {
89
95
  "bounded_actions": ["search", "compare", "recommend"],
90
96
  "escalation_triggers": [
91
97
  {
@@ -96,14 +102,23 @@ A structured declaration of an agent's alignment posture:
96
102
  ],
97
103
  "forbidden_actions": ["share_credentials", "subscribe_to_services"]
98
104
  },
99
- "audit_commitment": {
105
+ "audit": {
100
106
  "trace_format": "ap-trace-v1",
101
107
  "retention_days": 90,
102
- "queryable": true
108
+ "queryable": true,
109
+ "query_endpoint": "https://my-agent.example.com/api/traces"
103
110
  }
104
111
  }
105
112
  ```
106
113
 
114
+ > **Migration note (v2.0.0):** earlier releases used the AAP 0.5.0 card shape
115
+ > (`aap_version`, `autonomy_envelope`, `audit_commitment`). The card has moved
116
+ > to the unified / ADR-039 shape above: `autonomy_envelope` → `autonomy`,
117
+ > `audit_commitment` → `audit`, `aap_version` → `card_version`, plus the
118
+ > top-level `autonomy_mode` / `integrity_mode` master switches and a required
119
+ > `principal.identifier` when `principal.type != "unspecified"`. See the
120
+ > [Alignment Card Schema](https://docs.mnemom.ai/specifications/alignment-card-schema).
121
+
107
122
  ### AP-Trace
108
123
 
109
124
  An audit log entry recording each decision:
@@ -345,7 +360,7 @@ AAP aligns with and supports compliance for the following international standard
345
360
  | **[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
361
  | **[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
362
  | **[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) |
363
+ | **[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.retention_days` support Article 50 compliance. See [EU AI Act Compliance Guide](https://docs.mnemom.ai/guides/eu-compliance) |
349
364
 
350
365
  ## Contributing
351
366
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "agent-alignment-protocol"
7
- version = "0.5.0"
7
+ version = "2.0.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"
@@ -101,3 +101,10 @@ warn_unused_ignores = true
101
101
  [tool.pytest.ini_options]
102
102
  testpaths = ["tests"]
103
103
  asyncio_mode = "auto"
104
+ addopts = "--cov=src/aap --cov-report=xml --cov-report=term-missing"
105
+
106
+ [tool.coverage.run]
107
+ source = ["src/aap"]
108
+
109
+ [tool.coverage.report]
110
+ show_missing = true
@@ -1,7 +1,18 @@
1
1
  {
2
2
  "$defs": {
3
- "AuditCommitment": {
4
- "description": "Audit trail commitments (SPEC Section 4.7).",
3
+ "AlignmentMode": {
4
+ "description": "Master-switch mode shared by autonomy_mode and integrity_mode (unified / ADR-039).",
5
+ "enum": [
6
+ "off",
7
+ "observe",
8
+ "nudge",
9
+ "enforce"
10
+ ],
11
+ "title": "AlignmentMode",
12
+ "type": "string"
13
+ },
14
+ "Audit": {
15
+ "description": "Audit trail commitments (unified / ADR-039 §audit). Renamed from the legacy AAP 0.5.0 `audit_commitment`; semantics preserved.",
5
16
  "properties": {
6
17
  "trace_format": {
7
18
  "default": "ap-trace-v1",
@@ -11,22 +22,10 @@
11
22
  },
12
23
  "retention_days": {
13
24
  "description": "Minimum retention period in days",
14
- "minimum": 1,
25
+ "minimum": 0,
15
26
  "title": "Retention Days",
16
27
  "type": "integer"
17
28
  },
18
- "storage": {
19
- "anyOf": [
20
- {
21
- "$ref": "#/$defs/AuditStorage"
22
- },
23
- {
24
- "type": "null"
25
- }
26
- ],
27
- "default": null,
28
- "description": "Storage configuration"
29
- },
30
29
  "queryable": {
31
30
  "description": "Whether traces can be queried externally",
32
31
  "title": "Queryable",
@@ -62,38 +61,11 @@
62
61
  "retention_days",
63
62
  "queryable"
64
63
  ],
65
- "title": "AuditCommitment",
64
+ "title": "Audit",
66
65
  "type": "object"
67
66
  },
68
- "AuditStorage": {
69
- "description": "Audit log storage configuration.",
70
- "properties": {
71
- "type": {
72
- "$ref": "#/$defs/StorageType",
73
- "description": "Storage type"
74
- },
75
- "location": {
76
- "anyOf": [
77
- {
78
- "type": "string"
79
- },
80
- {
81
- "type": "null"
82
- }
83
- ],
84
- "default": null,
85
- "description": "Storage endpoint or location",
86
- "title": "Location"
87
- }
88
- },
89
- "required": [
90
- "type"
91
- ],
92
- "title": "AuditStorage",
93
- "type": "object"
94
- },
95
- "AutonomyEnvelope": {
96
- "description": "Autonomy bounds and escalation triggers (SPEC Section 4.5).",
67
+ "Autonomy": {
68
+ "description": "Autonomy bounds and escalation triggers (unified / ADR-039 §autonomy). Renamed from the legacy AAP 0.5.0 `autonomy_envelope`; semantics preserved.",
97
69
  "properties": {
98
70
  "bounded_actions": {
99
71
  "description": "Actions permitted without escalation",
@@ -141,17 +113,16 @@
141
113
  }
142
114
  },
143
115
  "required": [
144
- "bounded_actions",
145
- "escalation_triggers"
116
+ "bounded_actions"
146
117
  ],
147
- "title": "AutonomyEnvelope",
118
+ "title": "Autonomy",
148
119
  "type": "object"
149
120
  },
150
121
  "EscalationTrigger": {
151
- "description": "Condition that triggers escalation (SPEC Section 4.5).",
122
+ "description": "Condition that triggers escalation (unified / ADR-039 §autonomy).",
152
123
  "properties": {
153
124
  "condition": {
154
- "description": "Condition expression (see SPEC Section 4.6)",
125
+ "description": "Condition expression",
155
126
  "title": "Condition",
156
127
  "type": "string"
157
128
  },
@@ -205,7 +176,7 @@
205
176
  "type": "object"
206
177
  },
207
178
  "Principal": {
208
- "description": "Principal relationship declaration (SPEC Section 4.3).",
179
+ "description": "Principal relationship declaration (unified / ADR-039 §principal).",
209
180
  "properties": {
210
181
  "type": {
211
182
  "$ref": "#/$defs/PrincipalType",
@@ -221,7 +192,7 @@
221
192
  }
222
193
  ],
223
194
  "default": null,
224
- "description": "Principal identifier (DID, email, org ID)",
195
+ "description": "Principal identifier (DID, email, org ID). Required when type != 'unspecified'.",
225
196
  "title": "Identifier"
226
197
  },
227
198
  "relationship": {
@@ -270,16 +241,6 @@
270
241
  "title": "RelationshipType",
271
242
  "type": "string"
272
243
  },
273
- "StorageType": {
274
- "description": "Audit log storage type.",
275
- "enum": [
276
- "local",
277
- "remote",
278
- "distributed"
279
- ],
280
- "title": "StorageType",
281
- "type": "string"
282
- },
283
244
  "TamperEvidence": {
284
245
  "description": "Tamper-evidence mechanism for audit logs.",
285
246
  "enum": [
@@ -301,12 +262,20 @@
301
262
  "type": "string"
302
263
  },
303
264
  "ValueDefinition": {
304
- "description": "Definition of a custom value.",
265
+ "description": "Definition of a custom value (unified / ADR-039 §values).",
305
266
  "properties": {
306
267
  "name": {
307
- "description": "Human-readable name",
308
- "title": "Name",
309
- "type": "string"
268
+ "anyOf": [
269
+ {
270
+ "type": "string"
271
+ },
272
+ {
273
+ "type": "null"
274
+ }
275
+ ],
276
+ "default": null,
277
+ "description": "Human-readable name (optional)",
278
+ "title": "Name"
310
279
  },
311
280
  "description": {
312
281
  "description": "What this value means operationally",
@@ -315,20 +284,19 @@
315
284
  },
316
285
  "priority": {
317
286
  "default": 0,
318
- "description": "Priority for lexicographic ordering (higher = more important)",
287
+ "description": "Priority for lexicographic/weighted ordering (higher = more important)",
319
288
  "title": "Priority",
320
- "type": "integer"
289
+ "type": "number"
321
290
  }
322
291
  },
323
292
  "required": [
324
- "name",
325
293
  "description"
326
294
  ],
327
295
  "title": "ValueDefinition",
328
296
  "type": "object"
329
297
  },
330
298
  "Values": {
331
- "description": "Value declarations (SPEC Section 4.4).",
299
+ "description": "Value declarations (unified / ADR-039 §values).",
332
300
  "properties": {
333
301
  "declared": {
334
302
  "description": "List of value identifiers",
@@ -390,12 +358,13 @@
390
358
  "type": "object"
391
359
  }
392
360
  },
393
- "description": "Alignment Card \u2014 Agent alignment declaration (SPEC Section 4).\n\nA structured document declaring an agent's alignment posture. It MUST be\nmachine-readable (JSON) and SHOULD be human-readable.\n\nExample:\n card = AlignmentCard(\n aap_version=\"0.1.0\",\n card_id=\"ac-12345\",\n agent_id=\"did:web:agent.example.com\",\n issued_at=datetime.utcnow(),\n principal=Principal(type=PrincipalType.HUMAN, relationship=RelationshipType.DELEGATED_AUTHORITY),\n values=Values(declared=[\"principal_benefit\", \"transparency\"]),\n autonomy_envelope=AutonomyEnvelope(\n bounded_actions=[\"search\", \"recommend\"],\n escalation_triggers=[\n EscalationTrigger(\n condition='action_type == \"purchase\"',\n action=TriggerAction.ESCALATE,\n reason=\"Purchases require approval\",\n )\n ],\n ),\n audit_commitment=AuditCommitment(\n retention_days=90,\n queryable=True,\n query_endpoint=\"https://agent.example.com/api/traces\",\n ),\n )",
361
+ "description": "Alignment Card Agent alignment declaration (unified / ADR-039).\n\nA structured document declaring an agent's alignment posture. It MUST be\nmachine-readable (JSON) and SHOULD be human-readable. This is the unified\ncard shape accepted by `mnemom card validate` and the Mnemom platform;\nit renames the legacy AAP 0.5.0 `autonomy_envelope`→`autonomy` and\n`audit_commitment`→`audit` and adds the top-level master switches\n`autonomy_mode` + `integrity_mode`. Semantics are preserved.\n\nExample:\n card = AlignmentCard(\n card_version=\"unified/2026-04-26\",\n card_id=\"ac-12345\",\n agent_id=\"did:web:agent.example.com\",\n issued_at=datetime.now(timezone.utc),\n autonomy_mode=AlignmentMode.OBSERVE,\n integrity_mode=AlignmentMode.OBSERVE,\n principal=Principal(\n type=PrincipalType.HUMAN,\n identifier=\"did:web:user.example.com\",\n relationship=RelationshipType.DELEGATED_AUTHORITY,\n ),\n values=Values(declared=[\"principal_benefit\", \"transparency\"]),\n autonomy=Autonomy(\n bounded_actions=[\"search\", \"recommend\"],\n escalation_triggers=[\n EscalationTrigger(\n condition='action_type == \"purchase\"',\n action=TriggerAction.ESCALATE,\n reason=\"Purchases require approval\",\n )\n ],\n ),\n audit=Audit(\n retention_days=90,\n queryable=True,\n query_endpoint=\"https://agent.example.com/api/traces\",\n ),\n )",
394
362
  "properties": {
395
- "aap_version": {
396
- "default": "0.1.0",
397
- "description": "AAP specification version",
398
- "title": "Aap Version",
363
+ "card_version": {
364
+ "default": "unified/2026-04-26",
365
+ "description": "Unified alignment-card schema version (date-anchored identifier)",
366
+ "pattern": "^unified/\\d{4}-\\d{2}-\\d{2}$",
367
+ "title": "Card Version",
399
368
  "type": "string"
400
369
  },
401
370
  "card_id": {
@@ -428,6 +397,14 @@
428
397
  "description": "When this card expires",
429
398
  "title": "Expires At"
430
399
  },
400
+ "autonomy_mode": {
401
+ "$ref": "#/$defs/AlignmentMode",
402
+ "description": "Master switch for the action-policing pipeline (off | observe | nudge | enforce)"
403
+ },
404
+ "integrity_mode": {
405
+ "$ref": "#/$defs/AlignmentMode",
406
+ "description": "Master switch for the values/conscience pipeline (off | observe | nudge | enforce)"
407
+ },
431
408
  "principal": {
432
409
  "$ref": "#/$defs/Principal",
433
410
  "description": "Principal relationship declaration"
@@ -436,12 +413,12 @@
436
413
  "$ref": "#/$defs/Values",
437
414
  "description": "Value declarations"
438
415
  },
439
- "autonomy_envelope": {
440
- "$ref": "#/$defs/AutonomyEnvelope",
416
+ "autonomy": {
417
+ "$ref": "#/$defs/Autonomy",
441
418
  "description": "Autonomy bounds and escalation triggers"
442
419
  },
443
- "audit_commitment": {
444
- "$ref": "#/$defs/AuditCommitment",
420
+ "audit": {
421
+ "$ref": "#/$defs/Audit",
445
422
  "description": "Audit trail commitments"
446
423
  },
447
424
  "extensions": {
@@ -463,13 +440,15 @@
463
440
  "card_id",
464
441
  "agent_id",
465
442
  "issued_at",
443
+ "autonomy_mode",
444
+ "integrity_mode",
466
445
  "principal",
467
446
  "values",
468
- "autonomy_envelope",
469
- "audit_commitment"
447
+ "autonomy",
448
+ "audit"
470
449
  ],
471
450
  "title": "AlignmentCard",
472
451
  "type": "object",
473
452
  "$schema": "https://json-schema.org/draft/2020-12/schema",
474
- "$id": "https://aap.dev/schemas/alignment-card-v1.json"
475
- }
453
+ "$id": "https://aap.dev/schemas/alignment-card-unified.json"
454
+ }
@@ -36,11 +36,17 @@ Quick Start:
36
36
  See docs/SPEC.md for the full protocol specification.
37
37
  """
38
38
 
39
- __version__ = "0.4.0"
39
+ from importlib import metadata as _metadata
40
+
41
+ try:
42
+ # Single source of truth: the installed distribution version (pyproject.toml).
43
+ __version__ = _metadata.version("agent-alignment-protocol")
44
+ except _metadata.PackageNotFoundError: # pragma: no cover - editable/source tree fallback
45
+ __version__ = "2.0.0"
40
46
 
41
47
  # EU AI Act compliance presets
42
48
  from aap.compliance import (
43
- EU_COMPLIANCE_AUDIT_COMMITMENT,
49
+ EU_COMPLIANCE_AUDIT,
44
50
  EU_COMPLIANCE_EXTENSIONS,
45
51
  EU_COMPLIANCE_VALUES,
46
52
  )
@@ -53,10 +59,11 @@ from aap.schemas import (
53
59
  AlignmentCard,
54
60
  AlignmentCardRequest,
55
61
  AlignmentCardResponse,
62
+ AlignmentMode,
56
63
  Alternative,
57
64
  APTrace,
58
- AuditCommitment,
59
- AutonomyEnvelope,
65
+ Audit,
66
+ Autonomy,
60
67
  CoherenceResultMessage,
61
68
  Decision,
62
69
  Escalation,
@@ -148,16 +155,17 @@ __all__ = [
148
155
  "DriftAnalysis",
149
156
  "DriftDirection",
150
157
  "DriftIndicator",
151
- # Alignment Card
158
+ # Alignment Card (unified / ADR-039)
152
159
  "AlignmentCard",
160
+ "AlignmentMode",
153
161
  "Principal",
154
162
  "PrincipalType",
155
163
  "RelationshipType",
156
164
  "Values",
157
- "AutonomyEnvelope",
165
+ "Autonomy",
158
166
  "EscalationTrigger",
159
167
  "TriggerAction",
160
- "AuditCommitment",
168
+ "Audit",
161
169
  # AP-Trace
162
170
  "APTrace",
163
171
  "Action",
@@ -174,7 +182,7 @@ __all__ = [
174
182
  "CoherenceResultMessage",
175
183
  "ProposedCollaboration",
176
184
  # EU AI Act Compliance
177
- "EU_COMPLIANCE_AUDIT_COMMITMENT",
185
+ "EU_COMPLIANCE_AUDIT",
178
186
  "EU_COMPLIANCE_EXTENSIONS",
179
187
  "EU_COMPLIANCE_VALUES",
180
188
  ]
@@ -193,21 +193,25 @@ def _create_card_from_values(
193
193
  agent_id: str | None = None,
194
194
  card_id: str | None = None,
195
195
  ) -> dict[str, Any]:
196
- """Create a minimal Alignment Card from a list of values."""
196
+ """Create a minimal Alignment Card (unified / ADR-039) from a list of values."""
197
197
  now = datetime.now(timezone.utc)
198
+ resolved_agent_id = agent_id or f"agent-{uuid.uuid4().hex[:8]}"
198
199
  return {
199
- "aap_version": "0.1.0",
200
+ "card_version": "unified/2026-04-26",
200
201
  "card_id": card_id or f"ac-{uuid.uuid4().hex[:12]}",
201
- "agent_id": agent_id or f"agent-{uuid.uuid4().hex[:8]}",
202
+ "agent_id": resolved_agent_id,
202
203
  "issued_at": now.isoformat(),
204
+ "autonomy_mode": "observe",
205
+ "integrity_mode": "observe",
203
206
  "principal": {
204
207
  "type": "human",
208
+ "identifier": resolved_agent_id,
205
209
  "relationship": "delegated_authority",
206
210
  },
207
211
  "values": {
208
212
  "declared": value_list,
209
213
  },
210
- "autonomy_envelope": {
214
+ "autonomy": {
211
215
  "bounded_actions": ["search", "recommend", "compare", "summarize", "respond"],
212
216
  "escalation_triggers": [
213
217
  {
@@ -222,7 +226,7 @@ def _create_card_from_values(
222
226
  },
223
227
  ],
224
228
  },
225
- "audit_commitment": {
229
+ "audit": {
226
230
  "trace_format": "ap-trace-v1",
227
231
  "retention_days": 90,
228
232
  "queryable": False,
@@ -268,6 +272,13 @@ def _create_card_interactive(agent_id: str | None = None, card_id: str | None =
268
272
  default="human",
269
273
  )
270
274
 
275
+ # Principal identifier (required by the unified schema when type != unspecified)
276
+ default_identifier = agent_id or f"agent-{uuid.uuid4().hex[:8]}"
277
+ principal_identifier = click.prompt(
278
+ "Principal identifier (DID, email, org ID)",
279
+ default=default_identifier,
280
+ )
281
+
271
282
  # Relationship type
272
283
  relationship = click.prompt(
273
284
  "Relationship type",
@@ -291,18 +302,21 @@ def _create_card_interactive(agent_id: str | None = None, card_id: str | None =
291
302
 
292
303
  now = datetime.now(timezone.utc)
293
304
  return {
294
- "aap_version": "0.1.0",
305
+ "card_version": "unified/2026-04-26",
295
306
  "card_id": card_id or f"ac-{uuid.uuid4().hex[:12]}",
296
- "agent_id": agent_id or f"agent-{uuid.uuid4().hex[:8]}",
307
+ "agent_id": agent_id or default_identifier,
297
308
  "issued_at": now.isoformat(),
309
+ "autonomy_mode": "observe",
310
+ "integrity_mode": "observe",
298
311
  "principal": {
299
312
  "type": principal_type,
313
+ "identifier": principal_identifier,
300
314
  "relationship": relationship,
301
315
  },
302
316
  "values": {
303
317
  "declared": selected_values,
304
318
  },
305
- "autonomy_envelope": {
319
+ "autonomy": {
306
320
  "bounded_actions": bounded_actions,
307
321
  "escalation_triggers": [
308
322
  {
@@ -312,7 +326,7 @@ def _create_card_interactive(agent_id: str | None = None, card_id: str | None =
312
326
  },
313
327
  ],
314
328
  },
315
- "audit_commitment": {
329
+ "audit": {
316
330
  "trace_format": "ap-trace-v1",
317
331
  "retention_days": retention_days,
318
332
  "queryable": False,
@@ -6,14 +6,14 @@ transparency obligations. Spread them into your AlignmentCard fields.
6
6
 
7
7
  Usage:
8
8
  from aap.compliance import (
9
- EU_COMPLIANCE_AUDIT_COMMITMENT,
9
+ EU_COMPLIANCE_AUDIT,
10
10
  EU_COMPLIANCE_EXTENSIONS,
11
11
  EU_COMPLIANCE_VALUES,
12
12
  )
13
13
 
14
14
  card = AlignmentCard(
15
15
  ...,
16
- audit_commitment=AuditCommitment(**EU_COMPLIANCE_AUDIT_COMMITMENT),
16
+ audit=Audit(**EU_COMPLIANCE_AUDIT),
17
17
  values=Values(declared=EU_COMPLIANCE_VALUES, ...),
18
18
  extensions=EU_COMPLIANCE_EXTENSIONS,
19
19
  )
@@ -26,7 +26,8 @@ qualified legal counsel for your specific compliance obligations.
26
26
  from __future__ import annotations
27
27
 
28
28
  # Audit commitment values that satisfy Article 50(4) audit trail requirements.
29
- EU_COMPLIANCE_AUDIT_COMMITMENT: dict = {
29
+ # Spread into the unified card's `audit` section (Audit(**EU_COMPLIANCE_AUDIT)).
30
+ EU_COMPLIANCE_AUDIT: dict = {
30
31
  "retention_days": 90,
31
32
  "queryable": True,
32
33
  "query_endpoint": "https://audit.example.com/traces",
@@ -13,15 +13,19 @@ All models support:
13
13
  Example:
14
14
  from aap.schemas import AlignmentCard, APTrace
15
15
 
16
- # Create an Alignment Card
16
+ # Create an Alignment Card (unified / ADR-039 shape)
17
17
  card = AlignmentCard(
18
18
  card_id="ac-12345",
19
19
  agent_id="did:web:agent.example.com",
20
- issued_at=datetime.utcnow(),
21
- principal=Principal(type=PrincipalType.HUMAN, relationship=RelationshipType.DELEGATED_AUTHORITY),
20
+ issued_at=datetime.now(timezone.utc),
21
+ principal=Principal(
22
+ type=PrincipalType.HUMAN,
23
+ identifier="did:web:user.example.com",
24
+ relationship=RelationshipType.DELEGATED_AUTHORITY,
25
+ ),
22
26
  values=Values(declared=["principal_benefit", "transparency"]),
23
- autonomy_envelope=AutonomyEnvelope(...),
24
- audit_commitment=AuditCommitment(...),
27
+ autonomy=Autonomy(...),
28
+ audit=Audit(...),
25
29
  )
26
30
 
27
31
  # Serialize to JSON
@@ -33,16 +37,15 @@ Example:
33
37
 
34
38
  from aap.schemas.alignment_card import (
35
39
  AlignmentCard,
36
- AuditCommitment,
37
- AuditStorage,
38
- AutonomyEnvelope,
40
+ AlignmentMode,
41
+ Audit,
42
+ Autonomy,
39
43
  EscalationTrigger,
40
44
  HierarchyType,
41
45
  MonetaryValue,
42
46
  Principal,
43
47
  PrincipalType,
44
48
  RelationshipType,
45
- StorageType,
46
49
  TamperEvidence,
47
50
  TriggerAction,
48
51
  ValueDefinition,
@@ -61,6 +64,7 @@ from aap.schemas.ap_trace import (
61
64
  PrincipalResponse,
62
65
  TraceContext,
63
66
  TriggerCheck,
67
+ ValueScore,
64
68
  )
65
69
  from aap.schemas.value_coherence import (
66
70
  AlignmentCardRequest,
@@ -80,21 +84,20 @@ from aap.schemas.value_coherence import (
80
84
  )
81
85
 
82
86
  __all__ = [
83
- # Alignment Card (SPEC Section 4)
87
+ # Alignment Card (unified / ADR-039)
84
88
  "AlignmentCard",
89
+ "AlignmentMode",
85
90
  "Principal",
86
91
  "PrincipalType",
87
92
  "RelationshipType",
88
93
  "Values",
89
94
  "ValueDefinition",
90
95
  "HierarchyType",
91
- "AutonomyEnvelope",
96
+ "Autonomy",
92
97
  "EscalationTrigger",
93
98
  "TriggerAction",
94
99
  "MonetaryValue",
95
- "AuditCommitment",
96
- "AuditStorage",
97
- "StorageType",
100
+ "Audit",
98
101
  "TamperEvidence",
99
102
  # AP-Trace (SPEC Section 5)
100
103
  "APTrace",
@@ -109,6 +112,7 @@ __all__ = [
109
112
  "TriggerCheck",
110
113
  "PrincipalResponse",
111
114
  "TraceContext",
115
+ "ValueScore",
112
116
  # Value Coherence (SPEC Section 6)
113
117
  "AlignmentCardRequest",
114
118
  "AlignmentCardResponse",
@@ -1,13 +1,21 @@
1
- """Alignment Card schema — Agent alignment declaration.
1
+ """Alignment Card schema — Agent alignment declaration (unified / ADR-039).
2
2
 
3
- Defines the Alignment Card structure per SPEC Section 4. An Alignment Card
4
- is a structured document declaring an agent's alignment posture:
3
+ Defines the unified Alignment Card structure accepted by the Mnemom platform
4
+ and `mnemom card validate`. An Alignment Card is a structured document
5
+ declaring an agent's alignment posture:
5
6
  - Principal relationship
6
7
  - Declared values
7
- - Autonomy envelope
8
- - Audit commitment
8
+ - Autonomy bounds (`autonomy`)
9
+ - Audit commitments (`audit`)
10
+ - Two top-level master switches (`autonomy_mode`, `integrity_mode`)
9
11
 
10
- See SPEC.md Section 4 for complete specification.
12
+ This is the unified shape. It renames the legacy AAP 0.5.0
13
+ `autonomy_envelope`→`autonomy` and `audit_commitment`→`audit`, replaces
14
+ `aap_version` with the date-anchored `card_version`, and adds the top-level
15
+ master switches. Semantics are preserved; the migration is largely a rename.
16
+
17
+ See https://docs.mnemom.ai/specifications/alignment-card-schema for the
18
+ normative reference.
11
19
  """
12
20
 
13
21
  from __future__ import annotations
@@ -18,6 +26,28 @@ from typing import Any
18
26
 
19
27
  from pydantic import BaseModel, Field, model_validator
20
28
 
29
+ #: Current unified alignment-card schema version (date-anchored identifier).
30
+ CARD_VERSION = "unified/2026-04-26"
31
+
32
+
33
+ class AlignmentMode(str, Enum):
34
+ """Master-switch mode shared by ``autonomy_mode`` and ``integrity_mode``.
35
+
36
+ Strictest wins on composition: ``enforce > nudge > observe > off``.
37
+ """
38
+
39
+ OFF = "off"
40
+ """Pipeline disabled."""
41
+
42
+ OBSERVE = "observe"
43
+ """Log results; do not block."""
44
+
45
+ NUDGE = "nudge"
46
+ """Inject advisory annotation; do not block."""
47
+
48
+ ENFORCE = "enforce"
49
+ """Block violations and escalate."""
50
+
21
51
 
22
52
  class PrincipalType(str, Enum):
23
53
  """Type of principal the agent serves."""
@@ -42,13 +72,13 @@ class RelationshipType(str, Enum):
42
72
 
43
73
 
44
74
  class Principal(BaseModel):
45
- """Principal relationship declaration (SPEC Section 4.3)."""
75
+ """Principal relationship declaration (unified / ADR-039 §principal)."""
46
76
 
47
77
  type: PrincipalType = Field(
48
78
  ..., description="Type of principal"
49
79
  )
50
80
  identifier: str | None = Field(
51
- None, description="Principal identifier (DID, email, org ID)"
81
+ None, description="Principal identifier (DID, email, org ID). Required when type != 'unspecified'."
52
82
  )
53
83
  relationship: RelationshipType = Field(
54
84
  ..., description="Nature of authority delegation"
@@ -57,6 +87,15 @@ class Principal(BaseModel):
57
87
  None, description="Endpoint for escalation notifications"
58
88
  )
59
89
 
90
+ @model_validator(mode="after")
91
+ def identifier_required_when_typed(self) -> Principal:
92
+ """`identifier` is required when `type` is not 'unspecified' (ADR-039)."""
93
+ if self.type != PrincipalType.UNSPECIFIED and not self.identifier:
94
+ raise ValueError(
95
+ "principal.identifier is required when principal.type is not 'unspecified'"
96
+ )
97
+ return self
98
+
60
99
 
61
100
  class HierarchyType(str, Enum):
62
101
  """How value conflicts are resolved."""
@@ -72,17 +111,23 @@ class HierarchyType(str, Enum):
72
111
 
73
112
 
74
113
  class ValueDefinition(BaseModel):
75
- """Definition of a custom value."""
114
+ """Definition of a custom value (unified / ADR-039 §values).
115
+
116
+ Per the unified spec a definition carries a ``description`` and optional
117
+ ``priority``; ``name`` is optional (the value's identifier is the
118
+ ``definitions`` map key).
119
+ """
76
120
 
77
- name: str = Field(..., description="Human-readable name")
121
+ name: str | None = Field(None, description="Human-readable name (optional)")
78
122
  description: str = Field(..., description="What this value means operationally")
79
- priority: int = Field(
80
- default=0, description="Priority for lexicographic ordering (higher = more important)"
123
+ priority: float = Field(
124
+ default=0,
125
+ description="Priority for lexicographic/weighted ordering (higher = more important)",
81
126
  )
82
127
 
83
128
 
84
129
  class Values(BaseModel):
85
- """Value declarations (SPEC Section 4.4)."""
130
+ """Value declarations (unified / ADR-039 §values)."""
86
131
 
87
132
  declared: list[str] = Field(
88
133
  ..., description="List of value identifiers"
@@ -125,10 +170,10 @@ class TriggerAction(str, Enum):
125
170
 
126
171
 
127
172
  class EscalationTrigger(BaseModel):
128
- """Condition that triggers escalation (SPEC Section 4.5)."""
173
+ """Condition that triggers escalation (unified / ADR-039 §autonomy)."""
129
174
 
130
175
  condition: str = Field(
131
- ..., description="Condition expression (see SPEC Section 4.6)"
176
+ ..., description="Condition expression"
132
177
  )
133
178
  action: TriggerAction = Field(
134
179
  ..., description="Action to take when trigger matches"
@@ -145,14 +190,19 @@ class MonetaryValue(BaseModel):
145
190
  currency: str = Field(default="USD", description="ISO 4217 currency code")
146
191
 
147
192
 
148
- class AutonomyEnvelope(BaseModel):
149
- """Autonomy bounds and escalation triggers (SPEC Section 4.5)."""
193
+ class Autonomy(BaseModel):
194
+ """Autonomy bounds and escalation triggers (unified / ADR-039 §autonomy).
195
+
196
+ Renamed from the legacy AAP 0.5.0 ``autonomy_envelope``; semantics
197
+ preserved. ``escalation_triggers`` is now optional (defaults to an empty
198
+ list) to match the unified spec, where only ``bounded_actions`` is required.
199
+ """
150
200
 
151
201
  bounded_actions: list[str] = Field(
152
202
  ..., description="Actions permitted without escalation"
153
203
  )
154
204
  escalation_triggers: list[EscalationTrigger] = Field(
155
- ..., description="Conditions requiring escalation"
205
+ default_factory=list, description="Conditions requiring escalation"
156
206
  )
157
207
  max_autonomous_value: MonetaryValue | None = Field(
158
208
  None, description="Maximum transaction value without escalation"
@@ -161,13 +211,17 @@ class AutonomyEnvelope(BaseModel):
161
211
  None, description="Actions never permitted"
162
212
  )
163
213
 
164
-
165
- class StorageType(str, Enum):
166
- """Audit log storage type."""
167
-
168
- LOCAL = "local"
169
- REMOTE = "remote"
170
- DISTRIBUTED = "distributed"
214
+ @model_validator(mode="after")
215
+ def bounded_and_forbidden_disjoint(self) -> Autonomy:
216
+ """`bounded_actions` and `forbidden_actions` must be disjoint (ADR-039)."""
217
+ if self.forbidden_actions:
218
+ overlap = set(self.bounded_actions) & set(self.forbidden_actions)
219
+ if overlap:
220
+ raise ValueError(
221
+ "autonomy.bounded_actions and forbidden_actions must be disjoint; "
222
+ f"both contain: {', '.join(sorted(overlap))}"
223
+ )
224
+ return self
171
225
 
172
226
 
173
227
  class TamperEvidence(str, Enum):
@@ -178,24 +232,19 @@ class TamperEvidence(str, Enum):
178
232
  MERKLE = "merkle"
179
233
 
180
234
 
181
- class AuditStorage(BaseModel):
182
- """Audit log storage configuration."""
183
-
184
- type: StorageType = Field(..., description="Storage type")
185
- location: str | None = Field(None, description="Storage endpoint or location")
235
+ class Audit(BaseModel):
236
+ """Audit trail commitments (unified / ADR-039 §audit).
186
237
 
187
-
188
- class AuditCommitment(BaseModel):
189
- """Audit trail commitments (SPEC Section 4.7)."""
238
+ Renamed from the legacy AAP 0.5.0 ``audit_commitment``; semantics
239
+ preserved. The legacy ``storage`` sub-object is no longer part of the
240
+ unified shape (the platform validator rejects ``audit.storage``).
241
+ """
190
242
 
191
243
  trace_format: str = Field(
192
244
  default="ap-trace-v1", description="Trace format identifier"
193
245
  )
194
246
  retention_days: int = Field(
195
- ..., ge=1, description="Minimum retention period in days"
196
- )
197
- storage: AuditStorage | None = Field(
198
- None, description="Storage configuration"
247
+ ..., ge=0, description="Minimum retention period in days"
199
248
  )
200
249
  queryable: bool = Field(
201
250
  ..., description="Whether traces can be queried externally"
@@ -208,7 +257,7 @@ class AuditCommitment(BaseModel):
208
257
  )
209
258
 
210
259
  @model_validator(mode="after")
211
- def queryable_requires_endpoint(self) -> AuditCommitment:
260
+ def queryable_requires_endpoint(self) -> Audit:
212
261
  """If queryable is true, query_endpoint is required."""
213
262
  if self.queryable and not self.query_endpoint:
214
263
  raise ValueError("query_endpoint is required when queryable is true")
@@ -216,20 +265,27 @@ class AuditCommitment(BaseModel):
216
265
 
217
266
 
218
267
  class AlignmentCard(BaseModel):
219
- """Alignment Card — Agent alignment declaration (SPEC Section 4).
268
+ """Alignment Card — Agent alignment declaration (unified / ADR-039).
220
269
 
221
270
  A structured document declaring an agent's alignment posture. It MUST be
222
- machine-readable (JSON) and SHOULD be human-readable.
271
+ machine-readable (JSON) and SHOULD be human-readable. This is the unified
272
+ card shape accepted by `mnemom card validate` and the Mnemom platform.
223
273
 
224
274
  Example:
225
275
  card = AlignmentCard(
226
- aap_version="0.1.0",
276
+ card_version="unified/2026-04-26",
227
277
  card_id="ac-12345",
228
278
  agent_id="did:web:agent.example.com",
229
- issued_at=datetime.utcnow(),
230
- principal=Principal(type=PrincipalType.HUMAN, relationship=RelationshipType.DELEGATED_AUTHORITY),
279
+ issued_at=datetime.now(timezone.utc),
280
+ autonomy_mode=AlignmentMode.OBSERVE,
281
+ integrity_mode=AlignmentMode.OBSERVE,
282
+ principal=Principal(
283
+ type=PrincipalType.HUMAN,
284
+ identifier="did:web:user.example.com",
285
+ relationship=RelationshipType.DELEGATED_AUTHORITY,
286
+ ),
231
287
  values=Values(declared=["principal_benefit", "transparency"]),
232
- autonomy_envelope=AutonomyEnvelope(
288
+ autonomy=Autonomy(
233
289
  bounded_actions=["search", "recommend"],
234
290
  escalation_triggers=[
235
291
  EscalationTrigger(
@@ -239,7 +295,7 @@ class AlignmentCard(BaseModel):
239
295
  )
240
296
  ],
241
297
  ),
242
- audit_commitment=AuditCommitment(
298
+ audit=Audit(
243
299
  retention_days=90,
244
300
  queryable=True,
245
301
  query_endpoint="https://agent.example.com/api/traces",
@@ -247,8 +303,9 @@ class AlignmentCard(BaseModel):
247
303
  )
248
304
  """
249
305
 
250
- aap_version: str = Field(
251
- default="0.1.0", description="AAP specification version"
306
+ card_version: str = Field(
307
+ default=CARD_VERSION,
308
+ description="Unified alignment-card schema version (date-anchored identifier)",
252
309
  )
253
310
  card_id: str = Field(
254
311
  ..., description="Unique identifier for this card (UUID or URI)"
@@ -262,16 +319,24 @@ class AlignmentCard(BaseModel):
262
319
  expires_at: datetime | None = Field(
263
320
  None, description="When this card expires"
264
321
  )
322
+ autonomy_mode: AlignmentMode = Field(
323
+ default=AlignmentMode.OBSERVE,
324
+ description="Master switch for the action-policing pipeline",
325
+ )
326
+ integrity_mode: AlignmentMode = Field(
327
+ default=AlignmentMode.OBSERVE,
328
+ description="Master switch for the values/conscience pipeline",
329
+ )
265
330
  principal: Principal = Field(
266
331
  ..., description="Principal relationship declaration"
267
332
  )
268
333
  values: Values = Field(
269
334
  ..., description="Value declarations"
270
335
  )
271
- autonomy_envelope: AutonomyEnvelope = Field(
336
+ autonomy: Autonomy = Field(
272
337
  ..., description="Autonomy bounds and escalation triggers"
273
338
  )
274
- audit_commitment: AuditCommitment = Field(
339
+ audit: Audit = Field(
275
340
  ..., description="Audit trail commitments"
276
341
  )
277
342
  extensions: dict[str, Any] | None = Field(
@@ -288,10 +353,18 @@ class AlignmentCard(BaseModel):
288
353
  return cls.model_validate(data)
289
354
 
290
355
  def is_expired(self) -> bool:
291
- """Check if the card has expired."""
356
+ """Check if the card has expired.
357
+
358
+ Handles both timezone-aware and naive ``expires_at`` values: the
359
+ comparison ``now`` is built to match the awareness of ``expires_at``.
360
+ """
292
361
  if self.expires_at is None:
293
362
  return False
294
- return datetime.utcnow() > self.expires_at
363
+ if self.expires_at.tzinfo is None:
364
+ # Naive expiry — compare against naive UTC now.
365
+ return datetime.utcnow() > self.expires_at
366
+ # Aware expiry — compare against aware now in the same tz.
367
+ return datetime.now(self.expires_at.tzinfo) > self.expires_at
295
368
 
296
369
  def has_value(self, value: str) -> bool:
297
370
  """Check if a value is declared."""
@@ -299,8 +372,8 @@ class AlignmentCard(BaseModel):
299
372
 
300
373
  def is_action_bounded(self, action: str) -> bool:
301
374
  """Check if an action is in the bounded actions list."""
302
- return action in self.autonomy_envelope.bounded_actions
375
+ return action in self.autonomy.bounded_actions
303
376
 
304
377
  def is_action_forbidden(self, action: str) -> bool:
305
378
  """Check if an action is forbidden."""
306
- return action in (self.autonomy_envelope.forbidden_actions or [])
379
+ return action in (self.autonomy.forbidden_actions or [])
@@ -14,7 +14,7 @@ from __future__ import annotations
14
14
 
15
15
  from datetime import datetime
16
16
  from enum import Enum
17
- from typing import Any
17
+ from typing import Any, Literal
18
18
 
19
19
  from pydantic import BaseModel, Field, model_validator
20
20
 
@@ -87,6 +87,21 @@ class Alternative(BaseModel):
87
87
  )
88
88
 
89
89
 
90
+ class ValueScore(BaseModel):
91
+ """Per-value score from V2 observer scoring (Phase 3.3)."""
92
+
93
+ score: Literal["on_track", "off_track", "not_applicable"] = Field(
94
+ ..., description="Score against the catalog entry's observer_signals rubric"
95
+ )
96
+ rationale: str = Field(
97
+ ...,
98
+ description=(
99
+ "Free-form rationale citing one of the catalog "
100
+ "observer_signals patterns"
101
+ ),
102
+ )
103
+
104
+
90
105
  class Decision(BaseModel):
91
106
  """Decision process record (SPEC Section 5.5)."""
92
107
 
@@ -105,6 +120,18 @@ class Decision(BaseModel):
105
120
  confidence: float | None = Field(
106
121
  None, ge=0.0, le=1.0, description="Decision confidence"
107
122
  )
123
+ value_scores: dict[str, ValueScore] | None = Field(
124
+ None,
125
+ description=(
126
+ "Per-declared-value score against the alignment card's catalog "
127
+ "observer_signals (Phase 3.3 V2 observer surface). Optional — "
128
+ "present when the card declares catalog values with "
129
+ "observer_signals defined; absent on V1 observer output. Keyed "
130
+ "by catalog value id. `values_applied` is derived from "
131
+ "`value_scores` entries whose score is 'on_track' to preserve "
132
+ "the V1 surface contract for downstream consumers."
133
+ ),
134
+ )
108
135
 
109
136
  @model_validator(mode="after")
110
137
  def selected_must_be_in_alternatives(self) -> Decision:
@@ -48,6 +48,24 @@ from aap.verification.models import (
48
48
  )
49
49
 
50
50
 
51
+ def _card_autonomy(card: dict[str, Any]) -> dict[str, Any]:
52
+ """Read the autonomy section from a card.
53
+
54
+ Prefers the unified / ADR-039 ``autonomy`` key, falling back to the legacy
55
+ AAP 0.5.0 ``autonomy_envelope`` for interop with older cards.
56
+ """
57
+ return card.get("autonomy") or card.get("autonomy_envelope") or {}
58
+
59
+
60
+ def _card_audit(card: dict[str, Any]) -> dict[str, Any]:
61
+ """Read the audit section from a card.
62
+
63
+ Prefers the unified / ADR-039 ``audit`` key, falling back to the legacy
64
+ AAP 0.5.0 ``audit_commitment`` for interop with older cards.
65
+ """
66
+ return card.get("audit") or card.get("audit_commitment") or {}
67
+
68
+
51
69
  def action_matches_list(action_name: str, action_list: list[str]) -> bool:
52
70
  """Check if a (possibly compound) action name matches any entry in a list.
53
71
 
@@ -121,7 +139,7 @@ def verify_trace(
121
139
  raise ValueError("trace must contain 'decision.values_applied' field")
122
140
 
123
141
  # Warn if tamper_evidence is declared but not cryptographically enforced
124
- tamper_evidence = (card.get("audit") or {}).get("commitment", {}).get("tamper_evidence")
142
+ tamper_evidence = _card_audit(card).get("tamper_evidence")
125
143
  if tamper_evidence in ("signed", "merkle"):
126
144
  import warnings as _warnings
127
145
  _warnings.warn(
@@ -164,8 +182,9 @@ def verify_trace(
164
182
  trace_field="card.expires_at",
165
183
  ))
166
184
 
167
- # Extract envelope for remaining checks
168
- envelope = card.get("autonomy_envelope", {})
185
+ # Extract the autonomy section for remaining checks (unified `autonomy`,
186
+ # legacy `autonomy_envelope` fallback).
187
+ envelope = _card_autonomy(card)
169
188
  action = trace.get("action", {})
170
189
 
171
190
  # Check autonomy compliance
@@ -688,7 +707,8 @@ def _evaluate_condition(condition: str, trace: dict[str, Any]) -> bool:
688
707
  if isinstance(metadata, dict):
689
708
  actual = metadata.get(field)
690
709
  if actual is None:
691
- actual = (trace.get("action") or {}).get("parameters", {}).get(field)
710
+ params = (trace.get("action") or {}).get("parameters") or {}
711
+ actual = params.get(field)
692
712
  if actual is None:
693
713
  return False
694
714
 
@@ -295,8 +295,9 @@ class FeatureExtractor:
295
295
  """
296
296
  features: dict[str, float] = {}
297
297
 
298
- # Bounded action features
299
- envelope = card.get("autonomy_envelope", {})
298
+ # Bounded action features (unified `autonomy`, legacy
299
+ # `autonomy_envelope` fallback for interop with older cards)
300
+ envelope = card.get("autonomy") or card.get("autonomy_envelope") or {}
300
301
  for action in envelope.get("bounded_actions", []):
301
302
  features[f"action_name:{action}"] = 1.0
302
303
 
@@ -315,8 +316,8 @@ class FeatureExtractor:
315
316
  if principal_type:
316
317
  features[f"principal_type:{principal_type}"] = 1.0
317
318
 
318
- # Audit commitment features
319
- audit = card.get("audit_commitment", {})
319
+ # Audit features (unified `audit`, legacy `audit_commitment` fallback)
320
+ audit = card.get("audit") or card.get("audit_commitment") or {}
320
321
  if audit.get("queryable"):
321
322
  features["audit:queryable"] = 1.0
322
323
  tamper_evidence = audit.get("tamper_evidence")