@unifyplane/logsdk 1.0.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/.github/copilot-instructions.md +48 -0
- package/README.md +8 -0
- package/contracts/specs/LogSDKFuntionalSpec.md +394 -0
- package/contracts/specs/fanout-semantics.v1.md +244 -0
- package/contracts/specs/sink-contract.v1.md +223 -0
- package/contracts/specs/step-record.v1.md +292 -0
- package/contracts/specs/validation-rules.v1.md +324 -0
- package/docs/LogSDK-Unified-Execution-Logging-Framework.md +93 -0
- package/docs/log_sdk_test_cases_traceability_plan.md +197 -0
- package/docs/log_sdk_test_coverage_report.md +198 -0
- package/docs/prompts/AuditorSDK.txt +214 -0
- package/package.json +29 -0
- package/src/core/clock.ts +25 -0
- package/src/core/context.ts +142 -0
- package/src/core/fanout.ts +38 -0
- package/src/core/ids.ts +35 -0
- package/src/core/message_constraints.ts +66 -0
- package/src/core/outcomes.ts +5 -0
- package/src/core/record_builder.ts +269 -0
- package/src/core/spool.ts +41 -0
- package/src/core/types.ts +56 -0
- package/src/crypto-shim.d.ts +9 -0
- package/src/fs-shim.d.ts +15 -0
- package/src/index.ts +107 -0
- package/src/node-test-shim.d.ts +1 -0
- package/src/perf_hooks-shim.d.ts +7 -0
- package/src/process-shim.d.ts +1 -0
- package/src/sinks/file_ndjson.ts +42 -0
- package/src/sinks/file_ndjson_sink.ts +45 -0
- package/src/sinks/sink_types.ts +15 -0
- package/src/sinks/stdout_sink.ts +20 -0
- package/src/validate/api_surface_guard.ts +106 -0
- package/src/validate/noncompliance.ts +33 -0
- package/src/validate/schema_guard.ts +238 -0
- package/tests/fanout.test.ts +51 -0
- package/tests/fanout_spool.test.ts +96 -0
- package/tests/message_constraints.test.ts +7 -0
- package/tests/node-shim.d.ts +1 -0
- package/tests/record_builder.test.ts +32 -0
- package/tests/sequence_monotonic.test.ts +62 -0
- package/tests/sinks_file_ndjson.test.ts +53 -0
- package/tests/step1_compliance.test.ts +192 -0
- package/tools/test_results/generate-test-traceability.js +60 -0
- package/tools/test_results/normalize-test-results.js +57 -0
- package/tools/test_results/run-tests-then-prebuild.js +103 -0
- package/tools/test_results/test-case-map.json +9 -0
- package/tsconfig.json +31 -0
- package/validators/bootstrap/validate-repo-structure.ts +590 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
|
|
2
|
+
# 🧩 LogSDK Core — Sink / Emitter Contract (v1.0)
|
|
3
|
+
|
|
4
|
+
## Table of Contents
|
|
5
|
+
|
|
6
|
+
- [Purpose (Non-Negotiable)](#section-purpose-non-negotiable)
|
|
7
|
+
- [1. Conceptual Definition](#section-1-conceptual-definition)
|
|
8
|
+
- [2. Core Sink Contract (Conceptual Interface)](#section-2-core-sink-contract-conceptual-interface)
|
|
9
|
+
- [3. Input Guarantees (What the Core Promises to Sinks)](#section-3-input-guarantees-what-the-core-promises-to-sinks)
|
|
10
|
+
- [4. Sink Guarantees (What Sinks Must Promise)](#section-4-sink-guarantees-what-sinks-must-promise)
|
|
11
|
+
- [5. Sink Categories (Semantic, Not Technical)](#section-5-sink-categories-semantic-not-technical)
|
|
12
|
+
- [6. Failure Semantics (High-Level Only)](#section-6-failure-semantics-high-level-only)
|
|
13
|
+
- [7. What Sinks Are Explicitly Forbidden To Do](#section-7-what-sinks-are-explicitly-forbidden-to-do)
|
|
14
|
+
- [8. Why This Contract Is Minimal (And Correct)](#section-8-why-this-contract-is-minimal-and-correct)
|
|
15
|
+
- [9. Freeze Statement](#section-9-freeze-statement)
|
|
16
|
+
|
|
17
|
+
<a id="section-purpose-non-negotiable"></a>
|
|
18
|
+
## Purpose (Non-Negotiable)
|
|
19
|
+
|
|
20
|
+
A **Sink (Emitter)** is a **pure output boundary**.
|
|
21
|
+
|
|
22
|
+
Its only responsibility is to:
|
|
23
|
+
|
|
24
|
+
> **Accept an immutable Step Record and persist or forward it elsewhere.**
|
|
25
|
+
|
|
26
|
+
A sink:
|
|
27
|
+
|
|
28
|
+
* does **not** enrich
|
|
29
|
+
* does **not** interpret
|
|
30
|
+
* does **not** derive meaning
|
|
31
|
+
* does **not** influence execution
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
<a id="section-1-conceptual-definition"></a>
|
|
36
|
+
## 1. Conceptual Definition
|
|
37
|
+
|
|
38
|
+
A **Sink** is a component that:
|
|
39
|
+
|
|
40
|
+
1. Receives a **fully constructed, immutable Step Record**
|
|
41
|
+
2. Emits it to a destination
|
|
42
|
+
3. Acknowledges success or failure
|
|
43
|
+
4. Never mutates the record
|
|
44
|
+
|
|
45
|
+
That is all.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
<a id="section-2-core-sink-contract-conceptual-interface"></a>
|
|
50
|
+
## 2. Core Sink Contract (Conceptual Interface)
|
|
51
|
+
|
|
52
|
+
Every sink **must** conform to the following conceptual contract:
|
|
53
|
+
|
|
54
|
+
### Required Capability
|
|
55
|
+
|
|
56
|
+
| Capability | Meaning |
|
|
57
|
+
| -------------- | -------------------------------- |
|
|
58
|
+
| `emit(record)` | Accept one immutable Step Record |
|
|
59
|
+
|
|
60
|
+
### Optional Capability
|
|
61
|
+
|
|
62
|
+
| Capability | Meaning |
|
|
63
|
+
| ---------- | --------------------------------------- |
|
|
64
|
+
| `flush()` | Ensure buffered records are persisted |
|
|
65
|
+
| `close()` | Finalize resources (files, connections) |
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
<a id="section-3-input-guarantees-what-the-core-promises-to-sinks"></a>
|
|
70
|
+
## 3. Input Guarantees (What the Core Promises to Sinks)
|
|
71
|
+
|
|
72
|
+
Before a record reaches any sink, LogSDK Core guarantees:
|
|
73
|
+
|
|
74
|
+
* record is **canonical**
|
|
75
|
+
* record is **schema-complete**
|
|
76
|
+
* record is **immutable**
|
|
77
|
+
* record is **bounded**
|
|
78
|
+
* record integrity hash is present
|
|
79
|
+
* context is referenced, not embedded
|
|
80
|
+
|
|
81
|
+
Sinks **must not validate semantics** again.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
<a id="section-4-sink-guarantees-what-sinks-must-promise"></a>
|
|
86
|
+
## 4. Sink Guarantees (What Sinks Must Promise)
|
|
87
|
+
|
|
88
|
+
A compliant sink must guarantee:
|
|
89
|
+
|
|
90
|
+
### 4.1 Non-Mutation
|
|
91
|
+
|
|
92
|
+
* No field modification
|
|
93
|
+
* No field addition
|
|
94
|
+
* No field removal
|
|
95
|
+
* No re-interpretation
|
|
96
|
+
|
|
97
|
+
Transport metadata (e.g. HTTP headers) is allowed **outside** the record.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
### 4.2 Deterministic Handling
|
|
102
|
+
|
|
103
|
+
Given the same Step Record:
|
|
104
|
+
|
|
105
|
+
* the sink must behave the same way
|
|
106
|
+
* ordering must be preserved *as received*
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
### 4.3 Isolation
|
|
111
|
+
|
|
112
|
+
A sink:
|
|
113
|
+
|
|
114
|
+
* must not call other sinks
|
|
115
|
+
* must not depend on other sinks
|
|
116
|
+
* must not affect core behavior
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
<a id="section-5-sink-categories-semantic-not-technical"></a>
|
|
121
|
+
## 5. Sink Categories (Semantic, Not Technical)
|
|
122
|
+
|
|
123
|
+
### 5.1 Authoritative Evidence Sinks (Required)
|
|
124
|
+
|
|
125
|
+
These sinks define **evidence ownership**.
|
|
126
|
+
|
|
127
|
+
Examples:
|
|
128
|
+
|
|
129
|
+
* append-only file sink
|
|
130
|
+
* object storage sink
|
|
131
|
+
* immutable log archive
|
|
132
|
+
|
|
133
|
+
Rules:
|
|
134
|
+
|
|
135
|
+
* long retention
|
|
136
|
+
* append-only semantics
|
|
137
|
+
* replayable
|
|
138
|
+
* system-owned
|
|
139
|
+
|
|
140
|
+
At least **one authoritative sink is mandatory**.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
### 5.2 Observability Sinks (Optional)
|
|
145
|
+
|
|
146
|
+
These sinks exist for **human visibility**.
|
|
147
|
+
|
|
148
|
+
Examples:
|
|
149
|
+
|
|
150
|
+
* Grafana Loki
|
|
151
|
+
* stdout / console
|
|
152
|
+
* debug streams
|
|
153
|
+
|
|
154
|
+
Rules:
|
|
155
|
+
|
|
156
|
+
* best-effort delivery
|
|
157
|
+
* retention not guaranteed
|
|
158
|
+
* never authoritative
|
|
159
|
+
* may be dropped without governance impact
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
<a id="section-6-failure-semantics-high-level-only"></a>
|
|
164
|
+
## 6. Failure Semantics (High-Level Only)
|
|
165
|
+
|
|
166
|
+
Sink failures are classified conceptually:
|
|
167
|
+
|
|
168
|
+
| Sink Type | Failure Impact |
|
|
169
|
+
| ------------- | ---------------------- |
|
|
170
|
+
| Authoritative | **System-significant** |
|
|
171
|
+
| Observability | **Non-blocking** |
|
|
172
|
+
|
|
173
|
+
**Important:**
|
|
174
|
+
This classification informs **fan-out rules** (next step), not sink behavior itself.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
<a id="section-7-what-sinks-are-explicitly-forbidden-to-do"></a>
|
|
179
|
+
## 7. What Sinks Are Explicitly Forbidden To Do
|
|
180
|
+
|
|
181
|
+
A sink must never:
|
|
182
|
+
|
|
183
|
+
* inject labels / tags
|
|
184
|
+
* infer severity
|
|
185
|
+
* drop fields
|
|
186
|
+
* reorder records
|
|
187
|
+
* batch across executions
|
|
188
|
+
* correlate records
|
|
189
|
+
* compute metrics
|
|
190
|
+
* call UnifyPlane
|
|
191
|
+
* call other sinks
|
|
192
|
+
|
|
193
|
+
If any occur, the sink is **non-compliant**.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
<a id="section-8-why-this-contract-is-minimal-and-correct"></a>
|
|
198
|
+
## 8. Why This Contract Is Minimal (And Correct)
|
|
199
|
+
|
|
200
|
+
This design ensures:
|
|
201
|
+
|
|
202
|
+
* replayability
|
|
203
|
+
* deterministic intelligence derivation
|
|
204
|
+
* language neutrality
|
|
205
|
+
* storage freedom
|
|
206
|
+
* safe observability fan-out
|
|
207
|
+
* no governance coupling
|
|
208
|
+
|
|
209
|
+
Anything more would leak responsibility.
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
<a id="section-9-freeze-statement"></a>
|
|
214
|
+
## 9. Freeze Statement
|
|
215
|
+
|
|
216
|
+
This **Sink / Emitter Contract v1.0** is now:
|
|
217
|
+
|
|
218
|
+
* stable
|
|
219
|
+
* minimal
|
|
220
|
+
* sufficient
|
|
221
|
+
* extensible without breaking meaning
|
|
222
|
+
|
|
223
|
+
All current and future sinks **must** conform to this.
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
|
|
2
|
+
# 🧩 LogSDK Core — Canonical Step Record (v1.1)
|
|
3
|
+
|
|
4
|
+
## Table of Contents
|
|
5
|
+
- [Purpose (Non-Negotiable)](#section-purpose-non-negotiable)
|
|
6
|
+
- [Canonical Record: Field Set](#section-canonical-record-field-set)
|
|
7
|
+
- [1. Identity & Versioning](#section-1-identity-and-versioning)
|
|
8
|
+
- [2. Time (Dual Clock — Mandatory)](#section-2-time-dual-clock-mandatory)
|
|
9
|
+
- [3. System Ownership (Evidence Boundary)](#section-3-system-ownership-evidence-boundary)
|
|
10
|
+
- [4. Execution Correlation (SDK-Derived Only)](#section-4-execution-correlation-sdk-derived-only)
|
|
11
|
+
- [5. Execution Surface (Where This Happened)](#section-5-execution-surface-where-this-happened)
|
|
12
|
+
- [6. Source Location (Best-Effort, Factual)](#section-6-source-location-best-effort-factual)
|
|
13
|
+
- [7. Step Message (Only Human Input)](#section-7-step-message-only-human-input)
|
|
14
|
+
- [8. Context Capsule Reference (Frozen Once)](#section-8-context-capsule-reference-frozen-once)
|
|
15
|
+
- [9. Evidence References (Optional, Structured)](#section-9-evidence-references-optional-structured)
|
|
16
|
+
- [10. Integrity (Normative)](#section-10-integrity-normative)
|
|
17
|
+
- [Explicit Exclusions (Hard Rules)](#section-explicit-exclusions-hard-rules)
|
|
18
|
+
- [Semantic Meaning (Locked)](#section-semantic-meaning-locked)
|
|
19
|
+
- [Determinism Guarantees (Explicit)](#section-determinism-guarantees-explicit)
|
|
20
|
+
- [Freeze Statement](#section-freeze-statement)
|
|
21
|
+
- [Appendix A. Revision Notes (Non-Normative)](#appendix-a-revision-notes-non-normative)
|
|
22
|
+
<a id="section-purpose-non-negotiable"></a>
|
|
23
|
+
## Purpose (Non-Negotiable)
|
|
24
|
+
|
|
25
|
+
A **Step Record** represents **one execution step** as immutable execution evidence.
|
|
26
|
+
|
|
27
|
+
It must be:
|
|
28
|
+
|
|
29
|
+
* replayable
|
|
30
|
+
* bounded
|
|
31
|
+
* deterministic
|
|
32
|
+
* storage-agnostic
|
|
33
|
+
* derivation-ready
|
|
34
|
+
|
|
35
|
+
It must **not** encode decisions, payloads, intelligence, or interpretation.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
<a id="section-canonical-record-field-set"></a>
|
|
39
|
+
## Canonical Record: Field Set
|
|
40
|
+
|
|
41
|
+
<a id="section-1-identity-and-versioning"></a>
|
|
42
|
+
### 1. Identity & Versioning
|
|
43
|
+
|
|
44
|
+
| Field | Description |
|
|
45
|
+
| ---------------- | ------------------------------------------------------------ |
|
|
46
|
+
| `record_version` | Fixed identifier of the record contract (e.g. `log.step.v1`) |
|
|
47
|
+
| `record_id` | Unique identifier for this step record |
|
|
48
|
+
| `sequence` | Monotonic sequence number scoped to the SDK instance |
|
|
49
|
+
|
|
50
|
+
**Rules**
|
|
51
|
+
|
|
52
|
+
* `record_version` is immutable and schema-defining
|
|
53
|
+
* `record_id` must be globally unique per process and SDK instance
|
|
54
|
+
* `sequence` must start at `0` and increment by exactly `1`
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
<a id="section-2-time-dual-clock-mandatory"></a>
|
|
59
|
+
### 2. Time (Dual Clock — Mandatory)
|
|
60
|
+
|
|
61
|
+
| Field | Description |
|
|
62
|
+
| ---------------- | ------------------------------------------------------- |
|
|
63
|
+
| `timestamp_utc` | Wall-clock time in UTC (RFC 3339 / ISO-8601 profile) |
|
|
64
|
+
| `monotonic_time` | Monotonic clock value for strict intra-process ordering |
|
|
65
|
+
|
|
66
|
+
**Rules**
|
|
67
|
+
|
|
68
|
+
* Both fields are required
|
|
69
|
+
* Ordering **must never** depend on wall clock alone
|
|
70
|
+
* `monotonic_time` must be strictly increasing per record
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
<a id="section-3-system-ownership-evidence-boundary"></a>
|
|
75
|
+
### 3. System Ownership (Evidence Boundary)
|
|
76
|
+
|
|
77
|
+
| Field | Description |
|
|
78
|
+
| ---------------- | --------------------------------------------------- |
|
|
79
|
+
| `institution` | Owning organization or authority domain |
|
|
80
|
+
| `system_name` | Logical system emitting the step |
|
|
81
|
+
| `system_type` | `process` / `pipeline` / `service` / `content` |
|
|
82
|
+
| `environment` | `local` / `dev` / `staging` / `prod` |
|
|
83
|
+
| `system_version` | Deployed version or build identifier |
|
|
84
|
+
| `instance_id` | Runtime instance identifier (optional but expected) |
|
|
85
|
+
|
|
86
|
+
These fields define **who owns the evidence** and where its trust boundary lies.
|
|
87
|
+
|
|
88
|
+
They must be injected by the SDK or system adapter, never manually set per step.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
<a id="section-4-execution-correlation-sdk-derived-only"></a>
|
|
93
|
+
### 4. Execution Correlation (SDK-Derived Only)
|
|
94
|
+
|
|
95
|
+
| Field | Description |
|
|
96
|
+
| ---------------- | -------------------------------------------------------- |
|
|
97
|
+
| `trace_id` | Distributed trace identifier (if available) |
|
|
98
|
+
| `span_id` | Span identifier (if available) |
|
|
99
|
+
| `parent_step_id` | Parent step record ID (if hierarchical execution exists) |
|
|
100
|
+
|
|
101
|
+
**Rules**
|
|
102
|
+
|
|
103
|
+
* These fields are **derived automatically**
|
|
104
|
+
* No developer may set or override them
|
|
105
|
+
* Absence is valid if the execution model does not support correlation
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
<a id="section-5-execution-surface-where-this-happened"></a>
|
|
110
|
+
### 5. Execution Surface (Where This Happened)
|
|
111
|
+
|
|
112
|
+
| Field | Description |
|
|
113
|
+
| ------------------ | ------------------------------------------------------- |
|
|
114
|
+
| `surface_type` | `http` / `job` / `worker` / `page` / `cli` / `internal` |
|
|
115
|
+
| `surface_name` | Route, job name, page name, etc. |
|
|
116
|
+
| `surface_instance` | Request ID / job ID / execution ID |
|
|
117
|
+
|
|
118
|
+
**Rules**
|
|
119
|
+
|
|
120
|
+
* Derived by thin SDKs or runtime adapters only
|
|
121
|
+
* Must reflect *execution context*, not business semantics
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
<a id="section-6-source-location-best-effort-factual"></a>
|
|
126
|
+
### 6. Source Location (Best-Effort, Factual)
|
|
127
|
+
|
|
128
|
+
| Field | Description |
|
|
129
|
+
| ----------------- | ----------------------- |
|
|
130
|
+
| `source_file` | Repo-relative file path |
|
|
131
|
+
| `source_module` | Module or package name |
|
|
132
|
+
| `source_function` | Function or method name |
|
|
133
|
+
| `source_line` | Line number (nullable) |
|
|
134
|
+
|
|
135
|
+
**Rules**
|
|
136
|
+
|
|
137
|
+
* Automatically injected by the SDK where possible
|
|
138
|
+
* Must never be developer-supplied
|
|
139
|
+
* Absence (`null`) is acceptable when not reliably obtainable
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
<a id="section-7-step-message-only-human-input"></a>
|
|
144
|
+
### 7. Step Message (Only Human Input)
|
|
145
|
+
|
|
146
|
+
| Field | Description |
|
|
147
|
+
| -------------- | ------------------------------------------------ |
|
|
148
|
+
| `message` | Human-readable step description (bounded string) |
|
|
149
|
+
| `message_code` | Optional registry-defined step code |
|
|
150
|
+
|
|
151
|
+
**Hard Constraints**
|
|
152
|
+
|
|
153
|
+
* String only
|
|
154
|
+
* Non-empty
|
|
155
|
+
* Hard length limit
|
|
156
|
+
* No JSON, arrays, or objects
|
|
157
|
+
* No payloads
|
|
158
|
+
* No free-form metadata
|
|
159
|
+
|
|
160
|
+
This is the **only expressive input** a developer provides.
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
<a id="section-8-context-capsule-reference-frozen-once"></a>
|
|
165
|
+
### 8. Context Capsule Reference (Frozen Once)
|
|
166
|
+
|
|
167
|
+
| Field | Description |
|
|
168
|
+
| ----------------- | ------------------------------------------------- |
|
|
169
|
+
| `context_hash` | Hash reference to frozen context injected at init |
|
|
170
|
+
| `context_version` | Version of the context schema |
|
|
171
|
+
|
|
172
|
+
**Rules**
|
|
173
|
+
|
|
174
|
+
* Context is injected once at SDK initialization
|
|
175
|
+
* Context is normalized, canonicalized, and deeply frozen
|
|
176
|
+
* Context is **never embedded** in records
|
|
177
|
+
* Records reference context **by hash only**
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
<a id="section-9-evidence-references-optional-structured"></a>
|
|
182
|
+
### 9. Evidence References (Optional, Structured)
|
|
183
|
+
|
|
184
|
+
| Field | Description |
|
|
185
|
+
| --------------- | -------------------------------------------------- |
|
|
186
|
+
| `evidence_refs` | Array of references to external evidence artifacts |
|
|
187
|
+
|
|
188
|
+
**Rules**
|
|
189
|
+
|
|
190
|
+
* References only (IDs, URIs, digests)
|
|
191
|
+
* No embedded data
|
|
192
|
+
* No payload material
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
<a id="section-10-integrity-normative"></a>
|
|
197
|
+
### 10. Integrity (Normative)
|
|
198
|
+
|
|
199
|
+
| Field | Description |
|
|
200
|
+
| ---------------- | --------------------------------------- |
|
|
201
|
+
| `record_hash` | Hash of the canonical serialized record |
|
|
202
|
+
| `hash_algorithm` | Algorithm used (explicit, versioned) |
|
|
203
|
+
|
|
204
|
+
**Rules**
|
|
205
|
+
|
|
206
|
+
* Record must be canonically serialized before hashing
|
|
207
|
+
* `record_hash` must **exclude itself** from hash scope
|
|
208
|
+
* Canonical serialization must be deterministic across runtimes
|
|
209
|
+
* UTF-8 encoding is mandatory
|
|
210
|
+
|
|
211
|
+
This guarantees:
|
|
212
|
+
|
|
213
|
+
* immutability
|
|
214
|
+
* tamper detection
|
|
215
|
+
* replay stability
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
<a id="section-explicit-exclusions-hard-rules"></a>
|
|
219
|
+
## Explicit Exclusions (Hard Rules)
|
|
220
|
+
|
|
221
|
+
A Step Record **must never contain**:
|
|
222
|
+
|
|
223
|
+
* business payloads
|
|
224
|
+
* metrics or counters
|
|
225
|
+
* severity levels
|
|
226
|
+
* labels or tags
|
|
227
|
+
* inferred meaning
|
|
228
|
+
* decisions or judgments
|
|
229
|
+
* AI outputs
|
|
230
|
+
* free-form metadata
|
|
231
|
+
|
|
232
|
+
Presence of any of the above renders the record **invalid**.
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
<a id="section-semantic-meaning-locked"></a>
|
|
236
|
+
## Semantic Meaning (Locked)
|
|
237
|
+
|
|
238
|
+
> A Step Record asserts only:
|
|
239
|
+
> **“This execution step occurred at this point in this system.”**
|
|
240
|
+
|
|
241
|
+
It does **not** assert:
|
|
242
|
+
|
|
243
|
+
* correctness
|
|
244
|
+
* success
|
|
245
|
+
* legitimacy
|
|
246
|
+
* intent
|
|
247
|
+
* impact
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
<a id="section-determinism-guarantees-explicit"></a>
|
|
251
|
+
## Determinism Guarantees (Explicit)
|
|
252
|
+
|
|
253
|
+
Given identical:
|
|
254
|
+
|
|
255
|
+
* initialization context
|
|
256
|
+
* execution order
|
|
257
|
+
* SDK version
|
|
258
|
+
|
|
259
|
+
The sequence, structure, and meaning of Step Records must be **replay-stable**, aside from timestamps and identifiers.
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
<a id="section-freeze-statement"></a>
|
|
263
|
+
## Freeze Statement
|
|
264
|
+
|
|
265
|
+
This **Canonical Step Record v1.1** is:
|
|
266
|
+
|
|
267
|
+
* language-independent
|
|
268
|
+
* runtime-agnostic
|
|
269
|
+
* ABI-like
|
|
270
|
+
* safe for long-term replay and audit
|
|
271
|
+
|
|
272
|
+
All thin SDKs **must map into this shape exactly**, without extension or semantic enrichment.
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
<a id="appendix-a-revision-notes-non-normative"></a>
|
|
277
|
+
## Appendix A. Revision Notes (Non-Normative)
|
|
278
|
+
|
|
279
|
+
### Why this update matters
|
|
280
|
+
|
|
281
|
+
* Hashing and determinism are now **normative**, not implied
|
|
282
|
+
* Source and surface fields are clearly bounded
|
|
283
|
+
* The record is now **unambiguously evidence-only**
|
|
284
|
+
* This shape can survive **decades of system evolution**
|
|
285
|
+
|
|
286
|
+
If you want next, the logically correct follow-ups are:
|
|
287
|
+
|
|
288
|
+
* a **canonical JSON Schema** for this record
|
|
289
|
+
* a **hash canonicalization appendix** (RFC-aligned)
|
|
290
|
+
* or a **LogSDK → Step Record conformance checklist**
|
|
291
|
+
|
|
292
|
+
Say which one you want to proceed with.
|