RFC dan proposal mencatat rancangan. Untuk kemampuan yang benar-benar dapat dipakai, lihat matriks kapabilitas runtime dan catatan rilis.
Draft plan — Gate A: executable typed layered CRUD
Status: Proposed draft plan for review by the project owner. This document is written to be folded into the API completion plan or an RFC; it is not an accepted decision. Its implementation notes were refreshed on 2026-10-27 to reflect current code.
Source of truth: The current implementation status remains recorded in the runtime capability matrix and Appendix G status.
Goal
Close API completion Gate A: every generated CRUD operation dispatches through controller → service interface → service implementation → repository interface → repository implementation as typed YAZA code. YAZA repositories own operation selection, validation, and error mapping; a bounded native storage adapter may remain below that boundary until general YAZA-owned storage exists.
Current boundary (as of 2026-10-27)
- All six Product routes execute explicit YAZA forwarding functions; this is verified by the HTTP smoke.
- The compiler checks layer/interface metadata names, declaration order, unique method names, and exact one-to-one signature conformance. These declarations are metadata, not typed runtime dispatch contracts.
- With
DATABASE_URL, Product repository functions call the pure-YAZAstd/pg/api_records.yzadapter; local PostgreSQL 17.6 CRUD/restart and disposable PostgreSQL 18.6 lifecycle/CRUD evidence pass. Without a database URL, ProductRepository callsstd/api/memory_records.yz. It returns typed results through the ordinary handler-response path, while its bounded native adapter still mutates the runtime-owned memory table. Starter CRUD and the complete no-database API HTTP fixture pass, including chunked JSON creation. - API startup/schema/readiness hooks and Product PostgreSQL access use the pure-YAZA client and bounded process-local pool; generated API binaries have no
libpqdependency. Remote TLS verification, broader server-version/CI evidence, runtime-polymorphic interface dispatch, and generic YAZA-owned storage remain open. - Handler outcomes support
Text,Option[Text], andResult[Text, E]with fixed mappings for knownApiErrorvariants and safe validation field paths. TypedApiErrormapping exists, but typed model responses and one shared contract remain incomplete.
Staged implementation plan
Stage 1 — Typed interface dispatch in the compiler
- Give
implements IProductServiceexecutable meaning: the compiler lowers the implementing type into a C vtable structure matching the interface signature, or (preferred, simpler first pass) requires a concrete value stored in a project composition root and generates direct calls with compile-time conformance checks. - Extend
yaza checkso that a service value declared as the interface type can only call methods declared by that interface; a call to a method outside the interface fails compilation with the interface name and the offending method. - Reject implicit conformance: a value used where the interface is required must be checked against the interface method set at compile time (parameters, return types, and the error/optional types of each method).
- Negative compiler fixtures: missing method, wrong parameter type, wrong return type, wrong optional/error type, extra methods depending on the conformance strictness decision, duplicate implementation.
- Evidence: conformance smoke under normal and ASan/UBSan CLI builds; two consecutive self-host stages, byte-identical C; full YAZA suite remains green.
Exit evidence for this stage: one controller route calling a service through the interface compiles, runs, and rejects a deliberately broken implementation at compile time.
Stage 2 — YAZA-owned in-memory repository
- Implemented 2026-10-27, bounded adapter stage:
std/api/memory_records.yzexposes list/find/create/replace/patch/delete asResult[Text, Text]repository operations. The native adapter mutates the API's bounded resource table and never writes an HTTP response. ProductRepository maps stable adapter outcomes intoApiError; the normal handler path serializes results. - Starter CRUD and the complete API fixture pass, including request-supplied fields, server-generated IDs, chunked JSON, validation, and DELETE
204. The adapter validates its internal ID against the serialized record before using the schema validator, while ingress validation still rejects client-providedidfields. - Still required for this gate: move from the runtime-owned bounded record table to general YAZA-owned values/storage with an explicit lifetime/concurrency model; provide typed Product/Option results and runtime interface dispatch. Run RSS-growth and sanitizer evidence for the final storage semantics. The current adapter is a real layer improvement, not completion of fully YAZA-owned persistence.
Exit evidence: all six CRUD routes pass the HTTP smoke with zero generic-engine dispatch; record survives response-arena resets; RSS smoke stays within the recorded budget.
Stage 3 — PostgreSQL repository through the pure-YAZA client
- Implemented 2026-10-25: Product repository functions now use
std/pg/api_records.yz(built overstd/pg/transport.yz) for all six PostgreSQL CRUD actions. Live local PostgreSQL 17.6 migration/API CRUD/restart evidence passes. - Implemented 2026-10-26: startup/schema/readiness now use reachable YAZA lifecycle hooks and the pure-YAZA PostgreSQL client; generated API builds no longer link
libpq. Migration and the full database-configured HTTP smoke passed on disposable PostgreSQL 18.6. - Decode JSONB rows into Product shapes using the existing
pg_query_valuetyped accessors; usepg_query_with_parametersfor every runtime value; keep SQL templates static. - Implemented 2026-10-26: Product CRUD and lifecycle operations now use the bounded process-local pool; the API server and database operations remain single-threaded/synchronous.
- Passed locally 2026-10-25: the HTTP smoke's persistence-across-restart check passed with
DATABASE_URLand the pure-YAZA driver against PostgreSQL 17.6.
Exit evidence still required: repeat database-configured startup/schema/readiness and CRUD across the supported PostgreSQL matrix and automated CI; verify migration immutability/idempotence, rollback, invalid credentials, timeout, remote certificate validation, and failure paths in normal and ASan/UBSan builds. CI must also assert that generated API binaries remain free of libpq dependencies.
Stage 4 — Typed error contract
- Add a shared API error shape/variant (
ApiError:InvalidInput,NotFound,Conflict,Storage, with safe field paths) and allow handlers to returnResult[T, ApiError]with a stable status mapping: 400/404/409/500 respectively;errpayloads stay out of response bodies except for declared safe fields. - Derive the mapping, response schemas, and error codes from the same versioned contract that drives OpenAPI and Postman so generated artifacts cannot drift from runtime behavior.
- Update the HTTP smoke to assert the new status/body combinations and confirm no submitted values are reflected in error bodies.
Stage 5 — Retirement of the generic engine for generated APIs
- Once Stages 1–4 pass, switch the template to repository implementations only, keep the generic engine compiled out of the generated API unless a fallback mode is explicitly requested.
- Update the capability matrix, Appendix G, the roadmap progress ledger, and the template README with dated evidence for each replaced layer.
Acceptance criteria (traceable to Gate A)
- Each of list, get, create, replace, partial update, and delete executes controller → service interface → service implementation → repository interface → repository implementation in YAZA.
- In-memory and PostgreSQL repositories satisfy the same interface and pass the same smoke and CRUD assertions.
- Not-found, conflict, validation, and persistence failures use stable typed codes and safe responses that do not leak secrets or raw SQL errors.
- The compiler rejects non-conforming implementations at check/build time with source locations.
- Evidence is recorded under normal and ASan/UBSan builds plus the self-host byte-identical check for every compiler change above.
explicitly out of scope (this plan)
- General middleware pipeline, role-based authorization, TLS, HTTP client, and pooling (Gate D scope).
- Model-derived response schema generation beyond what Stage 4 produces; broader validators.
- Additional database providers (Gate E scope).