280 lines
8.8 KiB
Markdown
280 lines
8.8 KiB
Markdown
|
|
# Implementation Constraints (v1.1)
|
|||
|
|
|
|||
|
|
These constraints apply to every module in the system without exception. They are architectural rules, not guidelines. A module that violates any of them is not a valid UCWM module, regardless of whether it produces correct answers.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. No hidden state between modules
|
|||
|
|
|
|||
|
|
Every module must:
|
|||
|
|
- Accept only typed inputs defined by its contract
|
|||
|
|
- Produce only typed outputs defined by its contract
|
|||
|
|
- Not rely on hidden global context
|
|||
|
|
- Not rely on implicit latent carryover from prior calls
|
|||
|
|
|
|||
|
|
If a module needs information, it must be passed explicitly through the WorldState or arguments. A module that reads from a global variable or internal cache that is not visible in WorldState is invalid.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. WorldState is the source of truth
|
|||
|
|
|
|||
|
|
All state lives in WorldState. Modules must not:
|
|||
|
|
- Store their own internally evolving state across calls
|
|||
|
|
- Cache interpretations across calls unless that cache is explicitly registered as a field in WorldState
|
|||
|
|
- Mutate shared objects directly — all changes must be returned as typed outputs and applied by the receiving layer
|
|||
|
|
|
|||
|
|
All changes take the form:
|
|||
|
|
```
|
|||
|
|
Operation {
|
|||
|
|
type: "propose" | "merge" | "refine" | "link" | "suppress"
|
|||
|
|
target_refs: string[]
|
|||
|
|
payload: typed payload per operation type
|
|||
|
|
confidence_delta: float?
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. Every operation must be logged
|
|||
|
|
|
|||
|
|
All module outputs must include provenance. The provenance record must be sufficient to reconstruct:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
final_answer → constraints → facets → objects → source text
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Every Constraint, Facet, and Object created or modified must have a corresponding ProvenanceRecord with:
|
|||
|
|
```
|
|||
|
|
ProvenanceRecord {
|
|||
|
|
source_module: string
|
|||
|
|
input_refs: string[]
|
|||
|
|
output_refs: string[]
|
|||
|
|
reasoning_tag: string -- short label for what operation was performed
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
See `schemas/provenance.json` for the normative schema.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. Bounded output enforcement
|
|||
|
|
|
|||
|
|
Every module must declare and enforce explicit output caps in its manifest. No module may produce unbounded output.
|
|||
|
|
|
|||
|
|
Default caps (may be overridden per module manifest):
|
|||
|
|
```
|
|||
|
|
max_objects_proposed: 8
|
|||
|
|
max_constraints_emitted: 16
|
|||
|
|
max_facets_emitted: 8
|
|||
|
|
max_merges: 4
|
|||
|
|
max_splits: 2
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
If a module reaches a cap, it must stop and return what it has, not raise an error and discard all output. Partial output is valid. Unbounded output is not.
|
|||
|
|
|
|||
|
|
Gates have separate caps: a gate emits exactly 1 GateSignal. No cap needed — it is structurally enforced.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. No free-form text past the perception layer
|
|||
|
|
|
|||
|
|
After the perception / extraction stage:
|
|||
|
|
- No module may output free-form natural language as a primary output
|
|||
|
|
- All outputs must be structured, typed, and schema-compliant
|
|||
|
|
- Diagnostic `notes` fields in logs may contain free text, but these are not part of the reasoning chain
|
|||
|
|
|
|||
|
|
Only the final synthesis layer may produce language as output.
|
|||
|
|
|
|||
|
|
This rule applies to constraint `expression` fields too — they are informational annotations, not authoritative outputs.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. First-class error states
|
|||
|
|
|
|||
|
|
Every module must be able to return explicit error states. Forcing a resolution when insufficient information exists is a contract violation.
|
|||
|
|
|
|||
|
|
Valid first-class output states for any object, facet, or constraint:
|
|||
|
|
|
|||
|
|
| State | Meaning |
|
|||
|
|
|---|---|
|
|||
|
|
| `unknown` | The module could not determine a value |
|
|||
|
|
| `ambiguous` | Multiple valid interpretations exist |
|
|||
|
|
| `conflicting` | Two or more inputs contradict each other |
|
|||
|
|
| `insufficient_data` | Not enough evidence to propose anything |
|
|||
|
|
|
|||
|
|
These states must be returned as typed fields, not inferred from missing values or nulls.
|
|||
|
|
|
|||
|
|
Example — SpecialistError type:
|
|||
|
|
```
|
|||
|
|
SpecialistError {
|
|||
|
|
error_kind: "unknown" | "ambiguous" | "conflicting" | "insufficient_data"
|
|||
|
|
affected_refs: string[]
|
|||
|
|
description: string
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
The resolver preserves and propagates error states rather than collapsing them.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. Constraint-first thinking
|
|||
|
|
|
|||
|
|
Specialists should prefer emitting constraints over conclusions.
|
|||
|
|
|
|||
|
|
Wrong:
|
|||
|
|
```
|
|||
|
|
Q_result.value = 3
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Right:
|
|||
|
|
```
|
|||
|
|
quantity_difference(Q_result, Q1, Q2) -- status: unresolved
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Resolution happens in the UCWM resolver, not inside specialists. A specialist that resolves arithmetic or logical conclusions itself before emitting constraints is bypassing the resolver contract.
|
|||
|
|
|
|||
|
|
The exception: arithmetic that is provably deterministic with all operands present may be resolved inline by the quantity specialist, with the resolution logged in provenance.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8. Test-driven module design
|
|||
|
|
|
|||
|
|
For every module, the following test classes must exist before the module is considered complete:
|
|||
|
|
|
|||
|
|
| Test class | Validates |
|
|||
|
|
|---|---|
|
|||
|
|
| Input → output correctness | Expected outputs for known inputs |
|
|||
|
|
| Schema compliance | All outputs validate against declared schemas |
|
|||
|
|
| Bounded output | Output never exceeds declared caps |
|
|||
|
|
| Deterministic behavior | Same input → same output (where determinism is expected) |
|
|||
|
|
| Failure modes | Module returns valid error states on ambiguous/missing data |
|
|||
|
|
| Domain adherence | Module does not emit facet/constraint kinds outside its manifest |
|
|||
|
|
|
|||
|
|
See `tests/contracts/` for templates.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 9. Minimal vertical slice priority
|
|||
|
|
|
|||
|
|
Do not build everything before validating anything.
|
|||
|
|
|
|||
|
|
The first working pipeline must support:
|
|||
|
|
```
|
|||
|
|
Input sentence
|
|||
|
|
→ gate signals
|
|||
|
|
→ object extraction (1–3 objects)
|
|||
|
|
→ 1–2 specialists
|
|||
|
|
→ constraints
|
|||
|
|
→ resolution
|
|||
|
|
→ correct answer
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Suggested first domain: math word problems or simple transfer/state-change problems.
|
|||
|
|
|
|||
|
|
Expand coverage only after the vertical slice produces correct, inspectable, testable output.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 10. Language binding stubs
|
|||
|
|
|
|||
|
|
Two interface stubs must exist from the start, even if naive:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
to_ucwm(text_input: string) → WorldState
|
|||
|
|
from_ucwm(world_state: WorldState) → string
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
See `synthesis/language_bindings.md` for the full interface specification.
|
|||
|
|
|
|||
|
|
These stubs enforce that translation and generation remain separable from reasoning. The reasoning core must never depend on how language enters or exits the system.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 11. Composite routing must be multi-label
|
|||
|
|
|
|||
|
|
The router must activate multiple specialists simultaneously. Single-label routing is not valid for real-world inputs.
|
|||
|
|
|
|||
|
|
A valid RoutingDecision activates:
|
|||
|
|
```
|
|||
|
|
temporal: true
|
|||
|
|
causal: true
|
|||
|
|
quantity: true
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Not:
|
|||
|
|
```
|
|||
|
|
category: "quantity" ← wrong; exactly one specialist selected
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
See `schemas/routing.json#/$defs/RoutingDecision` — the `assignments[]` array is the mechanism.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 12. Facets must be independent
|
|||
|
|
|
|||
|
|
A facet describes only its own dimension. It must not modify or depend on another facet's fields.
|
|||
|
|
|
|||
|
|
A TemporalFacet must not modify ownership state. A QuantityFacet must not set truth status. Cross-facet interaction happens only through constraints, never through direct facet-to-facet references.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 13. Resolver must be replaceable
|
|||
|
|
|
|||
|
|
The resolver is defined by an interface, not an implementation:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
resolve(world_state: WorldState) → WorldState
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
The rest of the pipeline must not depend on resolver internals. Any implementation that satisfies `tests/contracts/resolver_contract_tests.md` is a valid resolver. This makes it possible to swap:
|
|||
|
|
|
|||
|
|
- Simple rule-based resolver
|
|||
|
|
- Graph-based constraint solver
|
|||
|
|
- Probabilistic constraint solver
|
|||
|
|
- SAT-style system
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 14. Keep implementations simple first
|
|||
|
|
|
|||
|
|
Prefer clarity over performance. Prefer correctness over cleverness. This system will become complex naturally — do not add complexity early.
|
|||
|
|
|
|||
|
|
Guidelines:
|
|||
|
|
- Use simple, flat data structures where possible
|
|||
|
|
- Avoid premature abstraction
|
|||
|
|
- An obvious implementation that is slow is better than a clever one that is wrong
|
|||
|
|
- Performance optimization begins after contract tests pass
|
|||
|
|
|
|||
|
|
Language choice is not prescribed. Whatever language is chosen, it must support schema validation of WorldState at every module boundary.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 15. Debug mode
|
|||
|
|
|
|||
|
|
Every implementation must support a debug mode that emits a step-by-step trace:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
[Step 1] Gate outputs: {gate_id: activated, confidence}
|
|||
|
|
[Step 2] Objects proposed: {object_id, kind, label, confidence}
|
|||
|
|
[Step 3] Routing decision: {specialist_id, target_refs, budget}
|
|||
|
|
[Step 4] Specialist outputs: {specialist_id, new_facets[], new_constraints[]}
|
|||
|
|
[Step 5] Constraints: {constraint_id, type, args, strength, status}
|
|||
|
|
[Step 6] Resolution log: {operation, affected_refs, result}
|
|||
|
|
[Step 7] Final answer: {answer, confidence, derivation_trace}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Debug mode must write to a structured log (JSON or equivalent), not only to stdout. The log must be sufficient to replay and inspect any inference.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Priority order
|
|||
|
|
|
|||
|
|
When any two implementation choices conflict, resolve by this priority:
|
|||
|
|
|
|||
|
|
1. Contracts (schema compliance, interface adherence)
|
|||
|
|
2. Testability (can this behavior be verified independently?)
|
|||
|
|
3. Inspectability (can intermediate state be read and debugged?)
|
|||
|
|
4. Correctness (does it produce right answers?)
|
|||
|
|
5. Performance (how fast?)
|
|||
|
|
6. Scale (how big?)
|