lib/alloc/phase/src/capacity/declaration.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

   1 const std = @import("std");
   2 const observer = @import("observer");
   3 const owner = @import("owner.zig");
   4 const spec = @import("spec.zig");
   5 
   6 const OwnerShape = owner.OwnerShape;
   7 const Sha256 = std.crypto.hash.sha2.Sha256;
   8 
   9 /// This validator limit specifies a maximum of 16 covered storage records in
  10 /// `SourceEnvelope.storage.covered`, requiring a valid list to be non-empty.
  11 pub const covered_max: usize = 16;
  12 /// This validator limit defines a maximum of 16 excluded descriptive strings in
  13 /// a valid non-empty list, without enforcing a uniqueness check.
  14 pub const excluded_max: usize = 16;
  15 /// This validator limit defines a maximum of 8 canonical dependency
  16 /// identifiers, permitting an empty list.
  17 pub const dependencies_max: usize = 8;
  18 /// This validator limit specifies a maximum of 24 named obligation records,
  19 /// requiring a valid list to be non-empty.
  20 pub const obligations_max: usize = 24;
  21 /// This validator limit specifies a maximum of 512 bytes for descriptive
  22 /// detail, work, or exclusion text, requiring at least 1 byte and excluding
  23 /// NUL, CR, and LF characters. This bound measures raw byte length rather than
  24 /// Unicode character count.
  25 pub const text_bytes_max: usize = 512;
  26 /// This validator limit specifies a maximum of 64 bytes for canonical dotted
  27 /// claim, dependency, or trust identifiers, under the root alias
  28 /// `claim_id_bytes_max`.
  29 pub const id_bytes_max: usize = 64;
  30 /// This validator limit specifies a maximum of 64 bytes for local
  31 /// covered-region and obligation keys, which must begin with a lowercase letter
  32 /// followed by lowercase letters, digits, or underscores.
  33 pub const local_id_bytes_max: usize = 64;
  34 /// This constant defines the 32-byte SHA-256 output digest size corresponding
  35 /// to the root alias `declaration_envelope_digest_bytes`. This value reflects
  36 /// the fixed digest output length rather than the input envelope size.
  37 pub const digest_bytes: usize = Sha256.digest_length;
  38 /// This hash domain specifies the exact string
  39 /// `tiny.alloc.claim-declaration/v2` used to separate framed format inputs. The
  40 /// domain tag provides input framing separation but does not offer a
  41 /// collision-proof guarantee.
  42 pub const digest_domain = "tiny.alloc.claim-declaration/v2";
  43 
  44 /// `Kind` specifies source classification as either `startup_static` or
  45 /// `phase_static`. Validation of `phase_static` requires valid seal and
  46 /// teardown bindings. In contrast, `startup_static` does not require or inspect
  47 /// optional phase bindings in `validateBindings`. The tag describes a claim and
  48 /// does not govern actual allocation behavior or enforce an operational
  49 /// lifetime.
  50 pub const Kind = enum {
  51     startup_static,
  52     phase_static,
  53 };
  54 
  55 /// LimitSource indicates whether memory capacity limits originate from the
  56 /// caller or from application defaults. Selecting caller forbids supplying a
  57 /// default_limits selector binding. Selecting application_default requires
  58 /// supplying a selector struct containing a public declaration member. The
  59 /// declaration validator verifies that this selector struct exists, but it
  60 /// checks no signature or value compatibility between that declaration and the
  61 /// owner limits.
  62 pub const LimitSource = enum {
  63     caller,
  64     application_default,
  65 };
  66 
  67 /// StorageLifetime labels the operational stage of a covered storage region
  68 /// using the initialization, steady, or transferred tags. These values provide
  69 /// descriptive metadata about when an owner uses a memory region. The enum
  70 /// performs no runtime lifetime tracking, memory management, or ownership
  71 /// operations.
  72 pub const StorageLifetime = enum {
  73     initialization,
  74     steady,
  75     transferred,
  76 };
  77 
  78 /// OverloadKind defines the policy an owner follows when an operation exceeds
  79 /// capacity. Compatibility depends on the storage source and shape of the
  80 /// owner. Exact shapes accept reject_before_seal or not_applicable. For
  81 /// rejecting shapes, allocator-backed owners accept reject_before_mutation,
  82 /// replace, drop, or terminal, while caller-provisioned owners accept only
  83 /// reject_before_mutation. The accompanying detail string describes which
  84 /// internal state is protected, such as allowing submitted and rejected
  85 /// counters to increment in a full fixture. Validation checks compatibility
  86 /// between the enum tag and the owner shape without inspecting operation
  87 /// bodies.
  88 pub const OverloadKind = enum {
  89     reject_before_seal,
  90     reject_before_mutation,
  91     replace,
  92     drop,
  93     terminal,
  94     not_applicable,
  95 };
  96 
  97 /// RiskStatus describes whether an identified hazard has evidentiary coverage
  98 /// through the witnessed, excluded, or open tags. Setting status to witnessed
  99 /// requires declaring a matching risk role obligation in the source envelope,
 100 /// but it does not establish that a test passed. Setting status to excluded
 101 /// documents that the hazard falls outside the operational scope of the claim.
 102 /// Setting status to open documents an unresolved claim status without
 103 /// satisfying an obligation requirement.
 104 pub const RiskStatus = enum {
 105     witnessed,
 106     excluded,
 107     open,
 108 };
 109 
 110 /// CoveredStorage describes a discrete memory region covered by an owner claim
 111 /// through its id, lifetime, and detail fields. The id string must contain 1 to
 112 /// 64 bytes, starting with a lowercase ASCII letter and followed only by
 113 /// lowercase ASCII letters, digits, or underscores. Each id must be unique
 114 /// within the containing covered list. The lifetime field holds a
 115 /// StorageLifetime tag, and the detail string must contain 1 to 512 single-line
 116 /// bytes without null bytes, carriage returns, or line feeds. The struct
 117 /// borrows these slices without owning allocations or enforcing lifetimes at
 118 /// runtime.
 119 pub const CoveredStorage = struct {
 120     id: []const u8,
 121     lifetime: StorageLifetime,
 122     detail: []const u8,
 123 };
 124 
 125 /// Storage specifies the memory coverage boundaries of a claim using covered
 126 /// and excluded slices, rather than holding the backing storage buffer of an
 127 /// owner. The covered list accepts 1 to 16 CoveredStorage records with unique
 128 /// local identifiers. The excluded list accepts 1 to 16 descriptive strings,
 129 /// each bounded to 1 to 512 single-line bytes excluding null bytes, carriage
 130 /// returns, and line feeds. Excluded entries are not checked for uniqueness,
 131 /// and their presence makes no claim that other process memory is absent. The
 132 /// struct holds borrowed slices rather than copying text or managing memory.
 133 pub const Storage = struct {
 134     covered: []const CoveredStorage,
 135     excluded: []const []const u8,
 136 };
 137 
 138 /// `Overload` describes declared overload behavior through its `kind` and
 139 /// `detail` fields, where `detail` identifies protected state. Full declaration
 140 /// validation checks that `kind` is compatible with `OwnerShape` and verifies
 141 /// that `detail` contains 1 to 512 bytes excluding NUL, LF, and CR characters.
 142 /// Merely constructing the record validates nothing and installs no dynamic
 143 /// policy.
 144 pub const Overload = struct {
 145     kind: OverloadKind,
 146     detail: []const u8,
 147 };
 148 
 149 /// Risk pairs a RiskStatus tag with a descriptive detail string explaining an
 150 /// operational boundary hazard. The detail string must contain 1 to 512
 151 /// single-line bytes without null characters, carriage returns, or line feeds.
 152 /// Declaration validation inspects the detail text grammar and verifies that
 153 /// any risk marked witnessed has a corresponding obligation role declared in
 154 /// the source envelope. The struct retains these values as source metadata
 155 /// without executing checks at runtime.
 156 pub const Risk = struct {
 157     status: RiskStatus,
 158     detail: []const u8,
 159 };
 160 
 161 /// Risks groups the operational hazards of an owner into transitive and foreign
 162 /// Risk records. The transitive field documents risks originating within
 163 /// callees or subsidiary components, while the foreign field documents risks
 164 /// arising from external resources. The descriptive details define the actual
 165 /// scope of each hazard. Declaration validation enforces grammar and witnessed
 166 /// obligations for both fields, but it does not compute or audit a transitive
 167 /// closure across components.
 168 pub const Risks = struct {
 169     transitive: Risk,
 170     foreign: Risk,
 171 };
 172 
 173 /// `Work` defines an `equation` field consisting of descriptive work bound text
 174 /// between 1 and 512 bytes long, excluding NUL, LF, and CR characters. It is
 175 /// required whenever an owner uses a caller-provisioned shape, and its presence
 176 /// requires declaring an obligation with the work_bound role. The equation text
 177 /// provides descriptive documentation that is neither parsed nor evaluated
 178 /// during validation. This record differs from the WorkLimits structure, which
 179 /// supplies concrete numeric limits.
 180 pub const Work = struct {
 181     equation: []const u8,
 182 };
 183 
 184 /// ObligationRole classifies the evidentiary purpose of a named obligation
 185 /// within a claim. Roles identify evidence requirements including
 186 /// capacity_model, overload, work_bound, transitive_risk, foreign_risk, seal,
 187 /// and teardown. Declaration validation enforces role presence rules for
 188 /// selected source fields, requiring capacity_model for every claim, overload
 189 /// unless overload handling is not applicable, work_bound when a work equation
 190 /// is present, and matching risk roles when transitive or foreign risks are
 191 /// witnessed. Assigning a role classifies the requirement within the
 192 /// declaration but does not establish that evidence exists or that any test
 193 /// passed.
 194 pub const ObligationRole = enum {
 195     capacity_model,
 196     acquisition,
 197     initialization_failure,
 198     overload,
 199     seal,
 200     teardown,
 201     work_bound,
 202     transitive_risk,
 203     foreign_risk,
 204     integration,
 205     custom,
 206 };
 207 
 208 /// Obligation pairs a claim-local identifier key with an ObligationRole tag.
 209 /// The key string must contain 1 to 64 bytes, beginning with a lowercase ASCII
 210 /// letter and containing only lowercase letters, digits, or underscores. The
 211 /// source envelope accepts a list of 1 to 24 obligations, and every key must be
 212 /// unique within that list. Validation mandates the capacity_model role in
 213 /// every claim, the overload role unless overload is not applicable,
 214 /// appropriate risk roles for witnessed risks, and the work_bound role when a
 215 /// work equation is declared. Keys remain local to the enclosing claim rather
 216 /// than resolving globally.
 217 pub const Obligation = struct {
 218     key: []const u8,
 219     role: ObligationRole,
 220 };
 221 
 222 /// `WitnessAnnotation` holds `claim_id` and `obligation_key` slices alongside a
 223 /// `role` value. The `witness` operation requires `Owner.claim` to have the
 224 /// exact type `Declaration` and verifies that the obligation key exists, but it
 225 /// does not validate the whole claim. Passing the returned annotation to
 226 /// `record` associates it with the enclosing test. Constructing the annotation
 227 /// alone does not record an association with a test or prove that a test
 228 /// passed, and it performs no test execution or assertion inspection.
 229 pub const WitnessAnnotation = struct {
 230     claim_id: []const u8,
 231     obligation_key: []const u8,
 232     role: ObligationRole,
 233 };
 234 
 235 /// SourceEnvelope contains the primary specification metadata of a claim,
 236 /// gathering its id, kind, limit_source, storage, capacity, overload, risks,
 237 /// optional work, dependencies, and obligations. The `id` must be a canonical
 238 /// identifier of 1 to 64 bytes consisting of at least two non-empty dot
 239 /// segments composed of lowercase letters, digits, or underscores, where
 240 /// leading digits and underscores are permitted. The `capacity` field is a
 241 /// typed `Spec` with semantic type fields requiring a compile-time
 242 /// representation rather than expression evaluation. The `dependencies` slice
 243 /// accepts up to 8 canonical identifiers, rejects duplicates or
 244 /// self-references, and performs no registry lookup or cycle analysis. The
 245 /// envelope borrows its referenced slices rather than deep-copying runtime
 246 /// strings.
 247 pub const SourceEnvelope = struct {
 248     id: []const u8,
 249     kind: Kind,
 250     limit_source: LimitSource,
 251     storage: Storage,
 252     capacity: spec.Spec,
 253     overload: Overload,
 254     risks: Risks,
 255     work: ?Work = null,
 256     dependencies: []const []const u8 = &.{},
 257     obligations: []const Obligation,
 258 };
 259 
 260 /// EnvelopeView provides a structurally uniform representation of a
 261 /// SourceEnvelope where the typed capacity specification is replaced by a
 262 /// SpecView. The remaining borrowed metadata fields, including id, kind,
 263 /// limit_source, storage, overload, risks, work, dependencies, and obligations,
 264 /// remain identical. This view enables structural serialization and digest
 265 /// computation without depending on semantic type coordinates. Slices
 266 /// referenced by the view remain borrowed and are not owned by the view struct.
 267 pub const EnvelopeView = struct {
 268     id: []const u8,
 269     kind: Kind,
 270     limit_source: LimitSource,
 271     storage: Storage,
 272     capacity: spec.View,
 273     overload: Overload,
 274     risks: Risks,
 275     work: ?Work = null,
 276     dependencies: []const []const u8 = &.{},
 277     obligations: []const Obligation,
 278 };
 279 
 280 /// PremiseClass names the form of basis that supports a phase binding. Its tags
 281 /// distinguish between mathematical theorem domains, checked semantic or path
 282 /// facts, certified claim summaries, and trusted user, external, or environment
 283 /// assertions. Selecting a tag identifies the expected authority category
 284 /// during premise validation, but the enum itself does not establish or
 285 /// evaluate the underlying evidence.
 286 pub const PremiseClass = enum {
 287     theorem_domain,
 288     checked_semantic_fact,
 289     checked_path_fact,
 290     certified_summary,
 291     trusted_user,
 292     trusted_extern,
 293     trusted_environment,
 294 };
 295 
 296 /// ObligationSelector identifies a claim-local obligation that grounds a
 297 /// theorem premise through its key field. Validation checks that the key is a
 298 /// valid local identifier and that it matches an obligation declared in the
 299 /// current source envelope. The check enforces no role restriction on the
 300 /// targeted obligation and performs no evaluation of the theorem.
 301 pub const ObligationSelector = struct {
 302     key: []const u8,
 303 };
 304 
 305 /// ClaimSelector designates an external claim supporting a certified summary
 306 /// premise through its id field. Validation confirms that the id string
 307 /// satisfies the syntax of a canonical dotted identifier containing at least
 308 /// two segments. The check verifies identifier syntax only and does not look up
 309 /// or confirm the existence of the referenced claim.
 310 pub const ClaimSelector = struct {
 311     id: []const u8,
 312 };
 313 
 314 /// TrustDeclarationSelector identifies a trust declaration supporting a trusted
 315 /// user, external component, or environment premise through its id field.
 316 /// Validation checks that the id string conforms to canonical dotted identifier
 317 /// syntax. The validator performs no resolution of the external identifier and
 318 /// does not validate the underlying trust declaration.
 319 pub const TrustDeclarationSelector = struct {
 320     id: []const u8,
 321 };
 322 
 323 /// PremiseAuthority specifies the justifying source for a premise as a tagged
 324 /// union over checker, theorem, certified_claim, and trusted variants. Each
 325 /// variant carries its respective selector, except checker, which carries no
 326 /// payload. The authority must pair with a compatible PremiseClass during
 327 /// validation: checker requires checked_semantic_fact or checked_path_fact,
 328 /// theorem requires theorem_domain, certified_claim requires certified_summary,
 329 /// and trusted requires trusted_user, trusted_extern, or trusted_environment.
 330 pub const PremiseAuthority = union(enum) {
 331     checker,
 332     theorem: ObligationSelector,
 333     certified_claim: ClaimSelector,
 334     trusted: TrustDeclarationSelector,
 335 };
 336 
 337 /// Premise pairs a PremiseClass category with a PremiseAuthority variant to
 338 /// justify a phase lifecycle binding. The validatePremise function checks that
 339 /// the class and authority are mutually compatible, that selector identifiers
 340 /// follow required canonical or local syntax, and that local theorem keys exist
 341 /// within the source obligations. Validation confirms structural and syntactic
 342 /// compatibility but produces no proof of the underlying fact.
 343 pub const Premise = struct {
 344     class: PremiseClass,
 345     authority: PremiseAuthority,
 346 };
 347 
 348 /// PhaseBinding associates a lifecycle transition with an implementation seam
 349 /// and an evidentiary premise through its family and premise fields. Both
 350 /// fields default to null, but validating a phase_static declaration requires
 351 /// both to be present. The family field must be a selector struct containing a
 352 /// public declaration member that resolves to a function. Validation does not
 353 /// inspect the function signature or body, nor does it require the function to
 354 /// match Owner.activate or Owner.deinit. The struct stores compile-time type
 355 /// and premise descriptors rather than a runtime callable closure.
 356 pub const PhaseBinding = struct {
 357     family: ?type = null,
 358     premise: ?Premise = null,
 359 };
 360 
 361 /// Bindings gathers compile-time type coordinates and lifecycle phase bindings
 362 /// separate from the source envelope. Fields include owner, default_limits,
 363 /// seal, teardown, and source, which all default to null. Validation requires
 364 /// owner to match the Owner type supplied to validateDeclaration. The
 365 /// default_limits binding is required for application_default limit sources and
 366 /// forbidden for caller limit sources, while seal and teardown bindings are
 367 /// required for phase_static declarations. The optional source type is retained
 368 /// as metadata but is not inspected by the validator. Envelope digests exclude
 369 /// all bindings and premises, and the struct owns no heap memory or reference
 370 /// counts.
 371 pub const Bindings = struct {
 372     owner: ?type = null,
 373     default_limits: ?type = null,
 374     seal: ?PhaseBinding = null,
 375     teardown: ?PhaseBinding = null,
 376     source: ?type = null,
 377 };
 378 
 379 /// Declaration couples a SourceEnvelope specification with its corresponding
 380 /// compile-time Bindings. The struct acts as a typed metadata container rather
 381 /// than a runtime resource allocation. Calling validateDeclaration checks the
 382 /// declaration against a specified Owner type, expected OwnerShape, and source
 383 /// constraints, but validating a declaration does not verify the whole owner
 384 /// shape by itself. Constructing or validating a declaration installs no
 385 /// automatic runtime enforcement.
 386 pub const Declaration = struct {
 387     source: SourceEnvelope,
 388     bindings: Bindings,
 389 };
 390 
 391 /// Violation enumerates the failure categories returned by the source
 392 /// declaration validator. When validation fails, the validator returns the
 393 /// first detected violation category rather than reporting a runtime allocation
 394 /// error. Malformed user types supplied in bindings may trigger Zig compile
 395 /// errors before validation completes. In root.zig, this type is exported under
 396 /// the public alias DeclarationViolation.
 397 pub const Violation = enum {
 398     id_format,
 399     storage_covered_missing,
 400     storage_covered_overflow,
 401     storage_region_id_invalid,
 402     storage_region_duplicate,
 403     storage_detail_invalid,
 404     storage_excluded_missing,
 405     storage_excluded_overflow,
 406     storage_excluded_invalid,
 407     capacity_limits_mismatch,
 408     capacity_field_path_invalid,
 409     capacity_type_selector_invalid,
 410     capacity_node_outside_fragment,
 411     capacity_assertion_invalid,
 412     overload_detail_invalid,
 413     overload_shape_incompatible,
 414     risk_detail_invalid,
 415     risk_obligation_missing,
 416     work_missing,
 417     work_equation_invalid,
 418     work_obligation_missing,
 419     dependencies_overflow,
 420     dependency_format,
 421     dependency_duplicate,
 422     dependency_self,
 423     obligations_missing,
 424     obligations_overflow,
 425     obligation_key_invalid,
 426     obligation_key_duplicate,
 427     capacity_model_obligation_missing,
 428     overload_obligation_missing,
 429     owner_binding_missing,
 430     owner_binding_mismatch,
 431     default_limits_binding_missing,
 432     default_limits_binding_unexpected,
 433     default_limits_binding_invalid,
 434     seal_binding_missing,
 435     teardown_binding_missing,
 436     seam_family_missing,
 437     seam_family_invalid,
 438     premise_missing,
 439     premise_authority_mismatch,
 440     premise_selector_invalid,
 441     premise_obligation_unknown,
 442 };
 443 
 444 /// selector takes any compile-time value and returns an anonymous struct type
 445 /// containing a public constant named declaration initialized to that value.
 446 /// This helper allows compile-time type fields to transport typed references
 447 /// and values. The requirement that declaration resolve to a function is not
 448 /// checked by selector itself, but is imposed only when validating a phase
 449 /// binding family. The function neither validates the wrapped value nor creates
 450 /// a callable runtime closure.
 451 pub fn selector(comptime value: anytype) type {
 452     return struct {
 453         pub const declaration = value;
 454     };
 455 }
 456 
 457 /// sourceView is an internal implementation function in declaration.zig that
 458 /// converts a compile-time SourceEnvelope into an EnvelopeView, and it is not
 459 /// exported from root.zig. It converts the typed capacity specification into a
 460 /// SpecView using spec.view, transforming typed inputs and type selectors into
 461 /// stable compile-time views while omitting semantic limit types and selected
 462 /// type facts. Other source slices and metadata fields are transferred directly
 463 /// into the view. The function performs no validation on the converted
 464 /// envelope.
 465 pub fn sourceView(comptime value: SourceEnvelope) EnvelopeView {
 466     return .{
 467         .id = value.id,
 468         .kind = value.kind,
 469         .limit_source = value.limit_source,
 470         .storage = value.storage,
 471         .capacity = spec.view(value.capacity),
 472         .overload = value.overload,
 473         .risks = value.risks,
 474         .work = value.work,
 475         .dependencies = value.dependencies,
 476         .obligations = value.obligations,
 477     };
 478 }
 479 
 480 /// envelopeDigest hashes the content of an EnvelopeView using SHA-256 under the
 481 /// domain tiny.alloc.claim-declaration/v2, and is exported from root.zig as
 482 /// declarationSourceEnvelopeDigest. The digest builder length-frames every
 483 /// field and ordered list element, incorporating storage details, the capacity
 484 /// specification digest, overload policy, risks, optional work equations,
 485 /// dependencies, and obligations. Because the view contains no bindings, all
 486 /// typed bindings and premises are excluded from the digest. The function
 487 /// performs no validation or formal proof, requiring callers to provide a valid
 488 /// bounded view.
 489 pub fn envelopeDigest(value: EnvelopeView) [digest_bytes]u8 {
 490     var builder = DigestBuilder.init();
 491     builder.addBytes("id", value.id);
 492     builder.addEnum("kind", value.kind);
 493     builder.addEnum("limit_source", value.limit_source);
 494     addStorage(&builder, value.storage);
 495     builder.addDigest("capacity", spec.digest(value.capacity));
 496     addOverload(&builder, value.overload);
 497     addRisk(&builder, "transitive", value.risks.transitive);
 498     addRisk(&builder, "foreign", value.risks.foreign);
 499     addWork(&builder, value.work);
 500     addTextList(&builder, "dependencies", value.dependencies);
 501     addObligations(&builder, value.obligations);
 502     return builder.finish();
 503 }
 504 
 505 /// declarationEnvelopeDigest computes the digest of a compile-time Declaration
 506 /// by converting its source envelope through sourceView and hashing the
 507 /// resulting EnvelopeView with envelopeDigest. Because the view omits bindings,
 508 /// changes to bindings such as the owner type, seam functions, or premises do
 509 /// not affect the digest. The underlying capacity digest also omits semantic
 510 /// types and sizing facts. The resulting hash establishes a content identity
 511 /// for selected source specification fields rather than an identity for the
 512 /// whole implementation or its evidence.
 513 pub fn declarationEnvelopeDigest(comptime value: Declaration) [digest_bytes]u8 {
 514     return envelopeDigest(sourceView(value.source));
 515 }
 516 
 517 /// validate evaluates a compile-time Declaration against an Owner type and an
 518 /// OwnerShape, returning the first detected Violation or null if validation
 519 /// passes, and is exported from root.zig as validateDeclaration. It checks
 520 /// identifier syntax, storage limits, the typed capacity specification against
 521 /// Owner.Limits, overload compatibility and detail text, risks, work equations,
 522 /// dependencies, obligations, and bindings. The function does not run the owner
 523 /// shape validator or record observer claims. Returning null
 524 /// indicates only that the declaration metadata is valid. The Owner type must
 525 /// define a Limits type compatible with the capacity specification, and the
 526 /// function makes no promise of universal safety for arbitrary type
 527 /// introspection.
 528 pub fn validate(
 529     comptime Owner: type,
 530     comptime value: Declaration,
 531     comptime shape: OwnerShape,
 532 ) ?Violation {
 533     if (!identifierValid(value.source.id)) return .id_format;
 534     if (validateStorage(value.source.storage)) |violation| return violation;
 535     if (spec.validate(Owner.Limits, value.source.capacity)) |violation| {
 536         return capacityViolation(violation);
 537     }
 538     if (!textValid(value.source.overload.detail)) {
 539         return .overload_detail_invalid;
 540     }
 541     if (!overloadCompatible(value.source.overload.kind, shape)) {
 542         return .overload_shape_incompatible;
 543     }
 544     if (validateRisk(value.source.risks.transitive)) |violation| return violation;
 545     if (validateRisk(value.source.risks.foreign)) |violation| return violation;
 546     if (validateWork(value.source.work, shape)) |violation| return violation;
 547     if (validateDependencies(value.source)) |violation| return violation;
 548     if (validateObligations(value.source)) |violation| return violation;
 549     if (validateBindings(Owner, value)) |violation| return violation;
 550     return null;
 551 }
 552 
 553 /// require is a public function within declaration.zig that is not re-exported
 554 /// from root.zig. It executes the same compile-time checks as validate, but it
 555 /// sets the evaluation branch quota to 1,000,000 and emits a compile error
 556 /// containing the violation tag name upon failure instead of returning an
 557 /// optional value. The function performs validation enforcement during
 558 /// compilation and does not record claim metadata or test annotations.
 559 pub fn require(
 560     comptime Owner: type,
 561     comptime value: Declaration,
 562     comptime shape: OwnerShape,
 563 ) void {
 564     @setEvalBranchQuota(1_000_000);
 565     if (comptime validate(Owner, value, shape)) |violation| {
 566         @compileError("invalid claim declaration: " ++ @tagName(violation));
 567     }
 568 }
 569 
 570 /// witness extracts a WitnessAnnotation for a specified Owner type and
 571 /// obligation key at compile time. It requires that Owner declare a public
 572 /// member named claim whose type is exactly Declaration, and that the
 573 /// obligation key exists within the claim obligations list, failing compilation
 574 /// if either condition is not met. It returns a WitnessAnnotation containing
 575 /// the claim id, obligation key, and associated obligation role from the source
 576 /// envelope. The function does not run full declaration validation, inspect
 577 /// test logic, or execute tests.
 578 pub fn witness(
 579     comptime Owner: type,
 580     comptime obligation_key: []const u8,
 581 ) WitnessAnnotation {
 582     if (comptime !@hasDecl(Owner, "claim") or
 583         @TypeOf(Owner.claim) != Declaration)
 584     {
 585         @compileError("test obligation owner lacks a typed claim declaration");
 586     }
 587     const role = comptime obligationRole(
 588         Owner.claim.source.obligations,
 589         obligation_key,
 590     ) orelse @compileError("test obligation key is not declared by its owner");
 591     return .{
 592         .claim_id = Owner.claim.source.id,
 593         .obligation_key = obligation_key,
 594         .role = role,
 595     };
 596 }
 597 
 598 /// `record` enters a witness annotation into the Stardust claim table for the
 599 /// enclosing test. It is `inline`, so the test stays the compiler's analysis
 600 /// owner and the recorded row names that test even outside `comptime`. Without
 601 /// the Stardust observer, as under an unpatched compiler or in a release, the
 602 /// call records nothing, while `witness` still checks the obligation key.
 603 pub inline fn record(comptime annotation: WitnessAnnotation) void {
 604     comptime observer.witness(annotation);
 605 }
 606 
 607 /// `validatePremise` accepts a compile-time `SourceEnvelope` and premise pair
 608 /// and returns the first optional `Violation` or null. It checks classification
 609 /// and authority compatibility between the supplied entities. For `theorem`,
 610 /// the function validates the local key and its existence in source obligations
 611 /// without applying role restrictions. Both `certified_claim` and `trusted`
 612 /// validate canonical `id` syntax without performing a registry lookup. The
 613 /// function does not validate the whole `SourceEnvelope` or inspect underlying
 614 /// evidence.
 615 pub fn validatePremise(
 616     comptime source: SourceEnvelope,
 617     comptime premise: Premise,
 618 ) ?Violation {
 619     if (!premiseAuthorityCompatible(premise)) {
 620         return .premise_authority_mismatch;
 621     }
 622     switch (premise.authority) {
 623         .checker => {},
 624         .theorem => |selected| {
 625             if (!localIdentifierValid(selected.key)) {
 626                 return .premise_selector_invalid;
 627             }
 628             if (!obligationKnown(source.obligations, selected.key)) {
 629                 return .premise_obligation_unknown;
 630             }
 631         },
 632         .certified_claim => |selected| {
 633             if (!identifierValid(selected.id)) {
 634                 return .premise_selector_invalid;
 635             }
 636         },
 637         .trusted => |selected| {
 638             if (!identifierValid(selected.id)) {
 639                 return .premise_selector_invalid;
 640             }
 641         },
 642     }
 643     return null;
 644 }
 645 
 646 /// declareWarmRetained declares a weak capacity owner associated with warm
 647 /// retained memory. It checks at compile time that the provided id satisfies
 648 /// canonical dotted identifier syntax and discards the Owner type parameter.
 649 /// The function records no observer claims and performs no actual
 650 /// retention policy, owner shape, or capacity bound checks.
 651 pub fn declareWarmRetained(comptime id: []const u8, comptime Owner: type) void {
 652     requireCanonicalId(id);
 653     _ = Owner;
 654 }
 655 
 656 /// The current implementation of `declareDynamicUnbounded` checks a canonical
 657 /// dotted `id` at compile time and discards `Owner`. It does not inspect
 658 /// whether `Owner` actually allocates, install behavior, record observer
 659 /// metadata, or register a proven bound.
 660 pub fn declareDynamicUnbounded(comptime id: []const u8, comptime Owner: type) void {
 661     requireCanonicalId(id);
 662     _ = Owner;
 663 }
 664 
 665 fn validateStorage(storage: Storage) ?Violation {
 666     if (storage.covered.len == 0) return .storage_covered_missing;
 667     if (storage.covered.len > covered_max) return .storage_covered_overflow;
 668     for (storage.covered, 0..) |region, index| {
 669         if (!localIdentifierValid(region.id)) return .storage_region_id_invalid;
 670         if (!textValid(region.detail)) return .storage_detail_invalid;
 671         for (storage.covered[0..index]) |earlier| {
 672             if (std.mem.eql(u8, earlier.id, region.id)) {
 673                 return .storage_region_duplicate;
 674             }
 675         }
 676     }
 677     if (storage.excluded.len == 0) return .storage_excluded_missing;
 678     if (storage.excluded.len > excluded_max) return .storage_excluded_overflow;
 679     for (storage.excluded) |excluded| {
 680         if (!textValid(excluded)) return .storage_excluded_invalid;
 681     }
 682     return null;
 683 }
 684 
 685 fn obligationRole(
 686     comptime obligations: []const Obligation,
 687     comptime key: []const u8,
 688 ) ?ObligationRole {
 689     for (obligations) |obligation| {
 690         if (std.mem.eql(u8, obligation.key, key)) return obligation.role;
 691     }
 692     return null;
 693 }
 694 
 695 fn capacityViolation(violation: spec.Violation) Violation {
 696     return switch (violation) {
 697         .limits_type_mismatch => .capacity_limits_mismatch,
 698         .input_field_path_invalid => .capacity_field_path_invalid,
 699         .type_selector_overflow,
 700         .type_selector_id_invalid,
 701         .type_selector_id_duplicate,
 702         .type_selector_fact_invalid,
 703         => .capacity_type_selector_invalid,
 704         .node_outside_fragment => .capacity_node_outside_fragment,
 705         else => .capacity_assertion_invalid,
 706     };
 707 }
 708 
 709 fn validateRisk(risk: Risk) ?Violation {
 710     if (!textValid(risk.detail)) return .risk_detail_invalid;
 711     return null;
 712 }
 713 
 714 fn validateWork(work: ?Work, shape: OwnerShape) ?Violation {
 715     const value = work orelse {
 716         if (shape.storage_source == .caller_provisioned) return .work_missing;
 717         return null;
 718     };
 719     if (!textValid(value.equation)) return .work_equation_invalid;
 720     return null;
 721 }
 722 
 723 fn validateDependencies(source: SourceEnvelope) ?Violation {
 724     if (source.dependencies.len > dependencies_max) return .dependencies_overflow;
 725     for (source.dependencies, 0..) |dependency, index| {
 726         if (!identifierValid(dependency)) return .dependency_format;
 727         if (std.mem.eql(u8, dependency, source.id)) return .dependency_self;
 728         for (source.dependencies[0..index]) |earlier| {
 729             if (std.mem.eql(u8, earlier, dependency)) return .dependency_duplicate;
 730         }
 731     }
 732     return null;
 733 }
 734 
 735 fn validateObligations(source: SourceEnvelope) ?Violation {
 736     if (source.obligations.len == 0) return .obligations_missing;
 737     if (source.obligations.len > obligations_max) return .obligations_overflow;
 738     for (source.obligations, 0..) |obligation, index| {
 739         if (!localIdentifierValid(obligation.key)) return .obligation_key_invalid;
 740         for (source.obligations[0..index]) |earlier| {
 741             if (std.mem.eql(u8, earlier.key, obligation.key)) {
 742                 return .obligation_key_duplicate;
 743             }
 744         }
 745     }
 746     if (!obligationRoleKnown(source.obligations, .capacity_model)) {
 747         return .capacity_model_obligation_missing;
 748     }
 749     if (source.overload.kind != .not_applicable and
 750         !obligationRoleKnown(source.obligations, .overload))
 751     {
 752         return .overload_obligation_missing;
 753     }
 754     if (source.risks.transitive.status == .witnessed and
 755         !obligationRoleKnown(source.obligations, .transitive_risk))
 756     {
 757         return .risk_obligation_missing;
 758     }
 759     if (source.risks.foreign.status == .witnessed and
 760         !obligationRoleKnown(source.obligations, .foreign_risk))
 761     {
 762         return .risk_obligation_missing;
 763     }
 764     if (source.work != null and
 765         !obligationRoleKnown(source.obligations, .work_bound))
 766     {
 767         return .work_obligation_missing;
 768     }
 769     return null;
 770 }
 771 
 772 fn validateBindings(comptime Owner: type, comptime value: Declaration) ?Violation {
 773     const bindings = value.bindings;
 774     const bound_owner = bindings.owner orelse return .owner_binding_missing;
 775     if (bound_owner != Owner) return .owner_binding_mismatch;
 776     switch (value.source.limit_source) {
 777         .caller => if (bindings.default_limits != null) {
 778             return .default_limits_binding_unexpected;
 779         },
 780         .application_default => {
 781             const Selector = bindings.default_limits orelse {
 782                 return .default_limits_binding_missing;
 783             };
 784             if (!selectorValid(Selector)) return .default_limits_binding_invalid;
 785         },
 786     }
 787     if (value.source.kind == .phase_static) {
 788         const seal = bindings.seal orelse return .seal_binding_missing;
 789         const teardown = bindings.teardown orelse return .teardown_binding_missing;
 790         if (validatePhaseBinding(value.source, seal)) |violation| return violation;
 791         if (validatePhaseBinding(value.source, teardown)) |violation| return violation;
 792     }
 793     return null;
 794 }
 795 
 796 fn validatePhaseBinding(
 797     comptime source: SourceEnvelope,
 798     comptime binding: PhaseBinding,
 799 ) ?Violation {
 800     const Family = binding.family orelse return .seam_family_missing;
 801     if (!selectorValid(Family)) return .seam_family_invalid;
 802     if (@typeInfo(@TypeOf(Family.declaration)) != .@"fn") {
 803         return .seam_family_invalid;
 804     }
 805     const premise = binding.premise orelse return .premise_missing;
 806     return validatePremise(source, premise);
 807 }
 808 
 809 fn selectorValid(comptime Selector: type) bool {
 810     return @typeInfo(Selector) == .@"struct" and
 811         @hasDecl(Selector, "declaration");
 812 }
 813 
 814 fn premiseAuthorityCompatible(premise: Premise) bool {
 815     return switch (premise.authority) {
 816         .checker => premise.class == .checked_semantic_fact or
 817             premise.class == .checked_path_fact,
 818         .theorem => premise.class == .theorem_domain,
 819         .certified_claim => premise.class == .certified_summary,
 820         .trusted => premise.class == .trusted_user or
 821             premise.class == .trusted_extern or
 822             premise.class == .trusted_environment,
 823     };
 824 }
 825 
 826 fn overloadCompatible(kind: OverloadKind, shape: OwnerShape) bool {
 827     return switch (shape.storage_source) {
 828         .allocator_backed => switch (shape.overload_shape) {
 829             .exact => kind == .reject_before_seal or kind == .not_applicable,
 830             .rejecting => switch (kind) {
 831                 .reject_before_mutation, .replace, .drop, .terminal => true,
 832                 else => false,
 833             },
 834         },
 835         .caller_provisioned => switch (shape.overload_shape) {
 836             .exact => kind == .reject_before_seal or kind == .not_applicable,
 837             .rejecting => kind == .reject_before_mutation,
 838         },
 839     };
 840 }
 841 
 842 fn obligationKnown(obligations: []const Obligation, key: []const u8) bool {
 843     for (obligations) |obligation| {
 844         if (std.mem.eql(u8, obligation.key, key)) return true;
 845     }
 846     return false;
 847 }
 848 
 849 fn obligationRoleKnown(
 850     obligations: []const Obligation,
 851     role: ObligationRole,
 852 ) bool {
 853     for (obligations) |obligation| {
 854         if (obligation.role == role) return true;
 855     }
 856     return false;
 857 }
 858 
 859 fn localIdentifierValid(value: []const u8) bool {
 860     if (value.len == 0 or value.len > local_id_bytes_max) return false;
 861     if (value[0] < 'a' or value[0] > 'z') return false;
 862     for (value[1..]) |byte| {
 863         const lower = byte >= 'a' and byte <= 'z';
 864         const digit = byte >= '0' and byte <= '9';
 865         if (!lower and !digit and byte != '_') return false;
 866     }
 867     return true;
 868 }
 869 
 870 /// identifierValid checks whether a byte slice adheres to canonical dotted
 871 /// identifier grammar, returning true on success. The slice must contain 1 to
 872 /// 64 bytes divided into at least two non-empty segments separated by dots.
 873 /// Segment characters are restricted to lowercase ASCII letters, digits, and
 874 /// underscores, and segments may begin with a digit or underscore. The function
 875 /// validates canonical identifier syntax only, without performing external
 876 /// registry lookups or enforcing claim-local key grammar.
 877 pub fn identifierValid(id: []const u8) bool {
 878     if (id.len == 0 or id.len > id_bytes_max) return false;
 879     var segments: usize = 1;
 880     var segment_length: usize = 0;
 881     for (id) |byte| {
 882         if (byte == '.') {
 883             if (segment_length == 0) return false;
 884             segments += 1;
 885             segment_length = 0;
 886             continue;
 887         }
 888         const lower = byte >= 'a' and byte <= 'z';
 889         const digit = byte >= '0' and byte <= '9';
 890         if (!lower and !digit and byte != '_') return false;
 891         segment_length += 1;
 892     }
 893     return segment_length != 0 and segments >= 2;
 894 }
 895 
 896 fn textValid(value: []const u8) bool {
 897     if (value.len == 0 or value.len > text_bytes_max) return false;
 898     for (value) |byte| {
 899         if (byte == 0 or byte == '\n' or byte == '\r') return false;
 900     }
 901     return true;
 902 }
 903 
 904 fn requireCanonicalId(comptime id: []const u8) void {
 905     if (comptime !identifierValid(id)) {
 906         @compileError("invalid memory owner id: " ++ id);
 907     }
 908 }
 909 
 910 const DigestBuilder = struct {
 911     state: Sha256,
 912 
 913     fn init() DigestBuilder {
 914         var result = DigestBuilder{ .state = Sha256.init(.{}) };
 915         result.addFramed(digest_domain);
 916         return result;
 917     }
 918 
 919     fn addBytes(self: *DigestBuilder, name: []const u8, value: []const u8) void {
 920         self.addFramed(name);
 921         self.addFramed(value);
 922     }
 923 
 924     fn addEnum(self: *DigestBuilder, name: []const u8, value: anytype) void {
 925         self.addBytes(name, @tagName(value));
 926     }
 927 
 928     fn addCount(self: *DigestBuilder, name: []const u8, value: usize) void {
 929         self.addFramed(name);
 930         self.addU64(value);
 931     }
 932 
 933     fn addDigest(
 934         self: *DigestBuilder,
 935         name: []const u8,
 936         value: [digest_bytes]u8,
 937     ) void {
 938         self.addBytes(name, &value);
 939     }
 940 
 941     fn addU64(self: *DigestBuilder, value: u64) void {
 942         var encoded: [8]u8 = undefined;
 943         std.mem.writeInt(u64, &encoded, value, .little);
 944         self.addFramed(&encoded);
 945     }
 946 
 947     fn finish(self: *DigestBuilder) [digest_bytes]u8 {
 948         var result: [digest_bytes]u8 = undefined;
 949         self.state.final(&result);
 950         return result;
 951     }
 952 
 953     fn addFramed(self: *DigestBuilder, value: []const u8) void {
 954         var length: [8]u8 = undefined;
 955         std.mem.writeInt(u64, &length, value.len, .little);
 956         self.state.update(&length);
 957         self.state.update(value);
 958     }
 959 };
 960 
 961 fn addStorage(builder: *DigestBuilder, storage: Storage) void {
 962     builder.addCount("covered", storage.covered.len);
 963     for (storage.covered) |region| {
 964         builder.addBytes("region_id", region.id);
 965         builder.addEnum("lifetime", region.lifetime);
 966         builder.addBytes("detail", region.detail);
 967     }
 968     addTextList(builder, "excluded", storage.excluded);
 969 }
 970 
 971 fn addOverload(builder: *DigestBuilder, overload: Overload) void {
 972     builder.addEnum("overload_kind", overload.kind);
 973     builder.addBytes("overload_detail", overload.detail);
 974 }
 975 
 976 fn addRisk(builder: *DigestBuilder, name: []const u8, risk: Risk) void {
 977     builder.addBytes("risk", name);
 978     builder.addEnum("risk_status", risk.status);
 979     builder.addBytes("risk_detail", risk.detail);
 980 }
 981 
 982 fn addWork(builder: *DigestBuilder, work: ?Work) void {
 983     builder.addCount("work", @intFromBool(work != null));
 984     if (work) |value| builder.addBytes("work_equation", value.equation);
 985 }
 986 
 987 fn addTextList(
 988     builder: *DigestBuilder,
 989     name: []const u8,
 990     values: []const []const u8,
 991 ) void {
 992     builder.addCount(name, values.len);
 993     for (values) |value| builder.addBytes("item", value);
 994 }
 995 
 996 fn addObligations(builder: *DigestBuilder, values: []const Obligation) void {
 997     builder.addCount("obligations", values.len);
 998     for (values) |value| {
 999         builder.addBytes("obligation_key", value.key);
1000         builder.addEnum("obligation_role", value.role);
1001     }
1002 }
1003 
1004 const PremiseTestSource = SourceEnvelope{
1005     .id = "test.premises",
1006     .kind = .phase_static,
1007     .limit_source = .caller,
1008     .storage = .{
1009         .covered = &.{.{
1010             .id = "state",
1011             .lifetime = .steady,
1012             .detail = "test state",
1013         }},
1014         .excluded = &.{"caller values"},
1015     },
1016     .capacity = .{
1017         .inputs = &.{},
1018         .nodes = &.{.{ .constant = 1 }},
1019         .assertions = &.{.{
1020             .scope = .closure_total,
1021             .measure = .retained,
1022             .relation = .exact,
1023             .expression = 0,
1024         }},
1025     },
1026     .overload = .{
1027         .kind = .reject_before_seal,
1028         .detail = "test admission rejects",
1029     },
1030     .risks = .{
1031         .transitive = .{ .status = .open, .detail = "test callees remain open" },
1032         .foreign = .{ .status = .open, .detail = "test foreign state remains open" },
1033     },
1034     .obligations = &.{
1035         .{ .key = "capacity", .role = .capacity_model },
1036         .{ .key = "overload", .role = .overload },
1037         .{ .key = "theorem", .role = .seal },
1038     },
1039 };
1040 
1041 test "premise declarations cover every authority class" {
1042     const premises = [_]Premise{
1043         .{ .class = .theorem_domain, .authority = .{
1044             .theorem = .{ .key = "theorem" },
1045         } },
1046         .{ .class = .checked_semantic_fact, .authority = .checker },
1047         .{ .class = .checked_path_fact, .authority = .checker },
1048         .{ .class = .certified_summary, .authority = .{
1049             .certified_claim = .{ .id = "other.claim" },
1050         } },
1051         .{ .class = .trusted_user, .authority = .{
1052             .trusted = .{ .id = "trust.user" },
1053         } },
1054         .{ .class = .trusted_extern, .authority = .{
1055             .trusted = .{ .id = "trust.extern" },
1056         } },
1057         .{ .class = .trusted_environment, .authority = .{
1058             .trusted = .{ .id = "trust.environment" },
1059         } },
1060     };
1061     inline for (premises) |premise| {
1062         try std.testing.expect(validatePremise(PremiseTestSource, premise) == null);
1063     }
1064 }
1065 
1066 test "premise declarations reject unknown obligations" {
1067     const premise = Premise{
1068         .class = .theorem_domain,
1069         .authority = .{ .theorem = .{ .key = "missing" } },
1070     };
1071     try std.testing.expectEqual(
1072         Violation.premise_obligation_unknown,
1073         validatePremise(PremiseTestSource, premise).?,
1074     );
1075 }
1076 
1077 test "claim declaration envelope excludes typed binding coordinates" {
1078     const digest = envelopeDigest(sourceView(PremiseTestSource));
1079     comptime var changed = PremiseTestSource;
1080     changed.overload.detail = "changed overload intent";
1081     const changed_digest = envelopeDigest(sourceView(changed));
1082     try std.testing.expect(!std.mem.eql(u8, &digest, &changed_digest));
1083 }
1084 
1085 test "weak capacity owners use the canonical declaration API" {
1086     const Warm = struct {};
1087     const Dynamic = struct {};
1088     comptime {
1089         declareWarmRetained("test.warm", Warm);
1090         declareDynamicUnbounded("test.dynamic", Dynamic);
1091     }
1092 }