add skills as symlinks
This commit is contained in:
parent
7a23bf6152
commit
aa442a8d18
4 changed files with 129 additions and 165 deletions
|
|
@ -2,23 +2,42 @@
|
|||
|
||||
Symlinks to the state that AI tooling reads and writes **for this repo
|
||||
only** — no global/all-projects state is linked here. Same convention as
|
||||
`log-watcher/.dev`: **user-specific absolute paths, gitignored** (only this
|
||||
README is committed). Each developer recreates them for their own machine
|
||||
`log-watcher/.dev`: **user-specific paths, gitignored** (only this README
|
||||
is committed). Each developer recreates the links for their own machine
|
||||
(commands below).
|
||||
|
||||
| Link | Points at | What a developer uses it for |
|
||||
| --- | --- | --- |
|
||||
| `claude-project/` | `~/.claude/projects/<this-repo, slashes→dashes>` | Claude Code's per-project state: session transcripts (`*.jsonl`) and `memory/` (the persistent memory index + facts). Grep a past session, read/curate what Claude remembers about this repo. |
|
||||
| `skills/<plugin>/<skill>.md` | Each installed plugin's `skills/*/SKILL.md` (`~/.claude/plugins/cache/…`, version-pinned) plus `~/.claude/skills/*` under `skills/user/` | Read the exact instructions a skill injects (caveman, context-mode, superpowers, …) without digging through the plugin cache. Links break when a plugin updates to a new version — rerun the recreate loop below. |
|
||||
|
||||
## references/ — related source trees
|
||||
## reference/ — v1 archive, smoke files, study-tree symlinks
|
||||
|
||||
`references/` holds read-only symlinks to source trees under `~/projects/`
|
||||
used as study material for the compiler/runtime work (same idea as the
|
||||
`reference/{linux,go}` links at the repo root):
|
||||
`reference/` (moved here from the repo root, then untracked entirely,
|
||||
2026-08-08) is **developer-local, gitignored** — disk-only on each
|
||||
machine; the v1 history remains reachable in git at the pre-move
|
||||
`reference/` path. It holds:
|
||||
|
||||
- `reference/crates/` — the v1 writeonce blog (13 `wo-*` crates, nested
|
||||
Cargo workspace, excluded from the root workspace). Port source for the
|
||||
dependency-removal plans; do not delete without checking
|
||||
`docs/runtime/database/07-wo-seg-migration.md`.
|
||||
- `reference/rest/` — `.rest` HTTP smoke files for the running runtime.
|
||||
- `reference/writeonce-api/`, `reference/writeonce-app/` — earlier cuts,
|
||||
archived.
|
||||
- Gitignored, user-specific symlinks to study trees:
|
||||
`linux`, `go`, `postgresql`, `mcp-python-sdk`, `colibri`, `llama-cpp`,
|
||||
`llvm-project` (recreate per machine; see `.gitignore` for the
|
||||
`ln -s` lines).
|
||||
|
||||
Study-tree notes:
|
||||
|
||||
| Link | Points at | Why it's a reference |
|
||||
| --- | --- | --- |
|
||||
| `references/llvm-project/` | `~/projects/llvm-project` (shallow clone) | Compiler-architecture study for the OCaml `woc` compiler: pass pipelines (`llvm/lib/Passes/`), IR design (`llvm/docs/LangRef.md`), Clang's lexer/parser/sema layering (`clang/lib/{Lex,Parse,Sema}/`), diagnostics machinery (`clang/include/clang/Basic/Diagnostic*.td`). Study-only — writeonce does NOT link against LLVM (zero-dep doctrine; `woc` emits `.wob` bytecode, no LLVM backend). |
|
||||
| `reference/llvm-project/` | `~/projects/llvm-project` (shallow clone) | Compiler-architecture study for the OCaml `woc` compiler: pass pipelines (`llvm/lib/Passes/`), IR design (`llvm/docs/LangRef.md`), Clang's lexer/parser/sema layering (`clang/lib/{Lex,Parse,Sema}/`), diagnostics machinery (`clang/include/clang/Basic/Diagnostic*.td`). Study-only — writeonce does NOT link against LLVM (zero-dep doctrine; `woc` emits `.wob` bytecode, no LLVM backend). |
|
||||
|
||||
(The former separate `references/` directory was merged into `reference/`
|
||||
on 2026-08-08 — one home for all study trees.)
|
||||
|
||||
Deliberately **not** linked (global, cross-project state): `~/.claude`
|
||||
(all projects' transcripts, credentials), `~/.config/opencode` and
|
||||
|
|
@ -37,9 +56,23 @@ links.
|
|||
```bash
|
||||
cd .dev
|
||||
ln -sfn "$HOME/.claude/projects/$(git rev-parse --show-toplevel | tr / -)" claude-project
|
||||
mkdir -p references
|
||||
git clone --depth 1 https://github.com/llvm/llvm-project.git ~/projects/llvm-project
|
||||
ln -sfn "$HOME/projects/llvm-project" references/llvm-project
|
||||
ln -sfn "$HOME/projects/llvm-project" reference/llvm-project
|
||||
|
||||
# skills/ — one .md link per installed skill (rerun after plugin updates)
|
||||
jq -r '.plugins | to_entries[] | .value[0].installPath' ~/.claude/plugins/installed_plugins.json | while read -r p; do
|
||||
plug=$(basename "$(dirname "$p")")
|
||||
for d in "$p"/skills/*/; do
|
||||
[ -f "${d}SKILL.md" ] || continue
|
||||
mkdir -p "skills/$plug"
|
||||
ln -sfn "${d}SKILL.md" "skills/$plug/$(basename "$d").md"
|
||||
done
|
||||
done
|
||||
for d in ~/.claude/skills/*/; do
|
||||
[ -f "${d}SKILL.md" ] || continue
|
||||
mkdir -p skills/user
|
||||
ln -sfn "${d}SKILL.md" "skills/user/$(basename "$d").md"
|
||||
done
|
||||
```
|
||||
|
||||
(`claude-project`: Claude Code names the directory after the repo's absolute
|
||||
|
|
|
|||
22
.gitignore
vendored
22
.gitignore
vendored
|
|
@ -1,6 +1,5 @@
|
|||
# Cargo build artifacts
|
||||
/target
|
||||
/.dev/reference/crates/target
|
||||
|
||||
# C++ prototype build output
|
||||
/prototypes/*/build
|
||||
|
|
@ -25,16 +24,15 @@
|
|||
# Legacy blog content and data (v1 writeonce storage)
|
||||
/content
|
||||
|
||||
# Developer-local links into agent-tooling state (Claude Code project data,
|
||||
# opencode config/data, llama.cpp cache) — user-specific absolute paths.
|
||||
# Committed inside .dev: README.md and reference/ (v1 archive + rest smoke files);
|
||||
# recreate the per-machine links as .dev/README.md describes.
|
||||
# Everything in .dev is developer-local (agent-tooling links, and the whole
|
||||
# reference/ area: v1 archive, rest smoke files, study-tree symlinks —
|
||||
# untracked 2026-08-08, disk-only; v1 history lives at the pre-move
|
||||
# reference/ path). Only this README survives:
|
||||
/.dev/*
|
||||
!/.dev/README.md
|
||||
!/.dev/reference/
|
||||
/.dev/reference/
|
||||
|
||||
# Symlinks to research source trees inside .dev/reference — user-specific
|
||||
# absolute paths. Each contributor sets their own via:
|
||||
# Study-tree symlinks each contributor recreates per machine:
|
||||
# ln -s <path-to-linux-src> .dev/reference/linux
|
||||
# ln -s <path-to-go-src> .dev/reference/go
|
||||
# ln -s <path-to-postgresql-src> .dev/reference/postgresql
|
||||
|
|
@ -42,13 +40,7 @@
|
|||
# (clone: https://github.com/modelcontextprotocol/python-sdk.git)
|
||||
# ln -s <path-to-colibri> .dev/reference/colibri
|
||||
# ln -s <path-to-llama.cpp> .dev/reference/llama-cpp
|
||||
/.dev/reference/linux
|
||||
/.dev/reference/go
|
||||
/.dev/reference/postgresql
|
||||
/.dev/reference/mcp-python-sdk
|
||||
/.dev/reference/colibri
|
||||
/.dev/reference/llama-cpp
|
||||
/.dev/reference/*
|
||||
# ln -s <path-to-llvm-project> .dev/reference/llvm-project
|
||||
|
||||
# Agent-orchestration scratch (SDD ledgers, briefs, review packages)
|
||||
/.superpowers/
|
||||
|
|
|
|||
211
CLAUDE.md
211
CLAUDE.md
|
|
@ -1,153 +1,92 @@
|
|||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
You are a senior Developer & Architect with a passion for performance & KISS.
|
||||
|
||||
## What this repo is
|
||||
Always use the caveman skill.
|
||||
|
||||
writeonce is a **declarative full-stack programming language**. You write `.wo` files; the runtime compiles them into a single binary that owns the database, serves REST, and (Stage 3+) pushes live subscriptions. Think: Go + Postgres + `net/http` + Phoenix LiveView folded into one language.
|
||||
## 0. Take Pride in providing outstanding results
|
||||
|
||||
## The end goal — zero external deps, kernel primitives only
|
||||
**The results speaks for themselves**
|
||||
|
||||
The runtime's north star — documented in [`docs/01-problem.md`](docs/01-problem.md), [`docs/02-recovery.md`](docs/02-recovery.md), and [`docs/plan/linux/00-linux.md`](docs/plan/linux/00-linux.md) — is **one binary, no external Rust crates, all I/O driven directly by Linux kernel primitives**. `epoll` (or `io_uring`), `inotify`, `eventfd`, `timerfd`, `signalfd`, `sendfile`, `mmap` — the kernel IS the subscription engine, the async runtime, and the file watcher.
|
||||
- You go the extra mile if the result is worth it
|
||||
- You dont sugarcoat subpar solutions, you despise them
|
||||
- You think outside the box
|
||||
|
||||
Target end state of `crates/rt/Cargo.toml`:
|
||||
## 1. Think Before Coding
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
libc = "0.2" # the unavoidable FFI bridge to syscalls
|
||||
**Don't assume. Don't hide confusion. Surface tradeoffs. Apply critical thinking.**
|
||||
|
||||
Before implementing:
|
||||
|
||||
- Don't outright trust existing code-comments. Question, validate & correct them.
|
||||
- State your assumptions explicitly. If uncertain, ask.
|
||||
- If multiple interpretations exist, present them - don't pick silently.
|
||||
- If a simpler approach exists, say so. Push back when warranted.
|
||||
- If something is unclear, stop. Name what's confusing. Ask.
|
||||
|
||||
## 2. Simplicity First
|
||||
|
||||
**Minimum code that solves the problem. Nothing speculative.**
|
||||
|
||||
- No features beyond what was asked.
|
||||
- No abstractions for single-use code.
|
||||
- No "flexibility" or "configurability" that wasn't requested.
|
||||
- No error handling for impossible scenarios.
|
||||
- If you write 200 lines and it could be 50, rewrite it.
|
||||
|
||||
Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.
|
||||
|
||||
## 3. Surgical Changes
|
||||
|
||||
**Touch only what you must. Clean up only your own mess.**
|
||||
|
||||
When editing existing code:
|
||||
|
||||
- Don't "improve" adjacent code, comments, or formatting.
|
||||
- Don't refactor things that aren't broken.
|
||||
- Match existing style, even if you'd do it differently.
|
||||
- If you notice unrelated dead code, mention it - don't delete it.
|
||||
|
||||
When your changes create orphans:
|
||||
|
||||
- Remove imports/variables/functions that YOUR changes made unused.
|
||||
- Don't remove pre-existing dead code unless asked.
|
||||
|
||||
The test: Every changed line should trace directly to the user's request.
|
||||
|
||||
## 4. Goal-Driven Execution
|
||||
|
||||
**Define success criteria. Loop until verified.**
|
||||
|
||||
Transform tasks into verifiable goals:
|
||||
|
||||
- "Add validation" → "Write tests for invalid inputs, then make them pass"
|
||||
- "Fix the bug" → "Write a test that reproduces it, then make it pass"
|
||||
- "Refactor X" → "Ensure tests pass before and after"
|
||||
|
||||
For multi-step tasks, state a brief plan:
|
||||
|
||||
```
|
||||
1. [Step] → verify: [check]
|
||||
2. [Step] → verify: [check]
|
||||
3. [Step] → verify: [check]
|
||||
```
|
||||
|
||||
Stage 2 today carries six transitional deps (`anyhow`, `serde`, `serde_json`, `tokio`, `axum`, `tower`). [`docs/plan/02`](docs/plan/02-event-loop-epoll.md) through [`docs/plan/08`](docs/plan/08-sendfile-static-assets.md) sequence the removal of each one, replaced by hand-rolled modules ported from the v1 crates that already did exactly this (`reference/crates/wo-event`, `wo-http`, `wo-route`, `wo-serve`, `wo-watch`). **When working on the runtime, default to direct-syscall solutions over reaching for new crates** — the `docs/plan/` docs name the port source for every module.
|
||||
Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification.
|
||||
|
||||
## Layout
|
||||
## 4. Fix Errors as you encounter them
|
||||
|
||||
The repo holds three cuts of the same project plus one research reference:
|
||||
**An error means a broken baseline. Fix any error you encounter. No bandaids.**
|
||||
|
||||
1. **`crates/rt/`** — the **active Rust runtime** (Stage 2 shipped). Monolithic on purpose for now: lexer, parser, AST, in-memory engine, axum REST server all in one crate. The `wo` binary lives at `crates/rt/src/bin/wo.rs`.
|
||||
2. **`crates/{ql,value,engine,txn,db,wal,sub,http,gen,policy,logic,service,ui,app}/`** — 14 **empty sibling crates** scaffolded to match the 7-phase design. Each has a `Cargo.toml` + `src/lib.rs` with just a doc comment pointing at its phase spec. Real code moves in from `rt` as each phase activates; do NOT refactor `rt` to use these today — it would break Stage 2.
|
||||
3. **`reference/crates/`** — the **v1 writeonce blog** (13 crates: `wo-seg`, `wo-index`, `wo-store`, `wo-htmlx`, etc.). This is a **nested Cargo workspace**, deliberately excluded from the root workspace. The v1 crates keep their `wo-` prefix; the new runtime crates dropped theirs. `cd reference/crates && cargo build` builds v1 standalone. See `docs/runtime/database/07-wo-seg-migration.md` for the plan replacing v1 with the new runtime.
|
||||
4. **`reference/linux/`** and **`reference/go/`** — **symlinks** to the Linux kernel source tree and the Go source tree respectively. Not committed (see `.gitignore`). Research resources:
|
||||
- **`reference/linux/`** — grep `io_uring/`, `fs/notify/inotify/`, `kernel/eventfd.c`, `include/uapi/linux/*.h` when designing the kernel-primitive modules. Paired with per-primitive reference cards at [`docs/plan/linux/`](docs/plan/linux/).
|
||||
- **`reference/go/`** — grep `src/runtime/netpoll_epoll.go`, `netpoll.go`, `os_linux*.go`, `asm_*.s`, `sys_linux_*.s` when designing the runtime layer. The `crates/rt/src/runtime/` module mirrors Go's `src/runtime/` file-per-flavour naming (`netpoll_epoll.rs` ↔ `netpoll_epoll.go`). The [`docs/plan/assembly/`](docs/plan/assembly/) docs cite this tree.
|
||||
- Each contributor sets their own targets via `ln -s <path-to-src> reference/{linux,go}`.
|
||||
Always inspect crashsites. Always measure. Never assume.
|
||||
|
||||
There is also **`prototypes/wo-db/`** — a ~2k-line **C++ prototype** of the query-layer engine (SQL + Cypher + document paths, `RETURNING` aliases, `LIVE` stub). It keeps its `wo-db` directory name (C++ project, separate from the Rust crate `db`). It's the reference implementation the Rust port follows; `make test` still passes.
|
||||
## 5. Tools
|
||||
|
||||
And **`runtime/`** — a single-file **C reference of the runtime layer** (edge-triggered epoll loop, signalfd shutdown, non-blocking listener, in-RAM store over minimal HTTP; libc only). It's the runtime-layer sibling of `wo-db`: each block maps one-to-one to a `crates/rt/src/runtime/` module (table in its README). `make -C runtime` builds it; `just rt-c-demo` exercises it. Its evolution into a multi-threaded io_uring RAM-database runtime (thread-per-core, mmap arena, WAL dual-write, recovery, ACID) is phased A–F in `docs/plan/exploration/c-runtime/00-plan.md`, with the one-address architecture trace beside it (`01-architecture.md`) — the proving ground for plans 09–12. **Documentation belongs under `docs/`** — prototype/crate directories keep only their orientation README. One recorded exception: the compiler track's plan documents live in `compiler/plan/` (architecture map + plans 2, 3, 8).
|
||||
- caveman
|
||||
- context-mode
|
||||
- web-search
|
||||
- superpowers
|
||||
|
||||
## Commands
|
||||
---
|
||||
|
||||
```bash
|
||||
# Build + test the runtime
|
||||
cargo build # compiles all 15 crates
|
||||
cargo test --lib # 14 unit tests (all in rt today)
|
||||
cargo test --lib parses_inline_struct -- --nocapture # single named test
|
||||
|
||||
# Run the runtime against a sample project
|
||||
cargo run --bin wo -- run docs/examples/blog # :8080 — blog sample
|
||||
cargo run --bin wo -- run docs/examples/ecommerce # :8080 — ecommerce sample
|
||||
WO_LISTEN=127.0.0.1:9000 cargo run --bin wo -- run docs/examples/blog # override port
|
||||
|
||||
# v1 blog codebase (nested workspace — must cd first)
|
||||
cd reference/crates && cargo build && cargo test
|
||||
|
||||
# C++ prototype of the query-layer engine
|
||||
cd prototypes/wo-db && make test # smoke.wo + checkout.wo
|
||||
cd prototypes/wo-db && make run # interactive REPL
|
||||
|
||||
# Manual HTTP smoke against a running `wo run ...`
|
||||
# Open reference/rest/blog.rest or ecommerce.rest in VS Code (with REST Client)
|
||||
# or JetBrains (built-in HTTP client). Or run curl per reference/rest/README.md.
|
||||
```
|
||||
|
||||
## Architecture — what requires reading multiple files to understand
|
||||
|
||||
### Naming convention
|
||||
|
||||
- **New runtime crates are unprefixed.** `ql`, `value`, `engine`, `txn`, `db`, `wal`, `sub`, `http`, `gen`, `policy`, `logic`, `service`, `ui`, `app`, `rt`. Internal imports read cleanly: `use ql::Parser`, `use db::Tx`, `use http::router`.
|
||||
- **V1 crates keep the `wo-` prefix.** `wo-seg`, `wo-index`, `wo-store`, `wo-htmlx`, `wo-md`, and v1's own `wo-rt`/`wo-http`/`wo-sub`. These live in `reference/crates/`.
|
||||
- **The C++ prototype directory is `prototypes/wo-db/`** — unchanged, not a Rust crate.
|
||||
- **The binary is `wo`** — defined in `crates/rt/Cargo.toml` `[[bin]]`. Independent of the crate name.
|
||||
|
||||
### The two-layer `.wo` language
|
||||
|
||||
Covered in `docs/runtime/database/02-wo-language.md`:
|
||||
|
||||
- **Schema layer** — unified `type Name { ... }` DSL (fields, embedded structs, `ref`, `multi @edge`, `multi via`, `backlink`, tagged unions, `policy`, `on <event>`, `service`). This is what developers write day-to-day.
|
||||
- **Query layer** — hybrid SQL + Cypher with five "fixed-glue" rules that make the three grammars share semantics: `$name` parameters everywhere, cross-paradigm `RETURNING col AS alias` visible to later statements in the same `BEGIN … COMMIT`, dotted paths identical in SQL/doc/Cypher, one transaction block syntax, one `LIVE` prefix on subscriptions.
|
||||
|
||||
Both layers are `.wo` files. The schema layer compiles down to query-layer operations — but only when Phase 5 codegen and Phase 6 full-stack blocks need a single authoritative input. Stage 2 ships with the schema layer only.
|
||||
|
||||
### Concurrency: thread-per-core event loops (09a shipped)
|
||||
|
||||
Since plans 09a+09b, `wo run` boots `WO_THREADS` pinned worker threads (default = online cores; `wo-shard-<t>` in `ps -T`), each running its own epoll `EventLoop` with its own `SO_REUSEPORT` listener (`crates/rt/src/runtime/scheduler.rs`) **and its own `Engine`** — there is no `Arc<Mutex<Engine>>` anywhere. Ids interleave per shard (`Engine::for_shard`; owner = `(id-1) % n`); cross-shard operations travel the shard bus (`crates/rt/src/shard.rs`: mpsc job mailboxes + mail eventfds; creates local, point ops hop once, lists fan out and merge). Deadlock-freedom: jobs never block, waiters pump their own inbox. Routers are thread-local (`HandlerFn` is not `Send`/`Sync`). Signals are blocked before spawn; worker 0 owns the signalfd and broadcasts shutdown via per-worker eventfds. Don't reintroduce shared mutable engine state — the doctrine below is now enforced by ownership.
|
||||
|
||||
### Single-threaded event loop (original doctrine)
|
||||
|
||||
Covered in `docs/runtime/database/02-wo-language.md § Concurrency Model` and `03-inmemory-engine.md`. The runtime is Redis/TigerBeetle-style: **one userland thread owns everything** — connection accept, parser, engine, subscription registry. The only non-userland thread is the kernel-owned io_uring SQPOLL helper. This is pinned architecturally — group commit still applies (loop drains many commits into one fsync SQE per tick), and scaling past one core is done by **sharding** independent engine processes, not by adding worker threads. Keep this in mind before proposing `Arc<Mutex<...>>` anything beyond what's already there.
|
||||
|
||||
### What's in `rt` today vs. what the empty crates promise
|
||||
|
||||
`rt`'s modules deliberately mirror the future crate names so the extraction is mechanical when each phase activates:
|
||||
|
||||
| `rt` module | Will move to | Phase |
|
||||
| --- | --- | --- |
|
||||
| `token.rs` + `lexer.rs` + `ast.rs` + `parser.rs` | `ql` | 2 |
|
||||
| `engine.rs` (Value + Row helpers) | `value` | 2 |
|
||||
| `engine.rs` (Engine + Catalog) | `engine` | 2 |
|
||||
| `compile.rs` | `engine` | 2 |
|
||||
| `method.rs` (13b method executor) | `logic` | 6 |
|
||||
| `pg.rs` + `mirror.rs` (16 Postgres backup mirror) | `db` | 3+ |
|
||||
| `server.rs` | `http` + `service` | 4 / 6 |
|
||||
| `bin/wo.rs` | stays in `rt` (the binary) | — |
|
||||
|
||||
The `sub`, `wal`, `txn`, `policy`, `logic`, `ui`, `app`, `gen` crates have no `rt` counterpart yet — they land when their phase activates.
|
||||
|
||||
### Sample projects drive the grammar
|
||||
|
||||
`docs/examples/blog/` and `docs/examples/ecommerce/` are **both docs artifacts and the de facto integration tests**. The parser survives these because specific features in them (nested `{...}` object literals inside trigger actions, `count(...)` / `words(...)` computed defaults, unions like `Pending | Paid | Shipped`) forced real fixes. When changing the parser, run the full end-to-end against both samples, not just `cargo test`.
|
||||
|
||||
The ecommerce sample in particular uses features that are deliberately **parse-and-discard** in Stage 2: `fn checkout(...) in txn snapshot`, type-attached `on update` triggers with multi-line `do` actions, `policy read for role ...`. These are part of the `.wo` language but Stage 2 does not execute them.
|
||||
|
||||
### The migration story
|
||||
|
||||
`docs/runtime/database/07-wo-seg-migration.md` specifies **phased coexistence**: abstract the v1 article store behind an `ArticleStore` trait, stand up the `.wo` engine as a second implementation, dual-write, cut over, decommission v1. Phase A (trait abstraction) hasn't started — the plan is on paper, the v1 code is still monolithic in `reference/crates/wo-store/`. Do not remove anything from `reference/crates/` without checking the migration doc.
|
||||
|
||||
### Stage progress
|
||||
|
||||
| Stage | Status |
|
||||
| --- | --- |
|
||||
| 1 — `wo run <dir>` discovers `.wo` files | ✅ shipped |
|
||||
| 2 — parser + engine + REST CRUD | ✅ shipped (`cargo run -- run docs/examples/blog`) |
|
||||
| 3 — LIVE subscriptions over WebSocket | pending — `/api/<type>/live` returns 501 as a stub |
|
||||
| 4+ — transactional `fn`, policies, triggers, `##ui`, WAL, codegen | design-only (see `docs/runtime/database.md`) |
|
||||
|
||||
Stage-3 stubs (501) and policy-shaped 405/404 responses are **intentional and documented** in `reference/rest/*.rest`. Don't "fix" them without checking those files first.
|
||||
|
||||
## Non-obvious gotchas
|
||||
|
||||
- **`rt` is monolithic on purpose.** Splitting it into the 14 sibling crates is Phase-by-Phase work, not a Stage-2 refactor.
|
||||
- **`reference/crates/` is its own workspace.** Running `cargo build` at the root does not build v1. Running it in `reference/crates/` does.
|
||||
- **Parser identifiers vs. keywords.** `subscribe`, `receive`, `expect_abort`, `me`, `self`, and lowercase `insert`/`select` are NOT keywords in the lexer — they stay as plain idents (only SQL-layer `INSERT`/`SELECT` are keywords). The 13b statement parser matches `insert` as an ident; the select expression is recognised by the two-token shape `select <Ident> {`. Adding these to the keyword map breaks `service rest "..." expose subscribe` and method bodies.
|
||||
- **Type-level annotations.** `@table(name: "...", index: [a, b])` before a `type`/`class` configures storage (it never toggles table-ness — every type IS a table). Unknown keys inside `@table(...)` are parse errors; unknown annotation *names* (`@foo`) skip silently. Engine secondary indexes are maintained ONLY via `Engine::row_insert`/`row_remove` — never touch `tables` directly or indexes drift.
|
||||
- **The Postgres mirror is a backup, never a commit path.** `WO_PG=…` streams committed mutations to Postgres asynchronously (`mirror.rs`, one `wo-pg` thread, hand-rolled wire client in `pg.rs` — no crates). Reads and acks must never depend on it: taps sit AFTER `wal_log` accepts, use `try_send`, and drop loudly on overflow. Boot re-pushes all RAM state (`mirror_sync_all`), so RAM stays authoritative and Postgres is always reconstructible from a restart. See `docs/plan/16-postgres-mirror.md`.
|
||||
- **Parser skip-on-block.** Unknown triggers (`on update do ...`) are parsed-and-discarded by brace-depth-aware skipping. Object literals like `{ article_id: self.id }` inside trigger actions contain `}` that must not be mistaken for the type's outer close brace — the depth counter exists specifically because of this. Exception since 13b: `fn` inside a `class` parses into a real `MethodDecl` (body statements + expressions, executed by `method.rs`); `fn` inside a plain `type` still skips.
|
||||
- **Newline significance.** The lexer emits `Kind::Newline` tokens and the parser uses them to end policy/trigger lines. Do not filter newlines globally.
|
||||
- **Default-value parsing.** `= now()` is recognised explicitly as `DefaultExpr::Now`; anything else falls into an opaque-expression path that `engine::eval_default` then **omits from created rows** (computed fields display as empty, not as debug-printed tokens).
|
||||
- **Binary variable shadowing.** `crates/rt/src/bin/wo.rs` has `let rt = ...` (a tokio runtime handle) inside `run()` that shadows the crate named `rt`. Inside `run()` the variable wins; inside `serve()` (a different function) `rt::` refers to the crate. Don't rename the variable without also auditing the crate-path references.
|
||||
|
||||
## Where to read next
|
||||
|
||||
- `docs/runtime/wo-language.md` — user-facing language overview
|
||||
- `docs/runtime/database.md` — 7-phase engineering series index
|
||||
- `docs/plan/linux/00-linux.md` — catalogue of kernel primitives the runtime leans on
|
||||
- `docs/plan/02-event-loop-epoll.md` through `08-sendfile-static-assets.md` — the dependency-removal phase sequence
|
||||
- `docs/plan/done/01-scafolding-crates.md` — the completed crate-scaffolding phase
|
||||
- `docs/examples/blog/README.md` — the canonical worked example
|
||||
- `prototypes/wo-db/README.md` — the C++ prototype that shows the query layer
|
||||
- `reference/rest/README.md` — how to exercise the running prototype
|
||||
- `reference/README.md` — what's in the v1 archive and why it's preserved
|
||||
- `reference/linux/` (symlink) — the Linux kernel source tree; grep `io_uring/`, `fs/notify/inotify/`, `include/uapi/linux/*.h` when designing kernel-facing modules
|
||||
- `reference/go/` (symlink) — the Go source tree; grep `src/runtime/netpoll_*.go`, `asm_*.s`, `sys_linux_*.s` when porting runtime-layer ideas (writeonce's `crates/rt/src/runtime/` mirrors this naming)
|
||||
- `docs/plan/assembly/00-overview.md` — role of assembly in a runtime; writeonce policy is "no custom asm, use Rust stdlib"
|
||||
- `crates/README.md` — inventory of all 15 crates with phase assignments
|
||||
**These guidelines are working if:** fewer unnecessary changes in diffs, fewer rewrites due to overcomplication, and clarifying questions come before implementation rather than after mistakes.
|
||||
|
|
|
|||
10
README.md
10
README.md
|
|
@ -18,7 +18,7 @@ cargo run --bin wo -- run docs/examples/blog # serve the sample blog on :808
|
|||
curl http://127.0.0.1:8080/api/articles # it's a real REST API now
|
||||
```
|
||||
|
||||
See [`reference/rest/blog.rest`](reference/rest/blog.rest) for a preconfigured HTTP-request file that drives the whole sample — open it in VS Code (with the REST Client extension) or JetBrains and click "Send Request" on each block.
|
||||
See [`.dev/reference/rest/blog.rest`](.dev/reference/rest/blog.rest) for a preconfigured HTTP-request file that drives the whole sample — open it in VS Code (with the REST Client extension) or JetBrains and click "Send Request" on each block.
|
||||
|
||||
## What this repository contains
|
||||
|
||||
|
|
@ -31,8 +31,8 @@ See [`reference/rest/blog.rest`](reference/rest/blog.rest) for a preconfigured H
|
|||
| [`docs/examples/blog/`](docs/examples/blog/) | Sample `.wo` project: blog with articles, authors, tags, comments. ~200 lines. |
|
||||
| [`docs/examples/ecommerce/`](docs/examples/ecommerce/) | Sample `.wo` project: storefront + live order-ops table + cross-paradigm checkout. ~300 lines. |
|
||||
| [`prototypes/wo-db/`](prototypes/wo-db/) | C++ prototype of the query-layer engine (SQL + Cypher + document paths, `RETURNING` aliases, `LIVE` stub). ~2k lines, smoke tests pass. Reference implementation the Rust port follows. |
|
||||
| [`reference/rest/`](reference/rest/) | `.rest` files (VS Code REST Client / JetBrains HTTP format) for manually testing the running prototype. |
|
||||
| [`reference/crates/`](reference/crates/) | The v1 writeonce blog — 13 Rust crates implementing the original `.seg` + sidecar-index storage engine and `.htmlx` templating. Preserved as a nested workspace; see [`reference/README.md`](reference/README.md). |
|
||||
| [`.dev/reference/rest/`](.dev/reference/rest/) | `.rest` files (VS Code REST Client / JetBrains HTTP format) for manually testing the running prototype. |
|
||||
| [`.dev/reference/crates/`](.dev/reference/crates/) | The v1 writeonce blog — 13 Rust crates implementing the original `.seg` + sidecar-index storage engine and `.htmlx` templating. Preserved as a nested workspace; see [`.dev/reference/README.md`](.dev/reference/README.md). |
|
||||
|
||||
## Current stage
|
||||
|
||||
|
|
@ -62,10 +62,10 @@ WO_LISTEN=127.0.0.1:9000 cargo run --bin wo -- run docs/examples/blog
|
|||
|
||||
## The v1 codebase (reference)
|
||||
|
||||
The original writeonce blog engine — 13 crates, flat-file `.seg` storage, sidecar indexes, `.htmlx` templates, hand-rolled `epoll` event loop — moved to [`reference/crates/`](reference/crates/) when the new runtime was scaffolded. It's a nested Cargo workspace:
|
||||
The original writeonce blog engine — 13 crates, flat-file `.seg` storage, sidecar indexes, `.htmlx` templates, hand-rolled `epoll` event loop — moved to [`.dev/reference/crates/`](.dev/reference/crates/) when the new runtime was scaffolded. It's a nested Cargo workspace:
|
||||
|
||||
```bash
|
||||
cd reference/crates
|
||||
cd .dev/reference/crates
|
||||
cargo build # all 13 v1 crates still compile
|
||||
cargo test # 12 unit tests, 1 ignored integration test
|
||||
```
|
||||
|
|
|
|||
Loading…
Reference in a new issue