intent-eval-core 0.7.0__py3-none-any.whl

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.
@@ -0,0 +1,71 @@
1
+ """intent-eval-core — Python distribution of the Intent Eval Platform contracts kernel.
2
+
3
+ The same canonical contracts the TypeScript ``@intentsolutions/core`` package
4
+ exposes as Zod validators + JSON Schemas, here as **Pydantic v2 models** for
5
+ Python consumers (LLM-harness lab, agent-runtime sandbox, ``validate-*`` skill
6
+ emit-evidence retrofits).
7
+
8
+ The models are codegen'd from the canonical ``schemas/v1/*.json`` JSON Schemas
9
+ (``datamodel-code-generator``) and validated for byte-for-byte parity against the
10
+ same golden fixtures the TypeScript/AJV side validates — so a payload accepted by
11
+ the Zod validator is accepted here, and one rejected there is rejected here.
12
+
13
+ Usage::
14
+
15
+ from intent_eval_core import GateResultV1, EvalSpec
16
+
17
+ gate = GateResultV1.model_validate(some_dict) # raises ValidationError on drift
18
+
19
+ Version is kept in lockstep with the npm ``@intentsolutions/core`` ``package.json``
20
+ version (the JSON Schemas are the shared source of truth for both).
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ from .models import (
26
+ GATE_RESULT_V1_URI,
27
+ CostRecord,
28
+ DashboardRenderV1,
29
+ EvalRun,
30
+ EvalSpec,
31
+ EvidenceBundle,
32
+ FailureTaxonomy,
33
+ GateResultV1,
34
+ JudgeDecision,
35
+ MatcherMap,
36
+ RegressionPack,
37
+ RetractionV1,
38
+ RolloutGate,
39
+ RuntimeReceipt,
40
+ SessionTrace,
41
+ SkillSnapshot,
42
+ ToolInvocation,
43
+ )
44
+
45
+ # Kept in lockstep with npm package.json#version by scripts/check_version_lockstep.py
46
+ # (CI-gated). The JSON Schemas under schemas/v1/ are the shared source of truth.
47
+ __version__ = "0.7.0"
48
+
49
+ __all__ = [
50
+ "__version__",
51
+ # Entities (Blueprint B § 2.1 – § 2.13)
52
+ "EvalSpec",
53
+ "EvalRun",
54
+ "MatcherMap",
55
+ "EvidenceBundle",
56
+ "JudgeDecision",
57
+ "RuntimeReceipt",
58
+ "RegressionPack",
59
+ "RolloutGate",
60
+ "SkillSnapshot",
61
+ "SessionTrace",
62
+ "ToolInvocation",
63
+ "CostRecord",
64
+ "FailureTaxonomy",
65
+ # Predicate bodies
66
+ "GateResultV1",
67
+ "RetractionV1",
68
+ "DashboardRenderV1",
69
+ # Constants
70
+ "GATE_RESULT_V1_URI",
71
+ ]
@@ -0,0 +1,38 @@
1
+ # `_generated/` — Pydantic codegen reference output (NOT the public API)
2
+
3
+ This directory holds the **raw output** of
4
+ [`datamodel-code-generator`](https://github.com/koxudaxi/datamodel-code-generator)
5
+ run against `schemas/v1/*.json`. It is the Python analogue of the Zod
6
+ `src/validators/v1/_generated/` directory — **reference material, not the
7
+ canonical public surface.**
8
+
9
+ The canonical Python surface lives one level up at
10
+ `intent_eval_core/models.py`, which:
11
+
12
+ 1. Re-exports each generated root model under its canonical name
13
+ (`GateResultV1`, `EvalSpec`, …) — the generator derives verbose class names
14
+ from each schema's `title`.
15
+ 2. Layers hand-written cross-field `model_validator`s for the `allOf`/`if-then`
16
+ conditional rules the generator cannot express (e.g. gate-result/v1's
17
+ "advisory requires advisory_severity", "fail/advisory/error requires a
18
+ non-empty reason"). These mirror the Zod `.superRefine()` blocks exactly.
19
+
20
+ ## Codegen invocation
21
+
22
+ ```bash
23
+ pnpm run codegen:pydantic # regenerate (pinned datamodel-code-generator)
24
+ pnpm run codegen:pydantic:check # idempotency gate (CI)
25
+ ```
26
+
27
+ The script (`scripts/codegen_pydantic.py`) is reproducible: same schemas + the
28
+ pinned generator version => byte-identical output. It normalizes the absolute
29
+ `$ref`/`$id` the predicate schemas carry down to relative refs so the generator
30
+ resolves them locally (AJV resolves them against each schema's `$id` base; we
31
+ collapse to relative paths — both arrive at the same target file).
32
+
33
+ ## What NOT to do
34
+
35
+ - **Don't import from `_generated/`** — import from `intent_eval_core` /
36
+ `intent_eval_core.models` (the public surface).
37
+ - **Don't edit `_generated/*.py` by hand** — they're overwritten on next codegen
38
+ and CI-gated for staleness.
@@ -0,0 +1,2 @@
1
+ # generated by datamodel-codegen:
2
+ # filename: schemas
@@ -0,0 +1,210 @@
1
+ # generated by datamodel-codegen:
2
+ # filename: _common.schema.json
3
+
4
+ from __future__ import annotations
5
+
6
+ from enum import Enum
7
+ from typing import Any
8
+
9
+ from pydantic import (
10
+ AwareDatetime,
11
+ BaseModel,
12
+ ConfigDict,
13
+ Field,
14
+ RootModel,
15
+ conint,
16
+ constr,
17
+ )
18
+
19
+
20
+ class CommonBrandedPrimitiveDefinitionsForIntentsolutionsCoreSchemas(RootModel[Any]):
21
+ root: Any = Field(
22
+ ...,
23
+ title="Common branded-primitive definitions for @intentsolutions/core schemas",
24
+ )
25
+ """
26
+ Shared $defs referenced by every entity schema and the gate-result/v1 predicate body. Branded primitives correspond to the TypeScript brands in src/primitives.ts — at the JSON Schema level, they are pattern-validated strings/numbers.
27
+ """
28
+
29
+
30
+ class Uuidv7(
31
+ RootModel[
32
+ constr(
33
+ pattern=r"^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
34
+ )
35
+ ]
36
+ ):
37
+ root: constr(
38
+ pattern=r"^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
39
+ )
40
+ """
41
+ UUIDv7 — time-ordered 128-bit identifier (RFC 9562). Time-ordered prefix means natural sort order matches insertion order. Per Blueprint B § 6.2 universal conventions.
42
+ """
43
+
44
+
45
+ class Sha256(RootModel[constr(pattern=r"^[a-f0-9]{64}$")]):
46
+ root: constr(pattern=r"^[a-f0-9]{64}$")
47
+ """
48
+ Bare 64-hex-char SHA-256 digest. Used for entity content_hash fields per Blueprint B § 2.x prose.
49
+ """
50
+
51
+
52
+ class Sha256Prefixed(RootModel[constr(pattern=r"^sha256:[a-f0-9]{64}$")]):
53
+ root: constr(pattern=r"^sha256:[a-f0-9]{64}$")
54
+ """
55
+ Prefixed SHA-256 digest in the form `sha256:<64-lowercase-hex>`. REQUIRED format for every *_hash field in the gate-result/v1 predicate body per Blueprint B § 7.4. Unknown algorithm prefixes cause row verification failure.
56
+ """
57
+
58
+
59
+ class Rfc3339(RootModel[AwareDatetime]):
60
+ root: AwareDatetime
61
+ """
62
+ RFC 3339 / ISO 8601 timestamp with timezone. Blueprint B requires UTC ('Z') with millisecond precision for fields in worker-lease ordering (clock-skew tolerance ±10 ms).
63
+ """
64
+
65
+
66
+ class Semver(
67
+ RootModel[
68
+ constr(pattern=r"^[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9.-]+)?(\+[A-Za-z0-9.-]+)?$")
69
+ ]
70
+ ):
71
+ root: constr(
72
+ pattern=r"^[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9.-]+)?(\+[A-Za-z0-9.-]+)?$"
73
+ )
74
+ """
75
+ SemVer 2.0.0 version string.
76
+ """
77
+
78
+
79
+ class KebabSlug(RootModel[constr(pattern=r"^[a-z0-9][a-z0-9-]*$")]):
80
+ root: constr(pattern=r"^[a-z0-9][a-z0-9-]*$")
81
+ """
82
+ Lowercase kebab-case slug.
83
+ """
84
+
85
+
86
+ class ActorIdentity(RootModel[constr(min_length=1)]):
87
+ root: constr(min_length=1)
88
+ """
89
+ Opaque actor identity string — engineer email, service-account name, or worker id. Format intentionally unspecified at this layer.
90
+ """
91
+
92
+
93
+ class StorageKey(RootModel[constr(min_length=1)]):
94
+ root: constr(min_length=1)
95
+ """
96
+ Object-storage key (content-addressed). Format opaque at this layer; storage backends own resolution.
97
+ """
98
+
99
+
100
+ class OtelSpanId(RootModel[constr(pattern=r"^[a-f0-9]{16}$")]):
101
+ root: constr(pattern=r"^[a-f0-9]{16}$")
102
+ """
103
+ OpenTelemetry span identifier — 16 lowercase hex characters per OTel spec.
104
+ """
105
+
106
+
107
+ class MicroUsd(RootModel[conint(ge=0)]):
108
+ root: conint(ge=0)
109
+ """
110
+ Cost in micro-USD for sub-cent precision. Per Blueprint B § 2.12. Convert to USD at display layer (value / 1_000_000).
111
+ """
112
+
113
+
114
+ class MmClass(Enum):
115
+ """
116
+ Matcher Map class — closed v1 canonical set per Blueprint B § 2.3. Extension via FailureTaxonomy proposed→canonical lifecycle (Class-1 ISEDC).
117
+ """
118
+
119
+ MM_1 = "MM-1"
120
+ MM_2 = "MM-2"
121
+ MM_3 = "MM-3"
122
+ MM_4 = "MM-4"
123
+ MM_5 = "MM-5"
124
+ MM_6 = "MM-6"
125
+
126
+
127
+ class MmClassId(RootModel[constr(pattern=r"^MM-[0-9]+$")]):
128
+ root: constr(pattern=r"^MM-[0-9]+$")
129
+ """
130
+ FailureTaxonomy natural key — accepts any MM-N value (broader than MmClass enum since taxonomy is upstream of kernel enum).
131
+ """
132
+
133
+
134
+ class RunnerIdentifier(
135
+ RootModel[
136
+ constr(
137
+ pattern=r"^[a-z0-9][a-z0-9-]*@[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9.-]+)?(\+[A-Za-z0-9.-]+)?$"
138
+ )
139
+ ]
140
+ ):
141
+ root: constr(
142
+ pattern=r"^[a-z0-9][a-z0-9-]*@[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9.-]+)?(\+[A-Za-z0-9.-]+)?$"
143
+ )
144
+ """
145
+ Tool + SemVer identifier in the form `<kebab-slug>@<semver>`.
146
+ """
147
+
148
+
149
+ class CommitSha(RootModel[constr(pattern=r"^[a-f0-9]{7,40}$")]):
150
+ root: constr(pattern=r"^[a-f0-9]{7,40}$")
151
+ """
152
+ Git commit SHA — full 40-hex or short 7-hex accepted per Blueprint B § 7.4 line 815.
153
+ """
154
+
155
+
156
+ class SubjectName(
157
+ RootModel[
158
+ constr(
159
+ pattern=r"^[a-z0-9][a-z0-9-]*:(client|server|ci|sandbox|local):[a-zA-Z0-9][a-zA-Z0-9.-]*$"
160
+ )
161
+ ]
162
+ ):
163
+ root: constr(
164
+ pattern=r"^[a-z0-9][a-z0-9-]*:(client|server|ci|sandbox|local):[a-zA-Z0-9][a-zA-Z0-9.-]*$"
165
+ )
166
+ """
167
+ in-toto subject name per Blueprint B § 7.3 line 779. Three segments: `<tool>:<side>:<gate-id>` where side ∈ {client, server, ci, sandbox, local}.
168
+ """
169
+
170
+
171
+ class Coverage(BaseModel):
172
+ """
173
+ Coverage declaration per Blueprint B § 7.4 line 807. Both arrays REQUIRED. Element type LOCKED as string per deferral-D (bd_000-projects-9xyk). NOT_APPLICABLE encoding (§ 7.4 line 832): gate_decision='pass' + populated dimensions_skipped + documented skip in gate_reasons.
174
+ """
175
+
176
+ model_config = ConfigDict(
177
+ extra="forbid",
178
+ )
179
+ dimensions_evaluated: list[str]
180
+ dimensions_skipped: list[str]
181
+
182
+
183
+ class Status(Enum):
184
+ evaluated = "evaluated"
185
+ skipped = "skipped"
186
+
187
+
188
+ class CoverageDimensionDetail(BaseModel):
189
+ """
190
+ Richer per-dimension coverage element (deferral-D lockup, bd_000-projects-9xyk). The OPTIONAL companion to `coverage`'s string arrays — adopted additively per § 7.2 so the `coverage` element type stays `string`. Descriptive only; MUST NOT drive ship/no-ship (mirrors metadata rule).
191
+ """
192
+
193
+ model_config = ConfigDict(
194
+ extra="forbid",
195
+ )
196
+ id: str
197
+ """
198
+ Dimension id — MUST appear in the matching coverage array (cross-field enforced at the validator layer).
199
+ """
200
+ status: Status
201
+ skip_reason: str | None = None
202
+ threshold: float | None = None
203
+ observed: float | None = None
204
+
205
+
206
+ class ErrorClass(RootModel[constr(pattern=r"^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$")]):
207
+ root: constr(pattern=r"^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$")
208
+ """
209
+ Tool-error class (deferral-E lockup, bd_000-projects-84li). A kernel-registered cross-cutting class OR a tool-defined `<domain>.<condition>` string. The registration CONVENTION is locked (dot-separated, lowercase); the enum stays OPEN.
210
+ """
@@ -0,0 +1,59 @@
1
+ # generated by datamodel-codegen:
2
+ # filename: cost-record.schema.json
3
+
4
+ from __future__ import annotations
5
+
6
+ from enum import Enum
7
+
8
+ from pydantic import BaseModel, ConfigDict, conint, constr
9
+
10
+ from . import _common_schema as schema
11
+
12
+
13
+ class AttributionClass(Enum):
14
+ """
15
+ Cost attribution class enum (Blueprint B § 2.12, closed 7-element set).
16
+ """
17
+
18
+ run = "run"
19
+ provider = "provider"
20
+ judge = "judge"
21
+ replay = "replay"
22
+ cache_decision = "cache_decision"
23
+ optimizer_experiment = "optimizer_experiment"
24
+ system = "system"
25
+
26
+
27
+ class CostrecordSingleCostResourceAttributionRowBlueprintB212(BaseModel):
28
+ """
29
+ Single terminal state `recorded`. Immutable. Rollups = separate rows with attribution_class='system'. NOT replay-deterministic (cost varies by cache state, pricing, seed routing). external_api_cost_micro_usd uses micro-USD per Blueprint B § 2.12 — NORMATIVE precision requirement. Predicate URI: cost-attribution/v1 (sigstore_staging).
30
+ """
31
+
32
+ model_config = ConfigDict(
33
+ extra="forbid",
34
+ )
35
+ id: schema.Uuidv7
36
+ eval_run_id: schema.Uuidv7 | None = None
37
+ """
38
+ Nullable for system-level rollups.
39
+ """
40
+ tool_invocation_id: schema.Uuidv7 | None = None
41
+ """
42
+ Nullable for run-level / system rollups.
43
+ """
44
+ attribution_class: AttributionClass
45
+ """
46
+ Cost attribution class enum (Blueprint B § 2.12, closed 7-element set).
47
+ """
48
+ provider_id: constr(min_length=1) | None = None
49
+ tokens_consumed: conint(ge=0)
50
+ prompt_tokens: conint(ge=0)
51
+ completion_tokens: conint(ge=0)
52
+ cached_tokens: conint(ge=0)
53
+ wall_clock_ms: conint(ge=0)
54
+ external_api_cost_micro_usd: schema.MicroUsd
55
+ recorded_at: schema.Rfc3339
56
+ cost_basis_version: constr(min_length=1)
57
+ """
58
+ Version tag of the cost-basis lookup table. Table itself forward-deferred to iel-E14b.
59
+ """
@@ -0,0 +1,78 @@
1
+ # generated by datamodel-codegen:
2
+ # filename: dashboard-render.schema.json
3
+
4
+ from __future__ import annotations
5
+
6
+ from pydantic import BaseModel, ConfigDict, Field, constr
7
+
8
+ from . import _common_schema as schema
9
+
10
+
11
+ class RenderedArtifact(BaseModel):
12
+ """
13
+ The rendered dashboard artifact this row attests.
14
+ """
15
+
16
+ model_config = ConfigDict(
17
+ extra="forbid",
18
+ )
19
+ uri: constr(min_length=1) | None = None
20
+ """
21
+ OPTIONAL location of the rendered artifact — relative path or absolute URL. The content_hash is the authoritative identifier; uri is a convenience pointer.
22
+ """
23
+ content_hash: schema.Sha256Prefixed
24
+ """
25
+ sha256-prefixed digest of the rendered HTML artifact bytes. Reproducing this from input_bundles is what a verifier checks.
26
+ """
27
+ media_type: constr(min_length=1) | None = None
28
+ """
29
+ OPTIONAL IANA media type of the rendered artifact (e.g., text/html).
30
+ """
31
+
32
+
33
+ class InputBundle(BaseModel):
34
+ model_config = ConfigDict(
35
+ extra="forbid",
36
+ )
37
+ bundle_id: schema.Uuidv7 | None = None
38
+ """
39
+ UUIDv7 of an input EvidenceBundle (FK → EvidenceBundle.id).
40
+ """
41
+ content_hash: schema.Sha256Prefixed | None = None
42
+ """
43
+ sha256-prefixed digest of the input bundle payload, pinning exact content.
44
+ """
45
+
46
+
47
+ class DashboardRenderV1InTotoPredicateBodyAttestingARenderedDashboardArtifact(
48
+ BaseModel
49
+ ):
50
+ """
51
+ Predicate body of an in-toto Statement v1 whose predicateType is https://evals.intentsolutions.io/dashboard-render/v1. Attests that a specific rendered dashboard HTML artifact was produced from a specific, content-addressed set of evidence inputs — i.e., 'this rendered page is a faithful function of exactly these signed bundles.' Enables sign-your-own-homework verification: a third party can re-run the renderer against the same inputs and reproduce rendered_artifact.content_hash. This schema validates ONLY the predicate body — the enclosing in-toto Statement envelope (_type, subject, predicateType) is validated separately. Each row independently verifiable; NO top-level bundle signature per Blueprint B § 7 line 754.
52
+
53
+ ADDITIVE in kernel v0.2.0 (B3 binding, sequenced): net-new predicate URI; no v0.1 contract changes. Per § 7.2 backward-compat, adding a predicate URI is allowed. Runs in sigstore_staging until a second independent verifier exists (sign-your-own-homework sequencing) and production-Rekor unlock per DR-010 Q3.
54
+ """
55
+
56
+ model_config = ConfigDict(
57
+ extra="forbid",
58
+ )
59
+ rendered_artifact: RenderedArtifact
60
+ """
61
+ The rendered dashboard artifact this row attests.
62
+ """
63
+ input_bundles: list[InputBundle] = Field(..., min_length=1)
64
+ """
65
+ Content-addressed evidence inputs the artifact was rendered from. Each entry pins a bundle by id and/or digest so the input set is reproducible. MUST be non-empty — a render with no evidence inputs is not attestable.
66
+ """
67
+ rendered_at: schema.Rfc3339
68
+ """
69
+ RFC 3339 UTC timestamp at which the render was produced.
70
+ """
71
+ renderer: schema.RunnerIdentifier
72
+ """
73
+ Renderer tool identity + version in the form `<kebab-slug>@<semver>` (e.g., intent-eval-dashboard@0.2.0). Mirrors gate-result/v1's `runner` discipline so the producing tool is always pinned.
74
+ """
75
+ renderer_config_hash: schema.Sha256Prefixed | None = None
76
+ """
77
+ OPTIONAL sha256-prefixed hash of the renderer configuration / template set, so a verifier can pin not just the tool version but the exact template inputs.
78
+ """
@@ -0,0 +1,97 @@
1
+ # generated by datamodel-codegen:
2
+ # filename: eval-run.schema.json
3
+
4
+ from __future__ import annotations
5
+
6
+ from enum import Enum
7
+
8
+ from pydantic import BaseModel, ConfigDict, constr
9
+
10
+ from . import _common_schema as schema
11
+
12
+
13
+ class State(Enum):
14
+ """
15
+ EvalRun state enum (Blueprint B § 2.2 + § 3.1). Terminal states: archived, skipped_due_to_gate, archived_failed.
16
+ """
17
+
18
+ queued = "queued"
19
+ running = "running"
20
+ judged = "judged"
21
+ reported = "reported"
22
+ archived = "archived"
23
+ skipped_due_to_gate = "skipped_due_to_gate"
24
+ archived_failed = "archived_failed"
25
+
26
+
27
+ class TerminalReason(Enum):
28
+ """
29
+ Why this Run terminated. Set per Blueprint B § 3.1 enumeration + § 1.3 (upstream_feed_failed).
30
+ """
31
+
32
+ queued_timeout_elapsed = "queued_timeout_elapsed"
33
+ run_timeout_elapsed = "run_timeout_elapsed"
34
+ worker_crash_exhausted = "worker_crash_exhausted"
35
+ credential_leak_detected = "credential_leak_detected"
36
+ judge_unavailable_exhausted = "judge_unavailable_exhausted"
37
+ token_ceiling_exceeded = "token_ceiling_exceeded"
38
+ evidence_contract_violation = "evidence_contract_violation"
39
+ upstream_feed_failed = "upstream_feed_failed"
40
+
41
+
42
+ class EvalrunSingleExecutionOfAnEvalspecAgainstASkillsnapshotBlueprintB22(BaseModel):
43
+ """
44
+ State machine spans 7 states with explicit transition table at Blueprint B § 3.1. Mutable in non-terminal states; frozen at terminal. Clock-skew tolerance ±10 ms across workers.
45
+ """
46
+
47
+ model_config = ConfigDict(
48
+ extra="forbid",
49
+ )
50
+ id: schema.Uuidv7
51
+ eval_spec_id: schema.Uuidv7
52
+ eval_spec_version: schema.Semver
53
+ """
54
+ Frozen at queue time — defends against mid-flight spec mutation.
55
+ """
56
+ eval_spec_content_hash: schema.Sha256
57
+ """
58
+ Frozen at queue time.
59
+ """
60
+ skill_snapshot_id: schema.Uuidv7
61
+ state: State
62
+ """
63
+ EvalRun state enum (Blueprint B § 2.2 + § 3.1). Terminal states: archived, skipped_due_to_gate, archived_failed.
64
+ """
65
+ terminal_reason: TerminalReason | None = None
66
+ queued_at: schema.Rfc3339
67
+ started_at: schema.Rfc3339 | None = None
68
+ judged_at: schema.Rfc3339 | None = None
69
+ reported_at: schema.Rfc3339 | None = None
70
+ archived_at: schema.Rfc3339 | None = None
71
+ worker_id: constr(min_length=1) | None = None
72
+ lease_expires_at: schema.Rfc3339 | None = None
73
+ session_trace_id: schema.Uuidv7
74
+ """
75
+ FK → SessionTrace.id. Populated as Run executes.
76
+ """
77
+ evidence_bundle_id: schema.Uuidv7 | None = None
78
+ """
79
+ FK → EvidenceBundle.id. Populated at judged → reported.
80
+ """
81
+ cost_record_id: schema.Uuidv7
82
+ """
83
+ FK → CostRecord.id. Populated continuously.
84
+ """
85
+ parent_run_id: schema.Uuidv7 | None = None
86
+ """
87
+ Multi-step DAG child link.
88
+ """
89
+ idempotency_key: schema.Uuidv7
90
+ """
91
+ Defaults to `id` if not explicitly provided.
92
+ """
93
+ submitted_by: schema.ActorIdentity
94
+ tenant_id: schema.Uuidv7 | None = None
95
+ """
96
+ RESERVED multi-tenancy slot (deferral-G, bd_000-projects-k0fj). OPTIONAL + additive per § 7.2; tenant-isolation semantics deferred to a future DR. SHOULD equal the parent EvalSpec.tenant_id when both present (runtime invariant). v1 single-tenant runs omit it.
97
+ """