Skip to content
GitHub

Canon blocks: one source of truth for shared rules in markdown

Canon blocks: sync a shared rule across markdown concepts

Section titled “Canon blocks: sync a shared rule across markdown concepts”

Write a rule once in its owner concept. okf copies it into other concepts and tells you when a copy drifts.

The measured version is okf 0.2.5. The runs below use a throwaway copy of the test catalogue.

okf sync-status lists every copy of a canon block and its state. Here the owner text changed after one copy was made:

okf sync-status
$ okf --root <catalogue> sync-status
synced handbook/ops/setup.md /kc-gov/ownership.md#ownership-rule
source-changed kc-gov/naming.md /kc-gov/ownership.md#naming-rule
sync-status: 1 synced, 1 source-changed, 0 consumer-modified, 0 both-changed, 0 source-missing, 0 malformed
[exit 5]

Exit 5 means drift was found. After okf sync-update --apply every copy is synced and the exit code is 0:

okf sync-update --apply, then sync-status
$ okf --root <catalogue> sync-update --apply
--- a/kc-gov/naming.md
+++ b/kc-gov/naming.md
@@ -9,8 +9,8 @@
-<!-- okf:sync id=naming-rule source=/kc-gov/ownership.md hash=68dca574d22c -->
+<!-- okf:sync id=naming-rule source=/kc-gov/ownership.md hash=5f1068e89974 -->
> [!quote] Synchronisiert aus `/kc-gov/ownership.md` — Canon-Owner, hier nicht bearbeiten.
<!-- okf:sync-body -->
-Names are lowercase, hyphenated and stable.
+Names are lowercase, hyphenated, stable and unique.
<!-- /okf:sync -->
updated kc-gov/naming.md /kc-gov/ownership.md#naming-rule
sync-update: 1 updated, 0 refused, 0 unresolvable.
[exit 0]
$ okf --root <catalogue> sync-status
synced handbook/ops/setup.md /kc-gov/ownership.md#ownership-rule
synced kc-gov/naming.md /kc-gov/ownership.md#naming-rule
sync-status: 2 synced, 0 source-changed, 0 consumer-modified, 0 both-changed, 0 source-missing, 0 malformed
[exit 0]

Edit the canon once and every consumer follows. You do not search for copies of a rule by hand.

flowchart LR
    O["Owner concept<br/>okf:canon id=naming-rule"] -- "sync-insert" --> C1["Consumer A<br/>okf:sync block"]
    O -- "sync-insert" --> C2["Consumer B<br/>okf:sync block"]
    O -. "edit the owner text" .-> D{"sync-status"}
    D -- "source-changed, exit 5" --> U["sync-update --apply"]
    U --> C1
    U --> C2

okf rename and okf archive of an owner rewrite source= in all its sync blocks (see Safe edits).

The owner concept declares a canon block between two comments:

kc-gov/ownership.md (owner)
<!-- okf:canon id=ownership-rule -->
Every normative statement has exactly one owner.
<!-- /okf:canon -->

A consumer concept holds the managed copy, a sync block. It carries the owner path in source= and a 12-hex hash=:

handbook/ops/setup.md (consumer)
<!-- okf:sync id=ownership-rule source=/kc-gov/ownership.md hash=594970cbf139 -->
> [!quote] Synchronisiert aus `/kc-gov/ownership.md` — Canon-Owner, hier nicht bearbeiten.
<!-- okf:sync-body -->
Every normative statement has exactly one owner.
<!-- /okf:sync -->

Do not edit the text between okf:sync-body and /okf:sync. The next sync-update replaces it.

The argument order of sync-insert is consumer, owner concept, block id. Without --apply okf prints a diff and writes nothing:

okf sync-insert
$ okf --root <catalogue> sync-insert handbook/glossary kc-gov/ownership naming-rule
--- a/handbook/glossary.md
+++ b/handbook/glossary.md
@@ -14,3 +14,9 @@
## Concept
One Markdown file with frontmatter.
+
+<!-- okf:sync id=naming-rule source=/kc-gov/ownership.md hash=5f1068e89974 -->
+> [!quote] Synchronisiert aus `/kc-gov/ownership.md` — Canon-Owner, hier nicht bearbeiten.
+<!-- okf:sync-body -->
+Names are lowercase, hyphenated, stable and unique.
+<!-- /okf:sync -->
would insert handbook/glossary.md /kc-gov/ownership.md#naming-rule
sync-insert (dry-run): re-run with --apply.

sync-update takes an optional target (<bundle> or <bundle>/<subdir>), --source and --block to narrow the blocks, and --force to discard local edits of a consumer.

sync-status reports one of: synced, source-changed, consumer-modified, both-changed, source-missing, malformed. The okf check rules kc/sync/block, kc/sync/canon-block and kc/sync/stale cover the same blocks (see Conformance checks).

  • The statuses consumer-modified, both-changed, source-missing and malformed are listed by okf; this page shows only runs with synced and source-changed.
  • After an owner rename --apply, the > [!quote] line of a consumer still names the old path until sync-update runs. Observed: source= is rewritten at once, the quote line is not. The status stays synced because the payload did not change [6peo].
  • Only one error path was run: sync-insert with a concept argument that does not exist prints not found: naming-rule and exits 3. sync-insert with a block id that does not exist in the owner prints no canon block `nope` in recipes/soup.md and also exits 3. sync-update on a path that is not a directory exits 3.