# description
Experiment-tier attestation envelope — the SECOND tier in IntelligencePro's 5-tier cryptographic chain-of-custody wedge (R16 cross-cutting): pipeline (R14 D1, cycle 314) → EXPERIMENT (R16 M1, THIS — cycle 317) → leaderboard (R15 B1, planned) → review (R16 R3, cycle 316) → governance (R14 G1, cycle 315). Closes SYNTHESIS-acquisition Round 16 P3 [[mlops-and-experiment-tracking]] M1 ship-first action. Per-experiment-run receipt binding {trackerId, trackerVersionSha, modelId, datasetSha, codeCommitSha, hyperparameters, finalMetrics, runnerDid, signature} for training-run / fine-tuning-run / hyperparameter-sweep workloads. Closes the cycle-301 regulatory-compliance audit P0-4's 'partial' tier (was 1 of 5 partial: training; this commit promotes it to fully shipped). Designed for: MLflow 3.x (LF AI Foundation; ~80M PyPI downloads/year; Vertex AI + Azure ML MLflow-API-compatible) + Weights & Biases (CoreWeave-owned post Dec-2024 $1.7B acquisition closed May-2025) + DAGsHub + ClearML + Comet ML + Neptune.ai (OpenAI-acquired; hosted service sunset 2026-03-04 = case study for closed-trust decay) + Galileo Evaluate (Cisco intent-to-acquire 2026-04-09) + Phoenix Arize + Langfuse (ClickHouse-acquired Jan-2026 at $15B) + Patronus AI + Aporia + W&B Weave (post-CoreWeave acquisition serverless eval runtime). Binds upward to OpenTelemetry GenAI semantic conventions (R16 M1b PR target — gen_ai.* attributes merged into official OTel semconv). Composes UPSTREAM with ip.pipeline.facet.v1 (cycle 314) via inputPipelineRunIds[] + ip.sandbox.run.attestation.v1 (cycle 307) + ip.eval.run.attestation.v1 (cycle 308) via runIds. Composes DOWNSTREAM with ip.leaderboard.receipt.v1 (R15 B1, planned) via experimentReceiptId — the experiment receipt is what a leaderboard cites when it claims 'model X scored Y on benchmark Z.'

# $comment
Discovery: https://ip.tekton.cc/.well-known/ip-knowledge.json (full descriptor) | Badge: https://ip.tekton.cc/api/badge/v1/attestation/experiment.receipt.v1/<subjectSha256> (shields.io endpoint) | Free dry-run: POST https://ip.tekton.cc/api/credentials/dry-run with body {kind:"experiment.receipt.v1", body:<candidate>} (no auth required, validates against this schema) | Verification recipe: https://ip.tekton.cc/docs/verification-recipe.md (3-layer trust model + curl trail) | Revocation: https://ip.tekton.cc/credentials/status/v1 (W3C BitstringStatusList v1.0; check bit at credentialStatus.statusListIndex)

# properties.schemaVersion.description
Semver of this schema. Bumps to 2.0.0 land at /credentials/experiment-receipt/v2 — v1 stays immutable (see /docs/schema-versioning.md for the cycle-726 canonical bump-mechanics + soft-change-detection contract).

# properties.rmfFunctionHint.description
Cycle 487 (cycle-483 follow-up): non-required NIST AI RMF 1.0 function hint. Experiment receipts span MAP-3.4 (context characterization of training runs) + MEASURE-2.5 (system metrics during training/eval). Default 'map' when the receipt's primary purpose is context-capture; 'measure' when it's metrics-driven. Companion to ip.governance.compliance.v1.rmfFunction.

# properties.chain.properties.parentSha256.description
Sha256 of the canonical-JSON bytes of the parent attestation (typically the ip.pipeline.facet.v1 that the experiment ingested). Lets a verifier walk upward from this experiment to the data-pipeline lineage without re-querying the registry. ⚠ Cycle 493 honest-disclosure (adversarial-auditor AA-485-P2-4): the platform does NOT verify parent-existence at issuance. A syntactically-valid 64-hex sha256 satisfies this pattern but the bytes may not resolve in any attestation store. Consumers walking the chain MUST resolve parentSha256 against their own attestation registry (the platform exposes no by-sha lookup as of cycle 493); see /docs/verification-recipe.md for the canonical walk. A dangling parentSha256 is an UNVERIFIED chain link, NOT a verified absence — distinguishing 'platform issued an unresolvable parent pointer' from 'parent was revoked and evicted' requires consumer-side state.

# properties.chain.properties.parentKind.description
Kind identifier of the parent attestation. For ip.experiment.receipt.v1 the parent is always a pipeline-facet record (the experiment consumed the pipeline's output).

# properties.chain.properties.parentAttestationId.description
Optional UUID of the parent attestation — convenience for consumers that index by id. parentSha256 is the authoritative cryptographic link; parentAttestationId is the human-readable redundancy.

# properties.chain.description
Cycle 484 (regulatory-compliance RC-480-F2 P0 fix): chain.parentSha256 + parentKind let an EU AI Act Art 13 deployer (or a regulator) walk upward from this experiment receipt to the pipeline facet it consumed. Pre-cycle-484 the schemas carried inconsistent downward refs (evidenceShaArray on governance, experimentReceiptId on leaderboard, inputPipelineRunIds on experiment) but no UNIFORM upward chain field. Now every non-pipeline wedge tier carries the same chain.* shape so a verifier holding a single tier's attestation can mechanically traverse to its parent without per-tier custom code. Optional for back-compat — existing experiment-receipts grandfather in. Pre-cycle-484 attestations can be re-issued with the chain field populated when the upstream pipeline-facet sha is known.

# properties.receiptId.description
Unique RFC 4122 UUID v4 or v7 — this receipt's canonical identifier. Lets a consumer dedupe across retries + replays and link this attestation back to a ip.attestation.event.v1 wire row via ipAttestationEventId.

# properties.trackerId.description
Stable handle for the experiment tracker. The enum covers the post-2025-Q4 + 2026-Q1 consolidated landscape per R16 P3 verified facts. 'opentelemetry-genai' = the official OTel GenAI semconv (gen_ai.* attributes merged in 2025). 'wandb-weave' = the W&B LLM-app framework runtime (separate from base wandb).

# properties.trackerVersionSha256.description
Sha256 of the canonical tracker-client artifact. For MLflow: sha256 of the mlflow-skinny wheel at the resolved version. For W&B: sha256 of the wandb wheel + W&B server build manifest. For Comet ML: sha256 of comet_ml wheel. Pins WHICH BUILD of the tracker captured the run.

# properties.modelId.description
Identifier of the model being trained / fine-tuned. For HF: 'meta-llama/Llama-3.1-70B-Instruct'. For OpenAI fine-tune: 'ft:gpt-4o-mini-2024-07-18:...'. For local: 'safetensors:<sha>'. Opaque to the wire schema; semantic verification is downstream.

# properties.modelBaseVersionSha256.description
Optional sha256 of the canonical base model artifact at experiment START. For fine-tuning / continued-pretraining: pins WHICH WEIGHTS were the starting point. Composes with R17 I1 ip.inference.response.v1 (planned) — the inference attestation can verify the model_version_sha256 against this experiment's output.

# properties.modelOutputSha256.description
Optional sha256 of the canonical OUTPUT model artifact at experiment END (the fine-tuned / continued-pretrained weights). Required for the experiment to chain DOWNSTREAM into ip.leaderboard.receipt.v1 (R15 B1, planned) — the leaderboard cites WHICH model was evaluated by referencing this sha.

# properties.datasetSha256.description
Sha256 of the canonical training-dataset bytes (or canonical-JSON manifest of multi-file dataset). LOAD-BEARING for contamination defense: pinned dataset sha prevents the LMArena 2025-04 36-Llama-4-variants pattern (where training data is silently swapped). Composes with R19 L1 ip.label.attestation.v1 (planned) — when training data was peer-attested, the dataset_sha walks to per-label attestations.

# properties.codeCommitSha.description
Optional git SHA-1 commit hash of the training-script repository at experiment START. 40-hex = git's canonical sha1. Pins the training-code shape that consumed the dataset + produced the model. When code is hosted on GitHub, downstream verifiers can re-fetch the commit + recompute behavior.

# properties.hyperparametersSha256.description
Sha256 of the canonical-JSON hyperparameter configuration (learning_rate, batch_size, num_epochs, optimizer, schedule, dropout, etc.). MLflow params, W&B config, Comet ML params, ClearML configuration_objects all hash here. Pins the run's recipe.

# properties.finalMetricsSha256.description
Sha256 of the canonical-JSON final-metrics object (the metrics the experiment emitted at completion — loss curves, accuracy, F1, ROUGE, custom evals). Required because LLM-tracker self-signed metrics are the most-cited downstream-trust-decay risk per R16 P3 (Neptune.ai sunset 2026-03-04 is the case study — orphaned cited metrics). Lets a downstream consumer re-verify metrics weren't altered post-experiment.

# properties.finalMetricsText.description
Optional human-readable JSON of the final metrics. When present, sha256(canonical(finalMetricsText)) MUST equal finalMetricsSha256.

# properties.inputPipelineRunIds.description
Array of ip.pipeline.facet.v1 runIds (R14 D1; cycle 314) that produced the training-dataset snapshot. Chains UPSTREAM to the pipeline tier — the experiment knows WHICH dbt/Airflow/Spark/Flink runs prepared its inputs. SOX 404 + EU AI Act Annex IV technical-documentation audit-traceable lineage requires this link when training-data lineage is regulator-relevant.

# properties.evalRunIds.description
Array of ip.eval.run.attestation.v1 runIds (R20 EV1; cycle 308) that evaluated this experiment's output model. Chains DOWNSTREAM to the harness tier — the experiment's final-metrics may be DERIVED from one or more eval-harness runs (Inspect AI, Promptfoo, lm-eval-harness, DeepEval, RAGAS, etc.).

# properties.sandboxRunIds.description
Array of ip.sandbox.run.attestation.v1 runIds (R21 SB1; cycle 307) that exercised this experiment's output in a sandbox. When the eval was a SANDBOX-based agent benchmark (OSWorld, WebArena, AppWorld, SWE-Gym), this is the upward chain link.

# properties.startedAt.description
Epoch milliseconds when the experiment started. Required because training runs are time-bounded (datasets evolve; weight-init RNG is time-seeded in some workflows).

# properties.completedAt.description
Optional epoch milliseconds when the experiment completed (success or failure). Matches tracker COMPLETE event timestamps. When present, completedAt >= startedAt.

# properties.status.description
Run-status enum harmonizing across trackers: MLflow uses {RUNNING, FINISHED, FAILED, KILLED, SCHEDULED}; W&B uses {running, finished, failed, killed, crashed, preempted}; Comet ML uses {running, finished, crashed}. Downstream consumers MUST refuse to cite metrics from FAILED / KILLED / CRASHED / PREEMPTED runs.

# properties.computeSpec.properties.gpuHours.description
Total GPU-hours consumed. Useful for downstream cost-and-carbon attestation per the Anthropic Bloom framework + EU AI Act Article 50 Code of Practice cost-disclosure dimensions.

# properties.computeSpec.properties.framework.description
Training framework — 'pytorch-2.x', 'jax', 'tensorflow', 'megatron-lm', 'deepspeed', 'fsdp', 'accelerate', 'unsloth', 'axolotl', 'trl', 'lit-gpt'.

# properties.computeSpec.description
Optional compute-resource block. Useful for downstream cost / carbon / supply-chain attestation.

# properties.judgesDigest.description
When this experiment receipt was peer-attested by 3+ independent verifiers, the canonical digest of the judges manifest. Chains to the same judgesDigest field used in CP's other manifests (cycle 303 derivationRecipes documentation applies).

# properties.ipAttestationEventId.description
When this receipt was emitted as a ip.attestation.event.v1 row (R11 T1) to the platform's Kafka/Tinybird/ClickHouse pipeline, the eventId of that wire row.

# properties.runnerDid.description
DID of the entity that ran the experiment. did:web for institutional ML platform (did:web:wandb.ai, did:web:huggingface.co, did:web:anthropic.com); did:key for individual researcher. Resolves to a JWKS that can verify the `signature` field below.

# properties.signature.description
Ed25519 signature (128 hex chars = 64 raw bytes) over the canonical-JSON bytes of (receiptId ⊕ experimentName ⊕ trackerId ⊕ trackerVersionSha256 ⊕ modelId ⊕ modelBaseVersionSha256? ⊕ modelOutputSha256? ⊕ datasetSha256 ⊕ codeCommitSha? ⊕ hyperparametersSha256? ⊕ finalMetricsSha256 ⊕ inputPipelineRunIds? ⊕ evalRunIds? ⊕ sandboxRunIds? ⊕ startedAt ⊕ completedAt? ⊕ status? ⊕ computeSpec? ⊕ judgesDigest? ⊕ ipAttestationEventId? ⊕ runnerDid). Verify against the publicKey published in the runnerDid's JWKS. RFC 8037 (Ed25519 in JWS) canonicalization rules apply: JCS (RFC 8785) ordering on the inner object. ⚠ INTEGRITY GAP (aa-824-P0-1, cycle 826 honest disclosure): `chain.*` and `extra` are presently OUTSIDE this signature pre-image. A wire-path or post-hoc rewrite of `chain.parentSha256` / `chain.parentKind` / `chain.parentAttestationId` does NOT invalidate this `signature`. Offline verifiers using `signature`+`publicKey` (the documented embedded-verification path) MUST treat `chain.*` as ADVISORY pointer-shape, NOT cryptographically bound to this attestation. For full-integrity verification including chain pointers, fetch the W3C DataIntegrityProof envelope from /credentials/<sha>/v1 and verify against the proof.cryptosuite=eddsa-jcs-2022 signature (which signs the FULL canonical-JSON body including chain). Cycle-484 added the chain block; cycles 778-784 swept it across the schema family; the signature pre-image was not re-derived alongside that sweep. Migration target: a v2 schema slug ($id pin per cycle-462 sp-457-P2-2) will widen the pre-image. See cycle 825 review.attestation.v1 for the first disclosure in this fan-out.

# properties.publicKey.description
Ed25519 public key (32 raw bytes = 64 hex) corresponding to the signature above. Verifier MAY prefer to resolve via runnerDid's JWKS — this field exists for offline / embedded verification when network resolution is unavailable.

# properties.extra.description
Open extension slot — tracker-specific or framework-specific payload (MLflow run-context provider data, W&B run-config tags, Comet ML environment_details, Galileo confidence intervals, OpenTelemetry GenAI gen_ai.* attribute map). Consumers MUST ignore unknown keys.