@systima/aiact-audit-log 0.1.0
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.
- package/COMPLIANCE.md +180 -0
- package/LICENSE +21 -0
- package/README.md +406 -0
- package/dist/ai-sdk/index.cjs +102 -0
- package/dist/ai-sdk/index.cjs.map +1 -0
- package/dist/ai-sdk/index.d.cts +341 -0
- package/dist/ai-sdk/index.d.ts +341 -0
- package/dist/ai-sdk/index.js +77 -0
- package/dist/ai-sdk/index.js.map +1 -0
- package/dist/ai-sdk/middleware/index.cjs +259 -0
- package/dist/ai-sdk/middleware/index.cjs.map +1 -0
- package/dist/ai-sdk/middleware/index.d.cts +323 -0
- package/dist/ai-sdk/middleware/index.d.ts +323 -0
- package/dist/ai-sdk/middleware/index.js +236 -0
- package/dist/ai-sdk/middleware/index.js.map +1 -0
- package/dist/cli/index.js +3332 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.cjs +1385 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +501 -0
- package/dist/index.d.ts +501 -0
- package/dist/index.js +1342 -0
- package/dist/index.js.map +1 -0
- package/dist/prompt-F4GUFYMH.js +755 -0
- package/dist/prompt-F4GUFYMH.js.map +1 -0
- package/package.json +91 -0
package/COMPLIANCE.md
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# COMPLIANCE.md
|
|
2
|
+
|
|
3
|
+
Compliance mapping for `@systima/aiact-audit-log` against the EU AI Act (Regulation (EU) 2024/1689).
|
|
4
|
+
|
|
5
|
+
This document defines the precise boundary of what the library covers and what it does not.
|
|
6
|
+
|
|
7
|
+
## 1. Scope of Compliance Claims
|
|
8
|
+
|
|
9
|
+
### 1.1 This package satisfies
|
|
10
|
+
|
|
11
|
+
- **Article 12(1)**: The technical capability requirement for automatic recording of events. Once configured, the logger captures events without manual intervention and operates over the lifetime of the system. The middleware integration strengthens this by intercepting LLM calls automatically.
|
|
12
|
+
- **Article 12(2)**: The traceability enablement requirement. The schema captures sufficient detail to enable risk identification (12(2)(a)), facilitate post-market monitoring (12(2)(b)), and support deployer monitoring (12(2)(c)).
|
|
13
|
+
- **Article 19(1)**: The minimum retention floor, when correctly configured. The logger enforces a 180-day minimum and stores logs in customer-controlled infrastructure.
|
|
14
|
+
|
|
15
|
+
### 1.2 This package supports but does not implement
|
|
16
|
+
|
|
17
|
+
- **Article 9**: Risk management system. The logger provides raw data that feeds into risk management, but does not define what constitutes a risk for a given system, does not implement risk scoring, and does not generate risk assessments.
|
|
18
|
+
- **Article 14**: Human oversight design. The logger records human interventions when they occur, but does not design the oversight mechanism, define when human review is required, or enforce oversight procedures.
|
|
19
|
+
- **Article 72**: Post-market monitoring procedures. The logger provides the data layer for monitoring (via stats, query, and export), but does not define monitoring KPIs, alert thresholds, or escalation procedures.
|
|
20
|
+
- **Annex IV**: Technical documentation. The logger's COMPLIANCE.md and schema documentation contribute to technical documentation, but do not constitute the complete technical documentation package required by Annex IV.
|
|
21
|
+
- **Articles 43-44**: Conformity assessment. The hash chain and verification tooling provide evidence for conformity assessment, but the assessment itself is conducted by a notified body or through internal procedures, not by a logging library.
|
|
22
|
+
|
|
23
|
+
### 1.3 What correct integration requires
|
|
24
|
+
|
|
25
|
+
Installing the package is not sufficient for Article 12 compliance. The deploying organisation must also:
|
|
26
|
+
|
|
27
|
+
1. **Ensure coverage**: all relevant events must be logged. This includes every inference call, tool invocation, system error, human override, configuration change, and session boundary. The middleware integration automates capture for LLM calls; other event types require explicit instrumentation. The coverage diagnostic helps identify gaps.
|
|
28
|
+
2. **Define "relevant events"**: Article 12(2)(a) requires logging events "relevant for identifying situations that may result in the AI system presenting a risk." What constitutes a relevant event depends on the system's risk profile and intended purpose. The organisation must define this, not the library.
|
|
29
|
+
3. **Maintain operational governance**: the library validates configuration on startup and provides health checks, but cannot prevent an operations team from deleting S3 lifecycle policies, disabling Object Lock, or misconfiguring IAM permissions. Ongoing compliance depends on operational discipline.
|
|
30
|
+
4. **Integrate with broader compliance architecture**: the logs must feed into the organisation's risk management system (Article 9), post-market monitoring plan (Article 72), and technical documentation (Annex IV).
|
|
31
|
+
|
|
32
|
+
## 2. What This Package Does Not Cover
|
|
33
|
+
|
|
34
|
+
The following obligations require organisational processes that a logging library cannot provide:
|
|
35
|
+
|
|
36
|
+
| Article | Obligation | Why the library cannot implement it |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| Article 9 | Risk management system | Requires defining risk criteria specific to the system's intended purpose, performing risk assessments, and implementing mitigation measures. These are organisational and domain-specific decisions. |
|
|
39
|
+
| Article 14 | Human oversight design | Requires designing oversight mechanisms, defining intervention criteria, and training personnel. The library records interventions; it cannot design or enforce them. |
|
|
40
|
+
| Article 72 | Post-market monitoring | Requires defining KPIs, setting alert thresholds, establishing escalation procedures, and reporting to authorities. The library provides data; the monitoring procedure is organisational. |
|
|
41
|
+
| Annex IV | Technical documentation | Requires a comprehensive documentation package covering system description, design choices, training data, validation methods, and more. The audit log schema documentation is one input among many. |
|
|
42
|
+
| Article 13 | Transparency and information | Requires providing information to deployers about the system's capabilities, limitations, and intended purpose. Outside the scope of a logging library. |
|
|
43
|
+
| Article 15 | Accuracy, robustness, cybersecurity | Requires technical measures for system performance. The logger's hash chain provides integrity evidence; it does not implement accuracy testing or cybersecurity measures. |
|
|
44
|
+
|
|
45
|
+
## 3. Article-by-Article Field Mapping
|
|
46
|
+
|
|
47
|
+
### Article 12(1): Automatic recording of events
|
|
48
|
+
|
|
49
|
+
> "High-risk AI systems shall technically allow for the automatic recording of events (logs) over the lifetime of the system."
|
|
50
|
+
|
|
51
|
+
| Schema field | How it satisfies the requirement |
|
|
52
|
+
|---|---|
|
|
53
|
+
| `entryId` (UUIDv7) | Unique identification of each recorded event |
|
|
54
|
+
| `systemId` | Identifies which AI system produced the log |
|
|
55
|
+
| `timestamp` (ISO 8601) | Records when each event occurred |
|
|
56
|
+
| `seq` (monotonic integer) | Establishes event ordering |
|
|
57
|
+
| `prevHash` + `hash` (SHA-256) | Provides tamper evidence for trustworthy recording |
|
|
58
|
+
| `captureMethod` | Documents how the event was captured (middleware = automatic) |
|
|
59
|
+
|
|
60
|
+
The middleware integration (`auditMiddleware`) satisfies the "automatic" requirement for LLM calls by intercepting every model invocation without manual instrumentation.
|
|
61
|
+
|
|
62
|
+
### Article 12(2)(a): Risk identification
|
|
63
|
+
|
|
64
|
+
> "...events relevant for identifying situations that may result in the high-risk AI system presenting a risk..."
|
|
65
|
+
|
|
66
|
+
| Schema field | How it satisfies the requirement |
|
|
67
|
+
|---|---|
|
|
68
|
+
| `eventType` | Categorises events for risk pattern detection |
|
|
69
|
+
| `modelId` | Tracks which model version produced each output |
|
|
70
|
+
| `input` | Captures what the system received (raw or hashed) |
|
|
71
|
+
| `output` | Captures what the system produced (raw or hashed) |
|
|
72
|
+
| `error` | Records error states that may indicate risk |
|
|
73
|
+
| `parameters` | Records model configuration at inference time |
|
|
74
|
+
| `decisionId` | Correlates related events for decision-level risk analysis |
|
|
75
|
+
| `toolCall` | Records tool invocations (key risk vector in agentic systems) |
|
|
76
|
+
| `humanIntervention` | Records when humans intervened in system decisions |
|
|
77
|
+
|
|
78
|
+
### Article 12(2)(b): Post-market monitoring
|
|
79
|
+
|
|
80
|
+
> "...facilitating the post-market monitoring referred to in Article 72..."
|
|
81
|
+
|
|
82
|
+
| Schema field | How it satisfies the requirement |
|
|
83
|
+
|---|---|
|
|
84
|
+
| `latencyMs` | Enables performance degradation detection |
|
|
85
|
+
| `usage` (token counts) | Enables cost and usage trend analysis |
|
|
86
|
+
| `error` | Enables error rate monitoring |
|
|
87
|
+
| `modelId` | Enables model version drift tracking |
|
|
88
|
+
| `output.finishReason` | Enables output quality monitoring |
|
|
89
|
+
|
|
90
|
+
The `stats` API and CLI command aggregate these fields for monitoring dashboards.
|
|
91
|
+
|
|
92
|
+
### Article 12(2)(c): Deployer monitoring
|
|
93
|
+
|
|
94
|
+
> "...monitoring the operation of high-risk AI systems referred to in Article 26(5)."
|
|
95
|
+
|
|
96
|
+
| Schema field | How it satisfies the requirement |
|
|
97
|
+
|---|---|
|
|
98
|
+
| All fields | The entire schema is documented and export-friendly (JSON Lines) |
|
|
99
|
+
| `metadata` | Extensible key-value pairs for deployer-specific context |
|
|
100
|
+
| `humanIntervention` | Records deployer oversight activities |
|
|
101
|
+
|
|
102
|
+
The `query`, `export`, and `stats` APIs enable deployers to monitor system operation using the logs the system generates.
|
|
103
|
+
|
|
104
|
+
### Article 12(3)(a): Usage period recording
|
|
105
|
+
|
|
106
|
+
> "...recording of the period of each use of the system (start date and time and end date and time of each use)..."
|
|
107
|
+
|
|
108
|
+
| Schema field | How it satisfies the requirement |
|
|
109
|
+
|---|---|
|
|
110
|
+
| `eventType: 'session_start'` | Records the start of a usage session |
|
|
111
|
+
| `eventType: 'session_end'` | Records the end of a usage session |
|
|
112
|
+
| `timestamp` | Provides the date and time for each boundary |
|
|
113
|
+
|
|
114
|
+
### Article 12(3)(b-d): Biometric system requirements
|
|
115
|
+
|
|
116
|
+
| Schema field | How it satisfies the requirement |
|
|
117
|
+
|---|---|
|
|
118
|
+
| `referenceDatabase` | 12(3)(b): identifies the reference database checked |
|
|
119
|
+
| `matchResult` | 12(3)(c): records whether input matched a database record |
|
|
120
|
+
| `humanIntervention.userId` | 12(3)(d): identifies the natural person who verified results |
|
|
121
|
+
|
|
122
|
+
These fields are optional; they apply to systems covered by Annex III, point 1(a).
|
|
123
|
+
|
|
124
|
+
### Article 19(1): Log retention
|
|
125
|
+
|
|
126
|
+
> "...the logs shall be kept for a period appropriate to the intended purpose of the high-risk AI system, of at least six months..."
|
|
127
|
+
|
|
128
|
+
| Mechanism | How it satisfies the requirement |
|
|
129
|
+
|---|---|
|
|
130
|
+
| `retention.minimumDays` default of 180 | Enforces the six-month floor |
|
|
131
|
+
| `ComplianceConfigError` on sub-minimum | Refuses to initialise below 180 days without explicit acknowledgement |
|
|
132
|
+
| S3 lifecycle policy management | Automates retention enforcement at the storage layer |
|
|
133
|
+
| Health check: `lifecycle_policy_exists` | Detects post-deployment drift in retention configuration |
|
|
134
|
+
|
|
135
|
+
### Article 19(2): Financial services
|
|
136
|
+
|
|
137
|
+
> "...providers that are financial institutions subject to requirements regarding their internal governance...shall maintain the logs...as part of the documentation kept under the relevant financial services law."
|
|
138
|
+
|
|
139
|
+
Supported via `retention.minimumDays: 2555` (7 years) for MiFID II compliance. The logs are stored in S3-compatible storage that can be integrated with existing financial services record-keeping infrastructure.
|
|
140
|
+
|
|
141
|
+
## 4. Hash Chain Integrity
|
|
142
|
+
|
|
143
|
+
Each log entry participates in a SHA-256 hash chain:
|
|
144
|
+
|
|
145
|
+
1. The genesis entry's `prevHash` is the SHA-256 of `@systima/aiact-audit-log:genesis:{systemId}`
|
|
146
|
+
2. Each subsequent entry's `prevHash` is the `hash` of the previous entry
|
|
147
|
+
3. Each entry's `hash` is the SHA-256 of the entry serialised with deterministic key ordering (excluding the `hash` field itself)
|
|
148
|
+
|
|
149
|
+
If any entry is modified, deleted, or inserted:
|
|
150
|
+
- The `hash` of the modified entry will not match its content
|
|
151
|
+
- The `prevHash` of the next entry will not match the `hash` of the modified entry
|
|
152
|
+
- The `verify` CLI command reports the break at the exact position
|
|
153
|
+
|
|
154
|
+
Combined with S3 Object Lock (Compliance mode), this provides strong evidence of log integrity for conformity assessment under Articles 43-44.
|
|
155
|
+
|
|
156
|
+
## 5. Coverage Diagnostic
|
|
157
|
+
|
|
158
|
+
The coverage diagnostic (`coverage` command / `analyseCoverage` API) addresses the real compliance risk: not the schema, but incomplete instrumentation. It analyses logs and reports:
|
|
159
|
+
|
|
160
|
+
- Event type distribution (what is logged, what is missing)
|
|
161
|
+
- Capture method distribution (middleware vs. manual)
|
|
162
|
+
- Warnings for common gaps (no human interventions, no session boundaries, tool call/result mismatches, long gaps)
|
|
163
|
+
- Recommendations for improving coverage
|
|
164
|
+
|
|
165
|
+
### Warning rules
|
|
166
|
+
|
|
167
|
+
| Code | Severity | Condition |
|
|
168
|
+
|---|---|---|
|
|
169
|
+
| `NO_HUMAN_INTERVENTIONS` | medium | Zero `human_intervention` events in period |
|
|
170
|
+
| `NO_SESSION_BOUNDARIES` | medium | Zero `session_start`/`session_end` events |
|
|
171
|
+
| `TOOL_CALL_RESULT_MISMATCH` | high | Tool call count differs from tool result count by >5% |
|
|
172
|
+
| `NO_SYSTEM_EVENTS` | low | Zero `system_event` entries |
|
|
173
|
+
| `ALL_MANUAL_CAPTURE` | medium | 100% of entries have `captureMethod: 'manual'` |
|
|
174
|
+
| `NO_ERROR_EVENTS` | low | Zero error entries across >1,000 entries |
|
|
175
|
+
| `SINGLE_MODEL_ID` | low | Only one model across >100 inference entries |
|
|
176
|
+
| `LONG_GAP` | high | Gap of >24 hours between consecutive weekday entries |
|
|
177
|
+
|
|
178
|
+
## 6. From Logging to Full Compliance
|
|
179
|
+
|
|
180
|
+
The audit log is the data layer. For a compliance assessment of your specific system covering risk management (Article 9), human oversight design (Article 14), monitoring procedures (Article 72), and technical documentation (Annex IV), contact [Systima](https://systima.ai).
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Systima
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
# @systima/aiact-audit-log
|
|
2
|
+
|
|
3
|
+
Structured, tamper-evident audit logging for AI systems. Technical logging capability for EU AI Act Article 12 compliance.
|
|
4
|
+
|
|
5
|
+
- **Schema mapped to Article 12**: every field documents which paragraph it satisfies
|
|
6
|
+
- **SHA-256 hash chains**: tamper-evident log integrity that a regulator can independently verify
|
|
7
|
+
- **S3-native storage**: logs stay in your infrastructure, under your control
|
|
8
|
+
- **AI SDK middleware**: automatic capture for every LLM call via [Vercel AI SDK](https://sdk.vercel.ai)
|
|
9
|
+
- **AsyncLocalStorage context**: correlate multi-step decisions without manual threading
|
|
10
|
+
- **CLI tooling**: query, reconstruct, verify, coverage diagnostics, and compliance export
|
|
11
|
+
- **Retention enforcement**: configurable minimum retention with Article 19(1) floor (180 days)
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
npm install @systima/aiact-audit-log
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
> **Important**: this package provides the **technical logging capability** required by Article 12. It is necessary infrastructure for compliance, not sufficient compliance in itself. See [From Logging to Compliance](#from-logging-to-compliance) and [COMPLIANCE.md](./COMPLIANCE.md).
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { AuditLogger } from '@systima/aiact-audit-log'
|
|
23
|
+
|
|
24
|
+
const logger = new AuditLogger({
|
|
25
|
+
systemId: 'loan-scorer-v2',
|
|
26
|
+
storage: {
|
|
27
|
+
type: 's3',
|
|
28
|
+
bucket: 'my-audit-logs',
|
|
29
|
+
region: 'eu-west-1',
|
|
30
|
+
},
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
await logger.log({
|
|
34
|
+
decisionId: 'dec_abc123',
|
|
35
|
+
eventType: 'inference',
|
|
36
|
+
modelId: 'anthropic/claude-sonnet-4-5-20250929',
|
|
37
|
+
providerId: 'anthropic',
|
|
38
|
+
input: { value: 'Assess credit risk for application #12345' },
|
|
39
|
+
output: { value: 'Risk score: 0.72, recommendation: approve with conditions' },
|
|
40
|
+
latencyMs: 342,
|
|
41
|
+
usage: { promptTokens: 150, completionTokens: 80, totalTokens: 230 },
|
|
42
|
+
parameters: { temperature: 0.7 },
|
|
43
|
+
error: null,
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
// Flush on shutdown
|
|
47
|
+
await logger.close()
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Automatic Capture with AI SDK Middleware
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import { auditMiddleware } from '@systima/aiact-audit-log/ai-sdk/middleware'
|
|
54
|
+
import { anthropic } from '@ai-sdk/anthropic'
|
|
55
|
+
import { generateText, streamText } from 'ai'
|
|
56
|
+
|
|
57
|
+
const model = auditMiddleware(anthropic('claude-sonnet-4-5-20250929'), {
|
|
58
|
+
logger,
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
// Every call through the wrapped model is automatically logged
|
|
62
|
+
const result = await generateText({
|
|
63
|
+
model,
|
|
64
|
+
prompt: 'Assess the credit risk for application #12345',
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
// Streaming works too; the log entry is written when the stream completes
|
|
68
|
+
const stream = streamText({
|
|
69
|
+
model,
|
|
70
|
+
prompt: 'Explain the assessment criteria',
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
for await (const chunk of stream.textStream) {
|
|
74
|
+
process.stdout.write(chunk)
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Context Propagation
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import { withAuditContext } from '@systima/aiact-audit-log'
|
|
82
|
+
|
|
83
|
+
await withAuditContext(
|
|
84
|
+
{ decisionId: 'dec_loan_12345', metadata: { endpoint: '/api/score' } },
|
|
85
|
+
async () => {
|
|
86
|
+
// All middleware-captured and manual log calls inherit the context
|
|
87
|
+
const result = await generateText({ model, prompt: 'Score this application' })
|
|
88
|
+
|
|
89
|
+
await logger.log({
|
|
90
|
+
eventType: 'human_intervention',
|
|
91
|
+
modelId: null,
|
|
92
|
+
providerId: null,
|
|
93
|
+
input: { value: '' },
|
|
94
|
+
output: { value: 'Approved with modified terms' },
|
|
95
|
+
latencyMs: null,
|
|
96
|
+
usage: null,
|
|
97
|
+
parameters: null,
|
|
98
|
+
error: null,
|
|
99
|
+
humanIntervention: {
|
|
100
|
+
type: 'modification',
|
|
101
|
+
userId: 'reviewer_hash_a1b2c3',
|
|
102
|
+
reason: 'Additional documentation provided',
|
|
103
|
+
timestamp: new Date().toISOString(),
|
|
104
|
+
},
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## API Reference
|
|
111
|
+
|
|
112
|
+
### `AuditLogger`
|
|
113
|
+
|
|
114
|
+
The core class for structured, tamper-evident audit logging.
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
const logger = new AuditLogger({
|
|
118
|
+
// Required
|
|
119
|
+
systemId: 'loan-scorer-v2',
|
|
120
|
+
storage: {
|
|
121
|
+
type: 's3',
|
|
122
|
+
bucket: 'my-audit-logs',
|
|
123
|
+
region: 'eu-west-1',
|
|
124
|
+
prefix: 'aiact-logs', // Default: 'aiact-logs'
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
// Compliance settings (safe defaults)
|
|
128
|
+
retention: {
|
|
129
|
+
minimumDays: 180, // Default: 180 (Article 19 floor)
|
|
130
|
+
autoConfigureLifecycle: true, // Default: true
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
// Privacy / GDPR
|
|
134
|
+
pii: {
|
|
135
|
+
hashInputs: false, // Store SHA-256 hashes instead of raw inputs
|
|
136
|
+
hashOutputs: false, // Store SHA-256 hashes instead of raw outputs
|
|
137
|
+
redactPatterns: [], // Regex patterns to redact before logging
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
// Performance
|
|
141
|
+
batching: {
|
|
142
|
+
maxSize: 100, // Flush after N entries
|
|
143
|
+
maxDelayMs: 5000, // Flush after N milliseconds
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
// Error handling
|
|
147
|
+
onError: 'log-and-continue', // 'log-and-continue' | 'throw' | (error) => void
|
|
148
|
+
|
|
149
|
+
// Immutability
|
|
150
|
+
objectLock: {
|
|
151
|
+
enabled: false, // Set true if bucket has Object Lock
|
|
152
|
+
mode: 'GOVERNANCE', // 'GOVERNANCE' | 'COMPLIANCE'
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
// Periodic health checks
|
|
156
|
+
healthCheck: {
|
|
157
|
+
enabled: false, // Set true to enable
|
|
158
|
+
intervalMs: 3_600_000, // Default: 1 hour
|
|
159
|
+
onDrift: 'warn', // 'warn' | 'throw' | (drift) => void
|
|
160
|
+
},
|
|
161
|
+
})
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
#### `logger.log(input)`
|
|
165
|
+
|
|
166
|
+
Log a single event. Returns the complete `AuditLogEntryExtended` with hash chain fields.
|
|
167
|
+
|
|
168
|
+
If no `decisionId` is provided and no `withAuditContext` scope is active, throws `MissingDecisionIdError`.
|
|
169
|
+
|
|
170
|
+
#### `logger.flush()`
|
|
171
|
+
|
|
172
|
+
Force flush all buffered entries to storage.
|
|
173
|
+
|
|
174
|
+
#### `logger.close()`
|
|
175
|
+
|
|
176
|
+
Flush remaining entries and release all resources. Call on shutdown.
|
|
177
|
+
|
|
178
|
+
#### `logger.healthCheck()`
|
|
179
|
+
|
|
180
|
+
Run a health check against the storage backend. Returns `HealthCheckResult` with individual check statuses.
|
|
181
|
+
|
|
182
|
+
### `AuditLogReader`
|
|
183
|
+
|
|
184
|
+
Query, reconstruct, verify, and analyse audit logs.
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
import { AuditLogReader } from '@systima/aiact-audit-log'
|
|
188
|
+
|
|
189
|
+
const reader = new AuditLogReader({
|
|
190
|
+
storage: { type: 's3', bucket: 'my-audit-logs', region: 'eu-west-1' },
|
|
191
|
+
systemId: 'loan-scorer-v2',
|
|
192
|
+
})
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
#### `reader.query(options?)`
|
|
196
|
+
|
|
197
|
+
Search logs by time range, event type, decision ID, with optional limit.
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
const entries = await reader.query({
|
|
201
|
+
from: '2026-03-01T00:00:00Z',
|
|
202
|
+
to: '2026-03-15T23:59:59Z',
|
|
203
|
+
eventType: 'inference',
|
|
204
|
+
limit: 1000,
|
|
205
|
+
})
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
#### `reader.reconstruct(decisionId)`
|
|
209
|
+
|
|
210
|
+
Reconstruct a complete decision trace from a single identifier. Returns all entries, a human-readable timeline, and integrity verification.
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
const trace = await reader.reconstruct('dec_abc123')
|
|
214
|
+
// { decisionId, entries, timeline, integrity: { valid, entriesChecked } }
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
#### `reader.verifyChain(options?)`
|
|
218
|
+
|
|
219
|
+
Validate hash chain integrity across all entries or a time range.
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
const result = await reader.verifyChain({
|
|
223
|
+
from: '2026-03-01T00:00:00Z',
|
|
224
|
+
to: '2026-03-31T23:59:59Z',
|
|
225
|
+
})
|
|
226
|
+
// { valid: boolean, entriesChecked: number, firstBreak: { seq, expectedPrevHash, actualPrevHash } | null }
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
#### `reader.stats(options?)`
|
|
230
|
+
|
|
231
|
+
Aggregate metrics for post-market monitoring (Article 72).
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
const stats = await reader.stats({ from: '2026-03-01T00:00:00Z', to: '2026-03-31T23:59:59Z' })
|
|
235
|
+
// { totalEntries, byEventType, byModel, errorRate, avgLatencyMs, p95LatencyMs, p99LatencyMs, tokenUsage }
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### `withAuditContext(context, callback)`
|
|
239
|
+
|
|
240
|
+
Propagate decision IDs and metadata through async call chains using `AsyncLocalStorage`.
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
await withAuditContext(
|
|
244
|
+
{ decisionId: 'dec_abc123', metadata: { endpoint: '/api/score' } },
|
|
245
|
+
async () => {
|
|
246
|
+
// All logger.log() and middleware calls inherit context
|
|
247
|
+
}
|
|
248
|
+
)
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### `getAuditContext()`
|
|
252
|
+
|
|
253
|
+
Read the current context (returns `undefined` if no context is active).
|
|
254
|
+
|
|
255
|
+
### `analyseCoverage(entries, options?)`
|
|
256
|
+
|
|
257
|
+
Analyse logs for completeness gaps. Returns event type distribution, capture method distribution, warnings, and recommendations.
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
import { analyseCoverage } from '@systima/aiact-audit-log'
|
|
261
|
+
|
|
262
|
+
const report = analyseCoverage(entries, { from: '2026-03-01', to: '2026-03-31' })
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### AI SDK Helper
|
|
266
|
+
|
|
267
|
+
Post-call helper for manual logging of AI SDK results (alternative to middleware):
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
import { logFromAISDKResult } from '@systima/aiact-audit-log/ai-sdk'
|
|
271
|
+
|
|
272
|
+
const result = await generateText({ model: anthropic('claude-sonnet-4-5-20250929'), prompt })
|
|
273
|
+
await logFromAISDKResult(logger, { decisionId: 'dec_123', prompt, result })
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### AI SDK Middleware
|
|
277
|
+
|
|
278
|
+
Automatic capture middleware:
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
import { auditMiddleware } from '@systima/aiact-audit-log/ai-sdk/middleware'
|
|
282
|
+
|
|
283
|
+
const model = auditMiddleware(anthropic('claude-sonnet-4-5-20250929'), {
|
|
284
|
+
logger,
|
|
285
|
+
captureInputs: true, // Default: true
|
|
286
|
+
captureOutputs: true, // Default: true
|
|
287
|
+
captureToolCalls: true, // Default: true
|
|
288
|
+
captureParameters: true, // Default: true
|
|
289
|
+
})
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
**What the middleware logs automatically**: every `generateText`, `streamText`, and `generateObject` call (including errors and tool calls).
|
|
293
|
+
|
|
294
|
+
**What requires manual `logger.log()`**: `human_intervention`, `session_start`, `session_end`, `system_event`, `tool_result` from external execution, and custom business logic events.
|
|
295
|
+
|
|
296
|
+
## CLI
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
npx @systima/aiact-audit-log <command> [options]
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
All commands accept `--bucket`, `--region`, `--prefix`, `--endpoint`, and `--system-id` flags, or read from `AIACT_S3_BUCKET`, `AIACT_S3_REGION`, `AIACT_S3_PREFIX`, `AIACT_S3_ENDPOINT`, and `AIACT_SYSTEM_ID` environment variables.
|
|
303
|
+
|
|
304
|
+
### Commands
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
# Query logs
|
|
308
|
+
npx @systima/aiact-audit-log query \
|
|
309
|
+
--system-id loan-scorer-v2 \
|
|
310
|
+
--from 2026-03-01 --to 2026-03-15 \
|
|
311
|
+
--event-type inference --format json
|
|
312
|
+
|
|
313
|
+
# Reconstruct a decision trace
|
|
314
|
+
npx @systima/aiact-audit-log reconstruct \
|
|
315
|
+
--system-id loan-scorer-v2 \
|
|
316
|
+
--decision-id dec_abc123 --format timeline
|
|
317
|
+
|
|
318
|
+
# Verify hash chain integrity
|
|
319
|
+
npx @systima/aiact-audit-log verify \
|
|
320
|
+
--system-id loan-scorer-v2 \
|
|
321
|
+
--from 2026-03-01 --to 2026-03-31
|
|
322
|
+
|
|
323
|
+
# Aggregate statistics
|
|
324
|
+
npx @systima/aiact-audit-log stats \
|
|
325
|
+
--system-id loan-scorer-v2 \
|
|
326
|
+
--from 2026-03-01 --to 2026-03-31
|
|
327
|
+
|
|
328
|
+
# Coverage diagnostic
|
|
329
|
+
npx @systima/aiact-audit-log coverage \
|
|
330
|
+
--system-id loan-scorer-v2 \
|
|
331
|
+
--from 2026-03-01 --to 2026-03-31
|
|
332
|
+
|
|
333
|
+
# Health check
|
|
334
|
+
npx @systima/aiact-audit-log health \
|
|
335
|
+
--system-id loan-scorer-v2
|
|
336
|
+
|
|
337
|
+
# Export compliance evidence package
|
|
338
|
+
npx @systima/aiact-audit-log export \
|
|
339
|
+
--system-id loan-scorer-v2 \
|
|
340
|
+
--from 2026-03-01 --to 2026-03-31 \
|
|
341
|
+
--include-verification --include-coverage \
|
|
342
|
+
--output ./compliance-evidence/
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
## Schema
|
|
346
|
+
|
|
347
|
+
Every log entry follows a schema explicitly mapped to Article 12 paragraphs. Required fields:
|
|
348
|
+
|
|
349
|
+
| Field | Type | Article Reference |
|
|
350
|
+
|---|---|---|
|
|
351
|
+
| `schemaVersion` | `'v1'` | Forward compatibility |
|
|
352
|
+
| `entryId` | UUIDv7 | 12(1) unique event identification |
|
|
353
|
+
| `decisionId` | string | 12(2)(a) risk identification |
|
|
354
|
+
| `systemId` | string | 12(1) system identification |
|
|
355
|
+
| `timestamp` | ISO 8601 | 12(1), 12(3)(a) automatic recording |
|
|
356
|
+
| `eventType` | enum | 12(2)(a) risk situation identification |
|
|
357
|
+
| `modelId` | string or null | 12(2)(a), 72 model version tracking |
|
|
358
|
+
| `providerId` | string or null | Provider identification |
|
|
359
|
+
| `input` | `{ type, value }` | 12(2)(a), 12(2)(c), 12(3)(c) |
|
|
360
|
+
| `output` | `{ type, value }` or null | 12(2)(a), 12(2)(b) |
|
|
361
|
+
| `latencyMs` | number or null | 12(2)(b), 72 performance monitoring |
|
|
362
|
+
| `usage` | token counts or null | 72 post-market monitoring |
|
|
363
|
+
| `error` | `{ code, message }` or null | 12(2)(a) risk identification |
|
|
364
|
+
| `parameters` | object or null | 12(2)(a) configuration tracking |
|
|
365
|
+
| `captureMethod` | `'middleware'` / `'manual'` / `'context'` | Coverage analysis |
|
|
366
|
+
| `seq` | number | 12(1) event ordering |
|
|
367
|
+
| `prevHash` | SHA-256 hex | Tamper evidence |
|
|
368
|
+
| `hash` | SHA-256 hex | Tamper evidence |
|
|
369
|
+
|
|
370
|
+
Extended fields (optional): `humanIntervention`, `stepIndex`, `parentEntryId`, `toolCall`, `referenceDatabase`, `matchResult`, `metadata`.
|
|
371
|
+
|
|
372
|
+
Event types: `inference`, `tool_call`, `tool_result`, `human_intervention`, `system_event`, `session_start`, `session_end`.
|
|
373
|
+
|
|
374
|
+
## Sector-Specific Configuration
|
|
375
|
+
|
|
376
|
+
| Sector | Recommended `retention.minimumDays` | Basis |
|
|
377
|
+
|---|---|---|
|
|
378
|
+
| General (default) | 180 | Article 19(1) floor |
|
|
379
|
+
| Financial services | 2555 (7 years) | MiFID II record-keeping |
|
|
380
|
+
| Healthcare | 3650 (10 years) | Clinical record retention |
|
|
381
|
+
| Employment | 1095 (3 years) | Tribunal limitation periods |
|
|
382
|
+
|
|
383
|
+
For systems processing personal data, enable `pii.hashInputs` and `pii.hashOutputs` to store SHA-256 hashes instead of raw content (GDPR Article 5(1)(c) data minimisation).
|
|
384
|
+
|
|
385
|
+
## From Logging to Compliance
|
|
386
|
+
|
|
387
|
+
This package provides the **technical logging capability** required by Article 12. Full EU AI Act compliance for a high-risk system also requires:
|
|
388
|
+
|
|
389
|
+
- **Risk management system** (Article 9): defining what constitutes a risk for your specific system, implementing risk scoring, and generating risk assessments. The audit log provides raw data that feeds into risk management; it does not define what constitutes a risk.
|
|
390
|
+
- **Human oversight design** (Article 14): designing and documenting oversight mechanisms, defining when human review is required. The audit log records human interventions when they occur; it does not design the oversight mechanism.
|
|
391
|
+
- **Post-market monitoring procedures** (Article 72): defining monitoring KPIs, alert thresholds, and escalation procedures. The audit log provides the data layer for monitoring (via `stats`, `query`, and `export`); it does not define monitoring procedures.
|
|
392
|
+
- **Technical documentation** (Annex IV): the complete documentation package required for conformity assessment. The audit log's schema documentation and COMPLIANCE.md contribute to this; they do not constitute the full package.
|
|
393
|
+
|
|
394
|
+
The audit log is the data layer. It provides the raw material that feeds into all of the above. It does not implement them.
|
|
395
|
+
|
|
396
|
+
For a compliance assessment of your specific system covering risk management, human oversight design, monitoring procedures, and technical documentation, visit [systima.ai](https://systima.ai).
|
|
397
|
+
|
|
398
|
+
## Requirements
|
|
399
|
+
|
|
400
|
+
- Node.js >= 18
|
|
401
|
+
- `@aws-sdk/client-s3` ^3.x (peer dependency)
|
|
402
|
+
- `ai` ^4.x (optional peer dependency, for AI SDK integration)
|
|
403
|
+
|
|
404
|
+
## Licence
|
|
405
|
+
|
|
406
|
+
[MIT](./LICENSE)
|