docs(kernel): authorize unary state-change delta slice
This commit is contained in:
parent
ca83d3846c
commit
7ee849970b
4 changed files with 1453 additions and 0 deletions
|
|
@ -769,3 +769,44 @@ counts. That PR is the explicit authorization boundary for this rebaseline.
|
||||||
|
|
||||||
### Workbench / UI Alignment Scope Note
|
### Workbench / UI Alignment Scope Note
|
||||||
The alignment scope for the CORE Workbench/UI under the latest proposal-first pivots is documented in `docs/sessions/workbench-proposal-first-alignment-scope-2026-06-20.md`. This is a docs-only session note that identifies UI gaps, non-goals, future acceptance criteria, and next PR briefs to align the frontend observatory with the backend's proposal-first and contract assessment authority architecture.
|
The alignment scope for the CORE Workbench/UI under the latest proposal-first pivots is documented in `docs/sessions/workbench-proposal-first-alignment-scope-2026-06-20.md`. This is a docs-only session note that identifies UI gaps, non-goals, future acceptance criteria, and next PR briefs to align the frontend observatory with the backend's proposal-first and contract assessment authority architecture.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Unary state-change delta authorization pointer
|
||||||
|
|
||||||
|
The 2026-06-21 design investigation found that broad
|
||||||
|
`state_change.transition` is not one safe organ. It combines unary delta,
|
||||||
|
binary transfer, containment movement, and before/after state topology.
|
||||||
|
|
||||||
|
Authorized for one future diagnostic-only implementation PR:
|
||||||
|
|
||||||
|
- `state_change.unary_delta` only;
|
||||||
|
- exact cue inventory `gained → increase`, `lost → decrease`;
|
||||||
|
- one exact scalar/object `quantity_entity` edge;
|
||||||
|
- one family-local exact action-cue record;
|
||||||
|
- `ConstructionProposal(status="proposed")` before binding;
|
||||||
|
- `ContractAssessment` as the sole runnable/refused authority;
|
||||||
|
- `diagnostic_only=True`, `serving_allowed=False`.
|
||||||
|
|
||||||
|
Explicitly not authorized: broad `state_change.transition`, transfer,
|
||||||
|
containment, before/after state, measurement delta, actor/owner inference,
|
||||||
|
coreference, cross-sentence binding, arithmetic, answers, serving, derivation
|
||||||
|
ledger integration, or quantity-family widening.
|
||||||
|
|
||||||
|
Controlling artifacts:
|
||||||
|
|
||||||
|
- `docs/sessions/unary-state-change-delta-authorization-2026-06-21.md`
|
||||||
|
- `docs/sessions/unary-state-change-delta-preflight-2026-06-21.md`
|
||||||
|
- `docs/specs/foundational-families/unary-state-change-delta.md`
|
||||||
|
|
||||||
|
The next PR should implement the preflight's copy-paste brief. Stop if it
|
||||||
|
requires changes to `_quantity_entity_proposals()`,
|
||||||
|
`_quantity_kind_dispositions()`, `generate.derivation.state`, actor/owner
|
||||||
|
parsing, a broader cue inventory, synthetic spans, serving paths, or any
|
||||||
|
non-empty wrong-ID list.
|
||||||
|
|
||||||
|
Validation performed in the fresh worktree: startup guard passed with
|
||||||
|
`HEAD == origin/main == ca83d384`; baseline and post-doc
|
||||||
|
`uv run python -m core.cli test --suite smoke -q` completed successfully;
|
||||||
|
requested positive/confuser ProblemFrame probes were run read-only;
|
||||||
|
`git diff --check` passed. No subagents were used.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,477 @@
|
||||||
|
# Authorization: Unary State-Change Delta Foundational Slice
|
||||||
|
|
||||||
|
**Status:** Authorized for one future diagnostic-only implementation PR after
|
||||||
|
this authorization PR merges
|
||||||
|
**Date:** 2026-06-21
|
||||||
|
**Authorized family:** `state_change.unary_delta`
|
||||||
|
**Broad family:** `state_change.transition` remains unauthorized and
|
||||||
|
unimplemented
|
||||||
|
**Serving status:** `diagnostic_only=True`, `serving_allowed=False`
|
||||||
|
**Governing doctrine:** ADR-0223, ADR-0224, PRs #851 and #853
|
||||||
|
|
||||||
|
## 1. Decision
|
||||||
|
|
||||||
|
Do not implement the broad `state_change.transition` family next.
|
||||||
|
|
||||||
|
Authorize only `state_change.unary_delta`: one explicit, local, count-valued
|
||||||
|
gain or loss event over one exactly grounded quantity/object pair. The first
|
||||||
|
cue inventory is deliberately closed:
|
||||||
|
|
||||||
|
| Exact cue | Direction disposition |
|
||||||
|
|---|---|
|
||||||
|
| `gained` | `increase` |
|
||||||
|
| `lost` | `decrease` |
|
||||||
|
|
||||||
|
The authorized construction recognizes that an explicit delta event is locally
|
||||||
|
present. It does not construct a before state, after state, owner state,
|
||||||
|
transfer, containment move, arithmetic equation, answer, or serving action.
|
||||||
|
|
||||||
|
The safe first relation is:
|
||||||
|
|
||||||
|
```text
|
||||||
|
one exact action cue
|
||||||
|
+ one exact scalar mention
|
||||||
|
+ one exact changed-object mention
|
||||||
|
+ one exact local quantity_entity edge
|
||||||
|
------------------------------------------------
|
||||||
|
one proposed unary-delta relation, assessed diagnostically
|
||||||
|
```
|
||||||
|
|
||||||
|
This is the exact capability unlocked by the hardened quantity-entity seam:
|
||||||
|
CORE can now distinguish a quantity-bearing object from an unbound number. The
|
||||||
|
next valid step is to bind that grounded pair to one explicit local change cue,
|
||||||
|
not to parse an entire story.
|
||||||
|
|
||||||
|
## 2. Serious design finding
|
||||||
|
|
||||||
|
`state_change.transition` is not one organ. The current constitutional spec
|
||||||
|
combines at least four distinct geometries:
|
||||||
|
|
||||||
|
1. unary delta: `gained/lost N object`;
|
||||||
|
2. containment movement: `put/took N object in/from container`;
|
||||||
|
3. binary transfer: `gave/sent N object to target`;
|
||||||
|
4. before/after state relation: `was N, now M`.
|
||||||
|
|
||||||
|
They do not share the same role topology. Unary delta has one changed object and
|
||||||
|
one signed delta. Transfer has at least two state owners plus a conservation
|
||||||
|
relation. Containment movement has source/target containers. Before/after has
|
||||||
|
two temporal states and may have no delta cue at all. Treating these as one
|
||||||
|
family would force optional roles to carry the semantics and would make illegal
|
||||||
|
partial states representable.
|
||||||
|
|
||||||
|
The current code confirms the split:
|
||||||
|
|
||||||
|
- `ProblemFrame` can expose exact scalar/object mentions and
|
||||||
|
`MentionBinding(binding_type="quantity_entity")` for `Ana gained 3 marbles.`;
|
||||||
|
- it does not expose a typed exact event/action cue or a bound unary-delta
|
||||||
|
relation;
|
||||||
|
- it already contains a separate narrow `BoundRelation(relation_type="transfer")`
|
||||||
|
regex path for `Tom gave Ana 3 apples.`;
|
||||||
|
- `generate.derivation.state` contains a legacy arithmetic-oriented
|
||||||
|
`SemanticLedger`, but it uses a different raw-text path, float quantities,
|
||||||
|
loose subject/pronoun continuation, and a replay bridge to derivation
|
||||||
|
candidates. It is not suitable as exact `ProblemFrame` grounding evidence.
|
||||||
|
|
||||||
|
Reusing the transfer relation would silently define every change as transfer.
|
||||||
|
Reusing the semantic ledger would bypass the proposal-first substrate and
|
||||||
|
couple diagnostic recognition to arithmetic candidate production. Both are
|
||||||
|
rejected.
|
||||||
|
|
||||||
|
## 3. Map: directions considered
|
||||||
|
|
||||||
|
The intrinsic space is not a story. It is a typed local event relation over an
|
||||||
|
already grounded scalar/object edge, with exact source coordinates and a
|
||||||
|
conjugate assessment that refuses incomplete topology.
|
||||||
|
|
||||||
|
| Direction | Structural effect | Decision |
|
||||||
|
|---|---|---|
|
||||||
|
| Implement broad `state_change.transition` | Mixes unary delta, transfer, containment, and temporal-state topology | Rejected |
|
||||||
|
| Reuse `generate.derivation.state.SemanticLedger` | Bypasses `ProblemFrame`; imports legacy raw parsing and arithmetic candidate semantics | Rejected |
|
||||||
|
| Add event-cue proposals only, with no closable relation | Safe but does not prove the new quantity/entity seam composes into a useful organ | Deferred as an internal stage, not the family boundary |
|
||||||
|
| Add one unary-delta relation over exact local evidence | Preserves proposal → grounding → assessment and has a closed first topology | Selected |
|
||||||
|
|
||||||
|
## 4. Safe capability ladder
|
||||||
|
|
||||||
|
The broad family is split into separately authorized rungs:
|
||||||
|
|
||||||
|
| Rung | Family | Status after this PR |
|
||||||
|
|---|---|---|
|
||||||
|
| SCT-0 | exact local action-cue publication | Internal prerequisite to SCT-1; no independent serving or assessment authority |
|
||||||
|
| SCT-1 | `state_change.unary_delta` | Authorized for one future diagnostic implementation PR |
|
||||||
|
| SCT-2 | containment movement | Not authorized |
|
||||||
|
| SCT-3 | binary transfer | Not authorized |
|
||||||
|
| SCT-4 | before/after state relation | Not authorized |
|
||||||
|
| SCT-5 | arithmetic state equation or answer production | Not authorized |
|
||||||
|
|
||||||
|
`state_change.transition` remains the broad constitutional umbrella only. Its
|
||||||
|
existing foundational registry entry must remain
|
||||||
|
`implementation_authorized=False`.
|
||||||
|
|
||||||
|
## 5. Why now, and why only after #853
|
||||||
|
|
||||||
|
#851 proved that a local quantity/object edge can be proposed, grounded, and
|
||||||
|
assessed. #853 then closed two authority leaks:
|
||||||
|
|
||||||
|
- `ConstructionProposal` can represent only `status="proposed"`;
|
||||||
|
- quantity-kind dispositions are emitted only inside their exact proposal
|
||||||
|
boundary, so no-proposal percent, rate, pronoun, list, or transfer confusers
|
||||||
|
receive quantity-family authority.
|
||||||
|
|
||||||
|
Those corrections are prerequisites. A state-change slice built before #853
|
||||||
|
could have mistaken proposal state for an assessment verdict or consumed a
|
||||||
|
quantity-kind disposition synthesized for a confuser. This authorization
|
||||||
|
therefore treats #853's hardened seam as immutable:
|
||||||
|
|
||||||
|
- no proposal carries `runnable`, `refused`, missing-role, or hazard authority;
|
||||||
|
- `ContractAssessment` is the sole diagnostic runnable/refused authority;
|
||||||
|
- the unary family must not widen `_quantity_entity_proposals()`;
|
||||||
|
- the unary family must not widen `_quantity_kind_dispositions()`;
|
||||||
|
- a raw `MentionBinding` may be consumed as grounding evidence, but the
|
||||||
|
`binding.quantity_entity` proposal and assessment are not backdoored.
|
||||||
|
|
||||||
|
## 6. Family metadata
|
||||||
|
|
||||||
|
| Field | Authorized value |
|
||||||
|
|---|---|
|
||||||
|
| `family_id` | `state_change.unary_delta` |
|
||||||
|
| display name | Unary state-change delta |
|
||||||
|
| relation type | `unary_delta` |
|
||||||
|
| candidate organ | `unary_delta_transition` |
|
||||||
|
| proposal status | Always `proposed` |
|
||||||
|
| diagnostic posture | `diagnostic_only=True` |
|
||||||
|
| serving posture | `serving_allowed=False` |
|
||||||
|
| implementation authorization | Authorized only by this merged document for one future bounded PR |
|
||||||
|
| implementation status after this docs PR | Unimplemented; no runtime registry/catalog/dispatch change |
|
||||||
|
| relation to `binding.quantity_entity` | Consumes a compatible exact local `quantity_entity` edge; does not require or create its proposal, disposition, or assessment |
|
||||||
|
|
||||||
|
The future implementation may add a new descriptive foundational registry
|
||||||
|
entry for `state_change.unary_delta`. It must not flip the existing broad
|
||||||
|
`state_change.transition` entry to authorized.
|
||||||
|
|
||||||
|
## 7. Authority gradient
|
||||||
|
|
||||||
|
The only authorized flow is:
|
||||||
|
|
||||||
|
```text
|
||||||
|
exact lexical cue (`gained` or `lost`)
|
||||||
|
→ ConstructionProposal(
|
||||||
|
family_id="state_change.unary_delta",
|
||||||
|
status="proposed",
|
||||||
|
diagnostic_only=True,
|
||||||
|
serving_allowed=False,
|
||||||
|
)
|
||||||
|
→ exact GroundedActionCue
|
||||||
|
→ existing exact GroundedScalar / GroundedMention / quantity_entity binding
|
||||||
|
→ BoundRelation(relation_type="unary_delta")
|
||||||
|
→ assess_unary_delta(frame)
|
||||||
|
→ ContractAssessment(runnable or refused)
|
||||||
|
```
|
||||||
|
|
||||||
|
The proposal is a hypothesis only. Exact role bindings ground it. The
|
||||||
|
assessment is its corrective/conjugate and is the only runnable/refused
|
||||||
|
authority. No step derives an answer.
|
||||||
|
|
||||||
|
## 8. Minimum evidence tuple
|
||||||
|
|
||||||
|
A proposed candidate may close only from this tuple:
|
||||||
|
|
||||||
|
```text
|
||||||
|
(
|
||||||
|
action_cue_span,
|
||||||
|
action_kind,
|
||||||
|
explicit_direction,
|
||||||
|
delta_quantity_mention,
|
||||||
|
changed_object_mention,
|
||||||
|
quantity_entity_binding,
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
Every member is source-backed. Every `SourceSpan` must satisfy:
|
||||||
|
|
||||||
|
```text
|
||||||
|
problem_text[span.start:span.end] == span.text
|
||||||
|
```
|
||||||
|
|
||||||
|
No composite or synthetic span may be manufactured by concatenating role
|
||||||
|
surfaces. A contiguous event envelope may be computed as offsets for locality
|
||||||
|
checking, but it is not a new semantic fact and must not replace the individual
|
||||||
|
role spans.
|
||||||
|
|
||||||
|
## 9. Required roles
|
||||||
|
|
||||||
|
| Role | Requirement |
|
||||||
|
|---|---|
|
||||||
|
| `action_cue` | Exactly one exact `gained` or `lost` span |
|
||||||
|
| `changed_object` | Exactly one local object mention targeted by the selected quantity/entity edge |
|
||||||
|
| `delta_quantity` | Exactly one source-grounded scalar mention |
|
||||||
|
| `direction` | Required in SCT-1 because the authorized cue itself explicitly states `increase` or `decrease`; it may not be inferred from context |
|
||||||
|
| `local_binding_relation` | Exactly one `MentionBinding(binding_type="quantity_entity")` joining the selected delta to the changed object |
|
||||||
|
| `local_event_containment` | Cue, quantity, and object occur in that order in one sentence/clause with no sentence boundary |
|
||||||
|
| `provenance_span` | Exact action, quantity, object, and binding evidence spans |
|
||||||
|
|
||||||
|
SCT-1 is count-valued only. A quantity/unit/object span collision, including
|
||||||
|
`3 pounds` where `pounds` is both unit and object under current extraction,
|
||||||
|
refuses. Measurement-valued state change requires a separate extension after
|
||||||
|
unit/property topology is designed.
|
||||||
|
|
||||||
|
## 10. Optional and deferred roles that must not be invented
|
||||||
|
|
||||||
|
`actor` is the only optional SCT-1 role. It may be carried only when an exact
|
||||||
|
actor mention is already grounded by the existing frame; the implementation is
|
||||||
|
not authorized to widen actor extraction to obtain it. Its absence does not
|
||||||
|
block the relation and does not license an owner inference.
|
||||||
|
|
||||||
|
The following are optional in the broader state-change problem space but are
|
||||||
|
not representable by SCT-1 at all:
|
||||||
|
|
||||||
|
- source;
|
||||||
|
- target;
|
||||||
|
- before quantity;
|
||||||
|
- after quantity;
|
||||||
|
- container or location;
|
||||||
|
- temporal marker;
|
||||||
|
- unit/measurement property.
|
||||||
|
|
||||||
|
Their presence therefore refuses or routes to a future family. In particular,
|
||||||
|
`Ana` in `Ana gained 3 marbles.` is not automatically asserted as a state owner.
|
||||||
|
SCT-1 asserts only that the local text contains an increase cue over the
|
||||||
|
explicitly quantified object `marbles`.
|
||||||
|
|
||||||
|
## 11. Non-inference rule
|
||||||
|
|
||||||
|
The family cannot infer or compute:
|
||||||
|
|
||||||
|
- an implicit source or target;
|
||||||
|
- a pronoun antecedent;
|
||||||
|
- a cross-sentence event binding;
|
||||||
|
- an initial, before, final, or after quantity;
|
||||||
|
- a total, remainder, result, or answer;
|
||||||
|
- a transfer partner or conservation law;
|
||||||
|
- ownership or possession continuity;
|
||||||
|
- a containment path;
|
||||||
|
- arithmetic sign application (`+N` or `-N`) to stored state;
|
||||||
|
- that `gave` subtracts from a giver or adds to a receiver;
|
||||||
|
- that `put` moves an object into a container;
|
||||||
|
- that `bought`, `received`, `ate`, `spent`, `added`, or `removed` are synonyms
|
||||||
|
for an authorized cue;
|
||||||
|
- any event hidden behind passive voice, negation, modality, or temporal order.
|
||||||
|
|
||||||
|
Unknown is not false. Missing or ambiguous evidence refuses.
|
||||||
|
|
||||||
|
## 12. Relationship to quantity/entity grounding
|
||||||
|
|
||||||
|
The relationship is monotonic but non-authoritative:
|
||||||
|
|
||||||
|
1. Existing `GroundedScalar`, `GroundedMention`, and
|
||||||
|
`MentionBinding(binding_type="quantity_entity")` may ground the delta and
|
||||||
|
changed-object roles.
|
||||||
|
2. The presence of such a binding does not imply an event. `There are 12
|
||||||
|
apples.` remains only a quantity/entity construction.
|
||||||
|
3. The presence of an event cue does not imply a valid delta relation. `Ana
|
||||||
|
gained apples.` lacks an explicit quantity and must refuse.
|
||||||
|
4. A unary-delta proposal does not create a `binding.quantity_entity` proposal,
|
||||||
|
`QuantityKindDisposition`, or quantity-entity assessment.
|
||||||
|
5. The quantity-entity family does not create a unary-delta proposal.
|
||||||
|
6. No-proposal quantity-entity confusers must continue to have no
|
||||||
|
quantity-kind disposition, exactly as hardened by #853.
|
||||||
|
|
||||||
|
## 13. Interaction safety with existing families
|
||||||
|
|
||||||
|
The future implementation must preserve these families byte-for-byte in
|
||||||
|
behavior and authority:
|
||||||
|
|
||||||
|
- `proportional_change.decrease_to_fraction`;
|
||||||
|
- `partition.percent_partition`;
|
||||||
|
- `binding.quantity_entity`.
|
||||||
|
|
||||||
|
Unary delta must not propose when any of these competing surfaces are active:
|
||||||
|
|
||||||
|
- percent or percentage;
|
||||||
|
- rate, `per`, or `each`;
|
||||||
|
- comparison (`more than`, `less than`, `fewer than`, `times as`);
|
||||||
|
- proportional `decrease to`, `decrease by`, or fraction-scale language;
|
||||||
|
- plain quantity/entity binding with no authorized action cue;
|
||||||
|
- transfer, transaction, or containment movement;
|
||||||
|
- list/enumeration topology;
|
||||||
|
- more than one state-change cue.
|
||||||
|
|
||||||
|
The generic `consumption` process-frame candidate may coexist because `gained`
|
||||||
|
and `lost` currently surface it. No other process-frame family may coexist in
|
||||||
|
the first slice. The process frame is candidate context only; it is not the
|
||||||
|
proposal, relation, or assessment authority.
|
||||||
|
|
||||||
|
## 14. ContractAssessment obligations
|
||||||
|
|
||||||
|
The future `assess_unary_delta(frame)` may report `runnable=True` only when:
|
||||||
|
|
||||||
|
- exactly one unary-delta proposal exists;
|
||||||
|
- exactly one authorized exact action cue exists;
|
||||||
|
- exactly one scalar mention and one compatible quantity/entity binding exist;
|
||||||
|
- the binding selects exactly one changed object;
|
||||||
|
- the cue direction is explicit and unambiguous;
|
||||||
|
- cue, delta, and object are ordered locally in one sentence/clause;
|
||||||
|
- all role and relation spans are exact slices of `problem_text`;
|
||||||
|
- no unit/object collision exists;
|
||||||
|
- no competing family, actor coordination, object list, negation, modality,
|
||||||
|
passive voice, temporal ambiguity, or second change cue is present.
|
||||||
|
|
||||||
|
The proposal must remain `status="proposed"` whether the assessment is runnable
|
||||||
|
or refused. A proposal-free frame must not dispatch the unary-delta contract.
|
||||||
|
The assessment grants diagnostic readiness only, never serving authority.
|
||||||
|
|
||||||
|
## 15. Stable refusal taxonomy
|
||||||
|
|
||||||
|
The first implementation must use stable organ-specific blocker/hazard codes.
|
||||||
|
The exact storage field follows current `ContractAssessment` conventions;
|
||||||
|
missing structural evidence belongs in `missing_bindings`, while active
|
||||||
|
ambiguity/context belongs in `unresolved_hazards`.
|
||||||
|
|
||||||
|
| Class | Required code | Expected locus |
|
||||||
|
|---|---|---|
|
||||||
|
| missing event cue | `unary_delta_proposal_required` / no proposal | No dispatch |
|
||||||
|
| missing quantity | `delta_quantity_unbound` | Proposed then refused |
|
||||||
|
| missing changed object | `changed_object_unbound` | Proposed then refused |
|
||||||
|
| multiple actors/coordination | `multiple_actor_surface` | No proposal or refused |
|
||||||
|
| multiple objects/list | `changed_object_ambiguous` / `list_context_ambiguous` | No proposal or refused |
|
||||||
|
| ambiguous direction | `delta_direction_ambiguous` | Refused |
|
||||||
|
| source/target ambiguity | `source_target_unlicensed` | Refused |
|
||||||
|
| pronoun without exact antecedent | `pronoun_antecedent_unresolved` | Refused |
|
||||||
|
| cross-sentence event | `cross_sentence_event` | Refused |
|
||||||
|
| implicit total | `implicit_total_unlicensed` | No proposal or refused |
|
||||||
|
| comparative phrasing | `comparative_context` | No proposal |
|
||||||
|
| rate phrasing | `rate_context` | No proposal |
|
||||||
|
| percent phrasing | `percent_context` | No proposal |
|
||||||
|
| unit conflict | `unit_object_conflict` | Refused |
|
||||||
|
| passive voice | `passive_voice_unsupported` | Refused |
|
||||||
|
| temporal ambiguity | `temporal_context_ambiguous` | Refused |
|
||||||
|
| quantity/entity binding but no event | no unary proposal or assessment | No dispatch |
|
||||||
|
| event cue but no grounded pair | `local_binding_relation_unbound` | Proposed then refused |
|
||||||
|
| transfer verb without explicit roles | `transfer_unlicensed` / no unary proposal | No dispatch |
|
||||||
|
| two state changes | `multiple_state_change_cues` | No proposal |
|
||||||
|
| chained state changes | `chained_state_changes` | No proposal |
|
||||||
|
| inexact/synthetic evidence | `provenance_span_inexact` | Refused |
|
||||||
|
| negated or modal event | `event_assertion_unlicensed` | Refused |
|
||||||
|
|
||||||
|
No blocker may be silently repaired by choosing the nearest mention.
|
||||||
|
|
||||||
|
## 16. Tiny positive seed set
|
||||||
|
|
||||||
|
These are illustrative future fixtures, not implementation in this PR:
|
||||||
|
|
||||||
|
| Surface | Expected diagnostic roles |
|
||||||
|
|---|---|
|
||||||
|
| `Ana gained 3 marbles.` | cue=`gained`, direction=`increase`, delta=`3`, changed_object=`marbles` |
|
||||||
|
| `The jar lost 2 cookies.` | cue=`lost`, direction=`decrease`, delta=`2`, changed_object=`cookies` |
|
||||||
|
| `The team gained 4 points.` | cue=`gained`, direction=`increase`, delta=`4`, changed_object=`points` |
|
||||||
|
|
||||||
|
The subject is not asserted as owner or actor. The result is not computed.
|
||||||
|
|
||||||
|
## 17. Negative and confuser set
|
||||||
|
|
||||||
|
The future PR must prove these dispositions:
|
||||||
|
|
||||||
|
| Surface | Required result |
|
||||||
|
|---|---|
|
||||||
|
| `There are 12 apples.` | No unary proposal: binding exists, event absent |
|
||||||
|
| `Tom has 12 apples.` | No unary proposal: state description, not change |
|
||||||
|
| `Tom gave Ana 3 apples.` | No unary proposal: binary transfer is deferred |
|
||||||
|
| `Tom gave her 3 apples.` | No unary proposal: transfer plus unresolved pronoun |
|
||||||
|
| `Tom gave Ana some apples.` | No unary proposal: no explicit quantity |
|
||||||
|
| `Tom had 12 apples and gave Ana 3.` | No unary proposal: transfer and unbound changed object |
|
||||||
|
| `Ana has 3 more apples than Tom.` | No unary proposal: comparison |
|
||||||
|
| `20% of the apples are red.` | No unary proposal: percent partition surface |
|
||||||
|
| `3 apples per child.` | No unary proposal: rate |
|
||||||
|
| `Tom bought 3 apples and 2 oranges.` | No unary proposal: transaction and list ambiguity |
|
||||||
|
| `The basket was filled with apples.` | No unary proposal: passive containment, no quantity |
|
||||||
|
| `The tank has 84 degrees.` | No unary proposal; existing quantity assessment remains refused |
|
||||||
|
| `There are 12 apples. Tom ate 3.` | No unary proposal: disallowed cue and cross-sentence binding |
|
||||||
|
| `Tom and Ana each got 3 apples.` | No unary proposal: multiple actors/rate-like `each` |
|
||||||
|
| `Tom moved 3 apples from the box to the bag.` | No unary proposal: containment movement |
|
||||||
|
| `The box now has 5 more pencils.` | No unary proposal: comparison/current-state surface |
|
||||||
|
| `Tom put 4 shells in the bag.` | No unary proposal: containment movement |
|
||||||
|
| `Ana gained apples.` | Proposal may exist; assessment refuses missing quantity |
|
||||||
|
| `Ana gained 3.` | Proposal may exist; assessment refuses missing object/binding |
|
||||||
|
| `Ana gained 3 apples and lost 2.` | No proposal: two/chained state-change cues |
|
||||||
|
| `Ana did not gain 3 apples.` | No proposal because `gain` is outside v1; future widening must also preserve negation refusal |
|
||||||
|
| `3 apples were gained by Ana.` | Proposal may exist; assessment refuses passive/order topology |
|
||||||
|
| `Ana gained 3 pounds.` | Proposal may exist; assessment refuses unit/object collision in count-only SCT-1 |
|
||||||
|
|
||||||
|
## 18. Explicit non-authorization
|
||||||
|
|
||||||
|
This PR does not authorize:
|
||||||
|
|
||||||
|
- `state_change.transition` implementation;
|
||||||
|
- the existing broad `state-change.md` required-role topology;
|
||||||
|
- source/target, ownership, possession, or conservation modeling;
|
||||||
|
- `gave`, `received`, `bought`, `sold`, `ate`, `spent`, `put`, `took`, `moved`,
|
||||||
|
`added`, or `removed` cues;
|
||||||
|
- initial/final or before/after state binding;
|
||||||
|
- measurement-valued delta events;
|
||||||
|
- multiple events, multiple quantities, multiple objects, or coordinated actors;
|
||||||
|
- pronoun/coreference resolution;
|
||||||
|
- cross-sentence inference;
|
||||||
|
- `SemanticLedger` integration or derivation candidate production;
|
||||||
|
- arithmetic, answer production, eval score movement, report mutation, serving,
|
||||||
|
teaching, memory, policy, identity, recall, Vault, field, or algebra changes.
|
||||||
|
|
||||||
|
## 19. Future implementation gates
|
||||||
|
|
||||||
|
The implementation PR may begin only after this authorization and its preflight
|
||||||
|
map merge. It must:
|
||||||
|
|
||||||
|
1. start from fresh `origin/main` and pass the startup guard;
|
||||||
|
2. add `state_change.unary_delta` without authorizing
|
||||||
|
`state_change.transition`;
|
||||||
|
3. introduce only the minimum exact action-cue type and ProblemFrame publication
|
||||||
|
path defined by the preflight;
|
||||||
|
4. preserve proposal-first ordering and #853's proposal schema;
|
||||||
|
5. keep all three current proposal-first families green;
|
||||||
|
6. prove deterministic replay and exact spans;
|
||||||
|
7. prove every confuser above refuses or does not propose as specified;
|
||||||
|
8. preserve train and holdout `wrong_ids == []` without updating reports;
|
||||||
|
9. avoid all serving and derivation paths;
|
||||||
|
10. stop if the positive cases require actor parsing, coreference, a broad verb
|
||||||
|
parser, synthetic spans, or quantity-family widening.
|
||||||
|
|
||||||
|
## 20. Stop conditions
|
||||||
|
|
||||||
|
Stop implementation and return to design if any of these becomes necessary:
|
||||||
|
|
||||||
|
- changing `_quantity_entity_proposals()` or `_quantity_kind_dispositions()`;
|
||||||
|
- consuming `QuantityKindDisposition` without its quantity-family proposal;
|
||||||
|
- importing `generate.derivation.state` into the ProblemFrame path;
|
||||||
|
- adding a generic verb/event parser or universal event IR;
|
||||||
|
- inferring an actor, owner, source, target, initial value, or final value;
|
||||||
|
- accepting more than the exact `gained`/`lost` cue inventory;
|
||||||
|
- touching serving, eval/report artifacts, teaching, policy, identity, recall,
|
||||||
|
Vault, field, or algebra;
|
||||||
|
- producing a runnable assessment with inexact, synthetic, ambiguous, or
|
||||||
|
cross-sentence evidence;
|
||||||
|
- any non-empty wrong-ID list.
|
||||||
|
|
||||||
|
## 21. Justification: the masterstroke
|
||||||
|
|
||||||
|
The masterstroke is the refusal to model a story. The new organ models a local
|
||||||
|
field differential: a direction-bearing action cue is conjugated with one
|
||||||
|
grounded delta/object edge. The proposal propagates a hypothesis; exact role
|
||||||
|
bindings reconstruct its coordinates; `ContractAssessment` opposes and
|
||||||
|
corrects every incomplete topology.
|
||||||
|
|
||||||
|
This preserves the intrinsic geometry. Unary delta, transfer, containment, and
|
||||||
|
before/after state are not optional-role variants of one object. They are
|
||||||
|
different manifolds and receive separate future contracts. The resulting slice
|
||||||
|
is small enough to make illegal states unrepresentable, yet powerful enough to
|
||||||
|
establish the first event-bearing composition over the quantity/entity seam.
|
||||||
|
|
||||||
|
## 22. Remaining risks discovered
|
||||||
|
|
||||||
|
- `docs/sessions/workbench-proposal-first-alignment-scope-2026-06-20.md`
|
||||||
|
predates #853 and still describes proposal statuses such as `partial`,
|
||||||
|
`closed`, and `refused`. That text is stale and must not be copied into this
|
||||||
|
implementation. Updating Workbench docs is a separate PR.
|
||||||
|
- The legacy semantic-state ledger is semantically adjacent and therefore a
|
||||||
|
likely source of accidental coupling. The implementation preflight requires
|
||||||
|
an explicit no-import/no-call proof.
|
||||||
|
- Existing mention extraction does not ground the subject of `gained/lost` as
|
||||||
|
an actor. This is a deliberate first-slice limit, not a gap to repair in the
|
||||||
|
implementation PR.
|
||||||
580
docs/sessions/unary-state-change-delta-preflight-2026-06-21.md
Normal file
580
docs/sessions/unary-state-change-delta-preflight-2026-06-21.md
Normal file
|
|
@ -0,0 +1,580 @@
|
||||||
|
# Preflight: `state_change.unary_delta` Implementation Map
|
||||||
|
|
||||||
|
**Status:** Design complete; implementation remains future work
|
||||||
|
**Date:** 2026-06-21
|
||||||
|
**Controlling authorization:**
|
||||||
|
`docs/sessions/unary-state-change-delta-authorization-2026-06-21.md`
|
||||||
|
**Target future PR:** `feat(kernel): introduce diagnostic unary-delta proposal seam`
|
||||||
|
|
||||||
|
## 1. Preflight result
|
||||||
|
|
||||||
|
The implementation is feasible without a broad story parser, but only after
|
||||||
|
splitting `state_change.transition` into the narrower
|
||||||
|
`state_change.unary_delta` family.
|
||||||
|
|
||||||
|
The current substrate already carries the scalar, object, and exact
|
||||||
|
`quantity_entity` edge needed by the two seed positives. It does not carry an
|
||||||
|
exact typed action cue. The minimum necessary type addition is therefore one
|
||||||
|
family-local cue record, not a universal event IR.
|
||||||
|
|
||||||
|
No implementation is present in this documentation PR.
|
||||||
|
|
||||||
|
## 2. Current relevant code map
|
||||||
|
|
||||||
|
### 2.1 Descriptive family gate
|
||||||
|
|
||||||
|
`generate/foundational_families.py`
|
||||||
|
|
||||||
|
- contains exactly two current registry entries;
|
||||||
|
- marks `binding.quantity_entity` implemented/authorized;
|
||||||
|
- keeps broad `state_change.transition` proposed and
|
||||||
|
`implementation_authorized=False`;
|
||||||
|
- is descriptive metadata only and is not runtime dispatch.
|
||||||
|
|
||||||
|
Future action: add a third exact entry for `state_change.unary_delta`. Do not
|
||||||
|
authorize or repurpose `state_change.transition`.
|
||||||
|
|
||||||
|
### 2.2 Construction proposal catalog
|
||||||
|
|
||||||
|
`generate/construction_affordances.py`
|
||||||
|
|
||||||
|
- `ConstructionProposal.status` is structurally restricted to `"proposed"`;
|
||||||
|
- proposals cannot store missing roles or active hazards;
|
||||||
|
- all catalog entries are diagnostic-only and serving-disallowed;
|
||||||
|
- `propose_construction(family_id, evidence_spans)` has hypothesis-only inputs;
|
||||||
|
- `make_proposal()` rejects all current catalog families and must remain a
|
||||||
|
loud legacy fence.
|
||||||
|
|
||||||
|
Future action: add `_UNARY_DELTA_FAMILY`, catalog it, and include it in the
|
||||||
|
proposal-first set. Do not change proposal schema or `make_proposal()`.
|
||||||
|
|
||||||
|
### 2.3 ProblemFrame types
|
||||||
|
|
||||||
|
`generate/problem_frame.py`
|
||||||
|
|
||||||
|
- carries exact mentions, bindings, bound relations, proposals, and
|
||||||
|
quantity-kind dispositions;
|
||||||
|
- has no event/action cue record;
|
||||||
|
- has no unary-delta-specific state;
|
||||||
|
- `QuantityKindDisposition` is family-local to quantity/entity and is not
|
||||||
|
available for state-change confusers after #853.
|
||||||
|
|
||||||
|
Future action: add one family-local `GroundedUnaryDeltaCue` and a
|
||||||
|
`ProblemFrame.unary_delta_cues` tuple with a matching builder method. Do not
|
||||||
|
widen `MentionKind` to a generic `event`/`action` universe.
|
||||||
|
|
||||||
|
### 2.4 Frame builder
|
||||||
|
|
||||||
|
`generate/problem_frame_builder.py::build_problem_frame`
|
||||||
|
|
||||||
|
Current order:
|
||||||
|
|
||||||
|
```text
|
||||||
|
scalars / units / hazards / process-frame candidates
|
||||||
|
→ proposal-first construction proposals
|
||||||
|
→ mentions / bindings / quantity disposition / bound relations / target
|
||||||
|
→ initial ProblemFrame
|
||||||
|
→ ContractAssessment dispatch
|
||||||
|
```
|
||||||
|
|
||||||
|
Relevant existing facts:
|
||||||
|
|
||||||
|
- `Ana gained 3 marbles.` produces one `consumption` process-frame candidate,
|
||||||
|
one exact scalar mention, one exact object mention, and one exact
|
||||||
|
`quantity_entity` binding; it produces no proposal or bound relation.
|
||||||
|
- `The jar lost 2 cookies.` has the same topology.
|
||||||
|
- `_quantity_entity_proposals()` intentionally refuses any active process
|
||||||
|
frame, so the state-change positive has no quantity-family proposal.
|
||||||
|
- `_quantity_kind_dispositions()` now requires exactly one
|
||||||
|
`binding.quantity_entity` proposal. This is the #853 hardening boundary and
|
||||||
|
must not be widened.
|
||||||
|
- `_TRANSFER_RE` separately constructs a `transfer` relation for a narrow
|
||||||
|
`gave` surface. It must not be reused as unary state change.
|
||||||
|
|
||||||
|
Future action: add one cue-proposal helper before mention binding, then publish
|
||||||
|
the exact cue and unary relation after mentions/bindings exist.
|
||||||
|
|
||||||
|
### 2.5 Contract assessment
|
||||||
|
|
||||||
|
`generate/problem_frame_contracts.py`
|
||||||
|
|
||||||
|
- `assess_contracts()` dispatches current catalog contracts only from an
|
||||||
|
existing family proposal;
|
||||||
|
- dedicated assessment functions hold family-specific closure logic;
|
||||||
|
- `ContractAssessment` is the sole runnable/refused authority;
|
||||||
|
- output ordering is deterministic by `candidate_organ`.
|
||||||
|
|
||||||
|
Future action: register `unary_delta_transition`, implement
|
||||||
|
`assess_unary_delta(frame)`, and dispatch only when the exact proposal exists.
|
||||||
|
|
||||||
|
### 2.6 Process-frame candidates
|
||||||
|
|
||||||
|
`generate/process_frames.py`
|
||||||
|
|
||||||
|
- the broad `consumption` candidate frame includes both `gain*` and `lose*`;
|
||||||
|
- its own `not_licensed` declarations forbid deciding gain/loss without exact
|
||||||
|
surface evidence and forbid computing remaining quantities;
|
||||||
|
- it is candidate context, not a grounded event role or contract.
|
||||||
|
|
||||||
|
Future action: allow the existing `consumption` candidate to coexist, but do
|
||||||
|
not treat it as cue, proposal, relation, or closure authority.
|
||||||
|
|
||||||
|
### 2.7 Legacy semantic-state derivation path
|
||||||
|
|
||||||
|
`generate/derivation/state/*`
|
||||||
|
|
||||||
|
- already models `set`, `gain`, and `loss` transitions for accumulation;
|
||||||
|
- parses raw clauses independently of `ProblemFrame`;
|
||||||
|
- stores numeric values as float-backed `SemanticQuantity` rather than exact
|
||||||
|
`GroundedScalar` fractions;
|
||||||
|
- permits loose pronoun continuation;
|
||||||
|
- replays to `GroundedDerivation` candidates.
|
||||||
|
|
||||||
|
Future action: none. The new diagnostic family must not import, call, wrap,
|
||||||
|
compare against, or emit `SemanticLedger`, `StateTransition`, or
|
||||||
|
`GroundedDerivation`.
|
||||||
|
|
||||||
|
### 2.8 Callers and consumers
|
||||||
|
|
||||||
|
The import/call-site sweep found:
|
||||||
|
|
||||||
|
- `build_problem_frame()` and `assess_contracts()` are consumed by focused
|
||||||
|
tests plus `scripts/gsm8k_problem_frame_adequacy.py` and
|
||||||
|
`scripts/gsm8k_substrate_morphology.py`;
|
||||||
|
- no `calibration/` module directly consumes this seam;
|
||||||
|
- no serving module directly imports `problem_frame_contracts`;
|
||||||
|
- current proposal-first tests enforce proposal ordering, exact spans,
|
||||||
|
diagnostic posture, and proposal-gated dispatch.
|
||||||
|
|
||||||
|
The future PR must preserve these callers and must not add a serving import.
|
||||||
|
|
||||||
|
## 3. Required type addition
|
||||||
|
|
||||||
|
Add only this family-local shape in `generate/problem_frame.py`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
UnaryDeltaDirection = Literal["increase", "decrease"]
|
||||||
|
UnaryDeltaActionKind = Literal["gain", "loss"]
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class GroundedUnaryDeltaCue:
|
||||||
|
cue_id: str
|
||||||
|
surface: str
|
||||||
|
action_kind: UnaryDeltaActionKind
|
||||||
|
direction: UnaryDeltaDirection
|
||||||
|
span: SourceSpan
|
||||||
|
```
|
||||||
|
|
||||||
|
Construction obligations:
|
||||||
|
|
||||||
|
- `surface` must equal `span.text`;
|
||||||
|
- `gained` must map only to `action_kind="gain"`,
|
||||||
|
`direction="increase"`;
|
||||||
|
- `lost` must map only to `action_kind="loss"`,
|
||||||
|
`direction="decrease"`;
|
||||||
|
- no other cue value is constructible;
|
||||||
|
- the frame carries cues as `tuple[GroundedUnaryDeltaCue, ...]` in stable source
|
||||||
|
order.
|
||||||
|
|
||||||
|
This type is intentionally not:
|
||||||
|
|
||||||
|
- a generic `EventMention`;
|
||||||
|
- a verb parse tree;
|
||||||
|
- an actor/source/target model;
|
||||||
|
- a temporal graph;
|
||||||
|
- a `SemanticLedger` transition;
|
||||||
|
- an arithmetic operator.
|
||||||
|
|
||||||
|
Do not add a new `SubstrateFact` variant or widen `MentionKind` in the first PR.
|
||||||
|
|
||||||
|
## 4. Closed cue inventory and recognition
|
||||||
|
|
||||||
|
The future builder owns one immutable mapping:
|
||||||
|
|
||||||
|
```text
|
||||||
|
gained → (gain, increase)
|
||||||
|
lost → (loss, decrease)
|
||||||
|
```
|
||||||
|
|
||||||
|
Recognition rules:
|
||||||
|
|
||||||
|
1. enumerate exact lexical-boundary occurrences using the existing lexical
|
||||||
|
boundary helper style;
|
||||||
|
2. zero hits: no proposal;
|
||||||
|
3. more than one hit, including repeated identical cues: no proposal;
|
||||||
|
4. one hit: use only its exact `SourceSpan` to create the proposal;
|
||||||
|
5. do not capture surrounding grammar or synthesize an event chunk;
|
||||||
|
6. block proposal creation when an explicit competing surface is already
|
||||||
|
visible: percent, rate/per/each, comparison, transfer, transaction,
|
||||||
|
containment, list coordination, or multiple event cues;
|
||||||
|
7. the only allowed process-frame set is empty or exactly `{"consumption"}`;
|
||||||
|
the two authorized cues currently produce `consumption`.
|
||||||
|
|
||||||
|
The proposal helper must be a closed lexical recognizer, not a broad regex with
|
||||||
|
verb, subject, object, source, target, and clause capture groups.
|
||||||
|
|
||||||
|
## 5. Required frame publication path
|
||||||
|
|
||||||
|
The future build order is fixed:
|
||||||
|
|
||||||
|
```text
|
||||||
|
1. Existing scalar/unit/hazard/process-frame extraction
|
||||||
|
2. Detect exactly one authorized cue span
|
||||||
|
3. ConstructionProposal(status="proposed") from cue span only
|
||||||
|
4. Existing mention and MentionBinding extraction
|
||||||
|
5. GroundedUnaryDeltaCue from the proposal-backed exact cue
|
||||||
|
6. BoundRelation(relation_type="unary_delta") from cue + existing binding
|
||||||
|
7. ProblemFrame publication
|
||||||
|
8. Proposal-gated ContractAssessment
|
||||||
|
```
|
||||||
|
|
||||||
|
The unary relation uses existing `BoundRelation` / `BoundRole`:
|
||||||
|
|
||||||
|
| Bound role | Target |
|
||||||
|
|---|---|
|
||||||
|
| `action_cue` | `GroundedUnaryDeltaCue.cue_id`, kind `unary_delta_cue` |
|
||||||
|
| `delta_quantity` | selected quantity `GroundedMention.mention_id` |
|
||||||
|
| `changed_object` | selected object `GroundedMention.mention_id` |
|
||||||
|
|
||||||
|
`direction` is an explicit field of the exact cue. The construction catalog
|
||||||
|
still declares direction as a required semantic obligation; assessment checks
|
||||||
|
the cue's typed disposition.
|
||||||
|
|
||||||
|
Relation publication requirements:
|
||||||
|
|
||||||
|
- exactly one `quantity_entity` binding;
|
||||||
|
- its source resolves to exactly one source-grounded scalar mention;
|
||||||
|
- its target resolves to exactly one object mention;
|
||||||
|
- cue precedes quantity, which precedes object;
|
||||||
|
- no `.`, `?`, or `!` boundary lies between the three spans;
|
||||||
|
- relation evidence is the ordered tuple of exact cue, quantity, and object
|
||||||
|
spans;
|
||||||
|
- no actor, owner, source, target, before, after, container, or temporal role
|
||||||
|
is synthesized.
|
||||||
|
|
||||||
|
If any requirement fails, publish no bound relation. The proposal may still be
|
||||||
|
assessed and refused from the missing evidence.
|
||||||
|
|
||||||
|
## 6. Construction catalog addition
|
||||||
|
|
||||||
|
The future `_UNARY_DELTA_FAMILY` must declare:
|
||||||
|
|
||||||
|
```text
|
||||||
|
family_id: state_change.unary_delta
|
||||||
|
relation_type: unary_delta
|
||||||
|
candidate_organ: unary_delta_transition
|
||||||
|
required roles: action_cue, changed_object, delta_quantity, direction,
|
||||||
|
local_binding_relation, local_event_containment,
|
||||||
|
provenance_span
|
||||||
|
optional roles: actor
|
||||||
|
diagnostic_only: True
|
||||||
|
serving_allowed: False
|
||||||
|
```
|
||||||
|
|
||||||
|
`unit`, `source`, `target`, `before_quantity`, `after_quantity`, `container`,
|
||||||
|
and `temporal_marker` stay absent from the first catalog signature. Listing
|
||||||
|
them as optional would imply the first relation can lawfully carry those
|
||||||
|
states; it cannot. They remain future-family roles, not optional SCT-1 data.
|
||||||
|
|
||||||
|
## 7. Contract assessment path
|
||||||
|
|
||||||
|
Add:
|
||||||
|
|
||||||
|
```python
|
||||||
|
def assess_unary_delta(frame: ProblemFrame) -> ContractAssessment:
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
Assessment order:
|
||||||
|
|
||||||
|
1. require exactly one `state_change.unary_delta` proposal;
|
||||||
|
2. require exactly one `GroundedUnaryDeltaCue` contained by proposal evidence;
|
||||||
|
3. require exactly one `BoundRelation(relation_type="unary_delta")`;
|
||||||
|
4. require exactly one action, delta, and changed-object role target;
|
||||||
|
5. prove delta mention → scalar provenance;
|
||||||
|
6. prove the exact `quantity_entity` edge joins the selected mentions;
|
||||||
|
7. prove typed cue/action/direction consistency;
|
||||||
|
8. prove local ordering and sentence containment;
|
||||||
|
9. prove every proposal, cue, role, binding, and relation span is an exact
|
||||||
|
`problem_text` slice;
|
||||||
|
10. reject unit/object collisions and all active competing contexts;
|
||||||
|
11. report `runnable=True` only if both blocker and hazard sets are empty.
|
||||||
|
|
||||||
|
The function does not calculate a signed number. It does not inspect a question
|
||||||
|
target. It does not produce a target value. Its meaning is only “this local
|
||||||
|
unary-delta construction is role-complete.”
|
||||||
|
|
||||||
|
## 8. Refusal code placement
|
||||||
|
|
||||||
|
### `missing_bindings`
|
||||||
|
|
||||||
|
- `unary_delta_proposal_required`
|
||||||
|
- `action_cue_unbound`
|
||||||
|
- `action_cue_ambiguous`
|
||||||
|
- `delta_quantity_unbound`
|
||||||
|
- `delta_quantity_ambiguous`
|
||||||
|
- `changed_object_unbound`
|
||||||
|
- `changed_object_ambiguous`
|
||||||
|
- `local_binding_relation_unbound`
|
||||||
|
- `local_binding_relation_ambiguous`
|
||||||
|
- `local_event_containment_unproven`
|
||||||
|
- `delta_direction_unbound`
|
||||||
|
- `unit_object_conflict`
|
||||||
|
- `provenance_span_inexact`
|
||||||
|
|
||||||
|
### `unresolved_hazards`
|
||||||
|
|
||||||
|
- `multiple_actor_surface`
|
||||||
|
- `delta_direction_ambiguous`
|
||||||
|
- `source_target_unlicensed`
|
||||||
|
- `pronoun_antecedent_unresolved`
|
||||||
|
- `cross_sentence_event`
|
||||||
|
- `implicit_total_unlicensed`
|
||||||
|
- `comparative_context`
|
||||||
|
- `rate_context`
|
||||||
|
- `percent_context`
|
||||||
|
- `passive_voice_unsupported`
|
||||||
|
- `temporal_context_ambiguous`
|
||||||
|
- `list_context_ambiguous`
|
||||||
|
- `transfer_unlicensed`
|
||||||
|
- `multiple_state_change_cues`
|
||||||
|
- `chained_state_changes`
|
||||||
|
- `event_assertion_unlicensed`
|
||||||
|
|
||||||
|
The implementation may use a strict subset on naturally unreachable
|
||||||
|
no-proposal paths, but direct assessment of a deliberately malformed frame must
|
||||||
|
remain fail-closed and legible.
|
||||||
|
|
||||||
|
## 9. Relationship to current quantity disposition
|
||||||
|
|
||||||
|
Do not reuse or widen `QuantityKindDisposition` in SCT-1.
|
||||||
|
|
||||||
|
Reason: #853 made that disposition valid only when an exact
|
||||||
|
`binding.quantity_entity` proposal exists. State-change text deliberately has a
|
||||||
|
process-frame context, so the quantity family does not propose. Making its
|
||||||
|
disposition generic again would recreate the authority leak #853 removed.
|
||||||
|
|
||||||
|
SCT-1 instead closes only a family-specific count-valued delta relation from
|
||||||
|
its own proposal plus the exact existing scalar/object binding. Measurement
|
||||||
|
support is deferred.
|
||||||
|
|
||||||
|
## 10. Required future code files
|
||||||
|
|
||||||
|
The bounded implementation is expected to touch only:
|
||||||
|
|
||||||
|
- `generate/foundational_families.py`
|
||||||
|
- `generate/construction_affordances.py`
|
||||||
|
- `generate/problem_frame.py`
|
||||||
|
- `generate/problem_frame_builder.py`
|
||||||
|
- `generate/problem_frame_contracts.py`
|
||||||
|
- focused tests listed below
|
||||||
|
|
||||||
|
Do not touch:
|
||||||
|
|
||||||
|
- `generate/derivation/*`
|
||||||
|
- `generate/math_candidate_graph.py`
|
||||||
|
- `evals/*` or reports
|
||||||
|
- runtime/serving paths
|
||||||
|
- teaching/proposals, packs, policy, identity, recall, Vault, field, algebra,
|
||||||
|
sealed artifacts, or `report.json`
|
||||||
|
|
||||||
|
## 11. Likely test files
|
||||||
|
|
||||||
|
Extend:
|
||||||
|
|
||||||
|
- `tests/test_foundational_families.py`
|
||||||
|
- `tests/test_construction_affordances.py`
|
||||||
|
- `tests/test_construction_proposal_seam.py`
|
||||||
|
- `tests/test_problem_frame_builder.py`
|
||||||
|
- `tests/test_problem_frame_contracts.py`
|
||||||
|
- `tests/test_quantity_entity_proposal.py`
|
||||||
|
- `tests/test_proportional_decrease_proposal.py`
|
||||||
|
- `tests/test_percent_partition_proposal.py`
|
||||||
|
|
||||||
|
Add:
|
||||||
|
|
||||||
|
- `tests/test_unary_delta_proposal.py`
|
||||||
|
|
||||||
|
No eval fixture or report file is required.
|
||||||
|
|
||||||
|
## 12. Exact future tests
|
||||||
|
|
||||||
|
### Type and catalog
|
||||||
|
|
||||||
|
1. only `gained` and `lost` construct `GroundedUnaryDeltaCue`;
|
||||||
|
2. cue action kind/direction pairs cannot be mismatched;
|
||||||
|
3. catalog entry is diagnostic-only and serving-disallowed;
|
||||||
|
4. broad `state_change.transition` stays implementation-unauthorized;
|
||||||
|
5. `state_change.unary_delta` is a distinct foundational entry;
|
||||||
|
6. `ConstructionProposal` remains proposed-only.
|
||||||
|
|
||||||
|
### Ordering and authority
|
||||||
|
|
||||||
|
7. proposal is published before cue binding/relation assessment;
|
||||||
|
8. proposal-free frame does not dispatch `unary_delta_transition`;
|
||||||
|
9. positive proposal remains `status="proposed"` after runnable assessment;
|
||||||
|
10. legacy `make_proposal()` is never used;
|
||||||
|
11. direct malformed-frame assessment refuses with stable codes.
|
||||||
|
|
||||||
|
### Exact evidence
|
||||||
|
|
||||||
|
12. every proposal/cue/relation/assessment span equals its source slice;
|
||||||
|
13. synthetic proposal span refuses;
|
||||||
|
14. synthetic cue span refuses;
|
||||||
|
15. mismatched relation role target refuses;
|
||||||
|
16. cue/quantity/object crossing a sentence boundary refuses;
|
||||||
|
17. repeated build produces identical cue, proposal, relation, and assessment.
|
||||||
|
|
||||||
|
### Positive fixtures
|
||||||
|
|
||||||
|
18. `Ana gained 3 marbles.` is diagnostically runnable;
|
||||||
|
19. `The jar lost 2 cookies.` is diagnostically runnable;
|
||||||
|
20. `The team gained 4 points.` is diagnostically runnable;
|
||||||
|
21. no positive produces an answer, target, serving flag, or derivation candidate.
|
||||||
|
|
||||||
|
### Negative/confuser fixtures
|
||||||
|
|
||||||
|
22. every table entry in authorization §17 has the specified no-proposal or
|
||||||
|
refusal disposition;
|
||||||
|
23. `Ana gained apples.` refuses `delta_quantity_unbound`;
|
||||||
|
24. `Ana gained 3.` refuses `changed_object_unbound`;
|
||||||
|
25. `3 apples were gained by Ana.` refuses passive/order topology;
|
||||||
|
26. `Ana gained 3 pounds.` refuses unit/object conflict;
|
||||||
|
27. `Ana gained 3 apples and lost 2.` has no proposal;
|
||||||
|
28. `Tom gave Ana 3 apples.` still has no quantity disposition and no unary
|
||||||
|
proposal;
|
||||||
|
29. plain `There are 12 apples.` keeps its quantity proposal and gains no
|
||||||
|
unary assessment;
|
||||||
|
30. current proportional-decrease and percent-partition positives remain
|
||||||
|
unchanged.
|
||||||
|
|
||||||
|
### Structural firewall
|
||||||
|
|
||||||
|
31. an AST/import guard proves the new ProblemFrame/catalog/contract path does
|
||||||
|
not import `generate.derivation.state`, `generate.derivation.accumulate`,
|
||||||
|
`generate.derivation.pool`, or `generate.derivation.verify`;
|
||||||
|
32. no new raw-prose parser appears under `generate/derivation/`;
|
||||||
|
33. the existing no-new-legacy guard remains green.
|
||||||
|
|
||||||
|
## 13. Manual probe plan
|
||||||
|
|
||||||
|
For every seed/confuser, print only:
|
||||||
|
|
||||||
|
```text
|
||||||
|
process frame names
|
||||||
|
proposal family IDs + exact evidence spans
|
||||||
|
unary cue records
|
||||||
|
mention IDs/kinds/spans
|
||||||
|
quantity_entity bindings
|
||||||
|
unary bound roles + spans
|
||||||
|
ContractAssessment organ/runnable/blockers/hazards
|
||||||
|
```
|
||||||
|
|
||||||
|
Required assertions:
|
||||||
|
|
||||||
|
- positives: exactly one unary proposal, cue, relation, and assessment;
|
||||||
|
- no-proposal confusers: no unary cue authority, relation, or assessment;
|
||||||
|
- proposed/refused cases: proposal remains proposed and blockers are exact;
|
||||||
|
- no case produces a quantity-kind disposition unless the independent
|
||||||
|
quantity-family proposal exists;
|
||||||
|
- no case touches or compares against legacy semantic-ledger output.
|
||||||
|
|
||||||
|
## 14. Validation plan
|
||||||
|
|
||||||
|
Run targeted tests first:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv run python -m pytest -q \
|
||||||
|
tests/test_foundational_families.py \
|
||||||
|
tests/test_construction_affordances.py \
|
||||||
|
tests/test_construction_proposal_seam.py \
|
||||||
|
tests/test_problem_frame_builder.py \
|
||||||
|
tests/test_problem_frame_contracts.py \
|
||||||
|
tests/test_quantity_entity_proposal.py \
|
||||||
|
tests/test_proportional_decrease_proposal.py \
|
||||||
|
tests/test_percent_partition_proposal.py \
|
||||||
|
tests/test_unary_delta_proposal.py \
|
||||||
|
tests/test_kernel_no_new_legacy_derivation_surfaces.py
|
||||||
|
|
||||||
|
uv run python -m core.cli test --suite smoke -q
|
||||||
|
|
||||||
|
uv run python -m compileall -q generate tests
|
||||||
|
|
||||||
|
uv run ruff check \
|
||||||
|
generate/foundational_families.py \
|
||||||
|
generate/construction_affordances.py \
|
||||||
|
generate/problem_frame.py \
|
||||||
|
generate/problem_frame_builder.py \
|
||||||
|
generate/problem_frame_contracts.py \
|
||||||
|
tests/test_foundational_families.py \
|
||||||
|
tests/test_construction_affordances.py \
|
||||||
|
tests/test_construction_proposal_seam.py \
|
||||||
|
tests/test_problem_frame_builder.py \
|
||||||
|
tests/test_problem_frame_contracts.py \
|
||||||
|
tests/test_quantity_entity_proposal.py \
|
||||||
|
tests/test_proportional_decrease_proposal.py \
|
||||||
|
tests/test_percent_partition_proposal.py \
|
||||||
|
tests/test_unary_delta_proposal.py
|
||||||
|
|
||||||
|
git diff --check
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the canonical train and holdout serving probes without writing reports.
|
||||||
|
Both must retain:
|
||||||
|
|
||||||
|
```text
|
||||||
|
wrong_ids == []
|
||||||
|
```
|
||||||
|
|
||||||
|
The PR must state any correct/refused count movement observed live, but it may
|
||||||
|
not update governed report artifacts.
|
||||||
|
|
||||||
|
## 15. Implementation stop conditions
|
||||||
|
|
||||||
|
Stop immediately if implementation requires:
|
||||||
|
|
||||||
|
- actor, owner, source, target, pronoun, or temporal resolution;
|
||||||
|
- more than the exact `gained`/`lost` cue inventory;
|
||||||
|
- a generic action/event parser;
|
||||||
|
- widening quantity-entity proposal or disposition generation;
|
||||||
|
- reusing `transfer` as unary delta;
|
||||||
|
- importing or invoking the semantic-state derivation ledger;
|
||||||
|
- synthetic spans or nearest-mention selection;
|
||||||
|
- question-target or arithmetic logic;
|
||||||
|
- serving, report, eval fixture, teaching, memory, policy, identity, recall,
|
||||||
|
Vault, field, or algebra changes;
|
||||||
|
- a non-empty wrong-ID list.
|
||||||
|
|
||||||
|
If exact local topology cannot make both seed positives runnable under these
|
||||||
|
constraints, return to design. Do not widen the parser to make fixtures pass.
|
||||||
|
|
||||||
|
## 16. Copy-paste future implementation brief
|
||||||
|
|
||||||
|
> **PR title:** `feat(kernel): introduce diagnostic unary-delta proposal seam`
|
||||||
|
>
|
||||||
|
> **Dependency:** Begin only after
|
||||||
|
> `docs(kernel): authorize unary state-change delta slice` merges. Create a
|
||||||
|
> fresh worktree from current `origin/main`; run `source
|
||||||
|
> scripts/agent_startup.sh`; prove the authorization and preflight documents
|
||||||
|
> are in the base.
|
||||||
|
>
|
||||||
|
> Implement only `state_change.unary_delta`, not broad
|
||||||
|
> `state_change.transition`. Add a family-local frozen
|
||||||
|
> `GroundedUnaryDeltaCue` with the closed exact cue mapping `gained →
|
||||||
|
> gain/increase`, `lost → loss/decrease`. Create
|
||||||
|
> `ConstructionProposal(status="proposed", diagnostic_only=True,
|
||||||
|
> serving_allowed=False)` from the exact cue span before mention/relation
|
||||||
|
> binding. Reuse the existing exact `GroundedScalar`, `GroundedMention`, and
|
||||||
|
> `MentionBinding(binding_type="quantity_entity")` to publish one
|
||||||
|
> `BoundRelation(relation_type="unary_delta")` with action cue, delta quantity,
|
||||||
|
> and changed object roles. Add proposal-gated `assess_unary_delta(frame)` as
|
||||||
|
> the sole runnable/refused authority.
|
||||||
|
>
|
||||||
|
> Keep the first slice count-only, single-cue, single-scalar, single-object,
|
||||||
|
> and single-sentence. Do not assert actor/ownership, source/target,
|
||||||
|
> before/after values, containment, transfer, arithmetic, answers, or serving.
|
||||||
|
> Do not widen `_quantity_entity_proposals()` or
|
||||||
|
> `_quantity_kind_dispositions()`. Do not import or call
|
||||||
|
> `generate.derivation.state`. Use the exact refusal taxonomy, tests, manual
|
||||||
|
> probes, validation commands, and stop conditions in this preflight. Preserve
|
||||||
|
> every current proposal-first family and train/holdout `wrong_ids == []`.
|
||||||
355
docs/specs/foundational-families/unary-state-change-delta.md
Normal file
355
docs/specs/foundational-families/unary-state-change-delta.md
Normal file
|
|
@ -0,0 +1,355 @@
|
||||||
|
# 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
|
||||||
|
|
||||||
|
```text
|
||||||
|
Signature: unary_delta
|
||||||
|
Candidate organ: unary_delta_transition
|
||||||
|
Relation type: unary_delta
|
||||||
|
```
|
||||||
|
|
||||||
|
The proposal-first chain is:
|
||||||
|
|
||||||
|
```text
|
||||||
|
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:
|
||||||
|
|
||||||
|
```text
|
||||||
|
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:
|
||||||
|
|
||||||
|
```python
|
||||||
|
@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`:
|
||||||
|
|
||||||
|
```text
|
||||||
|
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:
|
||||||
|
|
||||||
|
```text
|
||||||
|
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:
|
||||||
|
|
||||||
|
1. exactly one proposal exists;
|
||||||
|
2. exactly one typed cue exists and is contained by proposal evidence;
|
||||||
|
3. cue surface, action kind, and direction match the closed mapping;
|
||||||
|
4. exactly one unary-delta bound relation exists;
|
||||||
|
5. the selected delta resolves to exactly one source-grounded scalar;
|
||||||
|
6. the selected changed object is exact and unambiguous;
|
||||||
|
7. exactly one existing `quantity_entity` edge joins them;
|
||||||
|
8. cue, delta, and object satisfy exact local order/containment;
|
||||||
|
9. every proposal, cue, binding, role, and relation span is exact;
|
||||||
|
10. 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_required`
|
||||||
|
- `action_cue_unbound`
|
||||||
|
- `action_cue_ambiguous`
|
||||||
|
- `delta_quantity_unbound`
|
||||||
|
- `delta_quantity_ambiguous`
|
||||||
|
- `changed_object_unbound`
|
||||||
|
- `changed_object_ambiguous`
|
||||||
|
- `local_binding_relation_unbound`
|
||||||
|
- `local_binding_relation_ambiguous`
|
||||||
|
- `local_event_containment_unproven`
|
||||||
|
- `delta_direction_unbound`
|
||||||
|
- `unit_object_conflict`
|
||||||
|
- `provenance_span_inexact`
|
||||||
|
|
||||||
|
### Ambiguity/context hazards
|
||||||
|
|
||||||
|
- `multiple_actor_surface`
|
||||||
|
- `delta_direction_ambiguous`
|
||||||
|
- `source_target_unlicensed`
|
||||||
|
- `pronoun_antecedent_unresolved`
|
||||||
|
- `cross_sentence_event`
|
||||||
|
- `implicit_total_unlicensed`
|
||||||
|
- `comparative_context`
|
||||||
|
- `rate_context`
|
||||||
|
- `percent_context`
|
||||||
|
- `passive_voice_unsupported`
|
||||||
|
- `temporal_context_ambiguous`
|
||||||
|
- `list_context_ambiguous`
|
||||||
|
- `transfer_unlicensed`
|
||||||
|
- `multiple_state_change_cues`
|
||||||
|
- `chained_state_changes`
|
||||||
|
- `event_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_entity` proposal;
|
||||||
|
- create or consume a quantity-family `QuantityKindDisposition` outside 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
|
||||||
|
|
||||||
|
```text
|
||||||
|
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:
|
||||||
|
|
||||||
|
```text
|
||||||
|
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:
|
||||||
|
|
||||||
|
```text
|
||||||
|
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;
|
||||||
|
- `SemanticLedger` or 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.transition` stays 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.
|
||||||
Loading…
Reference in a new issue