Module 01 Exercises¶
Work against:
Keep the tracked snapshot unchanged unless an exercise explicitly asks you to make a local copy. Start by running:
Your work is complete only when that baseline still passes.
Exercise 1: Trace one value through the pure core¶
Starting context: RawDoc, RagEnv, and the four functions in
pipeline_stages.py.
Use this input:
RawDoc(
doc_id="paper-7",
title="Substitution",
abstract=" Pure values compose ",
categories="cs.PL",
)
and RagEnv(chunk_size=6).
Produce:
- the exact
CleanDoc; - every chunk's text, start, and end;
- the number and range of embedding components;
- the final canonical key order;
- a classification of each transition as pure value work or effect.
Constraints:
- derive values by calling the tracked implementation;
- do not hard-code an embedding tuple in application code;
- do not perform file I/O;
- preserve the exact-positive-integer
RagEnvinvariant.
Expected evidence:
- a runnable test with explicit assertions;
- a short explanation of why equal chunk text gets equal embedding even when identity differs.
Acceptance checks:
cleaned abstract == "pure values compose"
concatenated chunk text == cleaned abstract
every embedding has 16 values in [0.0, 1.0]
structural deduplication of final output changes nothing
Exercise 2: Repair a mixed transformation¶
Starting context: this deliberately mixed helper:
seen_ids: list[str] = []
def normalize_batch(docs: list[RawDoc]) -> list[CleanDoc]:
result: list[CleanDoc] = []
for doc in docs:
seen_ids.append(doc.doc_id)
result.append(clean_doc(doc))
return result
Objective: separate the returned-value transformation from audit recording.
Constraints:
- the pure function may depend only on its argument;
- it must not mutate the input list or its elements;
- do not hide
seen_idsin a default argument, closure, class, or cache; - preserve document order and
clean_docbehavior; - keep recording at an explicitly effectful caller.
Expected evidence:
- two calls with equal input return equal output;
- the pure call leaves
seen_idsunchanged; - the effectful caller records each ID once;
- a substitution explanation identifies why the original fails.
State what your tests prove and why they do not prove the absence of every possible hidden effect.
Exercise 3: Earn a typed composition¶
Starting context: RagPipe, clean_doc, and chunk_doc.
Implement in an exercise file:
Then build:
Constraints:
- use exact annotations without
Any; - return a callable specialized to one immutable
RagEnv; - do not modify
RagPipe; - do not add a generic flat-map combinator;
- preserve empty-abstract behavior.
Expected evidence:
- examples for empty text, exact-size text, and a final short chunk;
- a static-review note showing why
RagPipe(clean_doc).then(embed_chunk)is incompatible; - a judgment about whether the adapter belongs in Module 01 production code.
The earlier contract that must remain true is full text coverage by chunk_doc.
Exercise 4: Test the effect boundary¶
Starting context: rag_shell.py and the tracked
tests/learning/test_module_01_shell_boundary.py. First run:
The existing proof covers:
- a valid two-row CSV;
- a header-only CSV;
- a row missing a required
RawDocfield; - a missing input path.
Objective: explain why each case belongs at the boundary, then design one additional Module 01 case that adds a new observation instead of repeating those four routes.
Choose one:
- non-ASCII title and abstract content remain valid UTF-8 after JSONL serialization;
- duplicate valid rows produce the pure core's canonical structural result;
- an invalid UTF-8 input is translated to a contextual
ValueError.
Use pytest's tmp_path; do not write outside the test directory.
Constraints for the added case:
- derive expected valid output with
full_rag; - parse JSONL instead of comparing incidental whitespace;
- assert the documented exception type when selecting a failure route;
- identify which existing test would catch domain logic copied into the shell and which would not;
- do not add retry, atomic-write, logging, or protocol abstractions;
- do not weaken the pure-core learning proof.
Expected evidence:
- one focused shell test and an explanation of its distinct observation;
- a table classifying each operation in
rag_shellas read effect, pure transform, or write effect; - an explicit note that direct output may be partial if writing fails.
Acceptance checks:
- the original four-test proof remains green;
- the new assertion fails for the specific regression it names;
- successful output is compared to
full_ragafter JSON parsing; - the conclusion states what the added case still does not prove.
Exercise 5: Review a false fixed-point claim¶
A reviewer proposes:
Objective: replace the claim with a well-typed law and explain the difference between determinism, idempotence, and canonicalization.
Constraints:
- use the tracked public signatures;
- name the function to which idempotence actually applies;
- include a counterexample that is deterministic but not idempotent;
- include the unique-document-ID assumption for order independence.
Expected evidence:
- one type-based rejection of the proposed expression;
- one passing fixed-point assertion;
- one passing canonical-order assertion;
- one paragraph stating what neither assertion proves.
Preserve all Module 01 learning and property tests.
Completion route¶
Run the three named proof surfaces:
make PROGRAM=python-programming/python-functional-programming \
capstone-foundation-types
make PROGRAM=python-programming/python-functional-programming \
capstone-foundation-proof
make PROGRAM=python-programming/python-functional-programming \
capstone-shell-proof
The broader property suite remains in
capstone/module-reference-states/module-01/tests/test_laws.py and must stay green.
Before reading the answers, be able to identify:
- the exact application behavior your work exercised;
- the earlier invariant each change preserved;
- the strongest claim your evidence supports;
- at least one claim it does not support.