mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-10-25 22:10:25 +00:00
08236c7459
* test(web): enumerate $state declarations by STATEMENT in the fence-source core (BUG-3084 M12)
Four page guards carried `let\s+(\w+)\s*(?::[^=]*)?=\s*\$state` with the m flag.
The negated class admits a newline, so an uninitialised typed `let` on the
line above a `$state` declaration matched as ONE declaration named after the
wrong variable and the real one was never enumerated — the dashboard page has
exactly that pair, and its guard went red for a name that is not $state while
silently missing the one that is. The narrow fix ([^=\n]) closes that case and
opens the opposite one, a genuine annotation spanning lines.
`stateDeclarations()` walks each `let` statement to its terminating `;` at
bracket depth zero and asks whether it initialises with $state; it fails
closed on a statement that never ends. The core's suite drives the adjacency
case with the legacy regex as the control that must stay red, the multi-line
generic, an object type with semicolons inside, a string with a semicolon, and
the FenceSource binding. All four guards now read the core. Receipt: on the
library, roles and collection pages the legacy regex and the new enumerator
agree (9, 22, 49); on the dashboard they differ by exactly pollTimer→onboardingDismissed.
* test(web): the $state enumerator reads the grammar it walks, per Codex review (round 1)
Four constructed shapes, each accepted by the compiler, each read wrong by
the first scanner's bare depth counter: a regex literal containing a brace
swallowed every declaration after it; only the first binding of a
multi-binding let was inspected; a generic default (<T = string>) was taken
for the initialiser; and two statements joined by automatic semicolon
insertion recreated the wrong-name bug the hoist exists to close. Brackets
are now skipped with the core's own string/regex-aware matchDelimiter,
statement-level regex literals use its previous-significant-character rule,
a depth-zero comma outside a type annotation starts the next binding, angle
brackets are tracked only in type position, and a newline followed by a
statement keyword ends an uninitialised or already-initialised binding.
Destructuring patterns are walked and refused only when backed by $state.
Each shape is a fixture; the receipt on the real pages is unchanged.
* test(web): the $state enumerator's outer search is literal-aware and reads type arguments, per Codex review (round 2)
Three more compiler-accepted shapes: a type-argument list on the initialiser whose comma split the bindings; a parenthesised initialiser; and the outer let search matching inside a template literal and enumerating a phantom. The search is now the same literal-aware walk the statement scanner uses; angle brackets after the initialiser are tracked when they directly follow an identifier; a parenthesised $state is still $state. Each shape is a fixture; the receipt on the real pages is unchanged.
* test(web): type arguments are decided by their call paren and initialiser bodies are descended, per Codex review (round 3)
An unspaced comparison (1<2) opened an angle depth that suppressed every boundary to end of input; a let nested in an initialiser's function body was skipped, though the regex this replaces enumerated it. A < after the initialiser is now a type-argument list only when its matching > is immediately followed by (, and bracket bodies are walked for nested declarations rather than skipped. Both are fixtures; the receipt on the real pages is unchanged.
* test(web): interpolation bodies are walked, an enclosing closer ends a binding, nested type arguments keep depth, per Codex review (round 4)
A template's ${…} body is code and was skipped with the text around it; a binding with no semicolon ran past the } of its enclosing block into the next declaration; a nested < inside an open type-argument list did not increment the depth, so the inner > exposed a type comma as a binding separator and the guard threw on valid code. Each is a fixture; the receipt on the real pages is unchanged.
* test(web): whitespace in type arguments, arrow-returned regexes, type members named let, and the population table, per Codex review (round 5)
Three more constructed shapes fixed with fixtures. Five rounds each found new members of one class — grammar the scanner had not been told about — so per CONVE-35 the class is now written down: the doc comment carries the table of what the scanner reads, refuses, and does not read, bounded by the receipt that on every page in the family it agrees with the legacy regex except for the dashboard swap that motivated the hoist.
Pad Web UI
SvelteKit 2 + Svelte 5 frontend for Pad, compiled to static files and embedded into the Go binary.
Development
npm install
npm run dev # Dev server at localhost:5173 (proxies API to localhost:7777)
npm run build # Production build to build/
npm run check # Type checking with svelte-check
When developing, run the Go backend separately with make dev from the project root.
Building for Production
Do not build in isolation. Always use make build from the project root — this builds the web frontend, then compiles the Go binary with the build output embedded via //go:embed.
Stack
- Svelte 5 with runes (
$state,$derived,$effect) - SvelteKit 2 with
adapter-static(SPA mode) - Tiptap block editor with markdown round-trip
- svelte-dnd-action for drag-and-drop in board/list views
- SSE for real-time updates
- TypeScript throughout
Structure
src/
routes/ SvelteKit pages
+layout.svelte App shell (sidebar + main)
+page.svelte Landing/redirect
[workspace]/
+page.svelte Dashboard (collections, phases, activity)
+layout.svelte SSE connection per workspace
[collection]/
+page.svelte Collection view (board/list)
[collection]/[item]/
+page.svelte Item detail + editor
conventions/ Purpose-built conventions page
playbooks/ Purpose-built playbooks page
settings/ Workspace settings
lib/
api/client.ts HTTP API client
components/
layout/ Sidebar, navigation
editor/ Tiptap editor, raw markdown editor
fields/ FieldEditor, relation picker
items/ ItemCard, ItemDetail
collections/ BoardView, ListView
common/ StatusBadge, badges, modals
search/ CommandPalette
stores/ Svelte 5 reactive stores
workspace.svelte.ts Workspace state
collections.svelte.ts Collection + item state
ui.svelte.ts Sidebar, mobile state
types/index.ts TypeScript types and constants
app.css Global styles and design tokens