8000 docs(plan): detail #316 PR 4 — set bind forms, docs site, bindings by adityamukho · Pull Request #751 · project-minigraf/minigraf · GitHub
[go: up one dir, main page]

Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 80 additions & 4 deletions docs/superpowers/plans/2026-10-24-316-set-values.md
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,83 @@ Codex review, then PR into `v3` with no closing keyword; after merge close #316

## PR 4 — docs site and bindings

- `minigraf-docs`: `content/datalog-reference.md` (set literals, predicates, `collect-set`,
`@since v3.0.0`), `content/architecture.md` (Set row in the value table), `content/comparison.md`.
- Bindings (`v3` branches of python, c, node, java, swift, android): `value_to_json` set arm (array)
and a wildcard arm, consumer test returning a set; bump the core git-rev pin.
**Deviation from spec §9.** The spec predates #181, so it says no binding takes bind values. Since #181
every binding takes prepared bind values, and the UniFFI and Node/C fact-log records carry typed values,
so a set needs an input form as well as the JSON array output. Decided with the maintainer 2026-10-25:

| Family | Typed form (in and out) | Host sugar for a bind value |
|---|---|---|
| UniFFI (template, python, java, android, swift) | `MiniGrafValue::Set { value: Vec<MiniGrafValue> }` | Python `set`/`frozenset`; Kotlin/Java `Set`; Swift `Set` |
| C, Node 8000 | `{ "type": "set", "value": [ ...elements ] }` | Node: a JS `Set` |
| `BrowserDb` (core `src/browser/binds.rs`) | `{ type: 'set', value: [ ...elements ] }` | a JS `Set` |

- An element is a plain value or a typed *value* form (`string` … `null`); `entity`, `txCount`,
`timestamp`, `anyValidTime` and `set` as an element are rejected. A nested set reaches core as
`ValueSet::new` → API-021 where the form can express it (UniFFI); C/Node/BrowserDb reject it while
reading the form with the same API-021 code.
- Plain arrays/lists stay rejected as bind values: they are kept free for a possible later collection
binding.
- `execute()` JSON keeps spec §9: a set is a JSON array of its elements in canonical (`Value`) order. No
other value becomes an array, so a set stays recognisable; elements lose their type as keyword and ref
already do.
- UniFFI 0.31.1 generates the recursive enum for Python, Kotlin and Swift (checked 2026-10-25 in a
scratch crate: Python round-trips `SET([INT64, TEXT])`; Kotlin `data class Set(value: List<…>)`, Swift
`case set(value: [MiniGrafValue])`). In Kotlin the nested `MiniGrafValue.Set` shadows
`kotlin.collections.Set` inside the sealed class only; wrapper code names `kotlin.collections.Set`
explicitly where both appear.

### Step 21. Core: `BrowserDb` set bind form

On a `v3` branch (`feat/316-browser-set-bind`): `src/browser/binds.rs` reads `{ type: 'set', value: [...] }`
and a JS `Set` instance (`js_sys::Set`) into `BindValue::Val(Value::Set(ValueSet::new(..)?))`; module table
gains both rows. A non-array `value`, a bad element form, or a set element is API-017 / API-021 as for the
other typed forms. wasm-bindgen tests: bind a typed set and a JS `Set` to `[(in? ?v $s)]`, empty set, nested
set rejected (API-021), `entity` element rejected. CHANGELOG Unreleased: one line under the #316 entries.
Codex review, PR, merge commit.

### Step 22. Docs site

`minigraf-docs` branch `316-sets`, all `<!-- @since v3.0.0 -->`:
- `content/datalog-reference.md`: set literals `#{...}` (scalar elements, duplicates removed, canonical
order), the five predicates `in?`/`not-in?`/`any-in?`/`all-in?`/`none-in?` with operand shapes,
`collect-set` (per-row pattern reduction under the query's temporal view, `#{}` when none, allowed in
rules/`not`/`or`), `:order-by` over a set column if #306 has landed.
- `content/architecture.md`: Set row in the value table; v8 key tag `0x08`, ≤ 64-byte inline elements,
longer spill to value pages, DICT dedup.
- `content/comparison.md`: set values / membership predicates row.
- Per-binding examples (the #181 prepared-query tutorial page): binding a set and reading one back, in the
forms of the table above.
Error codes are read from core per tag; nothing copied. PR to `main`; doc-only, merge on green link check.

### Step 23. Binding template (UniFFI reference)

`minigraf-binding-template` `v3`, branch `feat/316-set-values`: pin → core `v3` head after step 21;
`MiniGrafValue::Set` + `From<Value>` set arm + wildcard arm. The wildcard is reachable only after a
future pin bump adds a `Value` variant; it maps to `Text { value: v.to_string() }` (the REPL form), never a
panic across FFI and never a silent `Null`, and the pin-bump PR that hits it adds a real arm. Same rule for
every binding's wildcard arms. `to_core` set arm via `ValueSet::new`; `value_to_json` array arm + wildcard; unit tests for both
directions and API-021. Merge commit.

### Step 24. UniFFI bindings

python, java, android, swift (`v3`, branch `feat/316-set-values` each): sync `lib.rs` with the template;
host sugar in each wrapper (Python `_bind_value`: `set`/`frozenset` → `Set`; Kotlin/Java and Swift wrapper
equivalents); consumer test: transact a set, query it back (typed and JSON), bind a set to `in?`, nested set
→ API-021. Python on the bench machine first; android on the emulator job; swift compiles in CI only.

### Step 25. Node and C

Node: `FactValue` gains `'set'` (value an array of `FactValue`), `bind_value` reads the typed form and a JS
`Set`, `value_to_json` array arm + wildcard, TS types updated. C: `ValueJson` gains `set`, `typed_value`
reads it, `value_to_json` arm + wildcard, header docs. Consumer tests as step 24.

### Step 26. wasm

`minigraf-wasm` `v3`: pin bump only in Rust; browser `contract.js` binds and returns a set through
`BrowserDb` (step 21), WASI contract queries a set literal.

### Step 27. Close-out

Every binding PR: Codex review, CI green, merge commit on approval (never squash a pin bump). Then core
`v3` docs PR: CHANGELOG bindings line for sets, ROADMAP, memory; this also unblocks the #181 pin follow-up.
Coordinate with #180 (UDFs, also edits the UniFFI shims): whichever binding PR merges second rebases.
Loading
0