Sprint 1: project skeleton, type system, and all architecture specs
- src/types.hpp: complete UCWM type system in C++20 — 19 enums, 11 facet data types, all core structs (CanonicalObject, Constraint, Facet, GateSignal, WorldState, etc.) with full JSON round-trip serialization - src/main.cpp: smoke test — constructs apple-problem WorldState by hand, serializes to JSON - tests/test_types.cpp: 19 tests, 123 assertions, all passing - CMakeLists.txt: CMake + CPM build with nlohmann/json, spdlog, Catch2 - schemas/: JSON Schema contracts for all UCWM data types - gates/, specialists/, resolver/, synthesis/: language-agnostic interface contracts and domain specs for all pipeline layers - docs/: architecture, vocabulary, decision matrices, roadmap (6 phases, 28 sprints), sprint_001, implementation_constraints Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
123
synthesis/contract.md
Normal file
123
synthesis/contract.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# Synthesis Interface Contract
|
||||
|
||||
The synthesis module is the final stage. It reads resolved WorldState and produces a natural language answer plus a derivation trace. The answer must be derivable from resolved constraints — not generated from surface token patterns.
|
||||
|
||||
---
|
||||
|
||||
## Design principle
|
||||
|
||||
Synthesis is translation, not reasoning. All reasoning was done by specialists and the resolver. Synthesis converts the stabilized structured state into human-readable output.
|
||||
|
||||
If the answer cannot be derived from resolved constraints, synthesis should say so rather than confabulate.
|
||||
|
||||
---
|
||||
|
||||
## Input
|
||||
|
||||
```
|
||||
SynthesisInput {
|
||||
world_state: WorldState -- must have stage = "resolved"
|
||||
original_query: string -- the user's original input text
|
||||
synthesis_mode: string -- "direct" | "explain" | "trace"
|
||||
}
|
||||
```
|
||||
|
||||
**Synthesis modes:**
|
||||
|
||||
- `direct`: produce the answer as a natural sentence. Minimal explanation.
|
||||
- `explain`: produce the answer with a short explanation of how it was derived.
|
||||
- `trace`: produce the answer plus a full derivation trace listing every constraint and resolver operation used.
|
||||
|
||||
---
|
||||
|
||||
## Output
|
||||
|
||||
```
|
||||
SynthesisOutput {
|
||||
answer: string
|
||||
confidence: float [0, 1]
|
||||
derivation_trace: string[] -- ordered list of constraint_ids / operations used
|
||||
open_questions: string[]? -- aspects the system could not resolve
|
||||
synthesis_mode: string -- echoes input mode
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Derivation trace
|
||||
|
||||
The `derivation_trace` must list, in order:
|
||||
1. The objects and facts the answer is based on
|
||||
2. The constraints that were applied
|
||||
3. The resolver operations that stabilized the relevant values
|
||||
|
||||
The trace must be sufficient for a reader to reconstruct the answer without the system.
|
||||
|
||||
---
|
||||
|
||||
## Invariants
|
||||
|
||||
1. **Grounded answer.** Every factual claim in the answer must correspond to a resolved constraint or a confirmed object in WorldState. Synthesis does not add new facts.
|
||||
|
||||
2. **Uncertainty acknowledgment.** If a relevant constraint has `status: contradicted` or is in `open_contradictions`, the answer must acknowledge the uncertainty rather than silently pick a side.
|
||||
|
||||
3. **Trace completeness.** `derivation_trace` must list all constraints used. If a claim appears in the answer, the constraint supporting it must appear in the trace.
|
||||
|
||||
4. **Stage check.** Synthesis must reject WorldState where `stage ≠ "resolved"` with an error, not a guess.
|
||||
|
||||
---
|
||||
|
||||
## Answer generation patterns
|
||||
|
||||
### Simple factual answer
|
||||
|
||||
When WorldState contains a single resolved quantity or state that directly answers the query:
|
||||
|
||||
```
|
||||
Template: "{Subject} {verb} {value} {unit}."
|
||||
Example: "Alice has 3 apples."
|
||||
|
||||
Derivation:
|
||||
1. E1 (Alice) — active entity
|
||||
2. Q_alice_final — quantity, value=3, unit="apples"
|
||||
3. C1: owns(Alice, apples, count=5) at t0 — resolved
|
||||
4. C2: transfers(Alice, Bob, apples, count=2) at t1 — resolved
|
||||
5. C3: quantity_difference(Q_alice_final, Q1, Q2) — resolved, computed 5-2=3
|
||||
6. Resolver Op: merge_coreference (she → Alice)
|
||||
7. Resolver Op: resolve_arithmetic (Q_alice_final.value = 3)
|
||||
```
|
||||
|
||||
### Uncertain answer
|
||||
|
||||
When `open_contradictions` is non-empty or relevant objects are low-confidence:
|
||||
|
||||
```
|
||||
Template: "{Subject} likely {verb} {value}, though {uncertainty description}."
|
||||
```
|
||||
|
||||
### No answer available
|
||||
|
||||
When the query asks for something not covered by any resolved constraint:
|
||||
|
||||
```
|
||||
Template: "The available information does not determine {query_topic}."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Synthesis does not do
|
||||
|
||||
- Infer new facts beyond resolved constraints
|
||||
- Choose between contradicted constraints without flagging the contradiction
|
||||
- Generate fluent text that goes beyond what WorldState supports
|
||||
- Add caveats, hedges, or stylistic embellishments not grounded in confidence values
|
||||
|
||||
---
|
||||
|
||||
## Contract test requirements
|
||||
|
||||
- Given resolved WorldState with Q_alice_final.value=3 and owns constraint resolved: answer must contain "3" and "Alice"
|
||||
- Given WorldState with `open_contradictions` non-empty: answer must not state a definitive value for the contradicted quantity
|
||||
- `derivation_trace` must be non-empty for any non-trivial answer
|
||||
- `stage` check: must raise error given WorldState where stage = "post_specialist"
|
||||
- All emitted `derivation_trace` entries must reference valid IDs in WorldState
|
||||
156
synthesis/language_bindings.md
Normal file
156
synthesis/language_bindings.md
Normal file
@@ -0,0 +1,156 @@
|
||||
# Language Binding Interface
|
||||
|
||||
The language binding layer is the boundary between messy natural language and the structured UCWM reasoning core. It consists of exactly two interface stubs:
|
||||
|
||||
```
|
||||
to_ucwm(text_input) → WorldState
|
||||
from_ucwm(world_state) → text_output
|
||||
```
|
||||
|
||||
These must remain separable. The reasoning core must never depend on how language enters or exits.
|
||||
|
||||
---
|
||||
|
||||
## `to_ucwm` — Input binding
|
||||
|
||||
```
|
||||
to_ucwm {
|
||||
input:
|
||||
text: string -- raw natural language input
|
||||
context: WorldState? -- optional prior world state (multi-turn)
|
||||
options: BindingOptions?
|
||||
|
||||
output:
|
||||
world_state: WorldState -- stage = "post_gate" with gate_signals populated
|
||||
-- and initial object proposals if perception runs here
|
||||
|
||||
BindingOptions {
|
||||
run_gates: boolean -- default: true
|
||||
run_perception: boolean -- default: true (runs object proposal)
|
||||
language: string? -- ISO 639-1 language code, default "en"
|
||||
debug: boolean -- emit step-by-step trace
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Responsibilities
|
||||
|
||||
`to_ucwm` is responsible for:
|
||||
1. Running the Relation Gate Array on the input text, producing `GateSignal[]`
|
||||
2. Running the perception / object proposal stage, producing initial `CanonicalObject[]`
|
||||
3. Packaging both into a `WorldState` with `stage = "post_gate"` or `"post_proposal"`
|
||||
4. Returning a valid WorldState — never raw text, never embeddings as primary output
|
||||
|
||||
### What `to_ucwm` must NOT do
|
||||
|
||||
- Run specialists
|
||||
- Emit constraints
|
||||
- Produce answers
|
||||
- Modify a prior WorldState in-place (multi-turn must pass context as a separate field, not mutate)
|
||||
|
||||
### Naive implementation (first slice)
|
||||
|
||||
A minimal `to_ucwm` implementation:
|
||||
1. Run all gates using rule-based implementations from `gates/simple_rules.md`
|
||||
2. For each activated gate, tag relevant spans
|
||||
3. Propose one `CanonicalObject` per clearly identified entity, quantity, or event span
|
||||
4. Return WorldState with these proposals
|
||||
|
||||
This is sufficient for the first vertical slice. Upgrade to a neural perception model later.
|
||||
|
||||
---
|
||||
|
||||
## `from_ucwm` — Output binding
|
||||
|
||||
```
|
||||
from_ucwm {
|
||||
input:
|
||||
world_state: WorldState -- must have stage = "resolved"
|
||||
original_query: string -- original user input text
|
||||
mode: string -- "direct" | "explain" | "trace"
|
||||
options: OutputOptions?
|
||||
|
||||
output:
|
||||
text: string -- natural language answer
|
||||
confidence: float
|
||||
derivation_trace: string[]
|
||||
open_questions: string[]?
|
||||
|
||||
OutputOptions {
|
||||
max_length: integer? -- max characters in output text
|
||||
language: string? -- ISO 639-1, default "en"
|
||||
debug: boolean
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Responsibilities
|
||||
|
||||
`from_ucwm` is responsible for:
|
||||
1. Checking WorldState.stage = "resolved" (reject otherwise with an error)
|
||||
2. Delegating to the synthesis module (see `synthesis/contract.md`)
|
||||
3. Returning a typed `SynthesisOutput` — never directly generating text from tokens
|
||||
|
||||
### What `from_ucwm` must NOT do
|
||||
|
||||
- Access raw input tokens
|
||||
- Run specialists or the resolver
|
||||
- Add facts not present in resolved WorldState
|
||||
|
||||
---
|
||||
|
||||
## Contract invariants
|
||||
|
||||
1. **Round-trip transparency.** For any resolved WorldState W:
|
||||
```
|
||||
from_ucwm(W).derivation_trace must reference only IDs that exist in W
|
||||
```
|
||||
|
||||
2. **Stage enforcement.** `to_ucwm` always produces a WorldState with stage at or before `post_proposal`. `from_ucwm` always requires stage = `resolved`. The pipeline between them is the responsibility of the caller.
|
||||
|
||||
3. **Stateless bindings.** Neither binding holds state. Multi-turn context is passed as an argument, not stored inside the binding.
|
||||
|
||||
4. **Language is at the edges only.** Raw language appears only at the input of `to_ucwm` and the output of `from_ucwm`. No other module may receive or emit raw language as a primary typed output.
|
||||
|
||||
---
|
||||
|
||||
## Multi-turn handling
|
||||
|
||||
For conversational multi-turn:
|
||||
|
||||
```
|
||||
turn_1:
|
||||
ws_1 = to_ucwm(text="Alice had 5 apples")
|
||||
ws_1_resolved = pipeline(ws_1)
|
||||
|
||||
turn_2:
|
||||
ws_2 = to_ucwm(text="She gave Bob 2.", context=ws_1_resolved)
|
||||
-- ws_2 inherits E1 (Alice), O_apples, Q1 from ws_1_resolved
|
||||
-- entity specialist resolves "She" → E1 via existing alias
|
||||
```
|
||||
|
||||
The context WorldState is read-only in `to_ucwm`. New proposals may reference objects from context but do not modify them directly. The resolver handles merges.
|
||||
|
||||
---
|
||||
|
||||
## Debug trace format
|
||||
|
||||
When `options.debug = true`, both bindings emit a structured log:
|
||||
|
||||
```json
|
||||
{
|
||||
"stage": "to_ucwm",
|
||||
"input_length": 42,
|
||||
"gates_fired": ["has_entity_reference", "has_quantity", "has_ownership_transfer"],
|
||||
"objects_proposed": 5,
|
||||
"world_state_stage": "post_proposal"
|
||||
}
|
||||
|
||||
{
|
||||
"stage": "from_ucwm",
|
||||
"world_state_stage": "resolved",
|
||||
"answer": "Alice has 3 apples.",
|
||||
"confidence": 0.97,
|
||||
"derivation_steps": 7
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user