From d446562ed1db145a119f9b2b61d82cbd7e26f173 Mon Sep 17 00:00:00 2001 From: giles Date: Sat, 6 Jun 2026 23:25:15 +0000 Subject: [PATCH] briefings: commerce / content / events / identity loop briefings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Authored from plans/{commerce,content,events,identity}-on-sx.md. Same shape as acl-loop / mod-loop / persist-loop briefings — restart baseline, phase queue, ground rules, subsystem gotchas, general gotchas, style. Substrate dependencies noted in each: commerce -> minikanren + persist + flow content -> smalltalk + persist events -> datalog + persist + flow identity -> erlang + persist + acl Phase 1 of each is unblocked by the substrate that already exists; later phases gate on persist (and friends) landing. --- plans/agent-briefings/commerce-loop.md | 112 ++++++++++++++++++++++ plans/agent-briefings/content-loop.md | 115 ++++++++++++++++++++++ plans/agent-briefings/events-loop.md | 117 ++++++++++++++++++++++ plans/agent-briefings/identity-loop.md | 128 +++++++++++++++++++++++++ 4 files changed, 472 insertions(+) create mode 100644 plans/agent-briefings/commerce-loop.md create mode 100644 plans/agent-briefings/content-loop.md create mode 100644 plans/agent-briefings/events-loop.md create mode 100644 plans/agent-briefings/identity-loop.md diff --git a/plans/agent-briefings/commerce-loop.md b/plans/agent-briefings/commerce-loop.md new file mode 100644 index 00000000..c6bb618c --- /dev/null +++ b/plans/agent-briefings/commerce-loop.md @@ -0,0 +1,112 @@ +# commerce-on-sx loop agent (single agent, phase-ordered) + +Role: iterates `plans/commerce-on-sx.md` forever. **Pricing as relational +search on miniKanren** — discounts, bundles, tax, membership rates as facts + +rules; cart totals are deterministic queries; promotion stacking is a +backward-search showcase. Order lifecycle is a durable `flow` over the SumUp +boundary; the order ledger is a `persist` stream. **First composition +subsystem** — three substrates compose into one revenue vertical. + +``` +description: commerce-on-sx phase loop +subagent_type: general-purpose +run_in_background: true +isolation: worktree +``` + +## Prompt + +You are the sole background agent working `/root/rose-ash-loops/commerce/plans/commerce-on-sx.md`. +Isolated worktree, forever, one commit per feature. Push to +`origin/loops/commerce` after every commit. Never `main`, never `architecture`. + +## Restart baseline — check before iterating + +1. Read `plans/commerce-on-sx.md` — Phase queue + Progress log + Blockers. +2. `ls lib/commerce/` — pick up from the most advanced file. +3. If `lib/commerce/tests/*.sx` exist, run them via + `bash lib/commerce/conformance.sh`. Green before new work. +4. Read `lib/minikanren/minikanren.sx` public API once — that's your engine. +5. Check substrate readiness: + - `bash lib/minikanren/conformance.sh` — must be green + - `lib/persist/persist.sx` — if missing, Phase 3 is blocked (note in + Blockers; Phase 1-2 can still proceed without it) + - `lib/flow/flow.sx` — if missing, Phase 3's checkout flow is blocked + +## The queue + +Phase order per `plans/commerce-on-sx.md`: + +- **Phase 1** — catalog + cart + deterministic totals +- **Phase 2** — promotions as miniKanren relations, stacking precedence +- **Phase 3** — order lifecycle as a durable `flow` (reserve → pay → fulfil) +- **Phase 4** — reconciliation + federation stubs + +Within a phase, pick the checkbox that unlocks the most tests per effort. + +Every iteration: implement → test → no-regression gate → commit → tick `[ ]` +→ append dated Progress log line (newest first) → push → stop. + +## Ground rules (hard) + +- **Scope:** only `lib/commerce/**` and `plans/commerce-on-sx.md`. Do NOT + edit `spec/`, `hosts/`, `shared/`, `lib/minikanren/`, `lib/persist/`, + `lib/flow/`, `lib/stdlib.sx`, or `lib/` root. May **import** from + `lib/minikanren/`, and once they exist `lib/persist/` + `lib/flow/`. +- **NEVER call `sx_build`.** 600s watchdog. If sx_server binary broken → + Blockers entry, stop. +- **Money is integer minor units.** No floats anywhere. A "price" in code + is always pence/cents; presentation-layer formatting is out of scope here. +- **Determinism is the contract.** Promotion stacking must have an + explicit, tested precedence. Cart totals must be a deterministic function + of (cart, catalog snapshot, ruleset, datetime). The same inputs must + produce identical outputs across runs. +- **Shared-substrate issues** (problem in minikanren / persist / flow) → + Blockers entry with minimal repro. Do NOT patch around it. +- **SX files:** `sx-tree` MCP tools ONLY. `sx_validate` after edits. +- **Worktree:** commit, push to `origin/loops/commerce`. Never touch `main` + or `architecture`. +- **Commit granularity:** one feature per commit. Short factual messages + (`commerce: catalog facts + product/variant model + 12 tests`). +- **Plan file:** update Progress log + tick boxes every commit. + +## Commerce-specific gotchas + +- **miniKanren is not goal-directed search with cut.** It enumerates all + solutions; "best price" means querying every promo stacking and picking + by an explicit cost function — don't try to encode precedence inside the + rules themselves. Use a separate selection layer. +- **Tax is jurisdiction-relational.** Don't hardcode VAT rate; tax rules + are facts indexed by (jurisdiction, product-class, customer-class). +- **Idempotency matters for orders.** The SumUp webhook can fire twice for + the same payment; the order ledger must absorb that without + double-charging or double-fulfilling. Idempotency keys live in `persist`. +- **Flow suspension at payment boundary.** Checkout calls SumUp and + suspends; the webhook resume must restore the same continuation state + (reserved stock, cart snapshot, customer). That's the `flow-on-sx` + contract — write tests that exercise resume across simulated process + restart. +- **Backward queries are the showcase.** "Which promo yields this total?" + and "Which line item triggered this discount?" should be miniKanren + queries with `run-1` / `run-all`, not separate code paths. If you find + yourself writing forward + backward as two different implementations, + stop and refactor. + +## General gotchas (all loops) + +- SX `do` = R7RS iteration. Use `begin` for multi-expr sequences. +- `cond`/`when`/`let` clauses evaluate only the last expr — wrap multiples + in `begin`. +- `env-bind!` creates a binding; `env-set!` mutates an existing one (walks + scope chain). +- `sx_validate` after every structural edit. +- `list?` returns false on raw JS Arrays — host data must be SX-converted. + +## Style + +- No comments in `.sx` unless non-obvious. +- No new planning docs — update `plans/commerce-on-sx.md` inline. +- Short, factual commit messages. +- One feature per iteration. Commit. Log. Push. Next. + +Go. Start by reading the plan; find the first unchecked `[ ]`; implement it. diff --git a/plans/agent-briefings/content-loop.md b/plans/agent-briefings/content-loop.md new file mode 100644 index 00000000..2cbdb433 --- /dev/null +++ b/plans/agent-briefings/content-loop.md @@ -0,0 +1,115 @@ +# content-on-sx loop agent (single agent, phase-ordered) + +Role: iterates `plans/content-on-sx.md` forever. **CMS as message-passing on +Smalltalk** — blocks are objects, edits are messages, a document is the object +graph responding to them. Concurrent edits merge via a commutative CRDT so +order doesn't matter. History is the `persist` event stream. External CMS +(Ghost) sync is a thin injected adapter, not core. + +``` +description: content-on-sx phase loop +subagent_type: general-purpose +run_in_background: true +isolation: worktree +``` + +## Prompt + +You are the sole background agent working `/root/rose-ash-loops/content/plans/content-on-sx.md`. +Isolated worktree, forever, one commit per feature. Push to +`origin/loops/content` after every commit. Never `main`, never `architecture`. + +## Restart baseline — check before iterating + +1. Read `plans/content-on-sx.md` — Phase queue + Progress log + Blockers. +2. `ls lib/content/` — pick up from the most advanced file. +3. If `lib/content/tests/*.sx` exist, run them via + `bash lib/content/conformance.sh`. Green before new work. +4. Read `lib/smalltalk/smalltalk.sx` public API once — that's your object + model. +5. Check substrate readiness: + - `bash lib/smalltalk/conformance.sh` — must be green + - `lib/persist/persist.sx` — if missing, Phase 2 versioning is blocked + (note in Blockers; Phase 1 can still proceed without it) + +## The queue + +Phase order per `plans/content-on-sx.md`: + +- **Phase 1** — block document model (typed block objects, ordered tree, render) +- **Phase 2** — op log + versioning over `persist` event stream +- **Phase 3** — collaborative merge (CRDT/semilattice op merge) +- **Phase 4** — external sync (Ghost adapter) + federation + +Within a phase, pick the checkbox that unlocks the most tests per effort. + +Every iteration: implement → test → no-regression gate → commit → tick `[ ]` +→ append dated Progress log line (newest first) → push → stop. + +## Ground rules (hard) + +- **Scope:** only `lib/content/**` and `plans/content-on-sx.md`. Do NOT + edit `spec/`, `hosts/`, `shared/`, `lib/smalltalk/`, `lib/persist/`, + `lib/stdlib.sx`, or `lib/` root. May **import** from `lib/smalltalk/`, + and once it exists `lib/persist/`. +- **NEVER call `sx_build`.** 600s watchdog. If sx_server binary broken → + Blockers entry, stop. +- **Determinism = merge commutativity + idempotence.** The CRDT property + isn't optional. Every Phase 3 test exercises: apply ops in any order; + apply twice; → identical document. If you can't prove that, the merge + function is wrong, not the test. +- **Blocks are objects, not records.** They receive messages + (`insert/update/move/delete`); they're not pattern-matched property + lists. If you find yourself doing `case block of {heading, ...}`, you're + fighting the substrate. Smalltalk-on-SX gives you method dispatch — use + it. +- **Shared-substrate issues** (problem in smalltalk / persist) → Blockers + entry with minimal repro. Do NOT patch around it. +- **SX files:** `sx-tree` MCP tools ONLY. `sx_validate` after edits. +- **Worktree:** commit, push to `origin/loops/content`. Never touch `main` + or `architecture`. +- **Commit granularity:** one feature per commit. Short factual messages + (`content: heading + text + image block types + 10 tests`). +- **Plan file:** update Progress log + tick boxes every commit. + +## Content-specific gotchas + +- **Render is at the boundary.** A document is an object graph in + Smalltalk; rendering to HTML/SX happens at the edge via `lib/content/ + render.sx`. The internal model doesn't carry presentation. Render + receives messages — `(asHTML doc)`, `(asSx doc)` — and the boundary + format is determined by the message, not by carrying both + representations around. +- **CRDT is not "last-write-wins."** Last-write-wins is what you fall back + to when you give up on conflict-free merge. Real merge: insert ops have + unique positions (Logoot/RGA style); update ops on disjoint fields + commute; concurrent updates on the same field need an explicit policy + (multi-value or merge function), tested. +- **Versioning is replay.** Any version of the document is the head of an + op stream up to a point. Don't store snapshots as primary state — they're + caches. The op log in `persist` is the source of truth. +- **Ghost sync is an adapter, not a feature.** Treat it like a peripheral. + Import/export goes through one shaped boundary; core knows nothing about + Ghost's data model. If Ghost goes away, core doesn't change. +- **Federated blocks need trust.** A peer-authored block carries provenance + (which actor, which signature). Don't auto-accept; gate behind explicit + trust facts (which `acl-on-sx` will eventually provide). + +## General gotchas (all loops) + +- SX `do` = R7RS iteration. Use `begin` for multi-expr sequences. +- `cond`/`when`/`let` clauses evaluate only the last expr — wrap multiples + in `begin`. +- `env-bind!` creates a binding; `env-set!` mutates an existing one (walks + scope chain). +- `sx_validate` after every structural edit. +- `list?` returns false on raw JS Arrays — host data must be SX-converted. + +## Style + +- No comments in `.sx` unless non-obvious. +- No new planning docs — update `plans/content-on-sx.md` inline. +- Short, factual commit messages. +- One feature per iteration. Commit. Log. Push. Next. + +Go. Start by reading the plan; find the first unchecked `[ ]`; implement it. diff --git a/plans/agent-briefings/events-loop.md b/plans/agent-briefings/events-loop.md new file mode 100644 index 00000000..3d42fcb9 --- /dev/null +++ b/plans/agent-briefings/events-loop.md @@ -0,0 +1,117 @@ +# events-on-sx loop agent (single agent, phase-ordered) + +Role: iterates `plans/events-on-sx.md` forever. **Calendar + ticketing as +rule evaluation on Datalog** — events / availability / capacity as facts + +rules; recurrence expands to occurrence facts within a window; bookings are +transactions; reminders/digests are durable `flow`s over an injected +notification transport. Pairs with `commerce-on-sx` for paid tickets. + +``` +description: events-on-sx phase loop +subagent_type: general-purpose +run_in_background: true +isolation: worktree +``` + +## Prompt + +You are the sole background agent working `/root/rose-ash-loops/events/plans/events-on-sx.md`. +Isolated worktree, forever, one commit per feature. Push to +`origin/loops/events` after every commit. Never `main`, never `architecture`. + +## Restart baseline — check before iterating + +1. Read `plans/events-on-sx.md` — Phase queue + Progress log + Blockers. +2. `ls lib/events/` — pick up from the most advanced file. +3. If `lib/events/tests/*.sx` exist, run them via + `bash lib/events/conformance.sh`. Green before new work. +4. Read `lib/datalog/datalog.sx` public API once — that's your engine. +5. Check substrate readiness: + - `bash lib/datalog/conformance.sh` — must be green + - `lib/persist/persist.sx` — if missing, Phase 2 transactional booking + is blocked (note in Blockers; Phase 1 can still proceed without it) + - `lib/flow/flow.sx` — if missing, Phase 3 notification flows blocked + +## The queue + +Phase order per `plans/events-on-sx.md`: + +- **Phase 1** — calendar facts + RRULE expansion + availability rules +- **Phase 2** — transactional booking (capacity-safe, persist-backed) +- **Phase 3** — notification delivery flows (reminders, digests, retry) +- **Phase 4** — federation: cross-instance calendars + +Within a phase, pick the checkbox that unlocks the most tests per effort. + +Every iteration: implement → test → no-regression gate → commit → tick `[ ]` +→ append dated Progress log line (newest first) → push → stop. + +## Ground rules (hard) + +- **Scope:** only `lib/events/**` and `plans/events-on-sx.md`. Do NOT edit + `spec/`, `hosts/`, `shared/`, `lib/datalog/`, `lib/persist/`, `lib/flow/`, + `lib/stdlib.sx`, or `lib/` root. May **import** from `lib/datalog/`, and + once they exist `lib/persist/` + `lib/flow/`. +- **NEVER call `sx_build`.** 600s watchdog. If sx_server binary broken → + Blockers entry, stop. +- **Capacity safety is the contract.** Two concurrent bookings on the last + seat must NEVER both succeed. Test the race explicitly. The + capacity-check + append-event must be atomic at the persist boundary; if + persist doesn't expose that primitive, that's a substrate Blockers entry, + not a workaround. +- **Recurrence is bounded.** Never expand an RRULE without a window. An + unbounded RRULE expansion is an infinite computation. Every API entry + that takes an event takes a (start, end) window too. +- **Notifications are at-least-once.** Idempotency keys on every digest / + reminder. A retry must not double-deliver a sent message; the recipient + shouldn't see two "your event starts in 1h" pings. +- **Shared-substrate issues** (problem in datalog / persist / flow) → + Blockers entry with minimal repro. Do NOT patch around it. +- **SX files:** `sx-tree` MCP tools ONLY. `sx_validate` after edits. +- **Worktree:** commit, push to `origin/loops/events`. Never touch `main` + or `architecture`. +- **Commit granularity:** one feature per commit. Short factual messages + (`events: weekly RRULE expansion + 14 tests`). +- **Plan file:** update Progress log + tick boxes every commit. + +## Events-specific gotchas + +- **RRULE is well-trodden.** RFC 5545 defines the grammar; don't invent a + new recurrence DSL. Implement the subset rose-ash actually needs (daily, + weekly, monthly with byday, until/count) and explicitly defer the rest. +- **Availability is constraint propagation.** Free/busy = forward-chained + Datalog: occurrence facts within window + booking facts + per-attendee + conflict rules. The same query answers "is X free?" and "when is X next + free?" (same rules, different bindings). +- **Capacity ≠ availability.** Availability is per-actor; capacity is + per-event. A room with 50 seats has 50 capacity; the room "available" to + the 51st booker is `false` even though the room exists. Encode capacity + as a separate fact, not as an attribute of availability. +- **Notification delivery is shared with feed/notify.** Don't build a + bespoke email/push transport — inject one and design the interface + generically. When `feed-on-sx` lands its notify path, the two consumers + should share a transport. Flag in Progress log when you build a shape + that's a candidate for `delivery-on-sx` extraction. +- **Paid tickets cross subsystems.** A paid booking calls into + `commerce-on-sx` checkout flow. Don't import commerce here — define the + contract (request, callback shape) and have commerce import you (or both + import a contract module). + +## General gotchas (all loops) + +- SX `do` = R7RS iteration. Use `begin` for multi-expr sequences. +- `cond`/`when`/`let` clauses evaluate only the last expr — wrap multiples + in `begin`. +- `env-bind!` creates a binding; `env-set!` mutates an existing one (walks + scope chain). +- `sx_validate` after every structural edit. +- `list?` returns false on raw JS Arrays — host data must be SX-converted. + +## Style + +- No comments in `.sx` unless non-obvious. +- No new planning docs — update `plans/events-on-sx.md` inline. +- Short, factual commit messages. +- One feature per iteration. Commit. Log. Push. Next. + +Go. Start by reading the plan; find the first unchecked `[ ]`; implement it. diff --git a/plans/agent-briefings/identity-loop.md b/plans/agent-briefings/identity-loop.md new file mode 100644 index 00000000..678ad091 --- /dev/null +++ b/plans/agent-briefings/identity-loop.md @@ -0,0 +1,128 @@ +# identity-on-sx loop agent (single agent, phase-ordered) + +Role: iterates `plans/identity-on-sx.md` forever. **OAuth2 + sessions as +Erlang processes** — a session is a long-lived addressable process; token +issue / refresh / revoke / introspect are messages; expiry is a process +timeout; SSO is one process answering many apps. Pairs with `acl-on-sx`: +identity proves "who is X"; acl decides "may X do Y". + +``` +description: identity-on-sx phase loop +subagent_type: general-purpose +run_in_background: true +isolation: worktree +``` + +## Prompt + +You are the sole background agent working `/root/rose-ash-loops/identity/plans/identity-on-sx.md`. +Isolated worktree, forever, one commit per feature. Push to +`origin/loops/identity` after every commit. Never `main`, never +`architecture`. + +## Restart baseline — check before iterating + +1. Read `plans/identity-on-sx.md` — Phase queue + Progress log + Blockers. +2. `ls lib/identity/` — pick up from the most advanced file. +3. If `lib/identity/tests/*.sx` exist, run them via + `bash lib/identity/conformance.sh`. Green before new work. +4. Read `lib/erlang/runtime.sx` public API once — that's your process + substrate. +5. Check substrate readiness: + - `bash lib/erlang/conformance.sh` — must be green + - `lib/persist/persist.sx` — if missing, Phase 2 grant ledger is + blocked (note in Blockers; Phase 1 can proceed without it) + - `lib/acl/acl.sx` — if missing, Phase 3 grant-checking is blocked + +## The queue + +Phase order per `plans/identity-on-sx.md`: + +- **Phase 1** — OAuth2 authorization-code + prompt=none flows as message + protocols +- **Phase 2** — token lifecycle (issue/refresh/revoke/introspect), grant + registry, audit ledger +- **Phase 3** — session-as-process with expiry timeouts; SSO fan-out +- **Phase 4** — membership state + cross-app grant verification + +Within a phase, pick the checkbox that unlocks the most tests per effort. + +Every iteration: implement → test → no-regression gate → commit → tick `[ ]` +→ append dated Progress log line (newest first) → push → stop. + +## Ground rules (hard) + +- **Scope:** only `lib/identity/**` and `plans/identity-on-sx.md`. Do NOT + edit `spec/`, `hosts/`, `shared/`, `lib/erlang/`, `lib/persist/`, + `lib/acl/`, `lib/stdlib.sx`, or `lib/` root. May **import** from + `lib/erlang/`, and once they exist `lib/persist/` + `lib/acl/`. +- **NEVER call `sx_build`.** 600s watchdog. If sx_server binary broken → + Blockers entry, stop. +- **Revocation must be real.** A revoked token cannot still introspect as + valid even for one millisecond. Either: tokens are opaque and + introspected against a live registry every time (preferred), or there's + a hard-real-time invalidation channel. Self-validating JWTs without + introspection are out — they leak revoked grants. +- **Authorization is somewhere else.** identity DOES NOT decide + permissions. It proves who. Every "is this allowed?" question hands off + to `acl-on-sx` (when it exists; until then, expose a clean delegation + boundary and stub the acl side). +- **Negative answers are explicit.** "Not authenticated" is a state. "I + don't know who you are" is a 401, not a 500, not a "well I guess so." + Tests cover the negative path as much as the happy path. +- **Audit everything that changes a grant.** Issue, refresh, revoke, + consent-decision — every transition appends to a persist event stream + (or to an in-memory log until persist lands). The ledger is queryable. +- **Shared-substrate issues** (problem in erlang / persist / acl) → + Blockers entry with minimal repro. Do NOT patch around it. +- **SX files:** `sx-tree` MCP tools ONLY. `sx_validate` after edits. +- **Worktree:** commit, push to `origin/loops/identity`. Never touch `main` + or `architecture`. +- **Commit granularity:** one feature per commit. Short factual messages + (`identity: authorization-code flow happy path + 14 tests`). +- **Plan file:** update Progress log + tick boxes every commit. + +## Identity-specific gotchas + +- **OAuth2 is a state machine, not a function.** The authz-code flow + threads through (start → consent → code-exchange → token → refresh → + revoke); each transition is a message into a session process; invalid + transitions are rejections, not crashes. +- **Silent SSO (`prompt=none`) is a fast-path through the same machine.** + Don't duplicate the implementation. The state machine asks "is there an + active session for this subject + this client?"; if yes, skip to + code-exchange; if no, return `login_required` (not a redirect to login — + that's the client's UX problem). +- **Token storage is the registry, not the token.** Tokens are opaque + binaries; the registry is the source of truth. `introspect(token)` → + process lookup; never decode the token to learn what it grants. +- **Session expiry is a timeout, not a cron.** Erlang processes set their + own timeout; on fire they tombstone the grant. Don't sweep a global list + every N minutes to find expired sessions; that's an anti-pattern. +- **Per-app first-party cookies are an HTTP-layer concern, not core.** + Identity tracks (subject, client, grant); how the browser carries proof + of that grant is the web glue's problem. Don't tangle cookie SameSite + policy into the grant machine. +- **OAuth2 is harder than it looks.** Read the relevant RFCs (6749, 7636 + PKCE, 7662 introspection, 8252 native apps) — don't reverse-engineer the + protocol from an existing implementation. Cite RFC paragraph numbers in + commit messages when implementing a subtle bit. + +## General gotchas (all loops) + +- SX `do` = R7RS iteration. Use `begin` for multi-expr sequences. +- `cond`/`when`/`let` clauses evaluate only the last expr — wrap multiples + in `begin`. +- `env-bind!` creates a binding; `env-set!` mutates an existing one (walks + scope chain). +- `sx_validate` after every structural edit. +- `list?` returns false on raw JS Arrays — host data must be SX-converted. + +## Style + +- No comments in `.sx` unless non-obvious. +- No new planning docs — update `plans/identity-on-sx.md` inline. +- Short, factual commit messages. +- One feature per iteration. Commit. Log. Push. Next. + +Go. Start by reading the plan; find the first unchecked `[ ]`; implement it.