Repository navigation
Propose: an additive client-side notation module (ckn) over the shipped verb surface #7
Description
Activity
- addedenhancementNew feature or requestNew feature or requestquestionFurther information is requestedFurther information is requestedP1Priority 1 — this releasePriority 1 — this release
on Jul 4, 2026 Maintainer response — yes to the direction, as an additive
./notationsubpath export, with the invariants as a hard acceptance bar. Answering the three in order.1. Does it belong in cklib? Yes — conditionally.
A CKN→construct compiler is pure client-side compilation over cklib's own verb surface, so cklib is its natural home: every client (a browser page, a Node service, an agent harness, any consuming application) gets the "one expression → one construct" surface once, instead of each consumer re-implementing it. The deciding reason is coupling direction — the compiler emits payloads shaped to cklib's exact method contracts (
create(type, body),link(source, predicate, target),transition(id, to_state),verify/provenance,propose/vote/apply). Those must version and be tested in lockstep with the surface they target; a separate package would perpetually chase our signatures. Co-location keeps them honest.It is "in" only if it holds the invariants that define this client — your sketch already commits to all of them, so I'm making them the bar:
- Plan-emitter, not a graph. Output is an ordered
[{verb, payload}]dispatch plan. No RDF, no quad store, no query language emitted — the L1 store-not-graph invariant inck.js's own header stays true. - Zero authority. The compiler resolves / evaluates / traverses nothing; every step goes through
ckp.dispatchand is governed server-side. pgCK stays the only authorization boundary; the plan is a proposal, the server still gates each step — decisive in the untrusted-JWT posture the client runs under. ck.jsunchanged. The module sits strictly aboveConceptKernel, consuming only its public methods. No new core methods, no new transport.- Zero runtime deps, vendored / air-gapped, offline-testable. The parser pulls nothing into the bundle;
compile()is pure (no I/O) so it tests without NATS, exactly like the existingsmoke-*.mjs. - Separately importable. Core clients that never import it pay nothing at runtime. (In the OCI bundle the file lands at image root beside the others — a browser loads it only if it
imports it — so keep it lean.)
2. Module boundary + naming.
- File:
ck-notation.js— sibling tock.js/ck-client.js/ck-store.js(keeps theck-*.jsconvention). - Export: public subpath
@conceptkernel/cklib/notation(beside././client; not under./internal— this is a first-class additive surface). - API — split compilation from execution:
compile(source) → plan— pure, I/O-free, inspectable (a caller can audit/authorize the plan before it runs).assemble(handle, planOrSource) → results— runs the plan through a liveConceptKernelhandle.
That inspect-then-run split is what makes it both offline-testable and safe in untrusted contexts.
- Ships as its own release cut, byte-verified, with
package.jsonfiles/exportsupdated — not folded into the v1.5.4 scoring byte-set (features don't share a bundle).
3. First-slice grammar scope — instance plane only.
Exactly the strands that compile to already-shipped, ungated verbs:
- χ / ρ (instances + properties) →
create - edges →
link - τ (transitions) →
transition(sealed-map gated server-side; an illegal move already returnsallowed) - π (attestation) →
verify/provenance
Defer the genome plane (σ/α/γ declaration →
propose ▸ vote ▸ apply) to slice 2 — that plane's reachability is still gated, and the compiler should degrade honestly togov_plane_unavailablethere, mirroring the existing_govpath, rather than pretend. Ship the instance plane on today's verbs; add the genome plane when that plane is reliably reachable.On the contribution + sequencing
Glad to take the reference pipeline (parse → plan → assemble) you mention. The gate is the usual bar: TDD (offline
compiletests + a live-verifiedassemblepath in thesmoke-*.mjsstyle), zero deps,ck.jsuntouched, plan-emitter-only. Adapt it tock-notation.js+compile/assembleand we're aligned. It's orthogonal to the scoring loop (blocks nothing, blocked by nothing), so it can proceed in parallel — but it lands as its own version cut after v1.5.4, not inside it.- Plan-emitter, not a graph. Output is an ordered
Reference implementation offered as #8 — framed as a suggestion in this direction, and handing authority to cklib: the module boundary, API, and grammar are yours to set. It's shaped to the three answers above (
ck-notation.js·@conceptkernel/cklib/notation·compile/assemblesplit · instance plane only · genome plane deferred), holds the acceptance bar (plan-emitter, zero authority,ck.jsuntouched, zero-dep, offline-tested 27/27), and stages as its own cut — not folded into the scoring byte-set. Adapt, rewrite, or reject freely; downstream consumers will align to whatever cklib lands.- addedP2Priority 2 — soonPriority 2 — soonand removedP1Priority 1 — this releasePriority 1 — this release
on Jul 8, 2026
Summary
conceptkernel.org describes cklib as a notation-ready dispatch client, and Concept Kernel Notation — the nine strands
χ · ρ · σ · α · γ · π · δ · φ ⟫ε— is published there as the canonical way to say what a kernel is and what to lay down in it. This proposes an additive module (working nameckn) that takes a CKN expression and assembles a construct on a live kernel by compiling it to the verbs that already ship inck.js. Notation in, sealed construct out — no new transport, no new authority.Motivation
Today an app or agent builds a multi-step construct by hand: a threaded sequence of
create/link/transition/verifycalls. A notation expression captures that same intent declaratively, in one form. A thin compiler closes the gap between the two without changing the surface beneath it — and gives every client (browser and Node) the same "one expression → one construct" surface.Design sketch — grounded in the shipped surface
The module sits above
ConceptKerneland composes only whatck.jsalready exposes:k.create(type, body)k.link(source, predicate, target)k.transition(id, toState)(sealed-map gated server-side)k.verify(id)/k.provenance(id)k.propose(op, detail)▸k.vote(iri, value)▸k.apply(iri)Declaring a new capability is a consented, multi-party act (propose ▸ vote ▸ apply), never a direct write — so the genome plane compiles to governance, and degrades honestly to
gov_plane_unavailablewhere that plane isn't reachable, exactly like the existing_govpath.The compiler's output is an ordered dispatch plan — a list of
{verb, typed-payload}steps — not a graph. This preserves the invariantck.jsstates in its own header: there is no RDF, quad store, or query engine on the client. The module adds notation sugar; it emits no query language and holds no authority of its own (pgCK remains the only authorization boundary — the handle is not).Scope for a first slice
What I'm asking
notationsubpath export beside the current././clientexports — keepingck.jsunchanged?I have a working reference implementation of this pipeline (parse → plan → assemble) validated end-to-end against a live kernel — an instance sealed with a real proof digest, sealed-map transitions, and re-verification — and I'm glad to contribute it or adapt it to whatever boundary the maintainers prefer.