Query Semantics: Query as contract
All entries made in the ledger have to be double entries—that is, if you make one creditor, you must make someone debtor.
This chapter formalizes query semantics as Anchor A25, defining a query as a contract that produces both candidates and obligations. A25 specifies candidate standing (certified, witnessed, proposed), witness policies (strict, best-effort, exploratory), equivalence policies for cross-context joins, and a structured receipt system that makes every inclusion, exclusion, and reconciliation auditable. The formalization builds on the certification contract (A19b), predicate packages (A24), and identity maintenance (A23), unifying them into a single query-level discipline. For the narrative motivation behind treating queries as contracts rather than filters, see Vol I, Chapter 7 (The Witness Protocol).
The Hidden Contract
"Show me puffy blue dresses under $200."
A simple request. The system returns twelve items. The user scrolls, clicks, perhaps purchases. Transaction complete.
But consider what the user cannot answer:
- Which catalog was searched? The full inventory, or only items in stock? Only the user's region, or global availability?
- Which definition of "puffy" was used? The measurement-based predicate from the styling team, or the embedding-based approximation from search?
- Was "blue" an exact match or a fuzzy one? Does navy count? Does teal?
- What happens if two merchants list the same dress at different prices? Which price was used? Both? Neither?
The user cannot answer these questions because the system never stated its assumptions. The query was a request for data. The response was data. What happened in between is invisible.
This is a contract problem. The user implicitly trusted the system to do something reasonable. The system implicitly assumed the user would accept whatever it returned. Neither party stated their terms.
When the query fails quietly (returning wrong items, missing relevant items, or mixing incompatible data), neither party can diagnose why. There is no receipt.
The Query Contract
Chapter 22 defined what predicates promise: the predicate package bundles a predicate's signature, intension, runtime spec, tests, invariants, provenance, and scope. A predicate's package is its citizenship papers.
This chapter defines what queries promise. A query in the Third Mode is not a filter but a contract that specifies what the caller is asking for, what evidence the caller requires, and what the substrate guarantees in return.
Definition (A25: Query Semantics). A query produces two things:
Candidates: Items satisfying the query predicates in the referenced contexts, each with a standing label.
Obligations: A structured record of what the query assumed and what the substrate guaranteed.
The obligations make the contract explicit:
QueryObligations {
contexts_referenced: [Context, ...],
predicates_used: [(PredicatePackage, version), ...],
witnesses_required: WitnessPolicy,
uncertainty_tolerated: UncertaintyBound,
equivalence_policy: EquivalencePolicy,
invariants_enforced: [Invariant, ...],
agreement_requirements: [(predicate, contract), ...]
}
The query declares these terms. The substrate enforces them. The result includes receipts proving enforcement.
Candidate Standing
Each candidate carries a standing label. This is the missing link between "queries return results" and "queries return auditable results."
CandidateResult {
item: Item,
standing: certified | witnessed | proposed,
standing_scope: Context,
standing_kind: identity | isomorphism | approximation,
witnessed_gaps: [GapType, ...],
confidence: Option<f64>
}
| Standing | Meaning | Downstream Use |
|---|---|---|
certified | Full witness chain; passes all invariants; no gaps | Safe for downstream computation |
witnessed | Evidence present but gaps exist | Use with caveats; inspect gaps |
proposed | No witness; high-confidence proposal only | Discovery only; not for downstream |
The standing tells you how much to trust the result. A certified candidate has full provenance: every predicate evaluation is witnessed, every equivalence used in joins is certified, every invariant passed. The witnessed_gaps list is empty. A witnessed candidate has partial provenance: most of the chain is solid, but one or more links are weaker. The witnessed_gaps list tells you exactly which links: equivalence_uncertified, invariant_partial, predicate_uncertified, or agreement_untested. A proposed candidate is a hypothesis: it looks like it might satisfy the query, but the system cannot certify it.
The standing_kind is the minimum kind in the candidate's evidence chain. If one join used approximation-kind equivalence while another used identity, the candidate's overall standing_kind is approximation. The weakest link determines the ceiling.
Confidence is required for proposed candidates, optional for others. Confidence is local to the generating mechanism and not globally comparable unless calibrated across mechanisms.
Unknown is not uncertified. Unknown implies absence: no witness exists. Uncertified implies presence below threshold: a witness exists but is not fully certified. Unknown handling applies to absent evidence; witnessed standing applies to present-but-gapped evidence.
Witness Policies
The query declares its evidence standard through a witness policy.
| Policy | Meaning | Standings Included |
|---|---|---|
strict | Only certified claims | certified only |
best_effort | Certified + witnessed | certified, witnessed |
exploratory | All standings with confidence scores | All three |
Strict. Use for compliance, audit, downstream computation. Every result can be traced to witnesses. If a predicate lacks certification, its results are excluded. If an equivalence is not certified, the join refuses to proceed. The substrate guarantees that every candidate has full standing.
Best effort. Use for operational search where recall matters but auditability is required. Certified candidates come first. Witnessed candidates are included but tagged, so the caller knows which results have partial provenance. Proposed candidates are excluded.
Exploratory. Use for discovery, research, hypothesis generation. All candidates are included with confidence scores. The caller can explore what the system thinks might be relevant, knowing that proposed results are explicitly non-standing. They are hypotheses to investigate, not facts to act upon.
This ties to A19b (Certification Contract): the query specifies whether it demands certification or accepts proposals. Chapter 17's distinction between similarity and equivalence becomes operational here. Similarity can generate proposals; only certification generates standing.
Equivalence Policy
When a query joins across contexts, it uses equivalences. The product in the merchant's catalog and the product in the inventory system may be recorded differently. Are they the same product? That depends on what equivalences exist and whether the query trusts them.
The equivalence policy declares how the query handles unknowns and conflicts:
EquivalencePolicy {
equivalence_unknown_handling: reject | include_tagged | explore,
conflict_handling: fail | include_obstruction | choose_precedence(rule)
}
| Handling | Meaning |
|---|---|
reject | Exclude items where equivalence is unknown or conflicted |
include_tagged | Include with explicit tag |
include_obstruction | Include with obstruction witness attached |
choose_precedence(rule) | Apply precedence rule |
Unknown equivalences. If the query joins two contexts and no equivalence is declared for a pair of items, what happens? Under reject, those items are excluded from the join. Under include_tagged, they are included but marked with an "equivalence_unknown" tag. Under explore, they are included as candidates for investigation.
Conflicting equivalences. If one context says two items are equivalent and another says they are not, what happens? Under fail, the query fails with an obstruction witness. Under include_obstruction, the candidates are included with the obstruction witness attached, so the caller can see the conflict. Under choose_precedence, the substrate applies a declared rule (most recent, narrowest scope, highest authority) to resolve the conflict.
Precedence rules are governance. They must themselves be declared policies with provenance: author, timestamp, authority. Otherwise you reintroduce silent semantics through the back door. The precedence rule is a first-class artifact, not a hidden default.
Query Decomposition
A natural language query decomposes into structured components. Consider: "puffy blue dresses under $200, not formal."
| Component | Predicate | Type | Package | Context |
|---|---|---|---|---|
| "puffy" | puffy(x) | Score | puffy_v1 | user_session |
| "blue" | color(x) = blue | Bool | color_v3 | product_catalog |
| "dresses" | category(x) = dress | Bool | category_v2 | product_catalog |
| "under $200" | price(x) < 200 | Bool | price_v1 | merchant_view |
| "not formal" | ¬formal(x) | Bool | formal_v1 | style_taxonomy |
The query spans four contexts: user_session (where "puffy" is meaningful), product_catalog (categories and colors), merchant_view (prices), and style_taxonomy (formality). These contexts may have different records for the "same" product. The join must be explicit.
join_on: equivalent(
merchant.product,
catalog.product,
U_product_identity,
kind ≥ isomorphism
)
The full query:
Query {
filter: puffy(x) > 0.7 ∧ color(x) = blue ∧ category(x) = dress
∧ price(x) < 200 ∧ ¬formal(x),
contexts: [user_session, product_catalog, merchant_view, style_taxonomy],
predicates: [puffy_v1, color_v3, category_v2, price_v1, formal_v1],
join_on: equivalent(merchant.product, catalog.product,
U_product_identity, kind ≥ isomorphism),
witnesses: best_effort,
uncertainty: {
equivalence_kind: approximation,
score_threshold: 0.7,
unknown_handling: reject
},
equivalence_policy: {
equivalence_unknown_handling: reject,
conflict_handling: include_obstruction
},
invariants: [price > 0, category ∈ valid_categories],
agreement_requirements: [(puffy, calibrated(ε=0.05)), (formal, decidable)]
}
This is T6 (puffy, an invented predicate), T7 (contextual equivalence for "same dress" across merchants), and T8 (subjective "formal" predicate) in one query. Each has explicit semantics. None is silent.
T6: Puffy in Query
The query references puffy_v1, the predicate package from Chapter 22. The package specifies that puffy is a measurement-based score with a calibrated test suite and known exemplar coverage.
The query declares:
- Version: puffy_v1 (pinned, not "latest")
- Threshold: > 0.7
- Agreement requirement: calibrated(ε=0.05)
If puffy has been versioned to puffy_v2 since the query was written, the substrate does not silently substitute. It either uses the pinned version or emits a version drift warning. The query can accept drift or fail; silent substitution is forbidden.
The agreement requirement specifies that if puffy is evaluated in multiple contexts, the values must agree within ε=0.05 on overlapping items. If merchant A's puffy score is 0.8 and merchant B's is 0.72, they agree. If merchant A's is 0.8 and merchant B's is 0.5, that is an agreement failure. The substrate produces an obstruction witness.
The query may only tighten (require stricter than) the predicate package's agreement contract, never weaken. If the query requests incompatible requirements (demanding decidable for a probabilistic-bound predicate), the query fails with an obstruction witness. Silent weakening is forbidden.
T7: Contextual Equivalence in Join
The query joins merchant_view and product_catalog. Both contexts contain product records. Are the records for the "same" product?
The query declares:
- Equivalence scope: U_product_identity
- Equivalence kind: ≥ isomorphism
- Unknown handling: reject
- Conflict handling: include_obstruction
The join clause is explicit:
join_on: equivalent(merchant.product, catalog.product,
U_product_identity, kind ≥ isomorphism)
If no equivalence is declared for a pair of products, the substrate excludes them from the join. The query will not silently conflate or silently separate. If equivalences exist but conflict (merchant A says two records are the same product; merchant B says they are different), the substrate includes the obstruction witness so the caller can see the disagreement.
This is Chapter 21's identity maintenance becoming operational. The context graph stores equivalence declarations. The query consults them. Joins are auditable.
T8: Subjective Predicate Resolution
"Formal" is a subjective predicate. Different contexts may define it differently. The fashion taxonomy's "formal" may differ from a wedding planner's "formal."
The query declares which context's "formal" to use: style_taxonomy. But what if multiple packages exist for "formal" in the query's contexts?
The substrate uses package resolution:
resolve_package(formal, query_contexts, intension_constraints, scope_constraints)
→ PredicatePackage | AmbiguityWitness
If resolution is unambiguous, the substrate uses the matching package. If multiple packages match (formal_fashion vs formal_events), the substrate returns AmbiguityWitness. The query must then:
- Specify which package explicitly
- Accept the substrate's precedence rule
- Fail with explicit ambiguity error
Silent resolution is forbidden. The query knows exactly which definition of "formal" was used, or it knows that ambiguity prevented resolution.
The Substrate's Promises
The substrate makes seven promises:
-
Scope fidelity. Results come only from declared contexts. The substrate will not silently expand scope to improve recall.
-
Version pinning. Predicates are evaluated at declared versions. If a predicate has been versioned, the substrate uses the pinned version or emits a migration notice.
-
Witness compliance. Results satisfy the witness policy. Each candidate carries a standing label. The result set respects the policy filter.
-
Uncertainty bounds. Results satisfy uncertainty bounds. If a score predicate's value is below threshold, the item is excluded or tagged per policy.
-
Equivalence compliance. Joins use declared equivalence scope and kind. Unknown equivalences and conflicts are handled per equivalence policy.
-
Invariant enforcement. Hard invariants are checked on results. Violations are excluded or surfaced as constraint conflicts.
-
Agreement on overlaps. If contexts overlap, predicate values are reconciled per agreement requirements. Failures produce obstruction witnesses.
These are not aspirations. They are enforceable. The result includes receipts proving each promise was kept.
Exclusions and Receipts
The query result includes not just candidates but the audit trail:
QueryResult {
candidates: [CandidateResult, ...],
obligations: QueryObligations,
receipts: {
contexts_consulted: [Context, ...],
predicate_evaluations: [(item, predicate, value, witness?, standing), ...],
equivalences_used: [(item_pair, equivalence, scope, kind), ...],
invariants_checked: [(invariant, status), ...],
agreement_reconciliations: [(overlap, predicate, status), ...]
},
exclusions: [
{ item: Item, reason: ExclusionReason, witness_ref: Option<Witness> }
],
warnings: [...]
}
Exclusions matter. Knowing what was excluded is as important as knowing what was included. The exclusions ledger tells you:
| Reason | Meaning |
|---|---|
below_threshold | Score predicate below declared threshold |
invariant_violation | Failed hard invariant check |
equivalence_unknown | Join failed due to unknown equivalence |
equivalence_conflict | Join failed due to conflicting equivalences |
agreement_failure | Overlap reconciliation failed |
standing_insufficient | Only proposed standing under strict policy |
If a dress was excluded because its puffy score was 0.65 (below the 0.7 threshold), the exclusions ledger records this. If a dress was excluded because two merchants disagreed about whether it was the same product, the exclusions ledger records this with the obstruction witness.
Receipts are summaries, not traces. The substrate stores witness references and evaluation keys, not replayed computations. References are stable IDs: witness hashes, evaluation keys, package version IDs. These enable audit without replay: given a receipt, a verifier can retrieve and check the referenced artifacts independently. Receipts are priced by the coherence budget (A21). They are cheap enough to always include, detailed enough to always audit.
Filter vs Contract
| Aspect | Query as Filter | Query as Contract |
|---|---|---|
| Scope | Implicit | Explicit (declared contexts) |
| Predicates | Implicit (current versions) | Explicit (pinned packages) |
| Witnesses | None required | Policy declared; standings labeled |
| Uncertainty | Hidden | Bounded and tagged |
| Equivalences | Silent join | Explicit scope, kind, policy |
| Invariants | Unchecked | Enforced and reported |
| Overlaps | Silent conflicts | Agreement or obstruction |
| Exclusions | Invisible | Logged with reasons |
| Audit | Impossible | Receipts included |
The filter model assumes the caller trusts the system. The contract model assumes the caller wants to verify.
Consequence
Chapter 22 defined what predicates promise: the package.
Chapter 23 defined what queries promise: the contract.
Together, they make the Third Mode auditable. Every predicate has citizenship papers specifying its signature, intension, runtime spec, tests, invariants, provenance, and scope. Every query has a contract specifying its contexts, predicates, witnesses, uncertainty bounds, equivalence policy, invariants, and agreement requirements. Every result has standing: certified, witnessed, or proposed. Every exclusion has a reason. Every evaluation has a receipt.
The Two Empires had different failure modes. String-dominant systems failed silently: they returned results, but nobody could trace why. Schema-dominant systems failed loudly but inflexibly: they enforced constraints, but those constraints were frozen in schema design.
The Third Mode fails explicitly. When a query cannot be satisfied, it says why. When results have partial standing, they are tagged. When equivalences conflict, obstruction witnesses are produced. When predicates drift, version warnings are emitted.
Explicit failure is not a bug but the price of auditability.
Chapter 24 asks the next question: how do predicates and queries survive time? Versioning, compatibility, and operational coherence.