@panaversity/ksor 0.0.40 → 0.0.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/CHANGELOG.md +869 -0
  2. package/README.md +11 -7
  3. package/dist/checker/check-main.mjs +14049 -0
  4. package/dist/cli.mjs +11528 -5213
  5. package/dist/gateway-api-CF4ED9_g-BQusM_dK.mjs +10895 -0
  6. package/dist/gateway.d.mts +52 -13
  7. package/dist/gateway.mjs +2 -2
  8. package/dist/index.d.mts +1 -1
  9. package/dist/index.mjs +1 -1
  10. package/dist/{src-pl4aOpVs.mjs → src-dqpI-p1a.mjs} +1 -0
  11. package/docs/authorization.md +8 -6
  12. package/docs/deploying.md +36 -25
  13. package/docs/index.md +26 -13
  14. package/docs/ingesting.md +70 -22
  15. package/docs/tool-surface.md +69 -16
  16. package/package.json +4 -3
  17. package/schema/migrations/2.4-2.5__okf-profile.sql +114 -0
  18. package/schema/schema.sql +77 -14
  19. package/templates/scaffold/.agents/skills/add-sources/SKILL.md +63 -18
  20. package/templates/scaffold/.agents/skills/format-checker/SKILL.md +42 -33
  21. package/templates/scaffold/.agents/skills/format-checker/check.mjs +13827 -1314
  22. package/templates/scaffold/.agents/skills/intake-interview/SKILL.md +65 -27
  23. package/templates/scaffold/.agents/skills/make-slides/SKILL.md +7 -5
  24. package/templates/scaffold/.agents/skills/make-summary/SKILL.md +13 -6
  25. package/templates/scaffold/.claude/skills/add-sources/SKILL.md +63 -18
  26. package/templates/scaffold/.claude/skills/format-checker/SKILL.md +42 -33
  27. package/templates/scaffold/.claude/skills/format-checker/check.mjs +13827 -1314
  28. package/templates/scaffold/.claude/skills/intake-interview/SKILL.md +65 -27
  29. package/templates/scaffold/.claude/skills/make-slides/SKILL.md +7 -5
  30. package/templates/scaffold/.claude/skills/make-summary/SKILL.md +13 -6
  31. package/templates/scaffold/.github/workflows/validate.yml +9 -1
  32. package/templates/scaffold/.ksor/governance.yaml +17 -0
  33. package/templates/scaffold/AGENTS.md +234 -113
  34. package/templates/scaffold/Dockerfile +5 -1
  35. package/templates/scaffold/README.md +160 -42
  36. package/templates/scaffold/env.example +37 -6
  37. package/templates/scaffold/gitignore +13 -8
  38. package/templates/scaffold/instance.md +21 -17
  39. package/templates/scaffold/knowledge/governance-ladder.md +6 -2
  40. package/templates/scaffold/knowledge/index.md +9 -0
  41. package/templates/scaffold/knowledge/surfaces/for-agents.md +7 -6
  42. package/templates/scaffold/knowledge/surfaces/for-people.md +7 -6
  43. package/templates/scaffold/knowledge/surfaces/index.md +4 -20
  44. package/templates/scaffold/knowledge/surfaces/overview.md +25 -0
  45. package/templates/scaffold/knowledge/what-is-a-ksor.md +6 -5
  46. package/templates/scaffold/knowledge/what-is-a-ksor.summary.md +4 -0
  47. package/templates/scaffold/package.json +3 -4
  48. package/templates/scaffold/pnpm-lock.yaml +3 -0
  49. package/templates/scaffold/system/gateways/content.ts +13 -0
  50. package/templates/scaffold/system/site/app/(home)/page.tsx +2 -2
  51. package/templates/scaffold/system/site/app/.well-known/mcp/server.json/route.ts +10 -0
  52. package/templates/scaffold/system/site/app/docs/[[...slug]]/page.tsx +126 -91
  53. package/templates/scaffold/system/site/app/global.css +13 -5
  54. package/templates/scaffold/system/site/app/layout.tsx +8 -3
  55. package/templates/scaffold/system/site/app/llms-full.txt/route.ts +13 -7
  56. package/templates/scaffold/system/site/app/llms.txt/route.ts +12 -7
  57. package/templates/scaffold/system/site/app/md/[[...slug]]/route.ts +26 -25
  58. package/templates/scaffold/system/site/components/footer-mark.tsx +3 -2
  59. package/templates/scaffold/system/site/components/governance.tsx +205 -87
  60. package/templates/scaffold/system/site/components/record-index.tsx +5 -5
  61. package/templates/scaffold/system/site/components/record-stack.tsx +10 -9
  62. package/templates/scaffold/system/site/components/sidebar-status.tsx +19 -18
  63. package/templates/scaffold/system/site/lib/attachment-rule.ts +6 -1
  64. package/templates/scaffold/system/site/lib/attachments.ts +0 -28
  65. package/templates/scaffold/system/site/lib/audience-rule.ts +15 -21
  66. package/templates/scaffold/system/site/lib/audience.ts +42 -146
  67. package/templates/scaffold/system/site/lib/embed-rule.ts +9 -0
  68. package/templates/scaffold/system/site/lib/governance.ts +339 -225
  69. package/templates/scaffold/system/site/lib/index-routes.ts +125 -0
  70. package/templates/scaffold/system/site/lib/lifecycle-rule.ts +52 -0
  71. package/templates/scaffold/system/site/lib/lock.ts +282 -0
  72. package/templates/scaffold/system/site/lib/order-rule.ts +37 -0
  73. package/templates/scaffold/system/site/lib/record-href.ts +68 -0
  74. package/templates/scaffold/system/site/lib/record-link.tsx +26 -0
  75. package/templates/scaffold/system/site/lib/rules-version.ts +11 -0
  76. package/templates/scaffold/system/site/lib/shared.ts +67 -104
  77. package/templates/scaffold/system/site/lib/sim-rule.ts +49 -0
  78. package/templates/scaffold/system/site/lib/source.ts +256 -186
  79. package/templates/scaffold/system/site/lib/stage-knowledge.ts +566 -492
  80. package/templates/scaffold/system/site/lib/stage-manifest.ts +128 -0
  81. package/templates/scaffold/system/site/package.json +1 -0
  82. package/templates/scaffold/system/site/record/actor.ts +23 -0
  83. package/templates/scaffold/system/site/record/check.ts +571 -0
  84. package/templates/scaffold/system/site/record/citations.ts +312 -0
  85. package/templates/scaffold/system/site/record/frontmatter.ts +134 -0
  86. package/templates/scaffold/system/site/record/git-ledger.ts +171 -0
  87. package/templates/scaffold/system/site/record/hygiene.ts +320 -0
  88. package/templates/scaffold/system/site/record/index-file.ts +150 -0
  89. package/templates/scaffold/system/site/record/index.ts +103 -0
  90. package/templates/scaffold/system/site/record/instance.ts +257 -0
  91. package/templates/scaffold/system/site/record/instant.ts +43 -0
  92. package/templates/scaffold/system/site/record/ledger.ts +694 -0
  93. package/templates/scaffold/system/site/record/load.ts +129 -0
  94. package/templates/scaffold/system/site/record/lock.ts +306 -0
  95. package/templates/scaffold/system/site/record/near-miss.ts +37 -0
  96. package/templates/scaffold/system/site/record/policy.ts +414 -0
  97. package/templates/scaffold/system/site/record/profile.ts +535 -0
  98. package/templates/scaffold/system/site/record/refusal.ts +106 -0
  99. package/templates/scaffold/system/site/record/yaml-file.ts +103 -0
  100. package/templates/scaffold/system/site/source.config.ts +77 -22
  101. package/dist/gateway-api-CmIthmJS-IUA9qS-T.mjs +0 -3225
  102. package/templates/scaffold/system/site/lib/denial-rule.ts +0 -220
  103. package/templates/scaffold/system/site/lib/page-order.ts +0 -93
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  name: intake-interview
3
- description: The first conversation with the owner of this Knowledge System of Record — six questions that define what it is authoritative for and who may read it, then write instance.md together. Use when the owner asks to set up, configure, or "get started with" this project, when instance.md still contains its scaffold placeholder text, or when the scope of the corpus is unclear.
3
+ description: The first conversation with the owner of this Knowledge System of Record — seven questions that define what it is authoritative for, who may read it and who may approve it, then write instance.md together. Use when the owner asks to set up, configure, or "get started with" this project, when instance.md still contains its scaffold placeholder text, or when the scope of the corpus is unclear.
4
4
  metadata:
5
- version: "1.3.0"
5
+ version: "1.5.0"
6
6
  ---
7
7
 
8
8
  # Intake interview
@@ -12,7 +12,7 @@ prose IS the agent surface's system prompt (`ksor serve` wires it into the MCP
12
12
  server's instructions). Do not draft it from guesses — interview the owner, one
13
13
  question at a time, and write down what they actually say.
14
14
 
15
- ## The six questions
15
+ ## The first six questions
16
16
 
17
17
  Ask these one at a time; follow up until each answer is concrete enough to
18
18
  act on:
@@ -31,33 +31,71 @@ act on:
31
31
  should it decline? ('Not in this corpus' is a correct answer here —
32
32
  confirm the owner wants that behavior and where they want it softened.)"
33
33
  6. **Audiences** — "Does every reader of this record see every document? If
34
- not, what are the audiences, from most public to most restricted?" A yes
35
- is the common answer and the whole answer: write no `audiences:` key and
36
- nothing about the project changes. A list means writing it into
37
- `instance.md`'s frontmatter ordered least- to most-restricted with
38
- `public` first, plus `default_visibility:` naming the audience a document
39
- takes when it says nothing (there is no safe guess, so the checker
40
- requires it). Tell the owner what the key does and does not do:
41
- documents carry `visibility:` and builds are made per audience, but
42
- anyone who can clone the repository reads everything in it if someone
43
- must not read a document and can clone, that document belongs in a
44
- different repository.
34
+ not, what are the audiences?" A yes is the common answer and the whole
35
+ answer: register none, and every document says `ksor.audience: [public]`.
36
+ Anything else means registering each audience in
37
+ `.ksor/governance.yaml` under `audiences:`, with a one-line
38
+ `description:` of who is in it — `public` is reserved and never
39
+ registered. There is no ranking and no default: a document lists the
40
+ audiences that may read it, a reader holds a list that always includes
41
+ `public`, and the document is visible when the two lists OVERLAP. Tell
42
+ the owner what this does and does not do: builds are made per audience,
43
+ but anyone who can clone the repository reads everything in it — if
44
+ someone must not read a document and can clone, that document belongs in
45
+ a different repository.
46
+
47
+ ## Then ask the seventh, because a policy cannot be guessed
48
+
49
+ 7. **Authority** — "Who may approve a document for publication, and who may
50
+ withdraw one?" Names, not roles-in-the-abstract: they become
51
+ `approval_authorities` and `takedown_authorities` in
52
+ `.ksor/governance.yaml`, and the checker refuses an approval or a
53
+ takedown by anyone the policy does not name. The scaffold ships
54
+ `human:you` in both — a placeholder that must not survive this
55
+ conversation. An actor is `human:<handle>`, `process:<name>` or
56
+ `<producer>/<version>`; handles are published with the record, so use the
57
+ handle the owner would put in a commit, never an email address.
45
58
 
46
59
  ## Then write
47
60
 
48
- - Rewrite `instance.md`'s body from the answers: first the `# H1` the
49
- record's **display title**, the human name every page will lead with
50
- ("Acme Operations Handbook", not the slug) then the authority sentence,
51
- boundary, audience, and strictness plain prose, written for a reader
52
- who must act on it. Leave the identity frontmatter keys alone; two things
53
- are written there when they apply: an audience model from question 6, as
54
- `audiences:` (a list) and `default_visibility:` (`pnpm check` holds the
55
- record to it from that moment on); and only when the owner stands up the
56
- served MCP rung — the `database:`/`embedding:`/`retrieval:` blocks (see
57
- `AGENTS.md` → "Serving to agents"; that is a later climb, not part of this
58
- interview). The strictness answer from question 5 is the intent behind the
59
- `retrieval.vector_floor` on that climb, measured by `ksor calibrate` — capture
60
- it in the prose now so it is ready.
61
+ - Rewrite `instance.md` from the answers. `title:` is the record's
62
+ **display title**, the human name every page leads with ("Acme Operations
63
+ Handbook", not the slug); `description:` is one sentence, and it seeds
64
+ `llms.txt` and the MCP discovery document; the BODY is the authority
65
+ sentence, boundary, audience and strictness plain prose, handed in full
66
+ to every connecting agent as the MCP server's instructions, so write it
67
+ for a reader who must act on it. There is no `# H1`: the title is a key.
68
+ Leave `name:` and `toolchain:` alone. One block is added here only when
69
+ the owner stands up the served MCP rung — `database:`/`embedding:`/
70
+ `retrieval:` (see `AGENTS.md` → "Serving to agents"; that is a later
71
+ climb, not part of this interview). The strictness answer from question 5
72
+ is the intent behind the `retrieval.vector_floor` on that climb, measured
73
+ by `ksor calibrate` — capture it in the prose now so it is ready.
74
+ - Write `.ksor/governance.yaml` from questions 6 and 7: `version: "0.1"`,
75
+ the `audiences:` registry if there is one, and the two authority sets with
76
+ real actors. That file is the root of authority — every approval, every
77
+ deprecation and every ledger entry is checked against it. **Keep
78
+ `ksor-starter/KSOR-STAMP-VERSION` in `approval_authorities` while any starter
79
+ document is still in `knowledge/`.** Those five are approved by it, so a
80
+ policy rewritten without it refuses the next build by name
81
+ (`ksor-approver-unauthorised`). It leaves when the last sample does.
82
+ - **Offer to start replacing the starter documents — they are already
83
+ published.** All five ship `status: stable`, approved by
84
+ `ksor-starter/KSOR-STAMP-VERSION`, so the site and `llms.txt` carry them from
85
+ the first build. They describe KSoR itself rather than the owner's
86
+ organisation. Say it plainly: "Five sample documents about KSoR are published
87
+ on your record right now. The tool that wrote them approved them — nobody has
88
+ reviewed them, which is what the _unverified_ tier on each page says. Shall we
89
+ start replacing them with yours?" Replacing means deleting the sample and
90
+ writing a real document at `status: draft`; the owner approves it afterwards,
91
+ and that act is theirs. When the last sample is gone, delete
92
+ `ksor-starter/KSOR-STAMP-VERSION` from `approval_authorities` in the same
93
+ change — nothing of theirs should be approved by a tool. Never record an
94
+ approval nobody gave, and never write a `verified` entry: the approval is not
95
+ a review, and inventing one would retire the tier that exists to say nobody
96
+ has checked this.
97
+ - Run `ksor build` afterwards: it regenerates every folder's `index.md` from
98
+ the new title and refuses anything the profile does not accept.
61
99
  - Restart `pnpm dev` afterwards so the site picks the new title up, and
62
100
  show the owner their name on the page.
63
101
  - Offer to capture the source list from question 4 as the first real
@@ -38,7 +38,8 @@ Read `<doc>.md` completely before writing anything. Note as you go:
38
38
  - **the numbers** — thresholds, deadlines, limits, and their units
39
39
  - **the cases** — what happens in each situation it names
40
40
  - **the boundary** — what it explicitly does NOT cover
41
- - **its governance** — `owner`, `effective`, `status` from the frontmatter
41
+ - **its governance** — `status`, `ksor.owner` and `ksor.effective_from` from
42
+ the frontmatter
42
43
 
43
44
  If the document carries `<doc>.summary.md`, read that too: it is a reviewed
44
45
  compression of the same thing, and it tells you what the author thought was
@@ -108,16 +109,17 @@ the session it was made for, because the next presenter trusts it.
108
109
  ## 4 · Verify it
109
110
 
110
111
  ```sh
111
- pnpm check # refuses an orphan, frontmatter, or a malformed deck
112
- pnpm dev # look at the page — the deck renders at the end
112
+ pnpm check # refuses an orphan deck
113
+ pnpm dev # look at the page — the deck renders after the introduction,
114
+ # immediately before the first `##` section
113
115
  ```
114
116
 
115
- `pnpm build` refuses:
117
+ `pnpm build` refuses — the deck's own shape is checked in the site build, not
118
+ by `pnpm check`:
116
119
 
117
120
  - `ksor-slides-empty` — neither `deck:` nor `slides.url:`; nothing to show
118
121
  - `ksor-slides-two-sources` — both, so nothing says which one governs
119
122
  - `ksor-attachment-orphan` — no `<doc>.md` beside it
120
- - `ksor-attachment-frontmatter` — an attachment carries none of its own
121
123
 
122
124
  ## 5 · Tell the owner what you did
123
125
 
@@ -2,7 +2,7 @@
2
2
  name: make-summary
3
3
  description: Write the summary of a document and attach it, so it renders as a second tab on that document's page. Use when the owner says "summarise X", "make a summary for this", "add summaries to the record", "give me the short version", or asks for a TL;DR, an abstract or a précis of a governed document.
4
4
  metadata:
5
- version: "1.0.0"
5
+ version: "1.1.0"
6
6
  ---
7
7
 
8
8
  # Writing the summary of a document
@@ -48,17 +48,24 @@ Read `<doc>.md` completely before writing anything. Note as you go:
48
48
  - **the numbers** — thresholds, deadlines, limits, and their units
49
49
  - **each `##` section** — and the one thing it is there to say
50
50
  - **the boundary** — what the document explicitly does NOT cover
51
- - **its governance** — `owner`, `effective`, `status` from the frontmatter
51
+ - **its governance** — `status`, `ksor.owner` and `ksor.effective_from` from
52
+ the frontmatter
52
53
 
53
54
  If the document already carries `<doc>.slides.yaml`, read it: it is a reviewed
54
55
  compression of the same thing, and the two must not disagree.
55
56
 
56
57
  ## 2 · Write the summary
57
58
 
58
- Write `<doc>.summary.md` beside the document. **No frontmatter** an
59
- attachment carries none, and the checker refuses one:
59
+ Write `<doc>.summary.md` beside the document. Its frontmatter is exactly one
60
+ key and the checker refuses any other — a summary inherits its parent's
61
+ audience, status and takedown, and a second key there would claim governance a
62
+ non-document cannot carry:
60
63
 
61
64
  ```markdown
65
+ ---
66
+ type: Summary
67
+ ---
68
+
62
69
  The lead: what this document settles, in one or two sentences, in the
63
70
  document's own words. **Bold the thing a reader must not misremember.**
64
71
 
@@ -107,14 +114,14 @@ document, not before it.
107
114
  ## 4 · Verify it
108
115
 
109
116
  ```sh
110
- pnpm check # refuses an orphan or an attachment carrying frontmatter
117
+ pnpm check # refuses an orphan, or frontmatter that is not exactly `type: Summary`
111
118
  pnpm dev # open the page — a Summary tab appears beside Document
112
119
  ```
113
120
 
114
121
  The build refuses:
115
122
 
116
123
  - `ksor-attachment-orphan` — no `<doc>.md` beside it
117
- - `ksor-attachment-frontmatter` — an attachment carries none of its own
124
+ - `ksor-attachment-frontmatter` — anything but exactly `type: Summary`
118
125
 
119
126
  If no Summary tab appears, the file name is wrong: it must be exactly
120
127
  `<doc>.summary.md`, matching the document's own name.
@@ -2,7 +2,7 @@
2
2
  name: add-sources
3
3
  description: Turn source material — documents, pages, pasted text, notes — into governed knowledge in knowledge/. Use when the owner shares material to add, says "add this to the knowledge base", or asks how to get existing content in. Not for editing the site.
4
4
  metadata:
5
- version: "1.2.0"
5
+ version: "1.3.0"
6
6
  ---
7
7
 
8
8
  # Add sources
@@ -16,31 +16,76 @@ The rules that make it _governed_ rather than merely stored:
16
16
  hyphens, a folder per natural grouping. Plain CommonMark `.md` — if the
17
17
  source is rich (tables, images), tables become markdown tables and images
18
18
  land _beside the document_ with relative links.
19
- - A folder's front page is `<folder>/index.md`; reading order is the
20
- `order:` frontmatter key (ordered documents first, ascending; the rest
21
- follow alphabetically) never `meta.json` or `sidebar_position`.
22
- - Frontmatter: `title` and `status: draft` always; add `owner` (who stands
23
- behind this content) and `provenance` (a list naming the actual sources —
24
- file names, systems, people, dates) whenever the owner can tell you.
25
- Precision matters: "Finance policy manual §4.2, 2025 edition" governs;
26
- "internal docs" does not.
27
- - When `instance.md` declares `audiences:`, ask the owner which audience the
28
- new material belongs to and write it as `visibility:` never guess that
29
- restricted material is public.
19
+ - A folder's `index.md` is GENERATED by `ksor build` and committed — never
20
+ author one. A folder's own introduction is a named document inside it,
21
+ such as `overview.md`. Reading order is the `order:` frontmatter key
22
+ (ordered documents first, ascending; the rest follow alphabetically)
23
+ never `meta.json` or `sidebar_position`.
24
+ - Frontmatter is the KSoR Profile of OKF. Always: `type: Document`, `title`,
25
+ `description` (one sentence), `status: draft`, and `ksor.audience` (a
26
+ list). Reach for a reserved `type` — `Policy`, `Procedure`, `Control`,
27
+ `Standard`, `Definition`, `Decision Record`, `Example`,
28
+ `Attested Computation` when the knowledge really is one; those additionally require `sources` and
29
+ `ksor.owner`, which is the point of them.
30
+
31
+ ```yaml
32
+ ---
33
+ type: Policy
34
+ title: Purchase approval
35
+ description: Who may approve a purchase, at which thresholds.
36
+ status: draft
37
+ sources:
38
+ - id: fin-2025
39
+ title: Finance policy manual §4.2, 2025 edition
40
+ resource: https://intranet.example.com/finance/manual.pdf
41
+ ksor:
42
+ audience: [public]
43
+ owner: team:finance
44
+ ---
45
+
46
+ A purchase above 10,000 needs a director's signature. [^fin-2025]
47
+
48
+ [^fin-2025]: Finance policy manual §4.2, 2025 edition.
49
+ ```
50
+
51
+ Every source needs a `resource` — a URL where one exists, otherwise the
52
+ scope descriptor that names it ("Finance policy manual §4.2, 2025
53
+ edition"). Precision matters: that governs; "internal docs" does not. A
54
+ claim cites ONE of them by footnote, and the label must match a
55
+ `sources[].id` or the checker refuses it.
56
+
57
+ - `status: draft` always, and never anything else from here: `stable` needs
58
+ `ksor.approval` by an actor `.ksor/governance.yaml` names, and recording
59
+ an approval nobody gave is the one thing this skill must never do. Ask the
60
+ owner; if they approve, THEY are the approver and you write down what they
61
+ said.
62
+ - When `.ksor/governance.yaml` registers audiences, ask the owner which of
63
+ them may read the new material and list every one in `ksor.audience` —
64
+ never guess that restricted material is public, and never write an
65
+ identifier the registry does not declare (the checker refuses it, because
66
+ a typo reads as a restriction).
30
67
 
31
68
  ## Fidelity rules
32
69
 
33
70
  - **Copy load-bearing values exactly** — numbers, thresholds, dates, names.
34
71
  Never round, never paraphrase a figure.
35
- - **Two disagreeing sources stay two statements**, each with its provenance
36
- — never smooth a conflict into one invented truth; flag it to the owner.
72
+ - **Two disagreeing sources stay two statements**, each with its own
73
+ footnote — never smooth a conflict into one invented truth; flag it to the
74
+ owner.
37
75
  - **Do not fill gaps from general knowledge.** If the source doesn't cover
38
76
  something, the record doesn't either — that boundary is the product.
39
- - A document replacing an older one: mark the old one `status: superseded`
40
- with `superseded_by:` pointing at the new never delete it.
77
+ - A document replacing an older one: mark the old one `status: deprecated`
78
+ with `ksor.deprecated: { by, at }` (a takedown authority the policy names, or
79
+ the owner an `ownership:` rule resolves — never the document's own
80
+ `ksor.owner`; ask, never guess) and `ksor.superseded_by:` naming the
81
+ successor by id (`policies/refunds-v2`, no `./` and no `.md`) — never
82
+ delete it. The successor must exist, be `stable`, and be readable by every
83
+ reader of the deprecated one.
41
84
 
42
85
  ## Finish every batch
43
86
 
44
87
  Run `pnpm check` and fix what it reports (its errors explain themselves),
45
- then show the owner the rendered result (`pnpm dev`) the site is the
46
- review surface: you write, they check.
88
+ then `ksor build` to regenerate every folder's `index.md` and write
89
+ `build.lock.json`, and commit both with the documents. Then show the owner
90
+ the rendered result (`pnpm dev`) — the site is the review surface: you write,
91
+ they check.
@@ -2,45 +2,54 @@
2
2
  name: format-checker
3
3
  description: The record's format rules as a runnable check — frontmatter, filenames, links, structure. Use before handing off any change to knowledge/, when a check fails and you need to fix it, or when unsure whether a document is well-formed. Run with `pnpm check` (or node .agents/skills/format-checker/check.mjs).
4
4
  metadata:
5
- version: "1.2.0"
5
+ version: "2.1.0"
6
6
  ---
7
7
 
8
8
  # Format checker
9
9
 
10
- `pnpm check` runs `check.mjs` — dependency-free Node, owned by this repo. It
11
- enforces what AGENTS.md states in prose:
10
+ `pnpm check` runs `check.mjs` — a self-contained Node program that needs no
11
+ install. It is **generated** by ksor from the same rule set `ksor build` and
12
+ `ksor ingest` run, so the three can never disagree about what a well-formed
13
+ record is. Do not edit it: `ksor init` writes it and `ksor migrate` rewrites
14
+ both copies of it when you upgrade the tool, so an edit is overwritten rather
15
+ than kept. It is read-only in the other direction too — it reports, and never
16
+ rewrites a file.
12
17
 
13
- - `knowledge/` holds CommonMark `.md` and images only no `.mdx`, no
14
- `meta.json`, no other file types and it is never empty; a record with no
15
- documents stands behind nothing.
16
- - Every document carries `title` + `status` (level-0 requirement); the full
17
- allowed key set is closed; a `superseded` document names a `superseded_by`
18
- that resolves to a document that exists.
19
- - Filenames are portable identities: lowercase, Windows-safe, no spaces, no
20
- case-collisions, no `foo.md` + `foo/index.md` pairs, no parentheses.
21
- (`.DS_Store` and friends are skipped, never reported.)
22
- - Relative links resolve and never leave `knowledge/` inline,
23
- `<angle-bracketed>`, and reference-style (`[text][label]` with its
24
- `[label]: target` definition) alike. Links inside code spans and fenced
25
- blocks are code, not links, and are ignored.
26
- - `instance.md` exists, is `format: 1`, and carries only the keys the format
27
- defines an unknown key is named, never ignored.
28
- - The audience model, when there is one: `audiences:` is ordered least- to
29
- most-restricted with `public` first, no duplicates, and never without
30
- `default_visibility:`; a document's `visibility:` names one of the declared
31
- audiences; and no link or `superseded_by:` points from a wider audience at a
32
- narrower one the leak no single build can catch, since the build that
33
- publishes the pointer has already dropped its target. A record that declares
34
- no `audiences:` is checked exactly as it was before the key existed.
18
+ If its refusals contradict this document, the checker is older than the record:
19
+ upgrade `@panaversity/ksor` and re-run `ksor migrate`, and never "fix" the
20
+ record by undoing what the migration wrote.
21
+
22
+ What it holds the record to (the full contract is ksor's record spec):
23
+
24
+ - Every document in `knowledge/` is a concept in the KSoR Profile of OKF:
25
+ frontmatter is real YAML carrying `type`, `title`, `description`, `status`
26
+ (`draft | stable | deprecated`) and `ksor.audience` (a list; `public` or
27
+ audiences registered in `.ksor/governance.yaml`). A `stable` concept carries
28
+ `generated` and an approval by an authorised actor; a `deprecated` one says
29
+ who deprecated it and usually names its successor; a reserved type (`Policy`,
30
+ `Procedure`, …) names `sources` and `ksor.owner`. Every timestamp is an
31
+ instant with an offset; every footnote label matches a `sources[].id`.
32
+ - `.ksor/governance.yaml` exists and names approval and takedown authorities;
33
+ `.ksor/takedowns.yaml` is append-only, every entry by a takedown authority,
34
+ and never names a concept that no longer exists.
35
+ - `index.md` files are generated by `ksor build`, never authored a stale or
36
+ missing one is refused (`ksor-index-stale`; run `ksor build`). `log.md` and
37
+ `README.md` are reserved names.
38
+ - Filenames are portable identities: lowercase ascii, no spaces, no
39
+ case-collisions, no `x.md` beside `x/`, no parentheses or leading
40
+ underscore. `knowledge/` holds `.md`, companions (`<doc>.summary.md`,
41
+ `<doc>.{flashcards,quiz,slides}.yaml`) and images only.
42
+ - Links resolve inside `knowledge/` — inline, `<angle-bracketed>` and
43
+ reference-style alike; code is never a link — and never reach a document
44
+ that not every reader of the source may read (the widening rule).
45
+ - `instance.md` is `format: 2` with the closed key set the profile defines.
35
46
  - `CLAUDE.md` stays a one-line pointer; `.agents/skills/` and
36
- `.claude/skills/` hold the same files byte for byte **in both directions**
37
- (a file only one tree carries is a rule nobody reviewed); the site contains
38
- no content files.
47
+ `.claude/skills/` hold the same files byte for byte in both directions; the
48
+ site contains no content files.
39
49
 
40
- Every failure prints what is wrong, why the rule exists, and the fix — obey
41
- the printed fix literally; if it doesn't resolve the problem, that is a bug
42
- worth reporting to ksor.
50
+ Every failure prints where, the rule's slug (`problem: ksor-…`), why the rule
51
+ exists, and the fix — obey the printed fix literally; if it doesn't resolve
52
+ the problem, that is a bug worth reporting to ksor.
43
53
 
44
54
  When you edit any skill under `.agents/skills/`, re-copy it to
45
- `.claude/skills/` — the checker holds the two trees identical, and it now
46
- notices a file added on either side.
55
+ `.claude/skills/` — the checker holds the two trees identical.