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,46 @@
1
+ # generated by datamodel-codegen:
2
+ # filename: regression-pack.schema.json
3
+
4
+ from __future__ import annotations
5
+
6
+ from pydantic import BaseModel, ConfigDict, Field, conint, constr
7
+
8
+ from . import _common_schema as schema
9
+
10
+
11
+ class OutcomeSummary(BaseModel):
12
+ model_config = ConfigDict(
13
+ extra="forbid",
14
+ )
15
+ pass_: conint(ge=0) = Field(..., alias="pass")
16
+ fail: conint(ge=0)
17
+ advisory: conint(ge=0) | None = None
18
+ not_applicable: conint(ge=0) | None = None
19
+ error: conint(ge=0) | None = None
20
+
21
+
22
+ class RegressionpackFrozenBundleOfEvalrunsProvingABehaviorContractBlueprintB27(
23
+ BaseModel
24
+ ):
25
+ """
26
+ State machine: draft → committed → superseded. Mutable in draft; immutable once committed. Predicate URI (deferred Phase B+): regression-pack/v1.
27
+ """
28
+
29
+ model_config = ConfigDict(
30
+ extra="forbid",
31
+ )
32
+ id: schema.Uuidv7
33
+ name: schema.KebabSlug
34
+ purpose: constr(min_length=1)
35
+ skill_snapshot_sha: schema.Sha256
36
+ eval_spec_ids: list[schema.Uuidv7]
37
+ eval_run_ids: list[schema.Uuidv7]
38
+ outcome_summary: dict[constr(pattern=r"^MM-[1-6]$"), OutcomeSummary]
39
+ """
40
+ Aggregate pass/fail (and optional extension) per MM-class. Partial because not every pack tests every class. Per Blueprint B § 2.7: 'aggregate pass/fail rates per matcher class' — others optional, not invented.
41
+ """
42
+ ancestor_pack_id: schema.Uuidv7 | None = None
43
+ delta_declaration: str
44
+ created_at: schema.Rfc3339
45
+ created_by: schema.ActorIdentity
46
+ content_hash: schema.Sha256
@@ -0,0 +1,77 @@
1
+ # generated by datamodel-codegen:
2
+ # filename: retraction.schema.json
3
+
4
+ from __future__ import annotations
5
+
6
+ from enum import Enum
7
+
8
+ from pydantic import BaseModel, ConfigDict
9
+
10
+ from . import _common_schema as schema
11
+
12
+
13
+ class RetractedSubject(BaseModel):
14
+ """
15
+ Reference to the subject being retracted — the prior EvidenceBundle / in-toto Statement. At least one of bundle_id or storage_key MUST be present so the retraction is resolvable to a concrete artifact.
16
+ """
17
+
18
+ model_config = ConfigDict(
19
+ extra="forbid",
20
+ )
21
+ bundle_id: schema.Uuidv7 | None = None
22
+ """
23
+ UUIDv7 of the EvidenceBundle being retracted (FK → EvidenceBundle.id).
24
+ """
25
+ storage_key: schema.StorageKey | None = None
26
+ """
27
+ Content-addressed object-storage key of the retracted bundle payload (EvidenceBundle.storage_key).
28
+ """
29
+ content_hash: schema.Sha256Prefixed | None = None
30
+ """
31
+ sha256-prefixed digest of the retracted artifact, pinning exactly which content is retracted even if a storage backend re-keys.
32
+ """
33
+
34
+
35
+ class ReasonClass(Enum):
36
+ """
37
+ CLOSED-SET reason class for the retraction (GC refusal binding — open text is rejected). Adding a value is a Class-1 ISEDC matter.
38
+ """
39
+
40
+ partner_request = "partner-request"
41
+ methodology_error = "methodology-error"
42
+ data_quality = "data-quality"
43
+ consent_withdrawn = "consent-withdrawn"
44
+ legal_hold = "legal-hold"
45
+ pre_publication_recall = "pre-publication-recall"
46
+
47
+
48
+ class RetractionV1InTotoPredicateBodyForRetractingAPriorAttestation(BaseModel):
49
+ """
50
+ Predicate body of an in-toto Statement v1 whose predicateType is https://evals.intentsolutions.io/retraction/v1. A retraction does NOT delete the original attestation (it remains in the transparency log); it is an APPEND-ONLY signed record stating that the platform has chosen not to surface a prior subject and why. The dashboard renders a tombstone at the deep link per the retraction-protocol binding. The `reason_class` enum is CLOSED — open-text reasons are rejected by the schema (GC refusal binding). 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.
51
+
52
+ ADDITIVE in kernel v0.2.0: net-new predicate URI; no v0.1 contract changes. Per § 7.2 backward-compat, adding a predicate URI is allowed; the body normative spec lands here. Runs in sigstore_staging until production-Rekor unlock per DR-010 Q3.
53
+ """
54
+
55
+ model_config = ConfigDict(
56
+ extra="forbid",
57
+ )
58
+ retracted_subject: RetractedSubject
59
+ """
60
+ Reference to the subject being retracted — the prior EvidenceBundle / in-toto Statement. At least one of bundle_id or storage_key MUST be present so the retraction is resolvable to a concrete artifact.
61
+ """
62
+ reason_class: ReasonClass
63
+ """
64
+ CLOSED-SET reason class for the retraction (GC refusal binding — open text is rejected). Adding a value is a Class-1 ISEDC matter.
65
+ """
66
+ reason: str | None = None
67
+ """
68
+ OPTIONAL human-readable free-text elaboration. The machine-actionable retraction class is carried by reason_class; this is operator context only and MUST NOT be parsed for decisions.
69
+ """
70
+ retracted_at: schema.Rfc3339
71
+ """
72
+ RFC 3339 UTC timestamp at which the retraction took effect.
73
+ """
74
+ retracted_by: schema.ActorIdentity | None = None
75
+ """
76
+ OPTIONAL actor identity (operator email / service account) that authored the retraction, for audit-trail attribution.
77
+ """
@@ -0,0 +1,53 @@
1
+ # generated by datamodel-codegen:
2
+ # filename: rollout-gate.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 Decision(Enum):
14
+ ship = "ship"
15
+ no_ship = "no_ship"
16
+ advisory = "advisory"
17
+ error = "error"
18
+
19
+
20
+ class SigningMode(Enum):
21
+ sigstore_staging = "sigstore_staging"
22
+ rekor_production = "rekor_production"
23
+ unsigned_experimental = "unsigned_experimental"
24
+
25
+
26
+ class RolloutgateEvaluationOfAnEvidencebundleAgainstADeploymentPolicyBlueprintB28(
27
+ BaseModel
28
+ ):
29
+ """
30
+ Single terminal state `evaluated`. Immutable at creation. Re-evaluations = new rows. Natural uniqueness: (eval_run_id, policy_ref). Decision enum is DELIBERATELY DIFFERENT from gate-result/v1.gate_decision — RolloutGate uses deployment language (ship/no_ship), the predicate body uses verdict language (pass/fail). Mapping is policy-driven and lives in the downstream intent-rollout-gate package, NOT this kernel.
31
+ """
32
+
33
+ model_config = ConfigDict(
34
+ extra="forbid",
35
+ )
36
+ id: schema.Uuidv7
37
+ eval_run_id: schema.Uuidv7
38
+ evidence_bundle_id: schema.Uuidv7
39
+ policy_ref: constr(pattern=r"^sha256:[a-f0-9]{64}:.+$")
40
+ """
41
+ Format: <content_hash>:<path>. Defends against mid-flight policy mutation.
42
+ """
43
+ policy_content_hash: schema.Sha256
44
+ decision: Decision
45
+ decision_reasons: list[str]
46
+ """
47
+ Structured reason strings. Per Blueprint B § 2.8: 'one per matched-or-unmatched policy rule.'
48
+ """
49
+ coverage: schema.Coverage
50
+ evaluated_at: schema.Rfc3339
51
+ gate_version: schema.Semver
52
+ signing_mode: SigningMode
53
+ rekor_log_index: conint(ge=0) | None = None
@@ -0,0 +1,99 @@
1
+ # generated by datamodel-codegen:
2
+ # filename: runtime-receipt.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 RuntimeLimitsInEffect(BaseModel):
14
+ """
15
+ Copy of EvalSpec.runtime_limits frozen at queue time.
16
+ """
17
+
18
+ model_config = ConfigDict(
19
+ extra="forbid",
20
+ )
21
+ token_ceiling: conint(ge=0)
22
+ wall_clock_ceiling_ms: conint(ge=0)
23
+ memory_ceiling_mb: conint(ge=0)
24
+ concurrency_hint: conint(ge=0)
25
+
26
+
27
+ class ActualResourceUsage(BaseModel):
28
+ """
29
+ Measured resource consumption per Blueprint B § 2.6 — fully spec-bound 4-field shape.
30
+ """
31
+
32
+ model_config = ConfigDict(
33
+ extra="forbid",
34
+ )
35
+ tokens_consumed: conint(ge=0)
36
+ wall_clock_ms: conint(ge=0)
37
+ peak_memory_mb: conint(ge=0)
38
+ network_egress_bytes: conint(ge=0)
39
+
40
+
41
+ class TerminalState(Enum):
42
+ """
43
+ Mirrors EvalRun.state's terminal value.
44
+ """
45
+
46
+ archived = "archived"
47
+ skipped_due_to_gate = "skipped_due_to_gate"
48
+ archived_failed = "archived_failed"
49
+
50
+
51
+ class TerminalReason(Enum):
52
+ queued_timeout_elapsed = "queued_timeout_elapsed"
53
+ run_timeout_elapsed = "run_timeout_elapsed"
54
+ worker_crash_exhausted = "worker_crash_exhausted"
55
+ credential_leak_detected = "credential_leak_detected"
56
+ judge_unavailable_exhausted = "judge_unavailable_exhausted"
57
+ token_ceiling_exceeded = "token_ceiling_exceeded"
58
+ evidence_contract_violation = "evidence_contract_violation"
59
+ upstream_feed_failed = "upstream_feed_failed"
60
+
61
+
62
+ class RuntimereceiptSignedRecordOfHowAnEvalrunExecutedBlueprintB26(BaseModel):
63
+ """
64
+ Single terminal state `issued`. Immutable at creation (signed before persistence). 1:1 cardinality with EvalRun. Predicate URI when emitted: runtime-receipt/v1 (currently sigstore_staging).
65
+ """
66
+
67
+ model_config = ConfigDict(
68
+ extra="forbid",
69
+ )
70
+ id: schema.Uuidv7
71
+ eval_run_id: schema.Uuidv7
72
+ created_at: schema.Rfc3339
73
+ eval_spec_content_hash: schema.Sha256
74
+ skill_snapshot_sha: schema.Sha256
75
+ provider_adapter_versions: dict[str, str]
76
+ """
77
+ Per-provider adapter version mapping. Key: provider id, Value: SemVer.
78
+ """
79
+ tool_versions: dict[str, str]
80
+ """
81
+ Per-tool version mapping. Key: tool id, Value: SemVer.
82
+ """
83
+ runtime_limits_in_effect: RuntimeLimitsInEffect
84
+ """
85
+ Copy of EvalSpec.runtime_limits frozen at queue time.
86
+ """
87
+ actual_resource_usage: ActualResourceUsage
88
+ """
89
+ Measured resource consumption per Blueprint B § 2.6 — fully spec-bound 4-field shape.
90
+ """
91
+ worker_identity: constr(min_length=1)
92
+ worker_host_fingerprint: schema.Sha256
93
+ terminal_state: TerminalState
94
+ """
95
+ Mirrors EvalRun.state's terminal value.
96
+ """
97
+ terminal_reason: TerminalReason
98
+ evidence_bundle_id: schema.Uuidv7
99
+ cost_record_id: schema.Uuidv7
@@ -0,0 +1,28 @@
1
+ # generated by datamodel-codegen:
2
+ # filename: session-trace.schema.json
3
+
4
+ from __future__ import annotations
5
+
6
+ from pydantic import BaseModel, ConfigDict, conint
7
+
8
+ from . import _common_schema as schema
9
+
10
+
11
+ class SessiontraceOtelCompatibleExecutionTraceForAnEvalrunBlueprintB210(BaseModel):
12
+ """
13
+ State machine: open → closed (closed terminal). 1:1 cardinality with EvalRun. Trace blob content-addressed (tamper-evident) in object storage.
14
+ """
15
+
16
+ model_config = ConfigDict(
17
+ extra="forbid",
18
+ )
19
+ id: schema.Uuidv7
20
+ eval_run_id: schema.Uuidv7
21
+ created_at: schema.Rfc3339
22
+ closed_at: schema.Rfc3339 | None = None
23
+ root_span_id: schema.OtelSpanId
24
+ total_spans: conint(ge=0)
25
+ max_loop_depth: conint(ge=0)
26
+ total_tool_invocations: conint(ge=0)
27
+ total_judge_decisions: conint(ge=0)
28
+ trace_blob_storage_key: schema.StorageKey
@@ -0,0 +1,38 @@
1
+ # generated by datamodel-codegen:
2
+ # filename: skill-snapshot.schema.json
3
+
4
+ from __future__ import annotations
5
+
6
+ from pydantic import BaseModel, ConfigDict
7
+
8
+ from . import _common_schema as schema
9
+
10
+
11
+ class SkillsnapshotContentAddressedPinOfASkillSSourceDepsConfigBlueprintB29(BaseModel):
12
+ """
13
+ Single terminal state `created`. Immutable. New snapshot = new row + new combined_sha. combined_sha = sha256(source_sha || dependency_lock_sha || config_sha) per Blueprint B § 2.9 — concatenation order is NORMATIVE. Predicate URI (deferred Phase B+): skill-snapshot/v1.
14
+ """
15
+
16
+ model_config = ConfigDict(
17
+ extra="forbid",
18
+ )
19
+ id: schema.Uuidv7
20
+ skill_id: schema.KebabSlug
21
+ """
22
+ Logical skill identifier — stable across snapshots of the same skill.
23
+ """
24
+ source_sha: schema.Sha256
25
+ dependency_lock_sha: schema.Sha256
26
+ config_sha: schema.Sha256
27
+ combined_sha: schema.Sha256
28
+ """
29
+ Load-bearing pin. sha256(source_sha || dependency_lock_sha || config_sha).
30
+ """
31
+ version_label: schema.Semver | None = None
32
+ storage_key: schema.StorageKey
33
+ created_at: schema.Rfc3339
34
+ created_by: schema.ActorIdentity
35
+ tenant_id: schema.Uuidv7 | None = None
36
+ """
37
+ RESERVED multi-tenancy slot (deferral-G, bd_000-projects-k0fj). OPTIONAL + additive per § 7.2; tenant-isolation semantics deferred to a future DR. v1 single-tenant snapshots omit it.
38
+ """
@@ -0,0 +1,60 @@
1
+ # generated by datamodel-codegen:
2
+ # filename: tool-invocation.schema.json
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import Any
7
+
8
+ from pydantic import BaseModel, ConfigDict, conint, constr
9
+
10
+ from . import _common_schema as schema
11
+
12
+
13
+ class Error(BaseModel):
14
+ model_config = ConfigDict(
15
+ extra="forbid",
16
+ )
17
+ enum_class: schema.ErrorClass
18
+ """
19
+ Error class — a kernel-registered cross-cutting class (network.timeout, provider.rate_limited, tool.crashed, …) OR a tool-defined `<domain>.<condition>` string. Registration pattern LOCKED per deferral-E (bd_000-projects-84li): the format is constrained, the enum stays open.
20
+ """
21
+ message: str
22
+
23
+
24
+ class ToolinvocationSingleToolProviderCallRecordedUnderASessiontraceBlueprintB211(
25
+ BaseModel
26
+ ):
27
+ """
28
+ Single terminal state `invoked`. Immutable at creation. Retries = new rows. HARD RULE per § 2.11: credential-shaped string in args or result_summary MUST cause runtime to reject + fail parent EvalRun with terminal_reason=credential_leak_detected (runtime concern, not enforced at this schema layer).
29
+ """
30
+
31
+ model_config = ConfigDict(
32
+ extra="forbid",
33
+ )
34
+ id: schema.Uuidv7
35
+ session_trace_id: schema.Uuidv7
36
+ parent_span_id: schema.OtelSpanId
37
+ tool_id: constr(min_length=1)
38
+ """
39
+ Tool identifier. Convention examples: 'audit-harness:escape-scan', 'provider:anthropic:claude-sonnet-4-5'. Format NOT enforced at this layer.
40
+ """
41
+ tool_version: schema.Semver
42
+ args: dict[str, Any]
43
+ """
44
+ Sanitized args (credentials redacted by runtime sanitizer).
45
+ """
46
+ args_hash: schema.Sha256
47
+ result_summary: dict[str, Any]
48
+ """
49
+ Sanitized result summary (inline-fit portion).
50
+ """
51
+ result_hash: schema.Sha256
52
+ result_storage_key: schema.StorageKey | None = None
53
+ invoked_at: schema.Rfc3339
54
+ latency_ms: conint(ge=0)
55
+ cost_record_ref: schema.Uuidv7
56
+ error: Error | None = None
57
+ retry_attempt: conint(ge=0)
58
+ """
59
+ 0-indexed retry attempt number.
60
+ """
@@ -0,0 +1,180 @@
1
+ """Canonical Pydantic v2 model surface for ``@intentsolutions/core`` (Python).
2
+
3
+ This is the **hand-authored public surface** — the Python analogue of the
4
+ TypeScript ``src/validators/v1/*.ts`` canonical validators. It re-exports the
5
+ ``_generated/`` datamodel-code-generator output under stable canonical names
6
+ (``GateResultV1``, ``EvalSpec``, …) and, for the schemas whose JSON Schema
7
+ carries ``allOf``/``if-then`` conditional rules, layers a hand-written
8
+ cross-field ``model_validator`` on top so the Python models accept/reject
9
+ **exactly** what AJV (the JSON-Schema reference) and Zod (the TypeScript
10
+ reference) accept/reject. No drift from the canonical kernel.
11
+
12
+ The ``_generated/`` package is reference material, NOT the public API — never
13
+ import from it directly (mirrors the Zod ``_generated/`` README discipline).
14
+ Import from here:
15
+
16
+ from intent_eval_core import GateResultV1, EvalSpec
17
+ from intent_eval_core.models import GATE_RESULT_V1_URI
18
+
19
+ Codegen handles the STRUCTURAL floor (fields, types, enums, ``constr`` patterns,
20
+ ``extra="forbid"`` closed-world). The cross-field rules below are the exact
21
+ Python mirror of the Zod ``.superRefine()`` blocks in
22
+ ``src/validators/v1/gate-result-v1.ts`` — the only place where the JSON Schema's
23
+ ``allOf``/``if-then`` semantics live (datamodel-code-generator cannot emit them).
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ # `typing.Self` is 3.11+; import from typing_extensions (a guaranteed transitive
29
+ # dependency of pydantic v2) so the 3.10 floor keeps working. The annotation
30
+ # itself is a string at runtime via `from __future__ import annotations`; this
31
+ # only guards the import statement.
32
+ from typing_extensions import Self
33
+
34
+ from pydantic import model_validator
35
+
36
+ # ── Generated root models, re-exported under canonical names ──────────────────
37
+ #
38
+ # datamodel-code-generator derives class names from each schema's `title`, which
39
+ # produces verbose names (e.g. EvalspecDeclarativeEvaluationSpecificationBlueprintB21).
40
+ # We alias them to the canonical entity names used across the platform.
41
+
42
+ from ._generated.cost_record_schema import (
43
+ CostrecordSingleCostResourceAttributionRowBlueprintB212 as CostRecord,
44
+ )
45
+ from ._generated.dashboard_render_schema import (
46
+ DashboardRenderV1InTotoPredicateBodyAttestingARenderedDashboardArtifact as DashboardRenderV1,
47
+ )
48
+ from ._generated.eval_run_schema import (
49
+ EvalrunSingleExecutionOfAnEvalspecAgainstASkillsnapshotBlueprintB22 as EvalRun,
50
+ )
51
+ from ._generated.eval_spec_schema import (
52
+ EvalspecDeclarativeEvaluationSpecificationBlueprintB21 as EvalSpec,
53
+ )
54
+ from ._generated.evidence_bundle_schema import (
55
+ EvidencebundleAppendOnlyCollectionOfSignedPredicateRowsBlueprintB24 as EvidenceBundle,
56
+ )
57
+ from ._generated.failure_taxonomy_schema import (
58
+ FailuretaxonomyCanonicalRegistryOfFailureModeClassesBlueprintB213 as FailureTaxonomy,
59
+ )
60
+ from ._generated.gate_result_schema import (
61
+ GateResultV1NormativeInTotoPredicateBody as _GateResultV1Generated,
62
+ )
63
+ from ._generated.judge_decision_schema import (
64
+ JudgedecisionSingleJudgeSVerdictOnAnEvalrunForAMatchermapBlueprintB25 as JudgeDecision,
65
+ )
66
+ from ._generated.matcher_map_schema import (
67
+ MatchermapReusableInputBehaviorPatternDefinitionBlueprintB23 as MatcherMap,
68
+ )
69
+ from ._generated.regression_pack_schema import (
70
+ RegressionpackFrozenBundleOfEvalrunsProvingABehaviorContractBlueprintB27 as RegressionPack,
71
+ )
72
+ from ._generated.retraction_schema import (
73
+ RetractionV1InTotoPredicateBodyForRetractingAPriorAttestation as RetractionV1,
74
+ )
75
+ from ._generated.rollout_gate_schema import (
76
+ RolloutgateEvaluationOfAnEvidencebundleAgainstADeploymentPolicyBlueprintB28 as RolloutGate,
77
+ )
78
+ from ._generated.runtime_receipt_schema import (
79
+ RuntimereceiptSignedRecordOfHowAnEvalrunExecutedBlueprintB26 as RuntimeReceipt,
80
+ )
81
+ from ._generated.session_trace_schema import (
82
+ SessiontraceOtelCompatibleExecutionTraceForAnEvalrunBlueprintB210 as SessionTrace,
83
+ )
84
+ from ._generated.skill_snapshot_schema import (
85
+ SkillsnapshotContentAddressedPinOfASkillSSourceDepsConfigBlueprintB29 as SkillSnapshot,
86
+ )
87
+ from ._generated.tool_invocation_schema import (
88
+ ToolinvocationSingleToolProviderCallRecordedUnderASessiontraceBlueprintB211 as ToolInvocation,
89
+ )
90
+
91
+ # ── Canonical predicate URI (CISO binding: evals.intentsolutions.io, never labs) ─
92
+ GATE_RESULT_V1_URI = "https://evals.intentsolutions.io/gate-result/v1"
93
+
94
+
95
+ class GateResultV1(_GateResultV1Generated):
96
+ """gate-result/v1 NORMATIVE predicate body (Blueprint B § 7.4).
97
+
98
+ Subclasses the generated structural model and adds the cross-field rules the
99
+ JSON Schema expresses via ``allOf``/``if-then`` — which
100
+ datamodel-code-generator cannot emit. This is the exact Python mirror of the
101
+ ``GateResultV1Schema.superRefine(...)`` block in
102
+ ``src/validators/v1/gate-result-v1.ts``:
103
+
104
+ 1. ``gate_decision == "advisory"`` REQUIRES ``advisory_severity``
105
+ (Blueprint B § 7.4 conditional rule).
106
+ 2. Empty ``gate_reasons`` is permitted ONLY for an unconditional ``pass`` —
107
+ ``fail`` / ``advisory`` / ``error`` MUST carry at least one reason
108
+ (Blueprint B § 7.4 line 829, ``[f-iec-validators-3]``).
109
+ 3. Every ``coverage_detail`` entry's ``id`` MUST appear in the matching
110
+ ``coverage`` array (``evaluated`` -> ``dimensions_evaluated``,
111
+ ``skipped`` -> ``dimensions_skipped``) — deferral-D cross-field invariant
112
+ (``bd_000-projects-9xyk``).
113
+
114
+ The generated parent already enforces ``extra="forbid"`` (closed-world),
115
+ the ``gate_decision`` / ``advisory_severity`` enums, and the
116
+ ``policy_ref`` / ``policy_hash`` / ``input_hash`` patterns.
117
+ """
118
+
119
+ @model_validator(mode="after")
120
+ def _enforce_blueprint_b_7_4(self) -> Self:
121
+ decision = (
122
+ self.gate_decision.value
123
+ if hasattr(self.gate_decision, "value")
124
+ else self.gate_decision
125
+ )
126
+
127
+ # Rule 1: advisory => advisory_severity present.
128
+ if decision == "advisory" and self.advisory_severity is None:
129
+ raise ValueError(
130
+ 'gate_decision="advisory" requires advisory_severity per '
131
+ "Blueprint B § 7.4 conditional rule"
132
+ )
133
+
134
+ # Rule 2: empty gate_reasons permitted ONLY for pass.
135
+ if decision in ("fail", "advisory", "error") and len(self.gate_reasons) == 0:
136
+ raise ValueError(
137
+ 'gate_reasons MUST be non-empty when gate_decision is "fail", '
138
+ '"advisory", or "error" per Blueprint B § 7.4 line 829 '
139
+ "(empty permitted ONLY for pass)"
140
+ )
141
+
142
+ # Rule 3: coverage_detail id must be a member of the matching coverage array.
143
+ if self.coverage_detail is not None:
144
+ evaluated = set(self.coverage.dimensions_evaluated)
145
+ skipped = set(self.coverage.dimensions_skipped)
146
+ for i, detail in enumerate(self.coverage_detail):
147
+ status = detail.status.value if hasattr(detail.status, "value") else detail.status
148
+ pool = evaluated if status == "evaluated" else skipped
149
+ if detail.id not in pool:
150
+ raise ValueError(
151
+ f'coverage_detail[{i}].id "{detail.id}" (status={status}) is '
152
+ f"not in coverage.dimensions_{status} (deferral-D cross-field "
153
+ "invariant)"
154
+ )
155
+
156
+ return self
157
+
158
+
159
+ __all__ = [
160
+ # Entities (Blueprint B § 2.1 – § 2.13)
161
+ "EvalSpec",
162
+ "EvalRun",
163
+ "MatcherMap",
164
+ "EvidenceBundle",
165
+ "JudgeDecision",
166
+ "RuntimeReceipt",
167
+ "RegressionPack",
168
+ "RolloutGate",
169
+ "SkillSnapshot",
170
+ "SessionTrace",
171
+ "ToolInvocation",
172
+ "CostRecord",
173
+ "FailureTaxonomy",
174
+ # Predicate bodies
175
+ "GateResultV1",
176
+ "RetractionV1",
177
+ "DashboardRenderV1",
178
+ # Constants
179
+ "GATE_RESULT_V1_URI",
180
+ ]
File without changes