Read FuncPipe by Behavior, Not Alphabetically¶
The live capstone contains the accumulated work of ten modules. Reading every file in tree order hides the important question: which code owns the behavior I am trying to understand?
Use this guide after the Capstone Map has identified the correct module state. Paths below describe the live endpoint; the same ownership pattern grows gradually through the tracked states.
Begin with one public promise¶
Choose a behavior before choosing a directory:
| Behavior you want to trace | First test surface | First source surface |
|---|---|---|
| clean, chunk, embed, and deduplicate documents | tests/unit/rag/ |
rag/stages.py, rag/chunking.py, rag/rag_api.py |
| preserve success and failure values in a stream | tests/unit/result/ |
result/types.py, result/stream.py, result/folds.py |
| keep traversal lazy and bounded | tests/unit/streaming/ and tests/unit/tree/ |
streaming/, tree/, then the consuming RAG function |
| validate or combine functional values | tests/unit/fp/ |
fp/ |
| assemble explicit pipeline policy | tests/unit/pipelines/ and tests/unit/policies/ |
pipelines/, policies/ |
| describe and execute effects | tests/unit/domain/ and tests/unit/infra/adapters/ |
domain/effects/, domain/capabilities.py, then infra/adapters/ |
| translate a library or process boundary | tests/unit/interop/ and tests/unit/boundaries/ |
interop/, then boundaries/ |
| accept or block a sustainment change | tests/unit/review/ |
review/, then boundaries/shells/review_cli.py |
Tests come first because they narrow “what does this package do?” into an observable contract. Source then explains how that contract is achieved.
Trace a document request¶
The central live route is full_rag_api_path in rag/rag_api.py:
flowchart LR
path["path: str"]
reader["RagBoundaryDeps.reader<br/>read_docs"]
result{"Result"}
core["full_rag_api_docs"]
keep["rule predicate"]
clean["cleaner"]
chunk["chunk + embed"]
dedup["structural dedup"]
output["Ok(chunks, observations)"]
path --> reader --> result
result -->|"Err"| failure["Err(message)"]
result -->|"Ok(docs)"| core
core --> keep --> clean --> chunk --> dedup --> output
Read the route in this order:
rag/config.pydefinesRagBoundaryDepsandRagCoreDeps. Identify which dependencies may perform effects and which are plain callables.rag/rag_api.py::full_rag_api_pathasks the reader for documents and translates the boundary result into the core call.rag/rag_api.py::full_rag_api_docsmaterializes at the API edge because it must produce counts, samples, taps, and a final list.rag/stages.pycontains deterministic cleaning, chunking helpers, embedding, and deduplication.- The matching tests in
tests/unit/rag/prove values and observations. Boundary tests separately prove reader failure.
Do not infer that all RAG routes materialize. iter_rag and iter_rag_core in the same
API module remain iterator-producing routes. The name and return type tell you which
contract you are reading.
Identify the functional core¶
“Core” does not mean one directory. It means code whose result depends only on explicit inputs and which does not execute external effects.
In FuncPipe, that responsibility spans:
rag/stages.pyfor deterministic RAG transformations;core/andrag/domain/for application values and predicates;result/for explicit success and failure flow;fp/for reusable composition and validation;streaming/andtree/for lazy data structure behavior; and- pure policy decisions in
policies/andreview/.
Check the function signature and body. A module living under domain/ is not
automatically pure, and a function under policies/ may still receive already-observed
measurements. Ownership comes from what the code is allowed to do, not from a slogan
about folder names.
Follow an effect from description to execution¶
For an I/O question, read inward from the test and outward from the plan:
- A capability names the smallest operation the application needs.
- An effect plan describes work as a value or delayed computation.
- A boundary shell selects dependencies and decides when execution occurs.
- An infrastructure adapter performs concrete storage, clock, or runtime work.
If a concrete adapter is imported into a pure RAG stage, ownership has leaked inward. If a capability mirrors an entire library API, the boundary is too broad to teach or replace cleanly.
Separate similarly named packages¶
Several names are intentionally close:
| Surface | Responsibility |
|---|---|
core/ |
reusable application-level rules and older RAG value contracts |
rag/ |
RAG assembly, stages, configuration, and current domain types |
domain/ |
cross-application capabilities, composition, and effect descriptions |
rag/domain/ |
values specifically owned by the RAG model |
boundaries/ |
process-facing shells and translation adapters |
infra/adapters/ |
concrete implementations of effect capabilities |
When two packages appear able to own a change, ask whether the behavior is RAG meaning, effect description, or concrete execution. That answer is more durable than choosing the nearest file.
Use the generated inventory carefully¶
From the capstone directory:
The output groups packages and tests by review ownership and counts Python files. It is an inventory, not an architecture proof. A group with many files is not more important; a listed owner does not prove every import respects the boundary.
Use the inventory to choose a starting group. Confirm actual behavior through source and tests.
Stop reading at the right boundary¶
For one study question, stop when you can name:
- the public input and output values;
- the pure transformation or policy decision;
- the effect owner, if any;
- the matching failure route;
- the test that observes the claim; and
- one neighboring package that should not own the behavior.
Opening more files after those answers are clear usually widens context without improving judgment. Continue only if a test or import leads across the boundary for a specific reason.