11 KiB
Foundational Family Specification: Unary State-Change Delta
Family ID: state_change.unary_delta
Status: Authorized for one future diagnostic-only implementation slice;
currently unimplemented
Related ADRs: ADR-0223, ADR-0224
Controlling authorization:
docs/sessions/unary-state-change-delta-authorization-2026-06-21.md
Serving: diagnostic_only=True, serving_allowed=False
Purpose
This family represents the smallest locally groundable state-change event: one explicit unary gain or loss cue applied to one explicit quantity/object pair.
It answers only this diagnostic question:
Does this one local clause contain enough exact evidence to ground a unary delta relation?
It does not answer a word problem and does not construct a complete state
history. It is a subordinate family beneath the broad constitutional
state_change.transition idea. The broad family remains implementation-
unauthorized because transfer, containment movement, before/after state, and
unary delta have different role geometries.
Family shape
Signature: unary_delta
Candidate organ: unary_delta_transition
Relation type: unary_delta
The proposal-first chain is:
exact action cue
→ ConstructionProposal(status="proposed")
→ exact cue + scalar/object binding
→ BoundRelation(relation_type="unary_delta")
→ ContractAssessment
→ diagnostic runnable/refused
ConstructionProposal is hypothesis only. ContractAssessment is the sole
runnable/refused authority.
Allowed cue surface
The first implementation has a closed inventory:
| Surface | Action kind | Explicit direction |
|---|---|---|
gained |
gain |
increase |
lost |
loss |
decrease |
No stemming, lemmatization, synonym expansion, semantic similarity, or broad verb classification is authorized. Exact lexical-boundary matching is allowed.
The following are explicitly outside the first inventory even when they may describe change in ordinary language:
gain, gains, gaining
lose, loses, losing
gave, received, bought, sold
ate, spent, used
put, took, moved
added, removed
grew, heated, cooled
was, became, now
Each widening requires evidence, confusers, and separate authorization.
Required roles
| Role | Type and obligation |
|---|---|
action_cue |
Exactly one source-backed GroundedUnaryDeltaCue |
delta_quantity |
Exactly one quantity mention resolving to one exact GroundedScalar |
changed_object |
Exactly one exact local object mention |
direction |
increase or decrease, carried only by the explicit authorized cue |
local_binding_relation |
Exactly one existing quantity_entity edge from delta to changed object |
local_event_containment |
Cue, quantity, and object in that order inside one sentence/clause |
provenance_span |
Exact source spans for cue, scalar, object, binding, and relation |
The first slice is count-valued. Unit/object collision refuses.
Optional and deferred roles
actor is the only catalog-visible optional SCT-1 role. It may be carried only
when exact grounded evidence already exists. The first implementation is not
required to publish it and may not add parsing to obtain it.
These are broader state-change roles, not roles in the first relation, and must not be invented:
- owner;
- source;
- target;
- before quantity;
- after quantity;
- container or location;
- temporal marker.
- unit or measurement property.
They belong to future family geometries.
Minimal typed cue
The future ProblemFrame may add one family-local frozen record:
@dataclass(frozen=True, slots=True)
class GroundedUnaryDeltaCue:
cue_id: str
surface: str
action_kind: Literal["gain", "loss"]
direction: Literal["increase", "decrease"]
span: SourceSpan
This is not a generic event IR. It cannot represent tense, modality, negation, actors, source/target, temporal ordering, causality, or arithmetic effects.
Bound relation
The future relation uses existing BoundRelation / BoundRole:
BoundRelation(
relation_type="unary_delta",
roles=(
action_cue → GroundedUnaryDeltaCue.cue_id,
delta_quantity → GroundedMention(quantity).mention_id,
changed_object → GroundedMention(object).mention_id,
),
evidence_spans=(action_span, quantity_span, object_span),
)
The relation carries no signed arithmetic operand. increase and decrease
are lexical event dispositions, not instructions to mutate state.
Evidence span rules
Every evidence span must be an exact original-text slice:
0 <= start <= end <= len(problem_text)
problem_text[start:end] == text
Additional rules:
- action, quantity, and object spans are non-overlapping;
- source order is
action < quantity < object; - no sentence terminator occurs between them;
- binding evidence is exactly
(quantity_span, object_span); - relation evidence contains only exact role spans in deterministic order;
- proposal evidence is the action cue span only;
- no span is widened, concatenated, repaired, or synthesized;
- a computed event envelope is locality telemetry only and is not a semantic evidence replacement.
Proposal conditions
A proposal may be created only when:
- exactly one authorized cue occurs;
- no second/repeated unary cue occurs;
- no explicit percent, rate, comparison, transfer, transaction, containment, actor-coordination, or list surface competes;
- the only compatible process-frame candidate is
consumption.
A cue may propose even if downstream quantity/object evidence is missing. That
is the purpose of the proposal/assessment split. Missing evidence then refuses
at ContractAssessment.
Assessment obligations
assess_unary_delta(frame) may report runnable=True only if:
- exactly one proposal exists;
- exactly one typed cue exists and is contained by proposal evidence;
- cue surface, action kind, and direction match the closed mapping;
- exactly one unary-delta bound relation exists;
- the selected delta resolves to exactly one source-grounded scalar;
- the selected changed object is exact and unambiguous;
- exactly one existing
quantity_entityedge joins them; - cue, delta, and object satisfy exact local order/containment;
- every proposal, cue, binding, role, and relation span is exact;
- no blocking context or ambiguity remains.
runnable=True means only that the diagnostic relation is role-complete. It
does not authorize a derived value, answer, state mutation, or serving path.
Refusal classes
Structural blockers
unary_delta_proposal_requiredaction_cue_unboundaction_cue_ambiguousdelta_quantity_unbounddelta_quantity_ambiguouschanged_object_unboundchanged_object_ambiguouslocal_binding_relation_unboundlocal_binding_relation_ambiguouslocal_event_containment_unprovendelta_direction_unboundunit_object_conflictprovenance_span_inexact
Ambiguity/context hazards
multiple_actor_surfacedelta_direction_ambiguoussource_target_unlicensedpronoun_antecedent_unresolvedcross_sentence_eventimplicit_total_unlicensedcomparative_contextrate_contextpercent_contextpassive_voice_unsupportedtemporal_context_ambiguouslist_context_ambiguoustransfer_unlicensedmultiple_state_change_cueschained_state_changesevent_assertion_unlicensed
No-proposal confusers do not dispatch the assessment. Direct assessment of a malformed frame remains fail-closed.
Relationship to binding.quantity_entity
The family may consume the existing exact scalar/object
MentionBinding(binding_type="quantity_entity") as grounding evidence.
It must not:
- create or require a
binding.quantity_entityproposal; - create or consume a quantity-family
QuantityKindDispositionoutside its proposal boundary; - dispatch
assess_quantity_entity(); - make a plain quantity/entity surface look eventful;
- make an event cue sufficient without the exact binding.
This separation preserves #853. Shared evidence is not shared authority.
Interaction exclusions
The family must not capture:
proportional_change.decrease_to_fraction;partition.percent_partition;- plain
binding.quantity_entity; - comparison language;
- percent or rate language;
- transfer or transaction language;
- containment movement;
- measurement changes;
- multiple or chained events.
Positive examples
Ana gained 3 marbles.
The jar lost 2 cookies.
The team gained 4 points.
For each, only cue, direction, delta quantity, and changed object are asserted. No owner, before state, after state, or result is inferred.
Negative examples
These must not propose:
There are 12 apples.
Tom has 12 apples.
Tom gave Ana 3 apples.
Tom gave her 3 apples.
Tom gave Ana some apples.
Tom had 12 apples and gave Ana 3.
Ana has 3 more apples than Tom.
20% of the apples are red.
3 apples per child.
Tom bought 3 apples and 2 oranges.
The basket was filled with apples.
The tank has 84 degrees.
There are 12 apples. Tom ate 3.
Tom and Ana each got 3 apples.
Tom moved 3 apples from the box to the bag.
The box now has 5 more pencils.
Tom put 4 shells in the bag.
Ana gained 3 apples and lost 2.
These may propose from the exact cue but must refuse:
Ana gained apples. # no explicit delta
Ana gained 3. # no changed object/binding
3 apples were gained by Ana. # passive/order topology
Ana gained 3 pounds. # unit/object collision in count-only SCT-1
Non-goals
- broad
state_change.transition; - event/story parsing;
- lemmatization or synonym expansion;
- actor/owner or pronoun resolution;
- source/target and transfer conservation;
- containment movement;
- before/after or initial/final state;
- multiple events;
- measurement-valued delta;
- arithmetic or answer production;
SemanticLedgeror derivation integration;- serving, eval/report mutation, teaching, memory, packs, policy, identity, recall, Vault, field, or algebra changes.
Implementation status and future gates
After this documentation PR:
- this family is authorized for one future bounded implementation PR;
- no code implements it;
- broad
state_change.transitionstays unauthorized; - no serving behavior changes.
Implementation requires all gates in
docs/sessions/unary-state-change-delta-preflight-2026-06-21.md, including:
- fresh-base startup guard;
- exact proposal-first ordering;
- family-local cue type only;
- full positive/confuser tests;
- no legacy semantic-state imports;
- deterministic replay;
- exact span proof;
- current proposal-first family preservation;
- train and holdout
wrong_ids == []; - no governed report changes.
Any need to widen cue inventory, parse actors, infer cross-sentence roles, or touch serving returns the work to design.