docs(standards): split genericity matrix and infra adapters into Tier A/B/C
This commit is contained in:
@@ -3,7 +3,9 @@
|
|||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
All external systems are reached through adapters in `infra/`. Prefer an
|
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.
|
- Transactions use a session context manager provided by the library.
|
||||||
|
|
||||||
**Library:** the Mongo operations library (see registry). Do not write raw
|
**Tier A — Library (Mongo Ops).** Do not write raw Motor calls in the domain;
|
||||||
Motor calls in the domain.
|
consult the registry and the library's MCP before touching the driver.
|
||||||
|
|
||||||
## HTTP response cache
|
## HTTP response cache
|
||||||
|
|
||||||
|
**Tier B — template.** Copy from `templates/app`; not a standalone library.
|
||||||
|
|
||||||
A generic GET cache sits behind a decorator.
|
A generic GET cache sits behind a decorator.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@@ -50,6 +54,8 @@ async def list_items(request): ...
|
|||||||
|
|
||||||
## Event / progress bus
|
## Event / progress bus
|
||||||
|
|
||||||
|
**Tier B — template.** Copy from `templates/app`.
|
||||||
|
|
||||||
A port with an in-memory default adapter (`publish`, `get_events`). Swap for a
|
A port with an in-memory default adapter (`publish`, `get_events`). Swap for a
|
||||||
durable broker in production (see Worker & Progress).
|
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
|
libraries. Construct them in the composition root and inject into
|
||||||
orchestrators.
|
orchestrators.
|
||||||
|
|
||||||
**Libraries:** the ingestion library (formats) and the mail library (email).
|
**Tier A — Libraries:** Omniread (formats) and Mail Intake (email).
|
||||||
|
|
||||||
## LLM clients
|
## 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
|
When a pipeline calls a model provider, route through a pool adaptor that
|
||||||
handles provider selection, retries, and client lifecycle:
|
handles provider selection, retries, and client lifecycle:
|
||||||
|
|
||||||
@@ -75,10 +83,17 @@ Providers are selected by `LLM_PROVIDER` and configured by environment.
|
|||||||
|
|
||||||
## Key-value store
|
## Key-value store
|
||||||
|
|
||||||
|
**Tier B — template.** Copy from `templates/app`.
|
||||||
|
|
||||||
For report/snapshot storage, provide a pluggable store port with a Redis
|
For report/snapshot storage, provide a pluggable store port with a Redis
|
||||||
adapter and an in-memory fallback.
|
adapter and an in-memory fallback.
|
||||||
|
|
||||||
## Rule
|
## Rule
|
||||||
|
|
||||||
If a capability already exists as a library (DB, DI, ingestion, mail, auth,
|
- **Tier A (libraries: DB, DI, ingestion, mail, auth, docs, pipelines)** — use
|
||||||
docs), **use it**. Writing a private copy of a library is a defect.
|
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
|
## Summary
|
||||||
|
|
||||||
This page states precisely what is **reusable as-is**, what is a **template to
|
This page states precisely what is **library-backed**, what is
|
||||||
adapt**, and what is **app-specific and must be authored**. Use it to scope a
|
**template-provided**, and what is **app-specific and must be authored**. Use it
|
||||||
new build.
|
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 |
|
These capabilities already exist as internal libraries. Reach them through the
|
||||||
|---|---|
|
library registry MCP (`find_library(capability)`) and read the library's own MCP
|
||||||
| Layering & dependency rule | the package layout and import rules |
|
for its API. Writing a private copy of any of these is a defect.
|
||||||
| 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 |
|
|
||||||
|
|
||||||
## 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 |
|
## Tier B — Template-provided (copy from `templates/app`, then adapt)
|
||||||
|---|---|
|
|
||||||
| `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 |
|
|
||||||
|
|
||||||
## 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 |
|
| Artifact | Why |
|
||||||
|---|---|
|
|---|---|
|
||||||
| Resource models | the business shape |
|
| Resource models | the business shape |
|
||||||
| Repository populate/cache rules | the relationships |
|
| Repository populate/cache rules | the relationships |
|
||||||
| Service business logic | domain behaviour |
|
| Service business logic | domain behaviour |
|
||||||
| Pipeline families (if any) | the transformation graph |
|
| Pipeline families | the transformation graph |
|
||||||
| Pattern/rule resources | data-driven policy |
|
| Pattern/rule resources | data-driven policy |
|
||||||
| Fixtures & golden outputs | test data |
|
| Fixtures & golden outputs | test data |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## The two axes
|
## The two axes
|
||||||
|
|
||||||
Everything app-specific reduces to **two axes**:
|
Everything app-specific reduces to **two axes**:
|
||||||
@@ -54,4 +72,5 @@ Everything app-specific reduces to **two axes**:
|
|||||||
the OpenAPI contract.
|
the OpenAPI contract.
|
||||||
2. **Pipeline family** — only if inputs require multi-step transformation.
|
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.
|
- **Worker & Progress** — queued work, progress reporting, and visibility.
|
||||||
- **Human-in-the-Loop** — guardrails and approvals inside automations.
|
- **Human-in-the-Loop** — guardrails and approvals inside automations.
|
||||||
- **Infra Adapters** — how infrastructure connects without leaking into domain.
|
- **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.
|
- **Library Registry** — the catalog of internal libraries behind all of it.
|
||||||
|
|
||||||
Read the **Wiki** for the philosophy and rationale; these pages are the
|
Read the **Wiki** for the philosophy and rationale; these pages are the
|
||||||
|
|||||||
Reference in New Issue
Block a user