The fe39fcb commit captured the file moves (git mv stages those automatically)
but didn't catch the content edits I made afterward — npm package rename
(@mizan/runtime → @mizan/base), path updates in Makefile/Dockerfile/examples,
and doc updates were all left unstaged at commit time.
This commit lands those:
- npm rename: 3 frontend package.jsons (base/vue/svelte) + mizan-base/src/index.ts + 4 codegen templates
- path updates: Makefile, Dockerfile.test, two Gitea workflows, four example/harness configs
- doc updates: CLAUDE.md, ROADMAP.md, ISSUES.md, docs/AFI_ARCHITECTURE.md
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8.0 KiB
Mizan — Known Issues
Identified by domain expert review (Cloudflare, Serverless, Vercel, React Query, Django, Laravel, Vue/Svelte).
Fixed
C1Scoped cache purge now passes user_idC2initSession retries 3x, resets on failureC3SSR backend injects__MIZAN_SSR_DATA__script tagC4SSR bridge uses _write_lock for stdinC5SSR bridge registers atexit handlerC7View-path mutations now purge origin cacheH1pendingScoped is Array, not Map (no overwrite)H2stableKey() sorts JSON keys (order-independent)H3mizanFetch retries 2x on 5xx/network errorsH4Named contexts skip refetch if SSR data existsH6refreshContext uses GET /ctx/ not POST /call/H10_meta always fresh dictH11Python normalizes True→"true" for cross-language HMACH13isValid checks all required fields are touchedM11execute_function return type includes HttpResponseBaseM18registerContext cleanup uses ?. (no crash)
Remaining Critical
C6. No loading/error/stale states in runtime
File: mizan-base/src/index.ts
The kernel stores only {params, refetch}. No data, status, error. Every adapter reinvents loading tracking. Blocks stale-while-revalidate.
Remaining High
H5. Mutation hooks expose no loading/error state
File: mizan-django/generate/generator/lib/adapters/react.mjs
Returns bare useCallback. No isPending, error, isSuccess.
H7. Redis SCAN blocks request path at scale
File: mizan-django/src/mizan/cache/backend.py
Synchronous SCAN at 1M keys: multi-second blocking.
H8. Svelte codegen uses Svelte 4 stores
File: mizan-django/generate/generator/lib/adapters/svelte.mjs
Should use Svelte 5 $state/$derived runes.
H9. Svelte destroy() not auto-called
File: mizan-django/generate/generator/lib/adapters/svelte.mjs
Memory leak if user forgets onDestroy.
H12. Forms triggerValidation captures stale data
File: mizan-react/src/forms.ts
Debounced validation uses stale closure data.
Remaining Medium
M1. SSR bridge not fork-safe
gunicorn prefork shares file descriptors and Redis connections.
M2. cache_purge_user() not implemented
No way to purge all cache entries for one user.
M3. No garbage collection for context entries
Runtime contexts Map grows monotonically.
M4. No cross-tab invalidation
No BroadcastChannel. Logout in tab 1 doesn't affect tab 2.
M5. React 18 Strict Mode double-fetch
useEffect runs twice in dev mode.
M6. No request deduplication
Two components mounting same context fire parallel fetches.
M7. SSR worker module cache never invalidates
Dynamic imports cached forever.
M8. Vue injection key not exported
Can't inject directly without generated composables.
M9. Vue onMounted won't pre-fetch in Vue SSR
Needs onServerPrefetch for Nuxt.
M10. Svelte should use setContext/getContext
Module-level stores don't scope to component tree.
M12. render_strategy heuristic uses hardcoded param names
Misses member_id, customer_id, non-English names.
M13. initSession called for token-auth requests
Wastes GET /session/ round-trip for JWT/MWT apps.
M14. Vue watch imported but unused
Params not watched — reactive param changes don't trigger refetch.
M15. Vue mutation composables misleading use prefix
export const useXxx = callXxx — not a real composable.
M16. Svelte mutation imports bypass Stage 1 index
Should import from '../index' consistently.
M17. Side effects in React state updater
Context listeners called inside setContextStore() updater.
Architectural / Cleanup Debt
A1. Legacy MizanProvider not yet removed
File: mizan-react/src/context.tsx (~750 lines)
Superseded by the kernel (mizan-base) + generated React adapter (useSyncExternalStore). Still exported as MizanProvider, useMizan, useMizanContext, etc. Must be deleted or replaced with thin shims that call configure() + delegate to the new generated hooks.
A2. Allauth pending extraction
File: legacy/allauth/ (44 files)
Sitting in legacy/ since the cleanup pass. Should become its own mizan-django-allauth package consuming Mizan's public API. Unblocks v1 mizan-react publishing.
A3. Forms codegen not adapted to kernel
File: mizan-react/src/forms.ts (~1163 lines)
Still uses useMizan().call() from the legacy MizanProvider. Needs rewrite to use mizanCall from the kernel. Currently the only consumer of MizanProvider — blocks A1.
A4. Codegen for Vue/Svelte not validated end-to-end
The Stage 2 templates produce code that compiles, but no example app exercises Vue or Svelte rendering against a live backend. React is the only adapter with full integration verification.
A5. ROADMAP.md is stale
File: ROADMAP.md
Lists SSR Bridge, Edge Manifest, Codegen Rewrite, etc. as "Next" — all are done. Doesn't reflect:
- Two-stage codegen with Vue/Svelte adapters
- C6 kernel-owned state (
ContextState<T>) - mizan-ts cross-language adapter
- Cleanup of djarea/Django-specific naming
A6. CLAUDE.md may also be stale
File: CLAUDE.md
Written before the kernel rewrite. References to MizanProvider responsibilities and the old codegen pattern are likely outdated. Needs audit.
Test Coverage Gaps
T1. No tests for C6 kernel state machine
File: mizan-base/ has no tests/ directory at all
The state-owning kernel has zero unit tests. No coverage of:
registerContextreturninggetState/subscribe/refetch/unregister- Status transitions: idle → loading → success/error
- Subscriber notifications on state change
- Refetch reusing the same entry on Strict Mode re-mount
unregisterclearing listeners
T2. No tests for generated Vue adapter output
The vue.mjs template produces code, but no test verifies it generates valid Vue 3 composables, that onServerPrefetch is wired correctly, or that the kernel subscription bridges to Vue reactivity.
T3. No tests for generated Svelte adapter output
Same as T2. Readable store factory pattern is unverified against actual Svelte components.
T4. No tests for view-path cache purge (C7 fix unverified)
The fix added _purge_cache_for_invalidation() to the view-path branch, but no test asserts that an HttpResponse-returning mutation actually purges the origin cache.
T5. No tests for SSR thread safety (C4 fix unverified)
The _write_lock was added but no concurrent-render test exists to prove it prevents JSON interleaving.
T6. No tests for SSR atexit cleanup (C5 fix unverified)
atexit.register(self.shutdown) was added but not exercised — no test that asserts the Bun process is reaped on Python exit.
T7. No tests for SSR hydration injection (C3 fix unverified)
The <script>window.__MIZAN_SSR_DATA__=...</script> was added to template output but no test asserts it appears in rendered HTML or that the JSON is valid/safe.
T8. No cross-language HMAC pin test for booleans/None (H11 fix unverified)
Python now normalizes True→"true", but there's no test comparing Python's derive_cache_key(secret, ctx, {flag: True}) against TypeScript's equivalent to prove they produce identical hex output.
T9. No tests for retry logic (H3)
fetchWithRetry retries 5xx/network errors with backoff. No test for: 5xx triggers retry, 4xx does not, mutation calls bypass retry, max retries respected.
T10. No end-to-end integration test
Nothing exercises the full pipeline: Django function defined → schema exported → codegen runs → generated React mounts → mutation fires → server response includes invalidate → kernel refetches → DOM updates. Each layer is tested in isolation.
T11. No tests for isValid requiring all required fields touched (H13 fix unverified)
The forms fix checks field.required && !touched but no test exercises a form with untouched required fields to confirm isValid === false.
T12. No tests for _meta fresh-dict isolation (H10 fix unverified)
The shared-dict fix replaced {**FunctionWrapper._meta, **meta} with {**meta}. No test confirms that mutating one function's _meta doesn't leak into others.