Module 05 Capstone Delta¶
Module 04 left FuncPipe able to stream documents while representing recoverable
failures with Result, absence with Option, and operational failures with
structured ErrInfo values. Those containers make failure visible, but they do
not decide which domain states are legal, how independent validation errors
should accumulate, or how a stored value retains its meaning across a boundary.
Module 05 makes those decisions against the same RAG values. It sharpens the
distinction between a prepared and indexed chunk, reuses Result as the
success-or-failure sum, adds lawful mapping and aggregation, accumulates
independent validation errors, validates complete indexed chunks at the edge,
and tests representation equivalence.
The application delta¶
| Delta question | Module 05 answer |
|---|---|
| Previous capability | Lazy and bounded RAG traversal with typed per-record failure, absence, retry, resource, and reporting policies |
| New pressure | Stage guarantees and boundary invariants are easy to lose when chunks are treated as loose fields or partial transport dictionaries |
| Concept introduced | Existing RAG products and sums made explicit, stage-typed transitions, functor mapping, applicative validation, monoidal aggregation, exhaustive matching, explicit codecs, and representation equivalence |
| Source surfaces | core/rag_types.py, rag/stages.py, result/types.py, fp/functor.py, fp/validation.py, fp/monoid.py, rag/domain/, and boundaries/adapters/ |
| Proof surfaces | Module 05 law and boundary tests plus tests/learning/test_module_05_data_modelling.py |
| Preserved behavior | Module 04 cleaning, chunking, embedding, lazy order, bounded traversal, typed failures, retries, and resource cleanup |
| Completed state | capstone/module-reference-states/module-05/ |
| Learner route | Run one named learning test, inspect the exact constructor or operation it exercises, then complete the matching exercise |
| Later states affected | Modules 06–09 and the live Module 10 capstone retain these value, validation, boundary, and equivalence contracts |
Read the delta as ownership¶
flowchart LR
input["Untrusted chunk payload"] --> adapters["ChunkModel\ncomplete edge validation"]
adapters --> indexed["Chunk\nindexed domain value"]
raw["RawDoc"] -->|clean_doc| clean["CleanDoc"]
clean -->|chunk_doc| prepared["ChunkWithoutEmbedding"]
prepared -->|embed_chunk| indexed
indexed --> operate["Pure operations\nmap + match + fold"]
operate --> output["Typed output"]
indexed --> optimized["Optimized batch"]
optimized --> proof["Observable-equivalence proof"]
proof --> output
The arrows are ownership boundaries:
- the boundary validates document identity, text, offsets, metadata, and the complete embedding before handing an ordinary immutable value inward;
- stage signatures make each added guarantee visible without a mutable status field;
- domain constructors own cross-field invariants;
mapchanges a successful value without inventing a failure policy;- applicative validation evaluates independent checks and preserves every reported problem in declared order;
- monoids aggregate only when an associative operation and identity are honest;
- pattern matching consumes a closed set of variants; and
- an optimized representation is accepted only after its public observables agree with the clear reference path.
Focus the reference-state comparison¶
The Module 04→05 snapshot includes a broad package reorganization. The meaningful new teaching surface is narrower:
src/funcpipe_rag/
├── core/
│ └── rag_types.py
├── fp/
│ ├── functor.py
│ ├── validation.py
│ └── monoid.py
├── rag/
│ ├── stages.py
│ └── domain/
│ ├── chunk.py
│ ├── text.py
│ ├── metadata.py
│ ├── embedding.py
│ └── perf.py
├── result/
│ └── types.py
└── boundaries/adapters/
├── pydantic_edges.py
└── serde.py
core/rag_types.py and rag/stages.py remain the primary application path.
rag/domain/ is a later focused lab for cross-field assembly and alternative
representation; it does not replace the pipeline values. Its result is named
AssembledChunk so learners do not mistake it for another pipeline stage. The
early Module 5 lessons and proofs use the cumulative values first, so the lab
has explicit context instead of appearing as a parallel application.
boundaries/adapters/ owns external validation and serialization so Pydantic
and transport envelopes do not leak into the core. Its ChunkModel converts
without discarding the document ID, offsets, metadata, or embedding.
These ownership paths begin in Module 05 and remain stable downstream. Package movement that previously appeared only in the Module 05→06 comparison is not a Module 06 flow concept and should not distract from that later delta.
What changed in the RAG application¶
FuncPipe's Module 5 evidence now lets a learner:
- trace
RawDoc → CleanDoc → ChunkWithoutEmbedding → Chunk; - use the existing
Ok | Errresult instead of a parallel chunk outcome; - prove that embedding preserves document identity, text, and offsets;
- transform successful typed values without manual unboxing;
- report all independent construction errors in one validation result;
- aggregate chunk metrics with an explicit identity and associative operation;
- reject inconsistent offsets, non-finite values, and any embedding dimension other than 16 at the external boundary;
- round-trip a complete indexed chunk without field loss;
- handle closed variants with structural pattern matching;
- preserve failure provenance through a versioned serialization envelope;
- assemble text, metadata, and embedding subsystems with cross-field checks; and
- choose a hybrid NumPy representation only when it preserves the clear pure path's observable results.
What did not change¶
Module 05 does not turn the complete RAG application into one large algebraic
framework. Existing streaming and resilience behavior remains in place.
It does not add a Pending | Running | Done | Failed job model: the application
has no persisted job lifecycle or progress events that would justify it. The
real transformations are represented by their input and output product types.
Result is still the right model for dependent fail-fast work; accumulating
Validation is for independent checks. Pydantic remains at the edge. A monoid
is not justified for every collection, and the NumPy path is not the default
merely because it is optimized.
Working route¶
- Compare
module-reference-states/module-04/withmodule-reference-states/module-05/. - Read this page before interpreting the broad file diff.
- Open the current lesson and its named test in
tests/learning/test_module_05_data_modelling.py. - Run that one test with the Module 05
src/directory onPYTHONPATH. - Inspect the matching law or boundary test in the Module 05 test directory.
- Complete the exercise and state what the evidence does not prove.
- Confirm the learning proof remains present in every downstream state.
Preservation checklist¶
Before accepting a modelling change, confirm that:
- previously valid RAG input still produces the same pipeline output;
- each stage adds its guarantee without mutating the earlier value;
- embedding preserves document identity, text, offsets, and metadata;
- invalid states are rejected by the narrowest responsible constructor;
Result,Option, andValidationkeep distinct meanings;- accumulated errors retain deterministic order and provenance;
- matching handles every declared variant;
- external schemas and codecs do not become core domain dependencies or discard domain fields during conversion;
- serialization round-trips the public value, not incidental object layout;
- an optimized representation preserves identity, order, metadata, and numeric results within the declared tolerance; and
- later snapshots still satisfy the Module 05 learning proofs.
Continue with Product and Sum Types.