133 lines
3.4 KiB
Markdown
133 lines
3.4 KiB
Markdown
|
|
# Quantity Specialist
|
||
|
|
|
||
|
|
**specialist_id:** `quantity`
|
||
|
|
**trigger_gates:** `has_quantity`, `is_math`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Responsibility
|
||
|
|
|
||
|
|
The quantity specialist extracts numeric values, attaches QuantityFacets to quantity objects, and emits arithmetic and comparison constraints. When arithmetic can be resolved deterministically, it resolves it. When resolution requires a solver, it emits a structured constraint for the resolver.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Manifest
|
||
|
|
|
||
|
|
```
|
||
|
|
declared_facet_kinds:
|
||
|
|
- quantity
|
||
|
|
|
||
|
|
declared_constraint_types:
|
||
|
|
- quantity_equals
|
||
|
|
- quantity_sum
|
||
|
|
- quantity_difference
|
||
|
|
- quantity_product
|
||
|
|
- quantity_quotient
|
||
|
|
- quantity_greater
|
||
|
|
- quantity_less
|
||
|
|
- quantity_at_least
|
||
|
|
- quantity_at_most
|
||
|
|
- quantity_bound
|
||
|
|
|
||
|
|
budget_caps:
|
||
|
|
max_objects_proposed: 6
|
||
|
|
max_facets_emitted: 6
|
||
|
|
max_constraints_emitted: 10
|
||
|
|
max_merges: 0
|
||
|
|
max_splits: 0
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Output: QuantityFacet
|
||
|
|
|
||
|
|
Attach to any object of kind `quantity`.
|
||
|
|
|
||
|
|
```
|
||
|
|
QuantityFacet fields used:
|
||
|
|
- value: number or symbolic expression
|
||
|
|
- unit: string (apples, dollars, meters, etc.)
|
||
|
|
- is_exact: true/false
|
||
|
|
- derived_from_refs: quantity object IDs this was computed from
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Output: Constraints
|
||
|
|
|
||
|
|
### `quantity_equals(Q_result, expression)`
|
||
|
|
|
||
|
|
Emit when a quantity is defined as equal to an expression.
|
||
|
|
|
||
|
|
```
|
||
|
|
{
|
||
|
|
"constraint_type": "quantity_equals",
|
||
|
|
"argument_refs": ["Q_alice_final", "Q_expr_5_minus_2"],
|
||
|
|
"expression": "quantity(Q_alice_final) = quantity(Q1) - quantity(Q2)",
|
||
|
|
"strength": "hard"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### `quantity_difference(Q_result, Q_minuend, Q_subtrahend)`
|
||
|
|
|
||
|
|
Preferred form when the specific operation is subtraction.
|
||
|
|
|
||
|
|
```
|
||
|
|
argument_refs order: [result, minuend, subtrahend]
|
||
|
|
```
|
||
|
|
|
||
|
|
### `quantity_sum(Q_result, Q_addend1, Q_addend2, ...)`
|
||
|
|
|
||
|
|
Result equals the sum of all argument quantities.
|
||
|
|
|
||
|
|
### `quantity_greater(Q_a, Q_b)`
|
||
|
|
|
||
|
|
Q_a > Q_b.
|
||
|
|
|
||
|
|
### `quantity_less(Q_a, Q_b)`
|
||
|
|
|
||
|
|
Q_a < Q_b.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Arithmetic resolution
|
||
|
|
|
||
|
|
When all inputs to an arithmetic constraint are exact numeric values, the quantity specialist SHOULD resolve the arithmetic inline and set the result quantity's `value` directly.
|
||
|
|
|
||
|
|
```
|
||
|
|
if quantity_difference(Q_result, Q1, Q2):
|
||
|
|
if Q1.value is exact numeric AND Q2.value is exact numeric:
|
||
|
|
Q_result.value = Q1.value - Q2.value
|
||
|
|
Q_result.is_exact = true
|
||
|
|
mark constraint as resolved
|
||
|
|
else:
|
||
|
|
emit constraint with status = unresolved
|
||
|
|
resolver handles it
|
||
|
|
```
|
||
|
|
|
||
|
|
This avoids unnecessary round-trips through the resolver for simple arithmetic.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Unit tracking
|
||
|
|
|
||
|
|
Units must be tracked and propagated. Emitting a `quantity_difference` constraint without units is not sufficient — the result unit must be declared or inferred.
|
||
|
|
|
||
|
|
Rules:
|
||
|
|
- Same unit on both operands: result inherits unit
|
||
|
|
- Different units on operands: emit a `quantity_bound` constraint marking the result as unit-ambiguous until a converter is applied
|
||
|
|
- Unitless operands: result is unitless
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Contract test requirements
|
||
|
|
|
||
|
|
- Given `Alice had 5 apples. She gave Bob 2 apples.`:
|
||
|
|
- Must emit Q1 with value=5, unit="apples"
|
||
|
|
- Must emit Q2 with value=2, unit="apples"
|
||
|
|
- Must emit `quantity_difference(Q_alice_final, Q1, Q2)` or `quantity_equals(Q_alice_final, "5-2")`
|
||
|
|
- Must set Q_alice_final.value = 3 (inline resolution)
|
||
|
|
- Must not emit temporal or entity constraints
|
||
|
|
- All quantity facets must have `unit` set or explicitly `"unitless"`
|
||
|
|
- All emitted constraints must have `source_module: quantity`
|