Artifact-source contract
Hephaestus may review work against a practice only from evidence with explicit semantics. Contract 1.0.0 defines the
logical source catalog, its capture states, and how well each source must be captured. A capture manifest records
what was supplied to one run; it does not prove that a practice is empirically observable.
If any required evidence clause is unsatisfied, refuse the review and create no observation. A source failure is never
NO_REVIEW_OCCASION, a strength, or evidence that desired behaviour is absent.
Contract boundary
The contract separates three identities:
- Source catalog: logical source kinds and their authority, identity anchoring, completeness, required capture quality, privacy, and absence-state semantics.
- Practice binding: the occasion a review runs on and the evidence that review requires before it may run at all. A source declares the artifact kinds it applies to, so the catalog constrains which sources a binding may name.
- Capture manifest: the state, provenance facts, and materialized artifacts for one invocation.
A binding's needs decide readiness, not staging. Every source the catalog says applies to the artifact
kind is captured and staged for every review of that kind, whether or not a practice named it: relevance is a
question for the practice criteria and the reviewing model, not a reason to withhold data from it. A binding
that names a source with a refusing stance still refuses the review when that source did not arrive, and an
EXHAUSTIVE stance still fences what the review may assert an absence over. Neither cuts the sandbox down.
Paths are materializations, not source identities. Prompts, practice files, task envelopes, runner code, model settings, and executables are invocation inputs and require separate evaluation provenance.
Runtime components must reference the exact contract version and catalog digest they implement. Inputs outside the catalog cannot satisfy a practice requirement.
This contract governs automated-review evidence, not every file used by the separate Mentor conversation runtime. Mentor inputs remain subject to Mentor consent and integration controls and cannot support an automated practice review. Reusing one for review requires registering it as a source kind first.
Source vocabulary
Authority and identity
| Authority | Meaning |
|---|---|
UPSTREAM_SNAPSHOT | Content captured from an upstream object. |
SYNCHRONIZED_MIRROR | A local projection whose currentness depends on upstream synchronization. |
DETERMINISTIC_DERIVATION | A deterministic transform of declared dependencies. |
LOSSY_DERIVATION | A sample, excerpt, aggregation, heuristic, or other information-losing transform. |
A source's authority constrains what it may claim. Only a capture anchored to an immutable upstream
identity may declare PINNED_IDENTITY — a SYNCHRONIZED_MIRROR reflects state that moves independently of
the capture — and a LOSSY_DERIVATION may never claim completeness. Both rules are enforced in
ArtifactSourceContract's constructor, so a catalog that breaks either one fails at startup.
A database row is not automatically authoritative for the current state of GitHub, GitLab, Slack, or Outline.
Required capture quality
How well a source must be captured is a fact about the source, recorded once in the catalog as
requiredQuality, rather than restated by every practice that names it.
| Value | Meaning |
|---|---|
ANY_CAPTURE | The capture must have succeeded. Whatever it holds, including nothing, is reviewable. |
COMPLETE | The capture must cover the whole selected scope; a fragment cannot ground a judgement about the whole. |
COMPLETE_AND_NON_EMPTY | Complete, and containing something. |
The three values are a ladder rather than two independent booleans, because the fourth cell of the cross-product — non-empty but possibly partial — asserts something no source can support: a partial capture that happens to contain something cannot rule out that what it omitted was the part that mattered.
A source that cannot report COMPLETE may not demand it, and a source that can never be validly empty may
not demand non-emptiness. Both are rejected when the catalog is read, so a requirement that would refuse
every review permanently cannot be stated.
Privacy classes
Privacy class describes risk; it does not authorize collection, disclosure, or model egress.
| Class | Scope | Minimum treatment |
|---|---|---|
INTERNAL | Non-public project or workspace content without person-level review observations | Workspace authorization and purpose-bound retention |
PERSONAL | User-linked project content, authorship, reviews, comments, or activity | Personal-data access, export, and erasure coverage |
SENSITIVE_PERSONAL | Private conversations or derived person-level review observations | Restricted audience and stricter disclosure and retention controls |
Each catalog source references separate source-use decisions whose purposes are machine-enforced. Capture requires
AUTOMATED_PRACTICE_REVIEW; observation persistence, delivery, and contributor evidence APIs require
PRACTICE_FEEDBACK_DELIVERY; mentor reuse requires CONVERSATIONAL_MENTORING; and workspace-admin evidence review
requires OPERATOR_EVIDENCE_REVIEW. Processor, region, transfer, and model-egress controls remain separate
deployment obligations. A source allowed in an internal mirror is not thereby allowed in an external model request.
Source catalog (1.0.0)
The machine-readable catalog,
its adjacent JSON Schemas, and the checks in
check:contracts
jointly define conformance. Schema validation alone is insufficient because standard JSON Schema uniqueItems
compares whole values rather than a selected identity property, so the script also rejects duplicate source
kinds and holds each schema's pinned catalogDigest to the catalog's actual hash. The cross-resource rules
that bind a source to its governance decisions run when the server reads the catalog, not in the script.
Prose does not maintain a second field-by-field catalog. Authoring tools resolve source kinds through the catalog and reject unknown kinds; a source declares the artifact kinds it applies to, so a practice on one kind of work can only name sources that suit it.
The constraints with direct authoring consequences are:
- Only sources anchored to an immutable upstream identity — the pull-request diff and the repository tree —
declare
PINNED_IDENTITY. Every mirrored source, including the pull-request and issue records themselves, has identity policyNOT_APPLICABLE. A source'sauthoritydecides whether it may anchor at all: aSYNCHRONIZED_MIRRORreflects upstream state that moves independently of the capture, so calling one pinned would describe a copy that has since drifted as demonstrably current. - A
LOSSY_DERIVATIONcannot satisfyCOMPLETE. It is a bounded summary of its subject rather than the subject, so it cannot answer "is all of it here?" — which is exactly what an author asserting an absence is asking. Outline documents and linked work items are both retrieved by heuristics that cannot establish they found everything, and neither reportsCOMPLETE. - Three
1.0.0sources cannot be logically empty — the pull-request, issue, and document core records. Every other source may be validly empty. - Two cannot be partial: the pull-request diff and the document core record. An available diff is
additionally pinned. It may be captured empty, but its
requiredQualityisCOMPLETE_AND_NON_EMPTY, so a practice that reads it is refused rather than left to grade the title and description instead.
ENGINEERING_BASELINE with ENGINEERING_APPROVED records maintainer approval of the shipped, minimized product
scope. It is not controller or DPO approval and cannot cover an expanded source, purpose, audience, processor,
retention policy, or collection scope. It is also the only basis the contract can express, and the only outcome:
a use nobody approved carries no decision rather than a recorded refusal, so no entry here can read as a
controller sign-off. The controller's own record remains separate. Approval is the gate that runtime
configuration cannot waive: a source whose decision is missing or expired is never read, whatever the
deployment sets. Within that boundary, connecting a workspace
integration and enabling a practice is what authorizes the everyday code sources the product exists to read, so a
default deployment reviews pull requests, issues and conversations without further configuration. Privacy
class does not gate collection — it records what treatment a source needs.
Changing a source's meaning, selection scope, limit, mapping, identity policy, required capture quality,
dependency, or normalization requires a new contract version. Repository history is not part of
scm.repository.tree and requires its own source and governance decision.
Capture state
Source absence is separate from quality so the manifest does not collapse unavailable, partial, and empty evidence into one state.
Availability
AVAILABLE: capture facts and logical content state are present.NOT_COLLECTED: no unexpired use decision permits the source for this purpose, or collection is switched off for it in this deployment. Never "no practice wanted it": every source that applies to the artifact kind is staged for every review, so relevance is not a reason a source can be missing.UNAVAILABLE: the source could not be retrieved for a non-error reason.REDACTED: the entire source was withheld for privacy or security.COLLECTION_ERROR: an attempted collection failed.
A non-available source contains no artifacts or source identifiers, and carries a typed
SourceAbsenceReason saying why — GOVERNANCE_NOT_EFFECTIVE, NO_PROVIDER, NO_WORKING_COPY,
CONSENT_NOT_ACTIVE, and the rest. Safe, typed reason codes may be role-filtered; free-form exception text
must not enter the manifest.
Available-source dimensions
Only AVAILABLE has:
- logical content:
EMPTYorNON_EMPTY; - completeness:
COMPLETE,PARTIAL, orUNKNOWN; - capture facts:
capturedAt— the only required one — plus an optionalobservedAt, an optionalsourceEffectiveAtwatermark, and an optional pinned identity; - artifacts.
Capture facts hold only what could not be known before the capture ran. Everything derivable from the catalog the manifest pins by digest — selection scope, limits, required capture quality, the states a source may report — is read from the catalog, never copied into the capture.
Logical content is independent of serialized bytes: a JSON file containing [] represents an EMPTY source.
Field-level redaction remains an available, usually partial source; whole-source redaction uses REDACTED.
There is no staleness verdict, and there is deliberately no age-based mode. An age threshold needs a
watermark recording when a copy was last verified against upstream; the mirror records only when a row was
last written, so an age derived from it measures time since the last upstream change — reporting a
correctly mirrored quiet record as stale and a record modified moments ago as current. Adding one therefore
has a prerequisite: a reconciliation pass that advances a verified-as-of watermark after confirming a record
is unchanged. Until that watermark exists, a currentness guarantee on a mirrored source would be a claim the
system cannot substantiate, so IdentityPolicy records only the honest half — whether a capture can be
anchored to something immutable at all.
A readiness report names the contract version, the catalog digest it was interpreted under, the artifact kind, the manifest's capture time, and one decision per practice. A manifest captured under a contract version the runtime no longer ships is unreplayable rather than invalid: the recorded result stands, and only the ability to re-derive it is unavailable.
Practice automated-review policy
The practice review glossary defines the canonical product and machine terms. A practice makes two separate statements.
The policy is the frame the review runs in: the contract version that names the sources, whether a model runs at all, the refusal behaviour, and the claims that kind of evidence can never support whatever the occasion. It does not itself list sources.
The binding is the occasion, carrying the evidence a review occasioned that way reads. A practice
declares exactly one; PracticeDefinitionValidator refuses a second, and the wire schema caps on at one
entry. Evidence belongs on the binding rather than on the practice because what a review needs is a function
of what occasioned it: a review that runs when a change merges may have to establish that no decision was
ever recorded, while a review of the same question when the change was opened is only reading what is in
front of it. Those are two practices, not two occasions on one — one row, one autonomy setting and one feedback
history then describe one habit. The on array keeps its list shape so that relaxing the rule stays a
validator change rather than a data migration.
One occasion may still name several signals, which is how a practice judged all the way along a piece of work is written. Its artifact kind is read off those signals' shared prefix and is never written down separately: a second statement of the same fact is a second thing to keep in agreement, and a practice whose declared kind contradicts its own signals cannot be resolved. All signals in the binding must therefore share one artifact kind.
A signal that names a hand-requested review is refused: such a review already covers every practice on that work type whatever state the work is in, so it is a door rather than an occasion an author opts into.
Each entry in needs names a source and the stance the practice takes towards it:
| Stance | Meaning |
|---|---|
REQUIRED | The claim reads this source. If it could not be captured to the quality its contract demands, the review is refused rather than run. |
EXHAUSTIVE | The claim reads this source and asserts something is not in it. Required, and additionally not satisfiable by a partial capture whatever the source contract's floor happens to be. |
CONTEXTUAL | Used when present, noted when absent, never a reason to refuse. |
EXHAUSTIVE exists because an absence is the one claim a fragment cannot support: a partial capture of the
review threads is consistent both with "nobody resolved this one" and with "the resolution was in the part we
did not fetch", and a review that cannot tell those apart still tells a developer they merged past an
unresolved thread. Where the corpus was not whole, the honest answer is INSUFFICIENT_EVIDENCE, never a
quiet NO_REVIEW_OCCASION.
{
"on": [
{
"signals": ["scm.pull_request.opened", "scm.pull_request.ready"],
"needs": [
{ "sourceKind": "scm.pull-request.core", "stance": "REQUIRED" },
{ "sourceKind": "scm.pull-request.diff", "stance": "REQUIRED" },
{ "sourceKind": "scm.repository.tree", "stance": "CONTEXTUAL" }
]
}
],
"automatedReviewPolicy": {
"sourceContractVersion": "1.0.0",
"automatedReview": {
"mode": "LANGUAGE_MODEL",
"evidenceSufficiency": "SUFFICIENT_WHEN_REQUIREMENTS_MET"
},
"whenEvidenceIsInsufficient": "SKIP_AUTOMATED_REVIEW",
"knownLimitations": [
{
"code": "RUNTIME_BEHAVIOR_NOT_OBSERVED",
"description": "Repository evidence does not establish behavior in a deployed runtime."
}
]
}
}
In the bundled catalog a binding may also be written as a bare signal name, which is shorthand for a binding
on that signal reading the artifact kind's default evidence. A binding may set onDrafts: true to be
occasioned by an artifact still marked draft; it defaults to false, because most practices judge work that
has been handed over.
Validation rejects unknown versions or source kinds, signals no registered domain declares, a signal that
names a hand-requested review, sources that do not apply to the binding's artifact kind, duplicate sources
within one binding, a binding with no signal, a second binding, a binding whose signals mix artifact kinds, an
EXHAUSTIVE stance over a source that can never report a complete capture, and a policy that carries needs
or a retired evidenceProfile. An EXHAUSTIVE stance over a
source that could never be captured whole is caught at authoring time rather than at review time, because
"switched on and permanently refusing" is indistinguishable from "nobody has done this yet" in the report it
produces.
knownLimitations records the claims the selected evidence cannot support even when every requirement passes.
The runtime appends them to the criteria it stages for the reviewing model, because a limitation the author records
and then withholds constrains nobody: the model still reaches the conclusion the author knew the evidence could not
carry. insufficiencyReason is separate and is present only when evidenceSufficiency is
DECLARED_EVIDENCE_INSUFFICIENT: it says why a person is needed, which is a different question from what the
evidence cannot show. Folded into the limitation list it stops being answerable, since a limitation on a
practice nobody reviews reads as one more caveat rather than the reason there is no review.
Every bundled practice that requires the pull-request diff lists scm.repository.tree as CONTEXTUAL. A diff
shows the changed lines and not the code they call into, so a reviewer restricted to it either guesses at the
surrounding contract or abstains. The tree is contextual rather than required deliberately: a deployment that
keeps no working copy, or a repository not yet mirrored, loses the surrounding code and still gets the review.
automatedReview is explicitly relative to Hephaestus, the pinned source contract, the declared bindings, and
the governed integrations. It does not claim that a practice is universally observable. A developer, peer, or human mentor may have different context for a particular practice. This contract makes no claim that human review is always possible.
mode is LANGUAGE_MODEL or NONE. evidenceSufficiency says whether passing every requirement is
enough, the declared sources cannot support review, or automated review is not configured. These are author-defined
settings, not empirical validation. automatedReviewValidation is bound to the exact automated-review
policy and review-rule fingerprint. Its only status is AUTHOR_DECLARED: nothing in the product validates a
policy independently, so the status carries no evaluator provenance and the type refuses to hold any. A
status the API can never return would describe a system other than this one.
Only LANGUAGE_MODEL with SUFFICIENT_WHEN_REQUIREMENTS_MET runs a model. These skip:
LANGUAGE_MODELwithDECLARED_EVIDENCE_INSUFFICIENT;NONEwithNONE.
Neither can be reviewed, so a practice declaring one is forced to OFF when it is created or
edited. The glossary maps each pair to the mentoring choice
an author sees. A skipped practice is omitted from that review request. Source readiness checks contain only
source-quality reasons — SOURCE_NOT_AVAILABLE, SOURCE_INCOMPLETE, SOURCE_EMPTY — so review-mode
limitations are never misreported as defective sources. Missing evidence never becomes a fabricated
NO_REVIEW_OCCASION observation.
Human review is outside this contract. A self-review, peer-review, or human-mentor channel carries its own review target, reviewer relationship, rubric, evidence provenance, consent, access, retention, result vocabulary, and validation status, none of which this contract supplies. Declaring that a person could observe a practice neither collects a human review nor makes an automated review ready to run, and a human review read back as automated-review input needs a governed source kind and purpose authorization of its own.
What runs before evidence
Two workspace-level gates decide whether a review is admitted at all, before any source is captured. Both refuse the signal with a typed reason rather than silently doing nothing.
- Practice autonomy. A practice at
OFFadmits no review;HUMAN_APPROVALandAUTOMATICboth run it and differ in whether a person must authorize release. When every practice bound to a signal sits atOFF, the signal is refused withPRACTICE_AUTONOMY_OFF. - Review scope. An artifact outside the workspace's declared branches or repositories is refused with
OUT_OF_REVIEW_SCOPE.
Both are defined in the practice review glossary, including which refusal is retryable and which is terminal. Neither is an evidence concern — they decide whether evidence is collected at all.
Conservative examples
Required evidence is insufficient
scope-one-reviewable-change is bound to scm.pull_request.opened and scm.pull_request.ready, and that
binding requires scm.pull-request.core and scm.pull-request.diff and reads scm.repository.tree
contextually. The diff's contract demands a complete, non-empty capture. If the diff cannot be read, or the
pinned commit is gone from the mirror, readiness refuses the practice and no observation is created. The
runtime makes no claim that the change is focused, sprawling, or NO_REVIEW_OCCASION. No stance can demand
a currentness the pull-request record cannot demonstrate; nothing available could substantiate one.
Empty evidence is valid
A complete pull-request comment query may materialize as []. Its state is
AVAILABLE + EMPTY + COMPLETE, and scm.pull-request.comments sits at ANY_CAPTURE, so that is valid
evidence rather than UNAVAILABLE. A redacted or failed query cannot support the same practice claim, and a
practice taking an EXHAUSTIVE stance is refused by a partial one.
Runtime behavior
The runtime resolves exact practice revisions before capture and then stages every governed source the
catalog declares for the artifact kind under review — all of them, on every review. There is no per-run
source selection: practice bindings decide which practices may run, never which sources are captured, so a
source listed as anything other than AVAILABLE always says why in a typed reason code and never because
no practice asked for it. Bindings enter afterwards, in the readiness check. Readiness is evaluated per
practice. A CONTEXTUAL failure does not skip an otherwise eligible practice; a REQUIRED or EXHAUSTIVE
failure does. If no practice is eligible, no model request is made.
One invocation may contain the governed union needed by several practices. The model can technically read that union; this runtime uses an attribution boundary rather than process isolation. The practice index lists each practice's admissible logical source kinds. Every model-authored observation must cite an exact quote and artifact path. The sandbox and server independently verify that the source is declared and available, the path belongs to that source in the pinned manifest, and the quote occurs in the digest-addressed artifact. Deterministic secret-scanner observations are the deliberate exception: the transient secret quote is verified by digest, then only its redacted location is persisted. Delivery fails atomically on any mismatch. This proves traceable grounding, not model causality; evaluations requiring non-interference must still run practices in isolated evidence views.
The internal readiness report records whether each practice is ready or skipped, and it is the one document
that stays server-side: it is persisted to agent_job.review_readiness and never staged. The manifest is
not internal — the same bytes persisted to agent_job.evidence_snapshot are staged into the sandbox at
inputs/manifest.json, carrying every absence reason code including GOVERNANCE_NOT_EFFECTIVE,
CONSENT_NOT_ACTIVE, and CONTENT_EVICTED. There is no redacted model-facing variant. Treat a reason code
you add to a capture state as model-visible, and put anything that must not be as a readiness decision
instead.
Change and staleness
Historical records keep their original contract and practice revision. Currentness is derived:
- source resources are immutable within a published contract version; any semantic change creates a new version;
- moving a practice to that version changes what its bindings may name and stales that practice's earlier claims;
- changing a practice's bindings or automated-review policy stales that practice's claims;
- adding a source cannot silently alter existing requirements because each binding names its sources explicitly;
- governance withdrawal disables its exact future use, including collection, observation persistence and delivery, mentoring reuse, or evidence disclosure, without rewriting historical semantics; and
- erasure or expiry may make a claim unreplayable without making the historical result false.
Semantic currentness, automated-review-validation status, governance eligibility, and replayability remain separate.
Observation and review APIs expose claimCurrentness as CURRENT, STALE, or UNVERIFIABLE by comparing the
evaluated practice revision's review-rule fingerprint with the current revision's fingerprint. Presentation-only
edits retain semantic currentness; rows without comparable versioned fingerprints are UNVERIFIABLE.
Adding or changing a source
Complete the artifact-source governance decision before enabling a new or expanded source use. Accuracy or product benefit alone does not authorize collection.
The rules are enforced mechanically, in two places:
check:contractsvalidates every contract resource and the bundled practice catalog against their schemas, rejects duplicate source kinds, holds each schema's pinned catalog digest to the catalog's actual hash, and exercises the policy schema against deliberately broken fixtures — including a retired evidence profile and evidence needs written onto a policy instead of a binding — because a guard whose failure path never runs is indistinguishable from one that cannot fail.- The server, when it reads the catalog at startup, rejects a mirror that pins an identity, a lossy derivation that claims completeness, a required capture quality the source can never report, a source whose use decisions do not cover every product purpose, and a decision whose retention or erasure policy disagrees with its source.
Prior art
- Gebru et al., "Datasheets for Datasets" — the source catalog is a datasheet: composition, selection scope, uses, and limitations recorded alongside the data.
- GDPR Article 5 — purpose limitation, minimization, accuracy, and storage limitation, which the source-use decisions record per source and purpose.