RFC 0006: Evaluator conformance
On this page
- Status: Accepted
- Type: Standards-track (Core amendment)
- Created: 2026-07-27
- Accepted: 2026-07-28
Adoption record. This RFC was accepted by the single maintainer under the interim review regime (RFC 0009), and the amendment it proposes lands in Core
0.2.0-draftin the same merge: §3.4 defines the evaluator conformance class, §8.2 its inputs, §8.3 the portable disposition, §8.4 the error contract, andconformance/evaluation/the seed corpus. The reviews of this RFC and of the amendment, with a written disposition for every finding, are recorded on the pull requests; RFC 0006's own review record is pull request 9.This document stays the record of the proposal. Where its sketch and the landed text differ — the disposition's exact members, the named error classes, and the sketch's requirement that corpus inputs fit mandated minimum limits (Core §10 mandates only that an implementation define and document its limits, and the corpus keeps its cases well inside any plausible one instead) — the specification governs; §1.1 makes an RFC informative in any case.
The Core-or-profile question below is resolved to Core, and two other questions were answered on acceptance. Of the rest, Core §13 carries four: evidence interchange, number representability, the trace minimum, and the machine-readable diagnostic contract. Graph interaction and the selection probe are not Core questions and stay with RFC 0002 and RFC 0004. Claim verification — where corpus results are published and who may check them — is carried nowhere normative and stays open in this RFC only; Core §3.4.1 requires a claim to state the results, which makes it an attestation by the claimant.
What the evidence supports, and what it does not. The evidence is two implementations and a 13/13 agreement corpus. Both implementations trace to one maintainer's direction — the second was written clean-room, inside an information barrier, by a different model family, but from reference texts this maintainer chose and including this RFC's own implementation-experience notes. Their agreement therefore corroborates the semantics; it does not independently confirm them.
Acceptance is at the maturity this RFC names. Per RFC 0000, acceptance approves a design for that maturity and makes nothing stable: this is design approval for a draft specification, not a stability claim, and
0.2.0-draftmay still change incompatibly. RFC 0000's bar for a stable normative feature — evidence from two independent implementations — is not met, and it is re-tested at stabilization rather than treated as satisfied by this acceptance. Third-party implementation experience remains the evidence this process cannot manufacture.
Summary
Propose that a later draft of the core specification define a normative evaluator conformance class: portable semantics for applying a pack to runtime facts and evidence, and a portable disposition that two independent evaluators must produce identically from the same inputs. The raw material is the informative §§7–8; promote them, close their portability gaps — one of which this RFC resolves in its own sketch — and test with an evaluation corpus beside the validation corpus.
Problem
Core 0.1.0-draft defines document conformance only; §3.4 says a tool "MUST NOT claim evaluator
conformance under 0.1.0-draft, even if it implements the experiments in §§7–8." Two runtimes
can therefore read the same pack and facts, both behave defensibly, and produce different results
— neither wrong, because there is no normative text to be wrong against. Affected: teams
comparing evaluators, auditors replaying a decision, integrators exchanging decision records.
Evidence
Three readers independently walked input instances for
data-request-intake-triage through §§7–8; an
adversarial review then reconstructed and re-walked the set independently (recorded on this RFC's
pull request). The instances, inputs, and expected results are committed in the
appendix below. Two findings survived both passes:
- One genuine semantic divergence. §8 step 2's binary test — "record
missing-required-evidenceif any required evidence is absent" — does not define "absent" in terms of §7.5's three-valued presence, and §7.5 makes presencefalseonly "when a complete evidence manifest is available and associates no item" while defining no manifest interchange form. For appendix instance 7, careful readers legitimately produce eitherunresolved/{missing-required-evidence}orunresolved/{unknown}from the same input, with different termination points. The sketch below resolves this. - One lossy-reporting finding, not a semantic divergence. §8 defines "a
not-applicableresult carrying reasonnot-applicable" — the result kind and the reason are both mandated, so an evaluator has exactly one correct result (appendix instance 1). What the spec does not define is a serialized result envelope, so a reporter that flattens kind and reason into one field invents a projection. This motivates the portable disposition; it is not evidence that careful evaluators disagree.
Specification (sketch)
- Inputs — a semantically conformant pack; one JSON facts document (
fact.pathas an RFC 6901 pointer); an evidence-availability document; the evaluator's supported-extension set. - Evidence availability — one JSON object keyed by declared
evidenceRequirements[].id, each valuepresent,absent, orunknown; an omitted key meansunknown; a duplicate or undeclared key is an input error.present/absent/unknownmap to §7.5's true/false/unknown, replacing the undefined evidence manifest with a portable tri-state. - Condition semantics — the §7 preamble (
literal) and §§7.1–7.5 become normative: three-valued logic, type-preserving equality, unresolved pointers yieldunknown. - Decimal ordering — an ordered comparison is defined iff both values are JSON strings
conforming to the §2.2 decimal grammar, compared by mathematical value; any other value —
including a JSON number — yields
unknown. Units and date/time stay out. - Resolution — §8 becomes normative with its step 2 restated in §7.5's terms: record
missing-required-evidenceiff any required requirement's presence is false; recordunknowniff any required requirement's presence is unknown and none is false. Either reason blocks outcomes and the fallback and yieldsunresolvedafter exception inspection, per §8's existing order. Conflict staysunresolved, never tie-broken. The §8 step order is contractual only where it affects the disposition; it mandates no implementation algorithm. - Disposition — required member
kind∈ {outcome,not-applicable,unresolved};outcomeIdrequired iffkind=outcomeand forbidden otherwise;reasonsan unordered, deduplicated set (set equality; empty iffkind=outcome);handoff∈ {none,requested} echoing the declared target when requested. Escalation is not a result kind. - Errors are not dispositions — an unsupported required extension, a malformed input, or resource exhaustion produces an explicit evaluation error, never a disposition; corpus inputs must fit mandated minimum limits so identical corpus runs cannot diverge on limits.
Product-only, now and later: fact acquisition, evidence collection, handoff delivery, authorization, and when to evaluate.
Alternatives
- No change — viable while demand is speculative, but the committed appendix and the independently reproduced divergence on instance 7 are concrete disagreement between careful readings, and §7.5's undefined manifest guarantees it recurs in implementations.
- Result format only — standardize the disposition envelope without the semantics. Viable and architecture-aligned (a format in the specification, engines in runtimes), and the fallback position if semantics stall — but evaluators would emit well-formed, comparable, disagreeing records; instance 7 would simply serialize its divergence.
- Evaluation profile — a separately named, opt-in profile defining the class outside Core. Viable; §9 forbids only optional extensions from changing Core semantics, and a profile is how Core-versus-profile (unresolved below) would land if Core amendment proves too heavy.
- Product-only — correct for engines, but the result and its semantics are a genuine interchange need.
Compatibility
Document conformance is untouched; every existing pack remains valid against 0.1.0-draft.
Defining the class touches more than §§7–8: the Purpose and §3 openings, §3.4, §3.5's
runtime-correctness non-claim, §§6.5–6.6's "informative" cross-references, §13, and the exact
specVersion, schema, and corpus metadata must change together in the later draft — a labeled
0.x breaking change per RFC 0000. Migration: a pack needs exactly one edit, its specVersion value,
because that value is exact (Core §4); it keeps its meaning and stays valid against the preserved
0.1.0-draft schema if left unedited. Evaluator-conformance claims attach only to the later exact
specVersion; nothing is acquired automatically, and claims against 0.1.0-draft remain forbidden
permanently.
Security and privacy
Runtime facts and evidence inputs are untrusted. The three-valued semantics makes missing-data
handling deterministic and author-controlled, not safe by default: known-absent evidence is
false under the tri-state input, onUnknown: ignore deliberately lets resolution continue, and
a strong all/any can decide despite an unknown child. The portable claim is that every
evaluator degrades the same way — the pack's declared onUnknown policy, not an implementation's
guess, decides. A conformance claim will be misread as proof decisions are correct or authorized;
the §3.5 truth, authenticity, authority, and safety non-claims extend to the class unchanged,
while §3.5's "a particular runtime applied the pack correctly" bullet must be rewritten — this
class makes exactly that limited claim and no other. Dispositions leak rule and
evidence-requirement ids across trust boundaries. Silent truncation forges a disposition; limit
exhaustion must be an explicit error.
Conformance
An evaluation corpus beside the validation corpus, with its own case carrier: pack reference, facts document, evidence-availability document, supported-extension set, and expected disposition (or expected error). The appendix instances seed the first rows — instance 7's two variants pin the semantics this RFC chooses — for example:
facts:
type=data-access, completeness=complete, appropriateness=pass, embargo=false; evidence:intake-form: present, sponsor-endorsement: absent→ expected{kind: unresolved, reasons: [missing-required-evidence], handoff: requested}.
Constructed cases add hostile optional-extension content that must stay inert during evaluation, rule-order permutations that must not change any result, and error rows (unsupported required extension; undeclared evidence key).
Implementation
The first implementation exists: the Go reference runtime implements this RFC's pinned semantics
as judgment-pack experimental evaluate and the experimental_evaluate MCP tool (its ADR-0007) —
unmistakably labeled, claiming no conformance, and outside the default validation path, per the
pre-stated guardrails in tooling-architecture. The nine
appendix instances run as its acceptance tests and reproduce identically over both of its
surfaces. The specification repository still owns no executable — the contract and corpus belong
here, engines do not.
Implementation experience recorded from that first implementation:
- The restated step 2 was implementable exactly as written; instances 7a and 7b are deterministic in practice.
- Number representability is a real gap: a syntactically valid JSON number can exceed an
exact-arithmetic implementation's range (an extreme exponent), making equality undeterminable.
The implementation maps this to §7.4's "incomparable values produce
unknown" — never a silent false — but the later draft should state representability explicitly and the corpus should carry a row for it. What landed: half of that ask. Core §8.3 names this as the single seam its byte-agreement requirement does not cover and §13 keeps the choice betweenunknownand an input error open, so the corpus deliberately carries no row — a row cannot state an expected result while the result is undecided. The corpus README records the absence. - §8.1's direct exception escalation with no
escalationobject was implemented as a requested handoff with no target; the later draft should confirm that shape. Confirmed: Core §8.1 and §8.3'sstaterule both sayrequestedwith no Core-defined destination, and the corpus carries a row for it. - Honoring the declared
additionalProperties: falserequired strict wire-argument decoding; an implementation that silently drops unknown argument keys produces a silently different disposition.
The second implementation exists — published, with its interpretation log, clean-room protocol, and agreement harness, in judgment-pack-evaluator-experiments: a clean-room, stdlib-only Python evaluator written from this RFC and the Core text alone — inside an information barrier (reference texts only; no access to the first implementation, its repository, or its tools; the session log was audited afterwards), by a different model family than the first implementation's authors, on the maintainer's machine. Its interpretation log records twenty-one numbered decisions with the text each relied on. Cross-implementation result: 13/13 semantic agreement with the first implementation — identical kind, outcome, reason set, and handoff state on ten rows over the nine walked appendix instances, counting both variants of instance 7, plus three probes (omitted evidence input, decimal-string ordering, missing exception fact): thirteen in total.
Those thirteen rows are the imported part of the landed corpus. The seven rows constructed after
acceptance — the handoff subset rule, state: none, no-match with no fallback, a direct exception
escalation with no escalation object, and §7.4's ordered comparison — are not part of the 13/13
result. They were derived from the landed text and replayed through the clean-room Python evaluator
alone; the corpus README says so rather than folding them into the agreement number.
The exercise also did the other half of its job — it found a genuine underdetermination:
- The disposition's concrete serialization is not pinned. "
handoff∈ {none,requested} echoing the declared target when requested" was read by the first implementation as a handoff object carrying a state and a target echo, and by the second as a bare two-value string with no target member — the second implementer explicitly declined to "invent an extra field" and flagged the target-echo phrase as under-specified. Semantic content agreed throughout; the JSON layout did not. The later draft must specify the disposition's exact members, not just their vocabulary.
Independence caveats, recorded rather than hidden: both implementations ultimately trace to the same maintainer's direction, and this RFC's own implementation-experience notes (above) were part of the second implementer's reference text — its no-destination handoff reading cites them, so that particular convergence is corroborated rather than blind. Third-party implementation experience remains the strongest evidence this process can add. Per RFC 0000, a stable normative feature should not be accepted without evidence from two independent implementations; that bar now has its first real data.
Unresolved questions
Acceptance answered three of these and left the rest open. An answered question keeps its text, struck, with the answer beside it; nothing is deleted, because what acceptance decided is only legible next to what it was choosing between.
- ~~Core or profile — this RFC proposes the class, not its packaging; the evaluation-profile alternative above is the live counter-proposal to Core amendment.~~ Answered on acceptance: Core. RFC 0008 and any future evaluation profile both need the error contract and the disposition shape, and neither should restate them; one shared place in Core is what makes a profile additive rather than a second, competing definition. The profile alternative stays on the record as the packaging that would have been chosen had Core amendment proved too heavy.
- Evidence interchange — does the tri-state evidence-availability input grow into
RFC 0003's evidence reference, or stay minimal? Core
0.2.0-draftships the tri-state (§8.2) and records the question in §13. - ~~Beyond decimals — units and date/time must be excluded explicitly, not
unknown-by-accident.~~ Answered by §7.4 as amended: excluded explicitly. An ordered comparison is defined iff both values are §2.2 decimal strings; any other value, including a JSON number, yieldsunknown, and a unit or date/time operand is not expressible in an ordered comparison at all rather than accidentally unknown. - Number representability — is equality between syntactically valid but arithmetically
unrepresentable JSON numbers
unknown(as the first implementation chose) or an explicit input error? Still open, and now bounded rather than merely implied: §7.4 confines the cannot-compare-exactly case to JSON numbers outside an implementation's exact range, §8.3 names it as the single seam in the byte-agreement requirement, and Core §13 carries the choice itself. - ~~Disposition serialization — the exact JSON members of the disposition (in particular the
handoff state and target echo) must be pinned; two independent implementations agreed on all
semantics while serializing
handoffincompatibly.~~ Answered by §8.3: pinned, and neither implementation's shape was adopted whole.handoffis an object — the second implementer's bare string cannot carry why a handoff was requested — but it carriesstateand, when requested,triggeredBy, and it does not echo the escalation target, which was the first implementation's reading. A copy of the target would let a disposition disagree with its own pack, and §6.7 makes the target a display name rather than an address. Set members are sorted and comparison is by set equality, with RFC 8785 named for the byte-level case. - Trace minimum — must a trace surface a true rule that a forced outcome skipped? Still open; §8.3 only requires that a trace live outside the disposition and change no member of it.
- Graph interaction — the disposition is a candidate representation for
RFC 0002's partial-failure question, not the answer: whether a
downstream pack sees an unresolved upstream as
absentorunknownevidence, which requirement receives it, how outcome identity survives the mapping, and whether downstream evaluation stops or accumulates are all edge semantics RFC 0002 still owes. - Selection probe — RFC 0004's thin selection query should not consume full dispositions (they couple selection to evidence and resolution); a separately exposed tri-state applicability check would preserve the separation, and applicability is never authorization.
- Claim verification — is passing the corpus self-asserted, or must results be published? Half answered: §3.4.1 requires that a claim state the version, the corpus version, and the results obtained, and forbids a claim without corpus results — but it does not say where those results are published or who may check them, so the claim remains an attestation by the claimant.
Appendix: walked instances (non-normative)
Evidence, not specification. Pack: data-request-intake-triage.
Facts abbreviate /request/*: type (default data-access where unstated), completeness (C),
appropriateness (A), embargoedInformationToUnauthorizedRecipients (E). Evidence availability
abbreviates intake-form (IF) and sponsor-endorsement (SE). Expected dispositions follow the
sketch's chosen semantics; before that choice, instance 7a was the recorded divergence — the
original three-reader exercise split it between {unknown} and {missing-required-evidence},
and the adversarial re-walk confirmed both readings were defensible under §§7–8 as written.
| # | Facts | Evidence | Expected disposition |
|---|---|---|---|
| 1 | type=dataset-deletion, others omitted |
IF present, SE present | not-applicable, reasons {not-applicable}, handoff requested |
| 2 | type missing |
IF present, SE present | unresolved, reasons {unknown}, handoff requested |
| 3 | C=complete, A=hard-fail, E=false | IF present, SE present | outcome: decline-redirect, no handoff |
| 4 | C=incomplete, A=pass, E=false | IF present, SE present | outcome: clarify-return, no handoff |
| 5 | C=complete, A=pending, E=false | IF present, SE present | outcome: clarify-return, no handoff |
| 6 | C=complete, A=pass, E=false | IF present, SE present | outcome: proceed, no handoff |
| 7a | C=complete, A=pass, E=false | IF present, SE unknown | unresolved, reasons {unknown}, handoff requested — the recorded divergence, resolved by the sketch |
| 7b | C=complete, A=pass, E=false | IF present, SE absent | unresolved, reasons {missing-required-evidence}, handoff requested |
| 8 | C=complete, A=pass, E=true | IF present, SE present | outcome: decline-redirect (forced; normal rules skipped), no handoff |
| 9 | C=incomplete, A=hard-fail, E=false | IF present, SE present | unresolved, reasons {conflict} (decline and clarify rules both true), handoff requested |
Instance 8's forced outcome bypasses a proceed rule that would otherwise be true — the trace
question above. Instance 9 is why conflict is never tie-broken: §8's closing rules out array
order, lexical id order, and implementation-defined priority. The no-match fallback path is
unreachable for this pack while fallbackOutcome is declared; a fallback-free variant belongs in
the constructed corpus rows.