docs(standards): split genericity matrix and infra adapters into Tier A/B/C
This commit is contained in:
@@ -3,7 +3,9 @@
|
||||
## Summary
|
||||
|
||||
All external systems are reached through adapters in `infra/`. Prefer an
|
||||
existing internal library over writing a new adapter.
|
||||
existing internal library over writing a new adapter; where no library exists,
|
||||
copy the Tier B scaffold from `templates/app`. See the Genericity Matrix for the
|
||||
Tier A / B / C split.
|
||||
|
||||
---
|
||||
|
||||
@@ -31,11 +33,13 @@ existing internal library over writing a new adapter.
|
||||
|
||||
- Transactions use a session context manager provided by the library.
|
||||
|
||||
**Library:** the Mongo operations library (see registry). Do not write raw
|
||||
Motor calls in the domain.
|
||||
**Tier A — Library (Mongo Ops).** Do not write raw Motor calls in the domain;
|
||||
consult the registry and the library's MCP before touching the driver.
|
||||
|
||||
## HTTP response cache
|
||||
|
||||
**Tier B — template.** Copy from `templates/app`; not a standalone library.
|
||||
|
||||
A generic GET cache sits behind a decorator.
|
||||
|
||||
```python
|
||||
@@ -50,6 +54,8 @@ async def list_items(request): ...
|
||||
|
||||
## Event / progress bus
|
||||
|
||||
**Tier B — template.** Copy from `templates/app`.
|
||||
|
||||
A port with an in-memory default adapter (`publish`, `get_events`). Swap for a
|
||||
durable broker in production (see Worker & Progress).
|
||||
|
||||
@@ -59,10 +65,12 @@ External fetchers (files, mail, HTTP) are adapters that wrap ingestion
|
||||
libraries. Construct them in the composition root and inject into
|
||||
orchestrators.
|
||||
|
||||
**Libraries:** the ingestion library (formats) and the mail library (email).
|
||||
**Tier A — Libraries:** Omniread (formats) and Mail Intake (email).
|
||||
|
||||
## LLM clients
|
||||
|
||||
**Tier B — template.** Copy the pool scaffold from `templates/app`.
|
||||
|
||||
When a pipeline calls a model provider, route through a pool adaptor that
|
||||
handles provider selection, retries, and client lifecycle:
|
||||
|
||||
@@ -75,10 +83,17 @@ Providers are selected by `LLM_PROVIDER` and configured by environment.
|
||||
|
||||
## Key-value store
|
||||
|
||||
**Tier B — template.** Copy from `templates/app`.
|
||||
|
||||
For report/snapshot storage, provide a pluggable store port with a Redis
|
||||
adapter and an in-memory fallback.
|
||||
|
||||
## Rule
|
||||
|
||||
If a capability already exists as a library (DB, DI, ingestion, mail, auth,
|
||||
docs), **use it**. Writing a private copy of a library is a defect.
|
||||
- **Tier A (libraries: DB, DI, ingestion, mail, auth, docs, pipelines)** — use
|
||||
the library; writing a private copy is a defect. Query `find_library` first.
|
||||
- **Tier B (cache, progress bus, LLM pool, KV store, composition shape, worker,
|
||||
tests)** — these are template code, not libraries: copy them from
|
||||
`templates/app` rather than searching the registry.
|
||||
- **Tier C (models, business logic, pipeline families, rules)** — author them
|
||||
yourself.
|
||||
|
||||
@@ -2,50 +2,68 @@
|
||||
|
||||
## Summary
|
||||
|
||||
This page states precisely what is **reusable as-is**, what is a **template to
|
||||
adapt**, and what is **app-specific and must be authored**. Use it to scope a
|
||||
new build.
|
||||
This page states precisely what is **library-backed**, what is
|
||||
**template-provided**, and what is **app-specific and must be authored**. Use it
|
||||
to scope a new build and to know, for any given capability, whether to call a
|
||||
library, copy template code, or write it yourself.
|
||||
|
||||
---
|
||||
|
||||
## Reusable as-is (do not rewrite)
|
||||
## Tier A — Library-backed (use; never reimplement)
|
||||
|
||||
| Area | Artifact |
|
||||
|---|---|
|
||||
| Layering & dependency rule | the package layout and import rules |
|
||||
| Composition root | the `init.py` shape, idempotency, `get_svc` overloading |
|
||||
| Web edge | `OpenAPIFirstApp` bootstrap, handler-name = `operationId`, thin handlers |
|
||||
| CRUD slice | the four-file pattern (model / ports-db / ports-service / converters) |
|
||||
| Generic CRUD service | the base service adaptor |
|
||||
| Repository factory | base / populating / cached selection |
|
||||
| Worker | the poll loop, backoff, retry, status machine |
|
||||
| Progress bus | the bus port + in-memory adapter + streaming endpoint |
|
||||
| Human-in-the-loop | the durable pause + question document + resolve endpoint + resume map |
|
||||
| Infra adaptors | HTTP cache decorator, KV store port, LLM pool scaffold |
|
||||
| Testing | integration harness with fakes, fixture-parity pattern |
|
||||
| Docs | GSDFC + generated stubs + MCP bundle pipeline |
|
||||
These capabilities already exist as internal libraries. Reach them through the
|
||||
library registry MCP (`find_library(capability)`) and read the library's own MCP
|
||||
for its API. Writing a private copy of any of these is a defect.
|
||||
|
||||
## Template to adapt (copy, then change names)
|
||||
| Capability | Library | MCP |
|
||||
|---|---|---|
|
||||
| Persistence: repositories, cache, populate, transactions | Mongo Ops (`mongo_ops`) | `:8007` |
|
||||
| Dependency injection / composition | Hexa (`hexa`) | `:8008` |
|
||||
| Deterministic multi-step transformation engine | DAG Pipe (`dagpipe`) | `:8006` |
|
||||
| Spec-first HTTP edge, client, codegen | OpenAPI First (`openapi_first`) | `:8004` |
|
||||
| Format-agnostic fetch + parse (HTML, PDF, CSV, XLSX) | Omniread (`omniread`) | `:8003` |
|
||||
| Read-only email ingestion | Mail Intake (`mail_intake`) | `:8002` |
|
||||
| JWT auth primitives (register, login, introspect) | Py JWT (`jwtlib`) | `:8005` |
|
||||
| Documentation build (MkDocs + MCP) | Doc Forge (`docforge`) | `:8001` |
|
||||
|
||||
| Artifact | Change |
|
||||
|---|---|
|
||||
| `pyproject.toml` | project name, dependencies |
|
||||
| `Dockerfile` / `docker-compose.yaml` | service name, ports, services |
|
||||
| `.env.example` | connection strings, provider keys |
|
||||
| `openapi.yaml` | every path/schema/operationId |
|
||||
| `scripts/` | seed and operator tasks |
|
||||
## Tier B — Template-provided (copy from `templates/app`, then adapt)
|
||||
|
||||
## App-specific (must be authored)
|
||||
These are reusable internal components shipped **inside** the template — they are
|
||||
not independent libraries. Copy them as-is, then rename/populate only what is
|
||||
app-specific. They give every app the same wiring shape as the reference app.
|
||||
|
||||
| Component | Template location | Action |
|
||||
|---|---|---|
|
||||
| Layering & dependency rule | the package layout + import rules | keep |
|
||||
| Composition root shape | `init.py` (`get_svc`/`get_db`, idempotency) | keep |
|
||||
| Spec-first web edge | `interfaces/openapi.py`, thin handlers bound to `operationId` | keep |
|
||||
| CRUD slice pattern | `domain/<resource>/{models.py, ports/db.py, ports/service.py, converters.py}` | rename + fill |
|
||||
| Generic CRUD service | `infra/adapters/service.py` (`CrudsServiceAdaptor`) | keep |
|
||||
| Repository factory | `infra/db/repos/mongo.py` (`_repo_factory`) | keep |
|
||||
| Worker poll + status loop | `worker.py` | keep |
|
||||
| Progress bus + streaming | bus port + in-memory adapter + SSE endpoint | keep |
|
||||
| Human-in-the-loop | durable pause + question document + resolve endpoint + resume map | keep |
|
||||
| HTTP response cache | `cache_response` decorator + generation invalidation | keep |
|
||||
| Key-value store | KV store port + Redis adapter + in-memory fallback | keep |
|
||||
| LLM client pool | provider-select + retry pool scaffold | keep |
|
||||
| Pipeline scaffold | `pipelines/shared/{ports,loader,registry}.py` + `pipelines/<family>/` | rename + fill |
|
||||
| Operator scripts | `scripts/` (`init()` / `get_svc()` / `shutdown()`) | rename |
|
||||
| Testing harness | integration fakes + fixture-parity pattern | keep |
|
||||
| Project scaffolding | `pyproject.toml`, `Dockerfile`, `docker-compose.yaml`, `.env.example`, `openapi.yaml` | rename + fill |
|
||||
|
||||
## Tier C — App-specific (must be authored)
|
||||
|
||||
| Artifact | Why |
|
||||
|---|---|
|
||||
| Resource models | the business shape |
|
||||
| Repository populate/cache rules | the relationships |
|
||||
| Service business logic | domain behaviour |
|
||||
| Pipeline families (if any) | the transformation graph |
|
||||
| Pipeline families | the transformation graph |
|
||||
| Pattern/rule resources | data-driven policy |
|
||||
| Fixtures & golden outputs | test data |
|
||||
|
||||
---
|
||||
|
||||
## The two axes
|
||||
|
||||
Everything app-specific reduces to **two axes**:
|
||||
@@ -54,4 +72,5 @@ Everything app-specific reduces to **two axes**:
|
||||
the OpenAPI contract.
|
||||
2. **Pipeline family** — only if inputs require multi-step transformation.
|
||||
|
||||
If you can specify those two axes, the rest of the app follows mechanically.
|
||||
If you can specify those two axes, the rest of the app follows mechanically:
|
||||
Tier A is imported, Tier B is copied, and Tier C is the only thing you author.
|
||||
|
||||
@@ -13,7 +13,7 @@ patterns, and the internal library catalog that agents consult while coding.
|
||||
- **Worker & Progress** — queued work, progress reporting, and visibility.
|
||||
- **Human-in-the-Loop** — guardrails and approvals inside automations.
|
||||
- **Infra Adapters** — how infrastructure connects without leaking into domain.
|
||||
- **Genericity Matrix** — what is generic vs app-specific.
|
||||
- **Genericity Matrix** — what is library-backed, template-provided, or authored.
|
||||
- **Library Registry** — the catalog of internal libraries behind all of it.
|
||||
|
||||
Read the **Wiki** for the philosophy and rationale; these pages are the
|
||||
|
||||
Reference in New Issue
Block a user