Corrected agent confabulations

This commit is contained in:
2026-06-04 12:05:13 -04:00
parent 66b2db81fb
commit b41f469bbd
5 changed files with 26 additions and 43 deletions

View File

@@ -110,13 +110,13 @@ Format: comma-separated contexts, semicolon-separated URL-encoded params per con
### 3. Frontend-Agnostic Rendering (SSR + PSR) ### 3. Frontend-Agnostic Rendering (SSR + PSR)
**SSR** — Django template backend integration. `render(request, 'ProfilePage', props)` calls a persistent Bun subprocess that runs `renderToString`. **SSR** — Django template backend integration. `render(request, 'components/Hello.tsx', props)` — the template name is a `.tsx`/`.jsx` **file path** (resolved against `DIRS`), not a component name — calls a persistent Bun subprocess that runs `renderToString`.
**PSR** (Preemptive Static Rendering) — pages re-rendered on mutation, not on request. Edge caches the result. Controlled by the manifest's `render_strategy` field. **PSR** (Preemptive Static Rendering) — pages re-rendered on mutation, not on request. Edge caches the result. Controlled by the manifest's `render_strategy` field.
**The Bun worker protocol** — JSON-RPC over stdin/stdout: **The Bun worker protocol** — JSON-RPC over stdin/stdout. The worker `import()`s the file and renders it (no component registry):
``` ```
→ {"id": 1, "method": "render", "params": {"component": "ProfilePage", "props": {"userId": 5}}} → {"id": 1, "method": "render", "params": {"file": "/abs/path/Hello.tsx", "props": {"name": "World"}}}
← {"id": 1, "html": "<div>...</div>"} ← {"id": 1, "html": "<div>...</div>"}
``` ```
@@ -356,8 +356,9 @@ Three independent secrets, each with its own blast radius:
TEMPLATES = [ TEMPLATES = [
{ {
'BACKEND': 'mizan.ssr.MizanTemplates', 'BACKEND': 'mizan.ssr.MizanTemplates',
'DIRS': [BASE_DIR / 'frontend'],
'OPTIONS': { 'OPTIONS': {
'worker_path': 'frontend/ssr-worker.tsx', 'worker': 'path/to/mizan-ssr/src/worker.tsx',
'timeout': 5, 'timeout': 5,
}, },
}, },
@@ -371,14 +372,14 @@ from django.shortcuts import render
def profile_page(request, user_id): def profile_page(request, user_id):
profile = get_user_profile(user_id) profile = get_user_profile(user_id)
return render(request, 'ProfilePage', {'profile': profile}) return render(request, 'components/Profile.tsx', {'profile': profile})
``` ```
`render()` calls `MizanTemplates.get_template('ProfilePage')` which returns a `MizanTemplate`. The template's `render(context)` sends JSON-RPC to the Bun worker. `render()` calls `MizanTemplates.get_template('components/Profile.tsx')` — the name is a file path resolved to an absolute path against `DIRS` which returns a `MizanTemplate`. The template's `render(context)` sends JSON-RPC (`{file, props}`) to the Bun worker.
### SSR Bridge (bridge.py) ### SSR Bridge (bridge.py)
- Spawns `bun run <worker_path>` on first render - Spawns `bun run <worker>` on first render
- Persistent subprocess — stays alive across requests - Persistent subprocess — stays alive across requests
- JSON-RPC over stdin/stdout with message ID correlation - JSON-RPC over stdin/stdout with message ID correlation
- Thread-safe: multiple Django workers can call `render()` concurrently - Thread-safe: multiple Django workers can call `render()` concurrently
@@ -388,8 +389,8 @@ def profile_page(request, user_id):
### Bun Worker (worker.tsx) ### Bun Worker (worker.tsx)
- Reads newline-delimited JSON from stdin - Reads newline-delimited JSON from stdin
- Component registry: `registerComponent('ProfilePage', ProfilePage)` - Resolves the component by **file path**`import(file)` (cached) — no registry
- Calls `renderToString(createElement(Component, props))` - Calls `renderToString(createElement(Component, props))` on the imported default export
- Returns `{"id": N, "html": "..."}` or `{"id": N, "error": "..."}` - Returns `{"id": N, "html": "..."}` or `{"id": N, "error": "..."}`
- Health check: `{"method": "ping"}``{"pong": true}` - Health check: `{"method": "ping"}``{"pong": true}`

View File

@@ -11,9 +11,9 @@ no longer exist.
- [ ] **Vue / Svelte frontend packages are unimplemented stubs.** `frontends/mizan-vue` and `frontends/mizan-svelte` contain only a `package.json` — no `src/`. The Rust codegen emits Vue composables and Svelte stores (`src/emit/vue.rs`, `src/emit/svelte.rs`, byte-checked by `vue_svelte_parity.rs`), but there is no runtime kernel-adapter package for either and no example app exercises them against a live backend. React is the only frontend with full integration verification. - [ ] **Vue / Svelte frontend packages are unimplemented stubs.** `frontends/mizan-vue` and `frontends/mizan-svelte` contain only a `package.json` — no `src/`. The Rust codegen emits Vue composables and Svelte stores (`src/emit/vue.rs`, `src/emit/svelte.rs`, byte-checked by `vue_svelte_parity.rs`), but there is no runtime kernel-adapter package for either and no example app exercises them against a live backend. React is the only frontend with full integration verification.
- [ ] **Svelte adapter emits Svelte 4 stores.** `src/emit/svelte.rs` generates `readable` stores from `svelte/store`. Svelte 5 `$state`/`$derived` runes are the current idiom. - [ ] **Svelte adapter emits Svelte 4 stores.** `src/emit/svelte.rs` generates `readable` stores from `svelte/store`. Svelte 5 `$state`/`$derived` runes are the current idiom.
- [ ] **Forms have no codegen target.** `mizan-react/src/forms.ts` (form core hooks) is hand-written and consumed via the pre-kernel `MizanProvider`; the e2e harness has its form fixtures removed. A form codegen target wired to `mizanCall` is owed. - [ ] **Forms have no codegen target.** `mizan-react/src/forms.ts` (form core hooks) is hand-written and consumed via the pre-kernel `MizanProvider`; the e2e harness has its form fixtures removed. A form codegen target wired to `mizanCall` is owed.
- [ ] **Upload dispatch not wired for Rust/Axum + Tauri.** The `Upload` type is first-class end to end — IR (`upload` KDL node), codegen (TS `File`), kernel (auto-multipart), and dispatch+constraint binding on Django and FastAPI. Rust/Axum and Tauri parse the IR node and emit the field, but their dispatch does not yet bind multipart file parts. - [ ] **Upload dispatch not wired for Rust/Axum + Tauri.** The `Upload` type is first-class end to end — IR (`upload` KDL node), codegen (TS `File`; the Rust target lowers it to `Vec<u8>`), kernel (auto-multipart), and dispatch+constraint binding on Django and FastAPI. The Rust/Axum and Tauri *adapters* have no upload concept at dispatch — they don't bind multipart file parts yet.
- [ ] **Pre-kernel MizanProvider still shipped.** `mizan-react/src/context.tsx` (~750 lines) is the pre-kernel provider, still imported by the desktop example. It coexists with the codegen-emitted `MizanContext` (which subscribes to `@mizan/base`). Migrating the desktop example onto the generated provider retires it. - [ ] **Pre-kernel MizanProvider still shipped.** `mizan-react/src/context.tsx` (~750 lines) is the pre-kernel provider, still imported by the desktop example. It coexists with the codegen-emitted `MizanContext` (which subscribes to `@mizan/base`). Migrating the desktop example onto the generated provider retires it.
- [ ] **Cache module open issues.** See `backends/mizan-django/src/mizan/cache/KNOWN_ISSUES.md`: purge atomicity, cross-language stringification, per-param sub-index cleanup, thundering-herd protection, `cache_get`/`cache_put` argument inconsistency, RedisCache test coverage. - [ ] **Cache module open issues.** See `backends/mizan-django/src/mizan/cache/KNOWN_ISSUES.md`: cross-language stringification of un-normalized value types, and no thundering-herd / single-flight protection.
- [ ] **Packages missing a README.** `frontends/mizan-base` (the kernel everything imports), `protocol/mizan-codegen` (the codegen binary), `frontends/mizan-vue`, `frontends/mizan-svelte`, `frontends/mizan-rust`, `backends/mizan-ts`, `backends/mizan-rust-axum`, `cores/mizan-python`. - [ ] **Packages missing a README.** `frontends/mizan-base` (the kernel everything imports), `protocol/mizan-codegen` (the codegen binary), `frontends/mizan-vue`, `frontends/mizan-svelte`, `frontends/mizan-rust`, `backends/mizan-ts`, `backends/mizan-rust-axum`, `cores/mizan-python`.
## Resolved this pass ## Resolved this pass

View File

@@ -52,7 +52,7 @@ The surface every Mizan adapter implements.
| Invalidation — JSON body | ✅ | ✅ | ✅ | ✅ | ✅ | | Invalidation — JSON body | ✅ | ✅ | ✅ | ✅ | ✅ |
| Invalidation auto-scoping (three-tier) | ✅ | ✅ | ✅ | ✅ | ✅ | | Invalidation auto-scoping (three-tier) | ✅ | ✅ | ✅ | ✅ | ✅ |
| Function discovery / registration | ✅ | ✅ | ✅ | ✅ | ✅ | | Function discovery / registration | ✅ | ✅ | ✅ | ✅ | ✅ |
| Codegen IR export (KDL) | ✅ | ✅ | ✅ ⁶ | ✅ ⁶ | ⁸ | | Codegen IR export (KDL) | ✅ | ✅ | ✅ ⁶ | ✅ ⁶ | ⁸ |
| File uploads (multipart, `Upload` type) | ✅ | ✅ | ❌ ⁹ | ❌ ⁹ | — ¹⁰ | | File uploads (multipart, `Upload` type) | ✅ | ✅ | ❌ ⁹ | ❌ ⁹ | — ¹⁰ |
### Edge, cache & enforcement ### Edge, cache & enforcement
@@ -107,12 +107,14 @@ target stack calls for them.
rather than fetching over HTTP. rather than fetching over HTTP.
7. FastAPI and Rust/Axum expose `GET /session/` returning a null CSRF token for wire 7. FastAPI and Rust/Axum expose `GET /session/` returning a null CSRF token for wire
parity; CSRF is Django-only. parity; CSRF is Django-only.
8. TypeScript is an edge/protocol-reference adapter (HMAC cache, manifest, PSR), not a 8. `mizan-ts` emits the Edge manifest (JSON) but has no KDL IR emitter, so it can't yet
codegen source — it demonstrates the cache + invalidation protocol is feed the codegen — an unbuilt gap. A TypeScript backend still needs the generated
language-agnostic. client (types + `callXxx`/`fetchXxx` + framework hooks); same language doesn't remove
9. The IR carries the `upload` type and the codegen emits the field across targets, but the need for it.
multipart dispatch binding is wired for Django and FastAPI only; Rust/Axum and Tauri 9. The `mizan-codegen` crate parses the `upload` KDL node and emits the field across
parse the IR node but do not yet bind uploads. targets (the Rust target lowers it to `Vec<u8>`). Multipart dispatch binding is wired
for Django and FastAPI only; the Rust/Axum and Tauri *adapters* have no upload concept
at dispatch yet.
10. The TypeScript column is the `mizan-ts` backend adapter, which has no upload 10. The TypeScript column is the `mizan-ts` backend adapter, which has no upload
dispatch. The matching client side lives in the kernel (`@mizan/base`): `mizanCall` dispatch. The matching client side lives in the kernel (`@mizan/base`): `mizanCall`
auto-switches to `multipart/form-data` when any argument is a `File`. auto-switches to `multipart/form-data` when any argument is a `File`.

View File

@@ -34,7 +34,7 @@
- [ ] **Svelte 5 runes** — the Svelte target emits Svelte 4 `readable` stores; migrate to `$state`/`$derived`. - [ ] **Svelte 5 runes** — the Svelte target emits Svelte 4 `readable` stores; migrate to `$state`/`$derived`.
- [ ] **Forms codegen target** — emit form clients wired to `mizanCall` from the kernel; retire the hand-written `mizan-react/src/forms.ts` and its dependence on the pre-kernel provider. - [ ] **Forms codegen target** — emit form clients wired to `mizanCall` from the kernel; retire the hand-written `mizan-react/src/forms.ts` and its dependence on the pre-kernel provider.
- [ ] **Desktop example onto the generated provider** — migrate `examples/django-react-desktop-app` off the pre-kernel `MizanProvider` (`mizan-react/src/context.tsx`) so it can be retired. - [ ] **Desktop example onto the generated provider** — migrate `examples/django-react-desktop-app` off the pre-kernel `MizanProvider` (`mizan-react/src/context.tsx`) so it can be retired.
- [ ] **Cache hardening**purge atomicity, per-param sub-index cleanup, thundering-herd protection, RedisCache coverage (see `backends/mizan-django/src/mizan/cache/KNOWN_ISSUES.md`). - [ ] **Cache hardening**thundering-herd / single-flight protection, and pinning cross-language stringification of un-normalized value types (see `backends/mizan-django/src/mizan/cache/KNOWN_ISSUES.md`).
- [ ] **Package READMEs**`mizan-base`, `mizan-codegen`, and the other packages missing one (see `ISSUES.md`). - [ ] **Package READMEs**`mizan-base`, `mizan-codegen`, and the other packages missing one (see `ISSUES.md`).
--- ---

View File

@@ -1,16 +1,12 @@
# Cache Module — Known Issues # Cache Module — Known Issues
Open issues against the current cache implementation. Resolved items are Open issues against the current cache implementation. The cache uses
removed once their fix lands. HMAC-derived keys with **no reverse indexes** (scoped purge recomputes the key;
broad purge is a prefix SCAN+UNLINK), so there are no index/sub-index races to
track. Resolved items are removed once their fix lands.
## Correctness ## Correctness
### Purge race condition (non-atomic index operations)
`cache_purge` reads the index and deletes as separate operations. A
concurrent `cache_put` between the two steps can orphan entries. Mitigated
by AND-intersection purge semantics, but full atomicity (Lua script or
`WATCH`/`MULTI` on the Redis backend) is still owed.
### Cross-language stringification divergence ### Cross-language stringification divergence
Python `str(True)``"True"` vs JS `String(true)``"true"`. `_normalize` Python `str(True)``"True"` vs JS `String(true)``"true"`. `_normalize`
canonicalizes `True`/`False`/`None` today, but the rules for the remaining canonicalizes `True`/`False`/`None` today, but the rules for the remaining
@@ -19,22 +15,6 @@ TypeScript HMAC keys can still diverge on an un-normalized type.
## Performance / Operability ## Performance / Operability
### Broad purge leaves per-param sub-indexes
A broad `cache_purge(context)` deletes the entries but not the per-param
sub-indexes — a slow Redis memory leak.
### No thundering-herd protection ### No thundering-herd protection
Concurrent cold misses on the same key all execute and write. No Concurrent cold misses on the same key all execute and write. No
single-flight / request-coalescing. single-flight / request-coalescing.
## API shape
### cache_get / cache_put argument inconsistency
`cache_get`/`cache_put` take explicit args while the executor resolves some
inputs from module globals — two access patterns for one concern.
## Coverage
### RedisCache lacks test coverage
Only `MemoryCache` is exercised by the suite. `RedisCache` (connection
pooling, TTL, SCAN/UNLINK batching, socket timeouts) is untested.