Skip to content
🚧 Early alpha — building the foundation. See the roadmap →

Primitives reconciliation — open decision register (verified findings, corpus-grounded options)

Created Updated

The engine-level primitives survive adversarial audit — two are genuinely novel — but the essence claim (“encoding meaning, not importing tables”) currently fails at a handful of missing fields in Tier 1 (the canonical Markdown-plus-frontmatter form every imported note takes, and the layer that has to be trustworthy for audit), the closed-grammar commitment has drifted into five contradictory counts, and the complexity worth removing lives in the vocabulary layer, not the code.

Validated strengthWhy it held
Junction notes are reified statements, done betterA junction note is one relationship (“control X maps to control Y”) stored as its own file. Independent reinvention of the RDF-reification / Wikidata-qualifier move — but as addressable, git-diffable, human-reviewable files. No established formalism has that combination.
Identity-before-render hashingconcept_cid (the fingerprint that says “this is the same concept regardless of where it sits in a folder tree”) hashes {curie, scope} before layout. Two vaults with different folder trees are provably the same knowledge.
Mandatory provenance on every nodeEvery note records where it came from. Stronger than RDF (optional) and SSSOM (mappings only).
Explicit closure with recorded depthclosure_cache.shortest_depth records how many relationship hops a derived fact took — beats opaque OWL entailment for audit.
managed / user_preserve splitThe declaration of which parts of a note the tool owns and which belong to the user. The entire re-import safety property. 18 of 19 shipped recipes declare it.
Two edge models (crosswalk-edge vs junction-note)A crosswalk edge is a compact row-shaped mapping; a junction note is the same relationship as a reviewable file. The complexity is in the standards they feed (STRM/SSSOM vs OSCAL), not in Crosswalker.
The two existing digests stay orthogonalconcept_cid (same concept?) × effective_target_hash (did output-affecting behavior change?) produce the 2×2 that makes drift diagnosable. Merging them collapses it to one bit.
AJV as the pre-write gateThe schema validator that runs before anything is written to the vault. The reason an external producer or agent is first-class without a code change. The actual moat.

Illustration 1 — the count drift, and the honest palette

Section titled “Illustration 1 — the count drift, and the honest palette”

Five different counts of “the Obsidian primitives” are live in the KB and code simultaneously. None cross-references the others.

Every claim below survived an independent refutation attempt. Corrections applied during verification are marked.

#FindingStatus
1The mechanism enum says 5; the workbench palette says 6; the preset schema and Destination union say 9; one code comment says “six” directly above the nine-variant unionConfirmed
2No ordinal field exists anywhere in Tier 1; enrichment re-sorts every derived list by curie (per-row generation still walks source order, but has nowhere to record it)Confirmed, scope tightened
3facet and hub notes have no schema branch — and they bypass validation entirely at write time; the vault reader knows kinds the contract does notConfirmed, stronger than claimed
4Junction-note endpoints are wikilink addresses; crosswalk-edge endpoints are CURIE identities; the docs claim identity for both; address-shaped parents do not resolve back to identity in Tier 2Confirmed
5The NOT predicate modifier exists in the spec prose and DDL block of the schema-spec page, and nowhere in the machine schema — a _NOT value would be rejected by the closed enumConfirmed
6Tier 2 concepts key on (curie-prefix, curie) with INSERT OR REPLACE, so two versions of one framework silently collide. mapping_set_id does ride in Tier 1 files as an unmodeled passthrough and round-trips through the SSSOM exporter — it is absent only from the schema contract and the Tier 2 projectionCorrected during verification
7Five artifact-role nouns (KnowledgeSet, SchemaContract, ExecutionRecord, PackageManifest, RecipeBinding) have zero occurrences in src/; MappingSet appears only as the SSSOM wire field; Carrier once in a commentCorrected during verification
8ShapeDispatchB: both call sites hardcode style A; a second AJV validator still compiles at every startup; tests run the matrix twiceConfirmed
9The Layer A query-primitive files are production-reachable only via the benchmark command — and query-composer.ts has zero production importers at allConfirmed, stronger than claimed
10The query DSL occupies lines 316–718 of the recipe schema (403 of 886 lines, 45.5%) and shares zero $defs with the import side; a shipped recipe carries a triply-nested empty andConfirmed, numbers corrected
11graph_edges / linkStyle: shortest are unexecuted and excluded from the effective-target hash — but they are non-blocking warnings, not blockers, and graph_edges is read for column collectionCorrected during verification
12The mappings and junction_notes tables have no foreign keys to concepts; dangling endpoints insert silentlyConfirmed
13Note bodies are outside the validation surface and are not exported — the densest meaning in the corpus is un-governed and lost on round-tripConfirmed
14computeRecipeHash hashes only {layout, also_emit, enrichment}; metadata.based_on.hash stores that same effective-target hashConfirmed

Illustration 2 — the corpus publishes order; Crosswalker drops it

Section titled “Illustration 2 — the corpus publishes order; Crosswalker drops it”

Three first-party sources independently ship an explicit ordinal column, converging on the same shape.

Illustration 3 — what “primitive” should mean

Section titled “Illustration 3 — what “primitive” should mean”

Twelve senses of the word are live in the KB. The proposed resolution: three families keep the word; everything else loses it.

Gate 1 — schema fields (Tier 1 field completions)

Section titled “Gate 1 — schema fields (Tier 1 field completions)”

All additive, all optional, none opens the closed layout grammar or adds an artifact noun. Each decision appears as an executive decision card — plain title, tradeoffs, recommendation — in the owner review queue (the single checklist of everything awaiting the owner’s ratification) § 1a.

#DecisionCorpus evidenceOptionsConnects to
P1Ordinal field. An optional string encoding position-within-parent (dotted, zero-padded path). Sub-decision: does it join concept_cid (the fingerprint that identifies a concept independently of where it lands in a folder tree)?First-party: CPRT ships a dedicated sort element per concept; 800-53A ships sort-as; CRI ships Outline Id. Generated CSF vault currently renders DETECT before GOVERN(a) adopt, excluded from concept_cid; (b) adopt, included; (c) deferTarget-structure synthesis (commits to lexical-sort canonicalization — must be amended); View shapes (deferred timeline shape); spec/tier1.schema.json
P2Identity-typed edge endpoints. Optional subject_curie / object_curie on junction notes (each junction note stores one relationship as its own reviewable file); parent_curie as the schema-blessed hierarchy carrier. Wikilinks remain the rendered affordanceAddress-shaped parents currently return null in Tier 2 identity resolution(a) add optional identity fields (makes the docs’ own invariant true); (b) keep address-only and fix the docs claimHierarchy primitives (“identity, not address”); spec/tier1.schema.json; src/tier2/projector.ts
P3Mapping-set identity + negation + version. Promote mapping_set_id (which published crosswalk release an assertion came from, e.g. NIST’s 800-53 Rev 4 to Rev 5 mapping) from unmodeled passthrough into the contract and Tier 2 (the rebuildable SQLite projection used for querying); add predicate_modifier: NOT (an explicit “these two are not equivalent” assertion); populate ontology versionThe SSSOM path already writes and round-trips mapping_set_id; the NOT modifier was the stated reason SKOS was rejected; r4/r5 silently collide today(a) all three now; (b) mapping_set_id + version now, NOT with the MappingSet envelopev0.1 schema spec (declares the modifier the schema lacks); SKOS registry page (gap #4); v0.1.7 milestone
P4Legalize facet/hub. Schema branches for the two note kinds the code already emits (a facet note is a slice of the graph, e.g. every control carrying one theme; a hub note is an index page for a level), plus write-time validation on hub pathsHub/facet notes currently bypass validateTier1Frontmatter entirely(a) add branches + validate; (b) constrain kind to a closed enum on the concept branch tooArtifact roles and authority (the anti-noun rule these kinds currently violate); src/generation/enrich.ts
P5Edge groups. Optional group_id marking the members of one joint-coverage conjunction (“A is covered jointly by B, C and D”), plus an importer guard on multi-target equalCRI “Full Summarily”: 1,478 rows where conjunction is a published predicate (3:1 majority in three mapping sets); CRI FCS is group-scoped by definition; 10 multi-target equal groups are already materialized as logically false pairwise equivalences in the test vault(a) group_id + guard now; (b) guard only, group_id with the MappingSet envelope; (c) nothing — ships a known correctness bugSTRM registry page; Terminology; src/import/sssom-importer.ts
P6Predicate characteristics registry. A small vocabulary table declaring inverse_of / symmetric / transitive per predicateGives closure a principled stopping rule; ends per-query “check both directions” conventions(a) now, for the STRM six; (b) with graph_edges in v0.2Ontology-web querying; src/tier2/ closure

Resolved by corpus evidence (no longer open): graph_edges stays reserved for v0.2. The corpus holds roughly 20,000 non-STRM edges (mitigates, D3FEND’s 20-plus object properties, CTID impact types, CPRT lifecycle relations), but the vocabulary is open-ended and entangled with unresolved version-lineage design — wiring it now would freeze a vocabulary before the design exists. v0.1’s honest carriers are named managed frontmatter conventions (800-53 Related Controls, mitigates) plus junction-note predicate strings, stated plainly in the schema spec.

Nothing here blocks the replay slice. Executive cards for these live in the owner review queue § 1b.

#DecisionVerified factsOptionsConnects to
P7Role nouns 16 → 7. Role nouns are the names the project gives to the kinds of thing it manages (Knowledge Set, Schema Contract, Execution Record, and so on). Keep schema, recipe, binding, MappingSet, live view, snapshot, projection (+ tiers). Demote the restFive nouns have zero code referent; MappingSet exists only as the SSSOM wire field; the anti-proliferation page itself introduced ~16 nouns while rejecting 1. The vocabulary layer is still uncommitted — cheapest pruning moment there will ever be(a) prune to 7 now, keep Execution Record / Package Manifest as a 3-line planned-envelopes note; (b) keep the full taxonomyArtifact roles and authority; artifact-role synthesis; Terminology
P8Split the recipe schema. spec/recipe.schema.json is the machine contract for a Recipe (the saved specification of how a source becomes notes). Import contract and query contract share zero $defs across an 886-line file (45.5% is the query DSL); query recipes must fake import-side fields to validateA shipped recipe carries "where": {"and":[{"and":[{"and":[]}]}]}(a) two schema files, additive $id bump; (b) keep one file, make source/target conditionalspec/recipe.schema.json; v0.1 schema spec; Query primitives
P9Delete ShapeDispatchB. ShapeDispatch is the validator’s two interchangeable ways of expressing the same rule set, documented as producing identical verdicts. Both callers hardcode style A; a second AJV validator compiles at every startup; ~350 doubled test linesStyles documented as producing identical verdicts(a) delete; (b) keepsrc/validation/validator.ts; spec/recipe.schema.json; tests/recipe-query-block.test.ts
P10Recipe models 5 → 2. Five in-code representations of one Recipe, with translation glue between each pair — every boundary a place a saved recipe can silently lose a field. render/index.ts’s hand-typed Recipe becomes an alias of the generated type; legacy config.ts models retire behind the shim with a date; close the table-row leak at the workbench UI instead of blocking at save~2,470 LOC of translation glue between five representations; the enrichment block is declared four times(a) collapse now; (b) collapse during the replay slicesrc/render/index.ts; src/types/config.ts; src/import/mapping/types.ts; Recipe fidelity synthesis
P11Consolidate reserved surface + dead code. One reference/reserved-for-v0.2 page for graph_edges, linkStyle: shortest, tag/wikilink mechanisms, Graph/Timeline parameter blocks; delete query-composer.ts (zero importers); “wire it or drop it” RC gate for the 1,558-LOC query-primitive islandquery-composer.ts is fully dead, not benchmark-only(a) consolidate + delete dead code + RC gate; (b) leave scatteredspec/recipe.schema.json; src/views/; v0.1-RC milestone

Naming and grammar only; no runtime behavior changes. Executive cards for these live in the owner review queue § 1b.

#DecisionOptionsConnects to
P12Re-base the grammar commitment. Commitment #2 is kept verbally while the real palette grew to 9 under three names. Restate it honestly: 9 destination primitives; 5 usable as layout mechanisms; wired/partial/reserved status per primitive; new-primitive review triggers on the palette, not the enum(a) restate on the true palette; (b) defend the number 5 and rename the additionsCh 22 synthesis; .claude/CLAUDE.md commitment #2; Hierarchy primitives
P13”Primitive” disambiguation. Three families + one stance + one adjective (Illustration 3). Rename sweep: transformation primitives → transforms (spec/primitives/ → spec/transforms/); TablePrimitives and siblings → TableParams (schema $id bump); ontology diff primitives → change primitives; retire the 13-item structural set (superseded note); “import primitive” → “import engine”(a) full sweep; (b) families only, defer renamesTerminology; Query primitives; ETL and import; spec/preset.schema.json
P14Terminology restructure. Split into a reader glossary (~180 lines: the 12 words that matter → overloaded-words collision table → three families → domain vocabulary → alias index) and an internals reference under agent-context; delete ~15 orphaned rows and the rejected-engine glossary(a) split as proposed; (b) trim in placeTerminology; UI lexicon

Gate 1 (schema fields) edits spec/tier1.schema.json — the machine-checked contract defining what a valid imported note looks like, and the same contract that the save-and-exact-replay register (the log tracking how a saved import re-runs later and produces the same result) locks a fingerprint scheme over in its own Gate 1, decision D1. Sequencing rule: this register’s Gate 1 lands before or together with replay D1. Changing Tier 1 fields after digests are locked would invalidate stored hashes. Gates 2 (cleanup) and 3 (language) are independent of the replay slice and can proceed in parallel.

The reader-journey audit split its findings into SAFE (decision-independent) and GATED items. The SAFE set is executing now, in parallel with this register:

ItemStatus
Sidebar orders for all concept pages (8 duplicates, 6 missing — terminology was sinking to the bottom of a collapsed list)Executing
Stale 7-verb query tables in terminology + system-architecture replaced with pointers to the canonical 8-verb pageExecuting
Dataview purge from the GRC landing page (commitment #6 violation, including a worked query)Executing
Quick-start rewritten against the shipped workspace tab (it documented a dead UI)Executing
New external-producer page: emit valid notes from your own toolsExecuting
Wrong file paths and the false _crosswalker.type claim in architecture pagesExecuting
Everything touching the word “primitive”, the noun set, or terminology structureGated on P7, P12–P14