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:
204
docs/sprint_001.md
Normal file
204
docs/sprint_001.md
Normal file
@@ -0,0 +1,204 @@
|
||||
# Sprint 1 — Skeleton
|
||||
|
||||
## Goal
|
||||
|
||||
The C++ project compiles cleanly. All core UCWM types are defined as C++ structs. A `WorldState` can be constructed in code and serialized to JSON. No logic runs yet — this sprint is purely about getting the type system right before anything else is built on top of it.
|
||||
|
||||
**If the types are wrong here, everything built on them will be wrong. Take the time to get them right.**
|
||||
|
||||
---
|
||||
|
||||
## Deliverables
|
||||
|
||||
| File | Description |
|
||||
|---|---|
|
||||
| `CMakeLists.txt` | Build system. CPM dependencies. Targets for main and tests. |
|
||||
| `src/types.hpp` | All core UCWM structs: CanonicalObject, all Facet types, Constraint, GateSignal, RoutingDecision, WorldState, Provenance, SpecialistError. |
|
||||
| `src/main.cpp` | Smoke test: constructs a minimal WorldState for the apple problem by hand, serializes to JSON, prints debug output. |
|
||||
| `tests/test_types.cpp` | Unit tests: construct each type, verify field access, verify JSON round-trip. |
|
||||
|
||||
---
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [ ] `cmake -B build && cmake --build build` succeeds with zero errors and zero warnings
|
||||
- [ ] `./build/ucwm` runs and prints a JSON-serialized WorldState to stdout
|
||||
- [ ] `./build/tests` runs and all type tests pass
|
||||
- [ ] Every field from `schemas/objects.json`, `schemas/facets.json`, `schemas/constraints.json`, `schemas/routing.json`, `schemas/provenance.json`, and `schemas/world_state.json` has a corresponding C++ field
|
||||
- [ ] No raw owning pointers — use `std::optional`, `std::variant`, `std::vector`, `std::unordered_map`
|
||||
- [ ] All string IDs typed as `std::string` (upgrade to a newtype wrapper in a later sprint if needed)
|
||||
|
||||
---
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Any gate logic
|
||||
- Any specialist logic
|
||||
- Any resolver logic
|
||||
- Any synthesis logic
|
||||
- JSON Schema validation (structs mirror the schemas, but no runtime validation yet)
|
||||
- Neural models of any kind
|
||||
- Performance optimization
|
||||
|
||||
---
|
||||
|
||||
## Dependencies (pulled via CPM)
|
||||
|
||||
```cmake
|
||||
CPMAddPackage("gh:nlohmann/json@3.11.3")
|
||||
CPMAddPackage("gh:gabime/spdlog@1.13.0")
|
||||
CPMAddPackage("gh:catchorg/Catch2@3.5.4")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Type design notes
|
||||
|
||||
### Use `std::variant` for sum types
|
||||
|
||||
Object kind, facet kind, constraint status, object status — these are closed enumerations in the schema. Use `enum class` for simple enums, `std::variant` when the type carries different data per variant.
|
||||
|
||||
```cpp
|
||||
enum class ObjectKind {
|
||||
Entity, Event, Concept, Proposition,
|
||||
RelationInstance, ProcedureStep, CodeObject,
|
||||
Quantity, Claim, State
|
||||
};
|
||||
|
||||
enum class ObjectStatus { Proposed, Active, Merged, Split, Invalidated };
|
||||
enum class ConstraintStrength { Hard, Soft, Probabilistic, Defeasible };
|
||||
enum class ConstraintStatus { Unresolved, Resolved, Contradicted, Suspended };
|
||||
enum class Polarity { Positive, Negative };
|
||||
```
|
||||
|
||||
### Use `std::optional` for nullable fields
|
||||
|
||||
Schema fields that are not in `required` should be `std::optional<T>` in C++. Never use raw nulls or sentinel values.
|
||||
|
||||
```cpp
|
||||
std::optional<SurfaceSpan> surface_span;
|
||||
std::optional<std::string> canonical_label;
|
||||
std::optional<std::string> merged_into;
|
||||
std::optional<float> probability; // only when strength=Probabilistic
|
||||
```
|
||||
|
||||
### Facets as a variant
|
||||
|
||||
All facet types share a base set of fields, then add domain-specific fields. Represent as a `std::variant` or a struct with a `std::variant` payload.
|
||||
|
||||
```cpp
|
||||
struct TemporalFacetData {
|
||||
std::optional<std::string> time_point;
|
||||
std::optional<std::string> interval_start;
|
||||
std::optional<std::string> interval_end;
|
||||
bool is_recurring = false;
|
||||
std::optional<std::string> recurrence_pattern;
|
||||
std::vector<std::string> temporal_order_refs;
|
||||
};
|
||||
|
||||
// ... one struct per facet kind ...
|
||||
|
||||
using FacetData = std::variant<
|
||||
TemporalFacetData,
|
||||
SpatialFacetData,
|
||||
CausalFacetData,
|
||||
LogicalFacetData,
|
||||
OwnershipFacetData,
|
||||
QuantityFacetData,
|
||||
SyntacticFacetData,
|
||||
SocialFacetData,
|
||||
PlanningFacetData
|
||||
>;
|
||||
|
||||
struct Facet {
|
||||
std::string facet_id;
|
||||
std::string object_ref;
|
||||
float confidence;
|
||||
std::string source_module;
|
||||
std::vector<std::string> provenance_refs;
|
||||
FacetData data; // kind is implicit in the variant index
|
||||
};
|
||||
```
|
||||
|
||||
### WorldState as maps
|
||||
|
||||
```cpp
|
||||
struct WorldState {
|
||||
std::string state_id;
|
||||
WorldStateStage stage;
|
||||
std::optional<std::string> input_text;
|
||||
std::unordered_map<std::string, CanonicalObject> objects;
|
||||
std::unordered_map<std::string, Facet> facets;
|
||||
std::unordered_map<std::string, Constraint> constraints;
|
||||
std::unordered_map<std::string, Provenance> provenance;
|
||||
std::optional<RoutingDecision> routing_decision;
|
||||
std::vector<GateSignal> gate_signals;
|
||||
std::vector<ResolutionEntry> resolution_log;
|
||||
std::vector<ContradictionRecord> open_contradictions;
|
||||
std::optional<std::string> synthesis_answer;
|
||||
std::optional<float> synthesis_confidence;
|
||||
std::vector<std::string> derivation_trace;
|
||||
};
|
||||
```
|
||||
|
||||
### JSON serialization
|
||||
|
||||
Use `nlohmann/json`'s `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE` macro or manual `to_json`/`from_json` overloads. Every type needs both directions for the debug trace and for loading fixtures.
|
||||
|
||||
```cpp
|
||||
// Example pattern for each type:
|
||||
void to_json(nlohmann::json& j, const CanonicalObject& o);
|
||||
void from_json(const nlohmann::json& j, CanonicalObject& o);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## File layout after Sprint 1
|
||||
|
||||
```
|
||||
ucwm/
|
||||
CMakeLists.txt
|
||||
cmake/
|
||||
CPM.cmake
|
||||
src/
|
||||
types.hpp ← all structs and enums
|
||||
main.cpp ← smoke test
|
||||
tests/
|
||||
test_types.cpp ← type construction + JSON round-trip tests
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Smoke test behavior (`main.cpp`)
|
||||
|
||||
`main.cpp` should:
|
||||
1. Construct the post-proposal WorldState from `examples/word_problem_001.json` by hand (hardcoded, not parsed — parsing the fixture comes in Sprint 2)
|
||||
2. Serialize it to JSON using nlohmann/json
|
||||
3. Print the JSON to stdout
|
||||
4. Print a simple debug header showing object count, constraint count
|
||||
|
||||
Expected output:
|
||||
```
|
||||
=== UCWM Smoke Test ===
|
||||
WorldState stage: post_proposal
|
||||
Objects: 7
|
||||
Facets: 0
|
||||
Constraints: 0
|
||||
|
||||
[full JSON follows]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Definition of done
|
||||
|
||||
Sprint 1 is done when:
|
||||
1. All acceptance criteria checkboxes are checked
|
||||
2. A second person (or the same person on a fresh read) can understand every field in `types.hpp` without referring back to the schemas
|
||||
3. The JSON output of `main.cpp` matches the structure of `examples/word_problem_001.json` for the post-proposal stage
|
||||
|
||||
---
|
||||
|
||||
## Next sprint preview
|
||||
|
||||
Sprint 2 builds the keyword gates and rule-based object proposal on top of these types. None of that can start until `types.hpp` is locked.
|
||||
Reference in New Issue
Block a user