Close three WO-WZ-004 review gaps in the guest db driver:
- toDbValue: nil []string now marshals to DbValue_Null (matching []byte /
json.RawMessage); empty-but-non-nil stays a non-NULL empty text[].
- DbValueFixtures: add edge entries (zero time.Time, negative + very-large
numeric strings, empty text[], and text[] elements forcing encodePgTextArray
quoting/escaping). Covered automatically by the table-driven round-trip and
driver-value tests; new dbvalue_test.go covers the toDbValue nil convention.
- Document that TextArray cannot represent a NULL array element (repeated
string has no per-element NULL) in the fixtures file and docs/wasm-abi.md,
a contract limit the WO-WZ-007 host executor must also honor.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bind the db.* driver over the same transport as the capability stubs so
deps.Pool keeps working for plugin sqlc code:
- dispatch.go: g.services.Pool = bnwasm.NewPool(capTransport) (nil on
native/DESCRIBE → fails cleanly, matching the caps stubs).
- hostcalls.go (wasip1): also bind the "bnwasm" database/sql driver's
process-global transport to CallHost.
- docs/wasm-abi.md: document the implemented guest driver + pgx-primary
rationale under the Pool disposition.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every CoreServices interface (core/plugin/deps.go) now has a guest-side stub
that marshals to the WO-WZ-001 capability messages and dispatches through the
generic host_call transport, so plugin service code compiles and runs
unchanged against content.Content, settings.Settings, plugin.PluginBridge, etc.
- core/plugin/wasmguest/caps/: one file per family (17 families, 38 methods),
a var _ <iface> = (*stub)(nil) compile proof each, and NewCoreServices(call)
assembling them. The transport is injected (CallFunc) so marshaling is
natively testable; the wasm shim binds it to CallHost, DESCRIBE probes pass
nil (capability calls fail cleanly instead of nil-panicking).
- Error mapping wraps AbiError with <family>.<method> context and maps
DEADLINE_EXCEEDED onto context.DeadlineExceeded.
- RAGService.RegisterContentFetcher stays guest-side (RAGStub) for
HOOK_RAG_FETCH dispatch; Query/OnContentChanged marshal out. dispatch.go and
describe.go now source fetchers from the caps RAG stub.
- caps_roundtrip_test.go: fake transport + 76 deterministic golden payloads
(family_method_{req,resp}.pb) covering 100% of families, plus error-mapping,
deadline, nil-transport, and guest-side-fetcher tests. WO-WZ-006 replays the
same goldens to prevent host/guest drift.
- Acceptance: testdata/fixture Load hook calls deps.Content/Settings/Bridge
unchanged (compiles for wasip1); caps_wasmhost_test.go drives it end-to-end
through a real wazero module + fake host_call table.
- Disposition table in docs/wasm-abi.md: every member stub | host-side
(Pool, Interceptors, AppURL/MediaPath, CoreServiceBindings host-side).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The wasip1 half of the ABI: bn_alloc/bn_invoke/bn_free exports with a
live-pin map so the GC never frees host-visible buffers, the generic
`blockninja.host_call` import (single import decided over per-family
symbols; recorded in wasm-abi.md), and a dispatch table adapting an
unmodified plugin.PluginRegistration to all nine v1 hooks. Panics inside
plugin hooks come back as ABI_ERROR_CODE_INTERNAL — the instance stays
callable; traps stay reserved for runtime corruption.
DESCRIBE builds the PluginManifest from the registration's static funcs
plus a capture-only Register pass (block metas via the same
PluginBlockRegistry prefixing the .so loader applies, template/system/
page-template/email-wrapper keys), probes JobHandlers/ServiceHandlers/
Load with capture-only services for job types, RBAC roles, core-service
bindings, and RAG fetcher types. RenderContext values are rehydrated
through the exact core/blocks context keys, so existing block code
reading from ctx works unchanged.
Plugins build in REACTOR mode (go build -buildmode=c-shared): init()
calls wasmguest.Serve (non-blocking), main is never called, and the host
runs _initialize before any bn_invoke. Command mode deadlocks or exits
(verified against wazero v1.12.0) — documented prominently in
wasm-abi.md, which also now reconciles the import module namespace to
`blockninja` and requires bn_alloc'd buffers on both directions.
Dispatch/describe/context logic is buildable on every GOOS; only
exports.go and hostcalls.go carry the wasip1 tag. dispatch_test.go
covers describe, hook routing, envelope mismatch, decode failures,
template-override resolution, panic recovery, and lifecycle hooks
natively.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CMS Go module renamed from git.dev.alexdunmow.com/block/ninja to
git.dev.alexdunmow.com/block/cms (along with the git remote rename
on gitea). All import paths, string-literal rules, test fixtures,
and doc references updated; (historical 'ninja-orchestrator' refs
preserved). go mod tidy regenerated checksums.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Repos consolidated under ~/src/blockninja/ parent (collection, not
monorepo). This repo moved from ~/src/core to ~/src/blockninja/core.
Updates historical plan/audit docs that referenced the old paths.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- ninja login forces account selection (interactive when >1); creds now
carry ActiveAccountID/Slug. New `ninja account` group.
- ninja plugin list / delete / delete-version split public vs active-account
@private sections; `publish --private` is sticky in plugin.mod.
- GetPluginRequest gains active_account_id so @private resolution works
alongside the public (scope, name) path.
- publish auto-commits a dirty plugin.mod (path-scoped, leaves other staged
paths alone) so the bump→publish loop never trips the dirty check.
--allow-dirty is replaced with --strict (default now ships dirty trees
via stash-create).
- bump auto-commits its plugin.mod write with `bump to X.Y.Z`; --no-commit
opts out.
- Design doc updated to match the new defaults.
Design for two coupled changes: drop git as the publish transport in
favour of tar.zst uploads, and add a first-class plugin kind plus a
configurable, validated category list.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>