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

10 KiB
Raw Blame History

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: High (blocks a 1-shot build), Medium (agent must work around), Low (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 noqas, 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.
  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 noqas, 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.