Python Customization
Keep generated packages replaceable. Domain shape belongs in KSML; trusted platform
state and infrastructure belong in UserContext; HTTP/CLI input mapping belongs in
handwritten application code.
Context factory
Create one async factory per deployment profile:
@dataclass(frozen=True)
class TrustedRequest:
tenant_id: int
actor_id: str
permissions: frozenset[str]
async def request_context(infra, trusted: TrustedRequest) -> UserContext:
ctx = UserContext()
# Register generated metadata, async provider, request policy and audit sinks.
# Inject trusted identity and authorization here.
return ctx
Handlers should never accept a provider argument beside the context, and client JSON must never initialize trusted resources.
Explicit dynamic-query adapter
Normalize and validate JSON before calling a generated Request. Use a closed mapping:
def apply_filter(request, item):
match item["field"], item["operator"]:
case "order_number", "contains":
return request.with_order_number_containing(require_string(item["value"]))
case _:
raise InvalidQuery("unsupported field or operator")
Reject unknown fields, excessive IN lists, reversed/wrongly typed ranges, deep paths, forbidden sorts, negative offsets and oversized pages. Build rows, count, aggregate, and facets from the same normalized filter object.
Validation and behavior
Implement the exact generated checker/behavior interfaces. Use them for entity-local normalization and invariants. Use request policy for tenant scope, permissions, purpose approval and platform limits. Test each extension through the public generated API so registration mistakes are visible.
Audit and application events
Every mutation carries audit_as. Preserve the runtime row/mutation audit event as
immutable evidence. Register a separate application sink for outbox or observability;
mask configured sensitive fields before serialization and attribute the event to the
trusted actor. An application log is not a replacement for runtime audit.
Async provider lifecycle
Create pools at application startup, attach them through context initialization, and close them at shutdown. Do not create a connection per generated Request. Provider qualification must include real persistence, reconnect, optimistic locking, native aggregates, stable pagination, and exact relation Top-N.
Packaging after release
Once published, pin the official PyPI runtime and provider extras in project metadata, record hashes in the lock file, and test the wheel in a clean environment. Until those coordinates are announced, documentation and examples must not claim a public install path.
If a customization needs edits in generated Q.py, E.py, models/, or requests/,
move the change to the model, generator, or runtime extension point and regenerate.