113 Commits (585f4b2f02b3181c14ca6340869cd6814652fcba)
 

Author SHA1 Message Date
Elijah Voigt 585f4b2f02 test(quotesdb): add handler-level tests for DB admin methods
Make MockRepo stateful for admin_auth_code and submissions_locked so
the new QuoteRepository methods can be exercised without a real DB.

Add four tests to src/bin/api/handlers/mod.rs:
- get_submissions_locked returns false by default
- set_submissions_locked(true) then get_submissions_locked returns true
- update_admin_auth_code with correct current succeeds and returns new code
- update_admin_auth_code with wrong current returns Forbidden

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt c9142edbbf feat(quotesdb): DB layer — add submissions_locked + update_admin_auth_code
Add three new QuoteRepository trait methods and a seed helper:
- update_admin_auth_code(current, new_code): replaces the admin code if
  `current` matches; generates a fresh passphrase when new_code is None;
  returns DbError::Forbidden on mismatch.
- get_submissions_locked(): reads the submissions_locked key from
  admin_config; returns false when the key is absent.
- set_submissions_locked(locked): upserts "1"/"0" into admin_config.
- seed_submissions_locked(): INSERT OR IGNORE "0" — safe to call on every
  startup without clobbering an active lock.

Implemented in both NativeRepository (rusqlite) and D1Repository (wasm32).
Updated startup seeding in main.rs (native and wasm32 paths) to call
seed_submissions_locked after the existing admin auth code seeding.

Added 7 unit tests in db/native.rs covering all four specified scenarios:
default false, set-then-get, seed does not overwrite, correct code succeeds,
None new_code generates passphrase, wrong code returns Forbidden, stored
code unchanged after Forbidden.

MockRepo in handlers/mod.rs updated with stub implementations of all four
new trait methods to satisfy the trait bound.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt 15d9de3947 docs(quotesdb): admin features design doc 3 months ago
Elijah Voigt 5dcbb334fa feat(quotesdb): Cloudflare Turnstile CAPTCHA on submit
- infra/turnstile.tf: provision Turnstile widget (managed mode, quotes.elijah.run domain) with site_key and secret_key outputs
- infra/variables.tf: add var.domain (default: quotes.elijah.run)
- src/lib.rs: add cf_turnstile_token: Option<String> (#[serde(default)]) to CreateQuoteInput; update doctest
- Cargo.toml: add reqwest (0.12, rustls-tls) under native-only dependencies
- src/bin/api/handlers/mod.rs: add verify_turnstile() and CAPTCHA gate in create_handler, both gated on #[cfg(not(target_arch = "wasm32"))]
- src/bin/api/db/native.rs: add cf_turnstile_token: None to all CreateQuoteInput struct literals in tests
- api/openapi.yaml: document cf_turnstile_token field in QuoteCreateRequest schema
- index.html: add Turnstile JS script tag
- src/bin/ui/pages/submit.rs: add turnstile_token state, use_effect_with callback registration, widget div, token included in CreateQuoteInput
- docs/LOCAL_DEV.md: add Cloudflare Turnstile CAPTCHA section

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt 014dc39ea4 feat(quotesdb): date range filter for quotes list
Add 6 optional query parameters to GET /api/quotes:
  date_after_year/month/day and date_before_year/month/day

Changes:
- QuoteRepository::list_quotes gains date_after and date_before params
- NativeRepository and D1Repository build ISO date prefix WHERE clauses;
  quotes with NULL date are excluded when any bound is set
- list_handler validates component ordering (month requires year, etc.)
  and returns 400 on invalid combinations
- build_date_bound helper converts y/m/d components to ISO prefix strings
- UI api::list_quotes and browse page gain From/To year filter inputs
- author page call updated to pass None for the new date params
- openapi.yaml extended with 6 new query parameter entries
- 6 new integration tests covering after, before, range, and 400 cases
- 1 new native DB unit test covering all filter combinations

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt 267a95aa13 feat(quotesdb): admin super auth code for quote moderation
Add an admin_config table storing a single admin auth code that
bypasses per-quote auth checks for update and delete operations.
The code is auto-generated on first startup and printed to stderr.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt bdf99b32c4 feat(quotesdb): add workers-rs WASM entry point to api binary
- Gate native Tokio/Axum main() with #[cfg(not(target_arch = "wasm32"))]
- Add #![cfg_attr(target_arch = "wasm32", no_main)] to suppress missing-main error
- Add #[worker::event(fetch)] entry point using worker::HttpRequest / http::Response<axum::body::Body>
- Enable `http` feature on worker dep so fetch handler uses standard http types
- Add axum (json+query features), tower-service, and http to wasm32 deps
- Move async-trait to shared [dependencies] so both targets have it
- Make db::d1 module pub so main.rs can access D1Repository on wasm32
- Fix worker::d1::Database → D1Database and PreparedStatement → D1PreparedStatement
- Add #[cfg_attr(target_arch = "wasm32", worker::send)] to all 7 handler fns
  so their futures satisfy Axum's Handler<Send> bound on single-threaded wasm32
3 months ago
Elijah Voigt d9f14bfc53 fix(quotesdb): resolve compiler warnings in api and ui
- Remove redundant #![cfg(target_arch="wasm32")] from d1.rs (module
  declaration in mod.rs already gates it)
- Remove unused D1Repository re-export from db/mod.rs
- Drop unused page/total_count fields from UI ListResponse struct
  (only total_pages is consumed by the browse page)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt 7e2f01e822 feat(quotesdb): implement D1Repository for Cloudflare Workers
Replace all 7 stub methods in src/bin/api/db/d1.rs with full working
implementations using the Cloudflare D1 API from workers-rs 0.5.

Implements:
- run_migrations: executes four DDL statements via db.exec()
- list_quotes: dynamic WHERE clause with positional params, COUNT query,
  paginated SELECT, per-quote tag fetch
- get_quote: prepared statement with first::<QuoteRow>()
- get_random_quote: ORDER BY RANDOM() LIMIT 1
- create_quote: INSERT + batch tag insert + read-back for timestamps
- update_quote: auth check, dynamic SET clause, optional tag replacement,
  read-back of updated row
- delete_quote: auth check, DELETE, returns DeleteResult enum

Also adds helper structs (QuoteRow, AuthRow, TagRow, CountRow),
fetch_tags() helper method, and unsafe Send/Sync impls required for
Arc<dyn QuoteRepository + Send + Sync> on single-threaded wasm32.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt b48f56712e fix(quotesdb): home page friendly empty state when no quotes
Detect 404 from random quote endpoint and render a friendly
'Nothing here yet — Submit a quote!' message with a link to
/submit instead of the generic error display.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt ad06c8befb fix(quotesdb): submit form UX fixes (6a4c61, dfd185, 5b3475)
- Replace 'Submit another' link with 'Browse all quotes' -> Route::Browse
- Change date input from type=text to type=date, remove placeholder
- Make author optional (defaults to Anonymous), update label
- Clarify auth code label to 'Edit/delete passphrase'

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt e3fe2253f9 fix frontend proxy issue 3 months ago
Elijah Voigt d8560ef3d5 chore(quotesdb): close all tickets — implementation complete
All 69 implementation tickets done. Root ticket ec118c closed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt 4f1aa5560a test(quotesdb): add integration test suite for all API endpoints
Adds 26 integration tests in handlers::integration_tests using a real
NativeRepository backed by a NamedTempFile SQLite database. Each test
gets an isolated database via test_router(). tempfile added to
[dev-dependencies]. Closes tickets: 5f5ba0, 9b581f, 789d0f, aa0eab,
f9f448, 4a4c26, 93f1b6, fae330, 8c87db, 893eba, e8f5cf, ce1e4f.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt 7529b43845 fix(quotesdb): gate UI binary on wasm32, update UI ticket statuses
- main.rs: add #[cfg(target_arch = "wasm32")] guards on all wasm32-only
  code; add stub fn main() for native targets so cargo check passes
- Ticket statuses updated for all completed UI page/component tickets

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt c436ba07c7 feat(quotesdb): merge full page implementations, tag filter, and stylesheet
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt d317648d2f feat(quotesdb): add comprehensive BEM stylesheet for all UI components
Covers all component and page classes:
- Navigation bar (nav, nav__brand, nav__links, nav__link)
- QuoteCard (quote-card, quote-card__text, footer, author, source, tags, tag, link)
- ErrorDisplay (error-display, error-display__message)
- Pagination (pagination, pagination__btn, pagination__info)
- AuthModal (auth-modal__overlay, auth-modal, auth-modal__title/input/actions)
- All page containers (page-home, page-browse, page-quote, page-author, page-submit)
- Edit form, submit form, success state with auth code box
- Base styles: reset, typography, buttons, form inputs
- Responsive breakpoint at 640px

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt 183994b3dc feat(quotesdb): implement all UI page components (Home, Browse, QuoteDetail, Author, Submit)
- HomePage: fetches random quote on mount, displays with QuoteCard and browse/submit links
- BrowsePage: paginated list with author and tag filter inputs, Pagination component
- QuotePage: view/edit/delete with AuthModal gating, 403/404 handling, sessionStorage auth
- AuthorPage: lists quotes by author with tag filter and pagination
- SubmitPage: full form with all fields, success state showing auth code prominently
- Tag filter (d3d502) integrated into Browse and Author pages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt bc48924d16 feat(quotesdb): implement API DB layer and all HTTP handlers
DB layer (src/bin/api/db/):
- native.rs: NativeRepository (tokio-rusqlite) implementing all CRUD ops,
  dynamic WHERE for filters, two-phase auth check for update, 13 unit tests
- d1.rs: D1Repository wasm32 stub (all methods return Internal error)
- connection.rs: open() helper — WAL + foreign_keys pragmas
- mod.rs: cfg-gate async_trait (Send on native, ?Send on wasm32)

Handlers (src/bin/api/handlers/mod.rs):
- All 7 routes: GET /api/, random, {id}, list, PUT create, POST update, DELETE
- Router order: random BEFORE {id} (prevents "random" matching as id)
- Auth: X-Auth-Code header validation → 403 on mismatch
- 13 handler unit tests with MockRepo

main.rs: opens DB, runs migrations, wraps in Arc<dyn Repo + Send + Sync>,
  binds on $PORT (default 3000)

Cargo.toml: tower dev-dep for ServiceExt::oneshot in tests

All 32 tests pass (26 api + 6 lib)

Tickets closed: 00aff0 a5049d 6e829e 28e7d9 886bfd 2ce22e 5dbb7d 05f8ae
                d792e2 5d9f5a b20b5a 175382 03bb91

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt 52e771e9c4 feat(quotesdb): merge UI shell, API client, storage and base components
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt 6f7614c0c8 feat(quotesdb): implement UI app shell, API client, storage, and base components
- Add BrowserRouter with all 5 routes (Home, Browse, QuoteDetail, Author, Submit)
- Implement typed API client (list, get, random, create, update, delete)
- Implement sessionStorage auth code helpers (set/get/clear)
- Add ErrorDisplay, QuoteCard, AuthModal, Pagination components
- Add stub page components for initial compilation
- Fix Cargo.toml: uuid js feature for wasm32, getrandom 0.3 wasm_js for rand dep,
  js-sys and Storage web-sys feature for API client and storage module

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt a7b2d6fd4e feat(quotesdb): add QuoteRepository trait, migrations, and thiserror dependency
- db/mod.rs: QuoteRepository async trait + ListResult/DeleteResult/DbError types
- db/migrations.rs: SQL DDL strings for quotes, quote_tags, and indexes
- lib.rs: fix rand 0.9 trait import (SliceRandom → IndexedRandom)
- Cargo.toml: add thiserror = "2" for DbError derive

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt 83f4aacdf5 feat(quotesdb): set up Trunk.toml and index.html for UI build
- Trunk.toml: target index.html, proxy /api/* to localhost:3000
- index.html: link CSS, Rust wasm binary (ui), copy _redirects

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt 8da0d754a0 chore(quotesdb): merge 9ef703 - add _redirects SPA fallback 3 months ago
Elijah Voigt af8c476305 chore(quotesdb): add _redirects SPA fallback for Cloudflare Pages routing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt 9f28d99a93 feat(quotesdb): add build.rs to convert api/openapi.yaml to JSON at compile time
- Create build.rs at crate root using serde_yaml (build-dep only) to parse
  api/openapi.yaml and write compact JSON to $OUT_DIR/openapi.json
- cargo:rerun-if-changed ensures re-conversion only when spec changes
- serde_yaml never enters the Workers or native binary (build-dep only)
- Downstream GET /api/ handler consumes via include_str!(concat!(env!("OUT_DIR"), "/openapi.json"))

Closes ticket 8892d5
3 months ago
Elijah Voigt b695cb5b6d feat(quotesdb): add Yew/Wasm UI dependencies to Cargo.toml
- Add yew 0.22 with csr feature for Rust/Wasm SPA frontend
- Add yew-router 0.19 for client-side routing
- Add gloo 0.11 for Web API utilities (timers, fetch, events)
- Add wasm-bindgen 0.2 matching Nix wasm-bindgen-cli 0.2.108
- Add wasm-bindgen-futures 0.4 for async fetch support
- Add web-sys 0.3 for raw DOM/browser API bindings
All UI deps scoped to wasm32 cfg target to avoid host build pollution

Closes ticket 93515e
3 months ago
Elijah Voigt 7bd2bf4ed5 chore(quotesdb): set up Cargo.toml with api and ui dependencies
- Add axum 0.8 + tokio 1 (native-only) for the HTTP API server
- Add rusqlite 0.32 + tokio-rusqlite 0.6 (native-only) for local SQLite
- Add async-trait 0.1 (native-only) for QuoteRepository abstraction
- Add worker 0.5 with d1 feature (wasm32-only) for Cloudflare Workers
- Add rand 0.9 + serde + serde_json (shared) for passphrase/serialisation
- Add build-dependencies: serde_json 1 + serde_yaml 0.9 for build.rs
- Pin rusqlite to 0.32 to match tokio-rusqlite 0.6 transitive dependency

Closes ticket 1f5bb5

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt b0cf17ec83 feat(quotesdb): add generate_id() using UUID v4 — WASM-compatible ID generation
- Add uuid = { version = "1", features = ["v4", "serde"] } to [dependencies]
- Add getrandom = { version = "0.4", features = ["wasm_js"] } under wasm32 cfg
- Implement generate_id() in src/lib.rs with rustdoc and doctest
- Add unit tests for length, hyphen count, and uniqueness

Closes ticket 7a0d9f

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt dc73fc8f69 plan to implement the current batch of tickets 3 months ago
Elijah Voigt 5926d33bcc chore(quotesdb): resolve all triage tickets and create implementation tickets
- All 21 TRIAGE decision tickets resolved with chosen approaches documented
- This session: e2bd9b (SPA routing → _redirects), 2ec8b1 (OpenAPI → build.rs),
  0d84fa (HTTP client → reqwest), 0bc655 (auth code → session storage)
- New implementation tickets created: 9ef703, 8892d5, 5379eb
- Downstream tickets updated with resolved approaches and correct dependencies
- ARCHITECTURE.md updated with pinned WASM dependency versions (yew 0.22,
  yew-router 0.19, wasm-bindgen 0.2)
- XML tags added to all tickets for improved LLM guidance

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt ec2a4055ca docs(quotesdb): add XML tags to all tickets for improved LLM guidance
All 80 nbd tickets updated with structured XML tags:
- Task tickets: <context>, <goal>, <constraints>, <skills>, <validation>, <commit>
- TRIAGE tickets: <context>, <question>, <options>, <resolution>, <commit>
- Project tickets: <context>, <goal>, <skills>, <validation>
- ec118c (root): <skills>, <goal>, <context>, <design>, <phases>, <verification>
- b38032 (done): <goal>, <current-state>, <target-state>, <changes>, <constraints>, <validation>, <summary>

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt 65b0fdf1e2 some tickets marked in progress 3 months ago
Elijah Voigt 91ecd91176 refactor(quotesdb): collapse to single crate with api and ui binaries
Replaces the three separate sub-crates (api/, ui/, tests/) with a single
Cargo crate at the quotesdb/ root. Shared code lives in src/lib.rs; the
api and ui are multi-binary targets; integration tests use the standard
Cargo tests/ layout. Trunk files moved to project root with data-bin="ui".

Closes ticket b38032.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt de99f1c047 chore(quotesdb): bootstrap project skeleton and design doc
- Scaffold api/, ui/, tests/, infra/, docs/ directories
- Stub Cargo.toml for api, ui, and tests crates
- Write finalized design doc to docs/plans/2026-02-27-quotesdb-design.md
- Add placeholder PLANNING.md, ARCHITECTURE.md, README.md per domain
- Add stub main.rs and tests.rs for api and ui
- Add index.html and Trunk.toml for ui
- Add placeholder infra/main.tf with Cloudflare provider stub

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt ba6425793a docs: add shell conventions — no python3, always use jq
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt 7c9d058ce6 feat(nbd): scope nbd next/ready by dependency subtree (#818598)
Add an optional positional `<id>` argument to `nbd next` and `nbd ready`
that restricts results to the dependency subtree of the given ticket.
The scoping ticket itself is excluded from results.

- CLI: add `id: Option<String>` to `Commands::Next` and `Commands::Ready`
- Logic: build a `TicketGraph`, call `subtree()`, restrict candidate pool
- Tests: 4 new integration tests covering scoped next/ready and --filter

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt 3c0665314a tickets(nbd): triage TODO.md → 818598 scope next/ready by subtree
- 818598: Scope nbd next and nbd ready by dependency subtree

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt 7e0ba78240 docs: improve CLAUDE.md structure and clarity
- Add working-directory rule to root and all project docs
- Generalize root from "HTTP web services" to "independent projects"
- Add @../CLAUDE.md inheritance to nbd, edu, quotesdb project docs
- Remove sections duplicated from root in project-level docs
- Wrap all sections in semantic XML tags for clearer agent parsing
- Rename Tech Stack → Common Patterns (framed as defaults, not requirements)
- Rename Running Services Locally → Running Projects Locally
3 months ago
Elijah Voigt c2c5fe923e markov chain exercise skeleton 3 months ago
Elijah Voigt 8232946b6e Merge development flakes 3 months ago
Elijah Voigt 75876988e0 claude generated openapi spec 3 months ago
Elijah Voigt 1c90c0fac1 tickets(quotesdb): assign all tickets to domain sub-projects with dependency graph
Evaluated all quotesdb tickets and assigned each to the correct sub-project
dependency (api/f3dc74, ui/c3503b, qa/ce1e4f, infra/25c413). Also wired
inter-ticket dependencies to enforce correct implementation order within each
domain and cross-domain (e.g. QA test suites depend on the API handlers they
exercise). Validated with `nbd graph --json` — 78 nodes, 200 edges, no cycles.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt 6d40671f28 fix(nbd): fix graph orientation to show goals at root, prerequisites as leaves
Roots are now tickets with no dependents (nobody depends on them —
top-level goals), and the ASCII tree traverses dependency edges so
prerequisites appear indented beneath the goal that needs them.

JSON edges are now {from: dependent, to: dependency} rather than
{from: blocker, to: blocked}.

All graph-related unit and integration tests updated to match the
new semantics.

Closes #668150

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt 380cfee6ca tickets(nbd): triage graph inversion bug into two tickets
- 668150: Fix graph orientation: show goals at root, prerequisites as leaves
- 06ca62: Fix nbd graph <id>: show ancestry path through ticket, not just subtree

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt bc17a9ae07 plan(quotesdb): create domain planning tickets for api, ui, qa, and infra
Adds 84 tickets across 4 sub-domains with a full dependency graph:

- quotesdb/api (f3dc74): 15 work tickets + 6 TRIAGE tickets
  Covers Cargo.toml, Workers entry point, DB migrations, all 7 endpoints,
  auth code gen, tag handling, error envelope, unit tests, and docs.

- quotesdb/ui (c3503b): 15 work tickets + 5 TRIAGE tickets
  Covers Yew/Wasm setup, Trunk config, app shell, API client, 5 pages,
  shared components (QuoteCard, auth modal, pagination, tag filter), and docs.

- quotesdb/qa (ce1e4f): 12 work tickets + 4 TRIAGE tickets
  Covers test harness, one test suite per endpoint, router ordering,
  tag operations, and README.

- quotesdb/infra (25c413): 10 work tickets + 6 TRIAGE tickets
  Covers OpenTofu setup, D1 database, Worker script + route, Pages project,
  custom domain (quotes.elijah.run), migration workflow, secrets, and README.

Dependency graph:
- Root ticket (ec118c) blocked on all 4 sub-project tickets
- Sub-project tickets blocked on their leaf work tickets
- Work tickets have intra-domain sequential deps (e.g. Cargo.toml → DB → handlers)
- QA test harness has a cross-domain dep on the completed api sub-project
- All 21 TRIAGE tickets are immediately unblocked as the highest-priority starting work

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt 04b659ee7c quotesdb scaffolding 3 months ago
Elijah Voigt 4c48370373 docs(quotesdb): add project CLAUDE.md with workflow and design reference
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt 05bad425a7 chore(quotesdb): init nbd and create root project ticket 3 months ago
Elijah Voigt 955cf029ab docs(edu): add lisp-to-C compiler course with stubs and tickets [67e284]
18-section interactive course teaching compiler construction in Rust
using nom. Covers MiniLisp parsing, AST design, semantic analysis,
and C code generation. All sections stubbed; one nbd task ticket per
section plus a project ticket (67e284) tracking completion.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago