Code and product audit

This document records what was inspected, what changed, and what remains intentionally out of scope. It is evidence for maintainers, not a claim that any framework can make every application correct automatically.

10 min read2,066 wordsClank 0.7.0

Audit date: 2026-07-25

This document records what was inspected, what changed, and what remains intentionally out of scope. It is evidence for maintainers, not a claim that any framework can make every application correct automatically.

Scope

The audit covered:

  • reactive ownership, computed invalidation, DOM updates, SSR, and hydration;
  • TSX public typing and event/control ergonomics;
  • runtime schemas and agent contracts;
  • form state, validation, submission, focus, and cancellation;
  • accessible disclosure, dialog, tabs, pagination, and directives;
  • semantic agent inspection and operation;
  • auth, passkeys, organization RBAC, data ownership, requests, files, deployment artifacts, migrations, secrets, ingress, backup, and release supervision;
  • examples, strict types, package contents, documentation, desktop rendering, and narrow viewports.

Findings resolved

FindingResolutionEvidence
A computed first read through peek() did not retain its own dependenciesComputed.peek() now suppresses only the caller subscription while evaluating with its own observerCore regression test
Boolean ARIA false was removedDOM and SSR now serialize explicit "true"/"false" statesDOM and SSR tests
Forms required repeated ad hoc signal/error codeAdded schema-aware headless forms with cancellation, focus, server errors, reset, manifests, and typed controlsForm tests and three site variants
Agent inspection relied heavily on custom labelsNative IDs, labels, roles, required/readonly/invalid/checked/multiple state, and placeholders are understoodAgent-surface tests
Semantic inspection could expose password input valuesPassword and file values are omitted; file input automation is refusedAgent-surface tests
Reusable interactive controls were application-specificAdded disclosure, modal dialog, tabs, pagination, outside-click, and autofocus primitivesUI tests and site variants
Common web schemas were verboseAdded email, URL, date, date-time, record, defaults, refinement, and numeric/boolean coercionSchema tests
JSX intrinsic elements were effectively anyAdded native element/property/event typing, reactive attributes, bind/ref/directive types, ARIA/data attributes, and custom-element supportStrict type tests
Existing examples covered mostly todosAdded commerce, SaaS dashboard, and multi-step booking applicationsBrowser verification
Concurrent build/watch output could briefly disappearFramework and public compiler builds now replace files atomically and remove only stale outputsConcurrent-build regression tests
Documented clean example URLs returned 404The development server now resolves trailing-slash directories to index.htmlBrowser and HTTP verification
Generated apps did not declare their runtime for local development and editor typesScaffolds now depend only on their matching Clank release and include build, dev, start, and deploy scriptsPackage-consumer scaffold verification
A refreshed authenticated deployment page still displayed the Sign in headingThe server-rendered and client-rendered auth card now derive their heading from the same session statePlatform regression test and browser refresh verification
The Proact name remained embedded across package, CLI, storage, protocol, and UI surfacesRenamed the product to Clank with in-place data migration and narrowly scoped legacy readersRename compatibility tests and migrated production-state copy
Authentication lacked production recovery and phishing-resistant credentialsAdded email verification, generic single-use recovery, bounded MFA, WebAuthn passkeys, and atomic counter advancementAuth and synthetic WebAuthn tests
Project authority was account-wideAdded organizations, invitations, four roles, scoped tokens, permission intersection, and removal-time revocationPlatform RBAC and isolation tests
Deploy coordination was local-onlyAdded durable authenticated leases, fences, nodes, desired generations, idempotent operations, retry, and stale-worker rejectionOrchestration and chaos tests
Backups were release-local snapshots or manual recovery points onlyAdded encrypted authenticated backup repositories, durable scheduling, cross-control-plane claims, retention, verification, restore confirmation, safety copies, path-safe API/console surfaces, and CLIRecovery, platform-backup, conformance, and chaos tests
The platform lacked a managed host/data-plane layerAdded exact-host ingress, DNS ownership challenges, external PostgreSQL transactions/migrations, and database provisioning contractsData-plane and platform tests
Release security evidence was manualAdded ASVS-oriented mapping, threat model, package/secret audit, immutable CI actions, CodeQL, chaos tests, and beta gatenpm run check and GitHub workflows
Hosted quotas could be bypassed through extra organizations and rejected domains could survive rollbackAdded account organization/site limits and moved domain capacity checks into the insert transactionPlatform quota and direct SQLite row-count regressions
Caller IP headers, passkey start responses, and recovery delivery timing exposed authentication side channelsBound rate limits to trusted adapter identity, switched to discoverable passkeys, and removed delivery from the response pathAuthentication enumeration, spoofing, and blocked-delivery regressions
Binary uploads and remote SQL responses could buffer past route limitsAdded shared bounded streaming readers that cancel at the first over-limit chunkArtifact, file-service, and PostgreSQL streaming regressions
Disconnects did not cancel every downstream stream and Docker arguments contained secret valuesPropagated cancellation through ingress/Node and changed Docker to name-only environment argumentsIngress, Node disconnect, and fake-Docker process-argument regressions
Repository leak checks covered only the package and a small credential setExpanded credential patterns and scan current repository files plus all reachable Git historynpm run security:audit
A green release did not enforce coverage or documentation/declaration integrityAdded minimum line/branch/function coverage and checked local links, guide indexing, declaration parity, and export targetsnpm run check and npm run docs:audit
CLI state writes and control-plane responses lacked complete interruption/resource boundsAdded strict bounded config/link parsing, atomic private replacement, request deadlines, strict UTF-8 JSON parsing, and response byte capsCLI regression tests and packaged conformance
/healthz reported a constant result and signal shutdown could skip platform cleanup after an HTTP close failureAdded storage-backed readiness, separate liveness, and bounded cleanup that attempts both layersPlatform readiness tests and conformance process shutdown
Repeated deployments retained unbounded extracted files and rollback snapshotsAdded locked per-project count/byte ceilings plus path-derived, rollback-scoped cleanup that preserves immutable evidencePlatform quota, authorization, symlink, snapshot, CLI, and dashboard regressions
Enforced site quotas had no safe user-facing reclamation pathAdded owner/admin-only permanent deletion with dual confirmation, scoped-token denial, durable locking, path-safe storage cleanup, metadata cascades, token revocation, and surviving audit evidencePlatform RBAC, CSRF, path substitution, runtime, storage, orchestration, quota/slug/port/domain reuse, CLI, and dashboard regressions
Deleted-site audit evidence survived in SQLite but became unreachable through the project APIAdded durable organization attribution, old-schema backfill, current-role filtering, project-token containment, stable cursor pagination, dashboard Activity, and structured CLI outputDeletion survival, migration, RBAC/scope, pagination/input, CLI, desktop/mobile, refresh, and browser-console regressions
Routine workspace access administration and invitation acceptance required CLI work, while replacement invitations remained validAdded complete browser invite/accept/member administration, CLI parity, administrator-only pending metadata, developer audit redaction, atomic invitation replacement, active-invite bounds, revocation, and existing-member rejectionRBAC, replay, email binding/privacy, cap, role/removal, CLI, CSRF, desktop/mobile, and browser-console regressions
Creating an additional workspace still required CLI knowledgeAdded quota-aware browser creation, normalized slug preview, immediate selection, and server-authoritative validationCSRF/quota regression, authenticated browser creation, and responsive dialog verification
Default bootstrap made invitations unusable for collaborators who did not already have an account; simultaneous control planes lacked a durable first-account claim; and platform/auth path normalization differedAdded email-bound invitation-assisted registration with rollback cleanup, an expiring SQLite bootstrap claim with insertion-order fallback, and one normalized signup-policy operationDisabled/bootstrap, repeated-slash/legacy path, origin, expiry, mismatch, replay, account-cleanup, and two-runtime concurrency regressions
Reusing the console after sign-out could retain the prior account's rendered People data and stale bootstrap button stateReload the server-rendered console on sign-out or session expiry so identity, policy, and DOM state are rebuilt togetherSame-browser owner-to-invitee onboarding, refresh, role/privacy, and console-error verification
Platform auth and device-start throttles reset per process, while successful login cleared a malformed keyAdded one atomic HMAC-keyed SQLite sliding-window store shared by auth and device onboarding, corrected successful-login clearing, and bounded high-cardinality retentionFramework reset, cross-runtime accumulation, restart persistence, raw-identity absence, clock rollback, 429, and 20k-key pruning regressions
Generated auth pages rendered correctly but mapped clank while compiled browser modules imported clank.run, preventing hydrationAligned both scaffold import maps with the compiler output and added generated-source regression coverageFresh scaffold registration and two-browser live-sync verification
CLI help could execute a command, offline dry-runs required auth, unknown options were ignored, and async failures had inconsistent exit behaviorAdded command-aware help, strict option validation and suggestions, reliable async error handling, offline dry-runs, readiness diagnostics, and structured agent outputCLI regression tests, local-checkout consumer, packaged conformance, and fresh-app browser review

Readability decisions

  • New behavior is split into focused forms.ts and ui.ts modules.
  • Public controllers are headless and return ordinary props.
  • Runtime schemas remain the source for TypeScript and agent contracts.
  • IDs are deterministic for SSR, hydration, accessibility, and agent operation.
  • Unsafe or unknown form keys throw rather than fail silently.
  • Examples use domain-specific names and semantic native HTML.

Large existing modules such as backend.ts, auth.ts, and platform.ts remain cohesive but substantial. Splitting them without changing their public boundaries is future maintainability work; a mechanical split was not treated as inherently safer than tested cohesive code.

Security posture

The existing security boundaries remain:

  • bounded request and artifact intake;
  • executable URL and inline-handler rejection;
  • safe SSR escaping and serialized state;
  • scrypt password hashing, CSRF, secure cookies, rate limits, roles, and revocation;
  • owned SQLite rows and auth-partitioned live queries;
  • traversal/symlink defenses;
  • encrypted deployment secrets;
  • immutable migration history, backup, health-gated activation, and rollback.

The audit added semantic password/file redaction and stricter form-key handling. Client forms and hidden UI are never authorization boundaries.

The 0.7.0 rename also preserves existing accounts, sessions, application rows, migration history, projects, releases, secrets, logs, and audit records. Clank writes only the new names after migration. See Renaming from Proact.

Application coverage

The current examples prove different mechanics:

  • hello: reactive primitives and agent actions.
  • todo: keyed client CRUD.
  • fullstack: SSR, SQLite, RPC, and live synchronization.
  • auth-todo: sessions, user-owned data, SSR, and multi-tab live updates.
  • commerce: search/filter/sort, cart state, modal checkout, validation, and async confirmation.
  • dashboard: tabs, metrics, responsive navigation, tables, filtering, pagination, invite dialog, and settings.
  • booking: multi-step composition, cross-field dates, room selection, computed pricing, guest validation, and confirmation.

These examples demonstrate framework breadth. They do not replace domain-specific payment, tax, inventory, medical, legal, or regulatory integrations.

Known limits

  • Form paths are intentionally top-level. Compose controllers for nested editors and independent wizard steps.
  • A capability-gated local file store and upload endpoint are included for trusted single-host deployments; production object storage, CDN delivery, and image transformation remain provider integrations.
  • No virtualized list is included yet; large datasets should page server-side.
  • Dialogs are rendered in place rather than through a portal.
  • The built-in process supervisor remains single-leader even though durable distributed coordination primitives are available.
  • The trusted process runner is not a sandbox; use the Docker runner for stronger isolation.
  • Clank now provides verified domain eligibility for Caddy On-Demand TLS, but certificate/key custody, WAF/DDoS service, WebSocket ingress, remote worker integration, and globally distributed control storage remain external or future platform work.
  • Tailwind's browser build is suitable for examples and zero-install prototyping; production applications should serve compiled CSS.

Release gate

A release is acceptable only after:

  1. the zero-dependency TS/TSX syntax-lowering build succeeds;
  2. checked-in declarations match built declarations, package export targets resolve, and local documentation links remain valid;
  3. all unit and end-to-end tests pass above the enforced 80% line, 65% branch, and 80% function coverage floors;
  4. package contents contain no databases, environment files, credentials, or platform state;
  5. fresh package consumers can scaffold and build;
  6. representative applications pass browser interaction, console/error, accessibility-tree, and responsive-layout checks;
  7. npm run conformance passes against a packed release through browser auth, CLI device authorization, live synchronization, user isolation, deployment, migration, failed activation, rollback, and data restoration;
  8. npm run security:audit verifies dependency, package-content, current-tree and reachable-history credential patterns, governance, least-privilege, immutable-action, OIDC, and evidence requirements; and
  9. deterministic chaos tests prove worker reclaim/fencing, corrupt-backup fail-closed behavior, and ingress recovery.

Clank deliberately does not install a TypeScript package. Its built-in compiler validates syntax lowering, while the checked-in declarations define the consumer contract. Run tsc --noEmit as an additional semantic type check when a separately provisioned, trusted TypeScript compiler is available; do not describe that optional external tool as part of the zero-dependency gate.

See docs/security.md and docs/platform-security.md for the separate security checklists.