Files
docs/trial_findings.md
Vishesh 'ironeagle' Bangotra 6c0d859a1e feat(standards): fix F11-F16 and rebuild bundle (43 components) + trial findings
- F11 PopulateRule field_name/collection_name corrections
- F12 service adaptor update handles PopulatingRepository
- F13 nested-references section; F14 authless /users/me guidance
- F15 template ruff-clean; F16 stop vendoring .ruff_cache, ship .gitignore
- document --template-style in build_recipe/spec_first_routing; refresh collected
  openapi-first + standards bundle (12 modules, 43 components)
- add trial.md and trial_findings.md (F1-F16, re-trial A/B evidence)
2026-10-13 19:35:12 +05:30

131 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Trial findings — build a khata app (no auth) from the Standards blueprint
Scope: reproduce `apps/khata-app` WITHOUT auth into `apps/khata-trial`, using ONLY
the standards (MCP bundle + library MCPs + `docs://`). khata-app consulted as the
answer key for intake only; implementation never copied.
Date: 2026-10-13. Status: trial build GREEN (imports, tests, live HTTP, pipeline).
## Verification evidence (what the standard successfully produced)
- `python -c "import main"` — OK; app builds with 46 routes (42 operationIds + 4
FastAPI defaults). Every no-auth operationId resolved to a handler.
- `pytest tests -q` — 6 passed, incl. the generic
`tests/integration/test_openapi_app_builds.py` that asserts each spec
operationId resolves against `interfaces.openapi`.
- Live end-to-end (real MongoDB, `TestClient`): 19 endpoints across all 8
resources returned 2xx — users(create/list/me/get/put), tags, accounts,
entities(+logo), expenses(create/list), fetch-requests(create/list/get/
ambiguities), reports(create/list). `FAILURES: none`.
- Deletes: `DELETE` returns 204 for entities/tags/accounts/expenses/
fetch-requests/reports; the follow-up `GET` correctly returns 404.
- Pipeline axis: `run_fetch_request` advanced status pending→completed and
published 7 progress events on the bus (`raw_lines`, `txn_blocks`,
`raw_expenses`, `enrich_entity`, `enrich_tags`, `save_expenses`).
- Layering respected: no `domain/` module imports fastapi/starlette; no Tier A
library reimplemented.
## Findings
Severity: **H**igh (blocks a 1-shot build), **M**edium (agent must work around),
**L**ow (rough edge).
| # | Area | Sev | Finding | Proposed standard fix |
|---|------|-----|---------|-----------------------|
| F1 | build_recipe | H | Recipe never mentioned the spec→code step; agent had to discover `python -m openapi_first.cli {models,routes}` unaided. | FIXED (P1): codegen codified in recipe + prompt + wiki. |
| F2 | codegen | H | `openapi-first` CLI output is not consumable as-is: models land in one file with globally renumbered enums (`Type`, `Type1`, `Type2`…), routes land in per-tag packages with `payload:`/sync signatures. | FIXED (P3): `--inject-request`, `--package`, `--use-models`, `--models-module`; documented shape. |
| F3 | wire vs doc | M | Generated wire models require top-level `id` + `created_at`/`updated_at`, but Mongo docs own those via `BaseDocument`; `class XDoc(X, BaseDocument)` keeps `id` required and fights the repo. | FIXED (P4): API-model→document convention documented; keep domain models id-free. |
| F4 | spec→slices | M | No documented bridge from spec tags/operationIds to domain slices; agent inferred the 9-slice split. | Build recipe now shows tag→slice mapping (P1). |
| F5 | authless | M | Authless path (strip global security + per-op `security: []` + `securitySchemes`) and the `/users/me` behaviour were manual/undefined. | FIXED (P5): authless guidance added. |
| F6 | components | H | `get_app_component` omitted `__init__.py` files and `interfaces/openapi.py`; no tool returned the whole tree. | FIXED (P6a): `get_app_template` returns the full tree; package-inits registered. |
| F7 | docs:// | H | Library MCP resource URIs regressed to `doc://`. | FIXED (P0): restored `docs://`. |
| F8 | Tier B | M | Tier-B files referenced by the docs (`http_cache`, progress bus, KV store) were not shipped. | FIXED (P6b): shipped `infra/http_cache.py`, `infra/adapters/{sse,kv}.py`. |
| F9 | prompts | M | Only `start_app` existed; no build/intake/trial prompts. | FIXED (P7): `build`, `intake`, `trial` added. |
| **F10** | codegen shape | L | Generated route stubs use `payload: <Model>`, sync `def`, body `raise NotImplementedError`; the template convention is `body: dict` + async. Both bind (binder introspects FastAPI signatures) but the mismatch is undocumented. | Document both accepted handler shapes, or emit template-style stubs. |
| **F11** | docs defect | H | `05_crud_template.md` and `09_infra_adaptors.md` show `PopulateRule(field="owner", collection="users")`, but the real dataclass fields are **`field_name`** / **`collection_name`** (`mongo_ops/populate/rules.py:37`). Copying the doc raises `TypeError`. | Correct the two doc examples to `field_name=`/`collection_name=`. **FIXED.** |
| **F12** | lib interop | M | `CrudsServiceAdaptor.update` (`infra/adapters/service.py`) always forwards a **dict**, but `PopulatingRepository.update(id, data: T)` calls `_depopulate(data)` → `document.model_dump(...)`, requiring a **model** (`mongo_ops/repository.py:404,384`). Populate + update through the adaptor raises `AttributeError`. | Adaptor now detects `PopulatingRepository` and builds the document model before calling `update`. **FIXED.** |
| **F13** | modeling | M | Wire contract declares refs expanded (`expense.entity: Entity`, `account.owner: User`), while id-free domain models store FKs. Trial chose embedded dicts / string FKs. No single documented convention. | Added a "Nested references" section to `05_crud_template.md` (embed / populate / id). **FIXED.** |
| **F14** | authless | L | `/users/me` (`get_current_user`, `update_current_user`, `x-profile: true`) has no defined authless semantics; agent invented "auto-create Demo User". | Added authless profile-endpoint guidance to `04_spec_first_routing.md`. **FIXED.** |
| **F15** | template lint | M | The template's own `pyproject.toml` sets `ruff select = ["E","F","I","UP"]` but template-shipped files violate it: `main.py` E402, `interfaces/openapi.py` F403, `infra/adapters/{kv,sse,service}.py` + `infra/http_cache.py` UP/I, `pipelines/shared/{registry,loader}.py` UP/I. | Fixed typing/imports, added file-level `noqa`s, and `extend-exclude = ["_gen"]`; template now `ruff check` clean. **FIXED.** |
| **F16** | template ship | M | The template vendors a `.ruff_cache/` directory into every generated app (`build.py` `copytree` ignore list only skipped `__pycache__`/`*.pyc`), and ships no `.gitignore`. | Hardened the `copytree` ignore list (`.ruff_cache`, `.pytest_cache`, `.mypy_cache`, `.venv`, `venv`, `.git`, `*.egg-info`, `htmlcov`), added a first-class `gitignore` component + template `.gitignore`. Component count 42→**43**. **FIXED.** |
## F10 resolution (emitter) + re-trial evidence
`openapi-first` now emits template-convention stubs when asked:
- `generate_routes(..., template_style=True)` / CLI `--template-style` emits
`async def`, a JSON body parameter named `body` (both `body: dict` and
`body: <Model>`), and (with `--inject-request`) a service-lookup hint comment
`# Resolve the service: request.app.state.db_resources["<resource>_svc"]`
before `raise NotImplementedError`. Default behaviour is unchanged
(`def` / `payload`).
- Tests: `tests/test_codegen_routes.py` gained
`test_template_style_async_body_model` and
`test_template_style_dict_body_without_models`; suite now **32 passed** (was
30); `ruff check` clean. Wiki `03_use_cases/04_codegen.md` documents the flag.
MCP bundle regenerated (`docs/mcp/modules/openapi_first.json` contains
`template_style`). Standards `spec_first_routing`/`build_recipe` modules
updated to reference `--template-style`.
**Re-trial A (template-level):** scaffolded the template into `apps/_tpl-check`,
`pytest` → 7 passed; `import main` → 11 routes; live `TestClient` Mongo smoke
→ `FAILURES: none`; targeted F12 populate+update check → `FAILURES: none`.
Scratch dir + DB removed.
**Re-trial B (full khata rebuild):** scaffolded `apps/khata-trial`, stripped auth
(2286-line spec), ran codegen with `--template-style` → 9 route files + `_gen`
models, authored all 9 domain slices, 42 handlers, composition root, worker, and
fetch pipeline. Then:
- `import main` → 46 routes (42 operationIds + 4 FastAPI defaults); every
operationId resolved.
- `pytest` → 2 passed.
- Live end-to-end (real MongoDB, `httpx.ASGITransport`): **43 checks, 0
failures** — all 9 resources CRUD, entity-logo multipart, `/users/me` authless
auto-create, deletes 204 + follow-up 404, pipeline pending→completed, SSE
events replay, raw octet-stream upload + download, report create/get/delete.
- One emitter-adjacent trap re-confirmed: a handler parameter named `response`
must be annotated (`response: Response`) or FastAPI binds it as a query param;
returning `Response(status_code=204)` from deletes is the safe template idiom.
- `apps/khata-trial` + `khata_trial` DB removed after verification.
## Recommended standard changes (from F10–F16)
1. Fix the `PopulateRule` examples (F11) — highest value, one-line corrections.
2. Resolve the populate/update interop gap (F12) — either fix the adaptor or
document the incompatibility.
3. Add a "nested refs" modeling subsection (F13) and authless `/users/me`
behavior (F14).
4. Make the shipped template pass its own ruff config and exclude generated code
(F15).
5. Document the two accepted codegen handler shapes (F10).
6. Stop vendoring `.ruff_cache` into apps and ship a `.gitignore` (F16).
## Resolution
F11–F16 applied to the standard sources and the MCP bundle rebuilt
(`build.py --name standards`: 12 modules, **43 components**, lib + wiki HTML):
- F11 — `field=`/`collection=` → `field_name=`/`collection_name=` in
`05_crud_template.md`, `09_infra_adaptors.md`.
- F12 — `infra/adapters/service.py` `update` handles `PopulatingRepository`.
- F13 — new "Nested references" section in `05_crud_template.md`.
- F14 — authless profile-endpoint guidance in `04_spec_first_routing.md`.
- F15 — template `ruff check` clean (`extend-exclude = ["_gen"]`, file-level
`noqa`s, typing/import fixes); template recompiles.
- F16 — `build.py` ignore list hardened; `gitignore` component + template
`.gitignore` added.
The running `docs` image bakes the bundle, so it was rebuilt
(`aetos-docs:standards5`) and the `docs` container swapped onto it; MCP
`:8009` live-verified (tools/prompts/resources unchanged, 43 components,
`gitignore` present).
## Outcome
Trials (original + re-trial A + re-trial B) proved the standard buildable
end-to-end; F1–F16 recorded and F11–F16 fixed. F10 resolved in the
`openapi-first` emitter. `apps/khata-trial` removed after verification. Remaining
items in "Recommended standard changes" are cosmetic/documentation-only and will
not meaningfully change build outcome quality.