gcf-aif-ext 0.2.0

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 (294) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +41 -0
  3. package/commands/gcf.js +173 -0
  4. package/extension.json +24 -0
  5. package/hooks/pre-commit.js +91 -0
  6. package/injections/commit-status.md +6 -0
  7. package/injections/plan-context.md +8 -0
  8. package/injections/review-pillars.md +7 -0
  9. package/lib/anchors.js +109 -0
  10. package/lib/audit-core.js +102 -0
  11. package/lib/context.js +77 -0
  12. package/lib/frontmatter.js +26 -0
  13. package/lib/gcf-paths.js +60 -0
  14. package/lib/git.js +19 -0
  15. package/lib/id.js +42 -0
  16. package/lib/index-gen.js +51 -0
  17. package/lib/linter.js +61 -0
  18. package/lib/playtest-list.js +13 -0
  19. package/lib/safe-path.js +71 -0
  20. package/lib/transitions.js +30 -0
  21. package/lib/validate-card.js +48 -0
  22. package/lib/verdict-fs.js +126 -0
  23. package/node_modules/cnlp-kit/CHANGELOG.md +625 -0
  24. package/node_modules/cnlp-kit/LICENSE +21 -0
  25. package/node_modules/cnlp-kit/README.md +242 -0
  26. package/node_modules/cnlp-kit/bin/cnlp.js +334 -0
  27. package/node_modules/cnlp-kit/cnlp-format.md +470 -0
  28. package/node_modules/cnlp-kit/package.json +40 -0
  29. package/node_modules/cnlp-kit/profiles/adr.md +129 -0
  30. package/node_modules/cnlp-kit/profiles/api.md +87 -0
  31. package/node_modules/cnlp-kit/profiles/concept.md +70 -0
  32. package/node_modules/cnlp-kit/profiles/docset.md +103 -0
  33. package/node_modules/cnlp-kit/profiles/guide.md +51 -0
  34. package/node_modules/cnlp-kit/profiles/profile.md +69 -0
  35. package/node_modules/cnlp-kit/profiles/reference.md +61 -0
  36. package/node_modules/cnlp-kit/profiles/skill.md +75 -0
  37. package/node_modules/cnlp-kit/profiles/task.md +65 -0
  38. package/node_modules/cnlp-kit/quality-rules.md +69 -0
  39. package/node_modules/cnlp-kit/skills/cnlp-docset/SKILL.md +73 -0
  40. package/node_modules/cnlp-kit/skills/cnlp-migrate/SKILL.md +64 -0
  41. package/node_modules/cnlp-kit/src/cnlp.js +534 -0
  42. package/node_modules/cnlp-kit/src/config.js +352 -0
  43. package/node_modules/yaml/LICENSE +13 -0
  44. package/node_modules/yaml/README.md +172 -0
  45. package/node_modules/yaml/bin.mjs +11 -0
  46. package/node_modules/yaml/browser/dist/compose/compose-collection.js +88 -0
  47. package/node_modules/yaml/browser/dist/compose/compose-doc.js +43 -0
  48. package/node_modules/yaml/browser/dist/compose/compose-node.js +109 -0
  49. package/node_modules/yaml/browser/dist/compose/compose-scalar.js +86 -0
  50. package/node_modules/yaml/browser/dist/compose/composer.js +219 -0
  51. package/node_modules/yaml/browser/dist/compose/resolve-block-map.js +115 -0
  52. package/node_modules/yaml/browser/dist/compose/resolve-block-scalar.js +198 -0
  53. package/node_modules/yaml/browser/dist/compose/resolve-block-seq.js +49 -0
  54. package/node_modules/yaml/browser/dist/compose/resolve-end.js +37 -0
  55. package/node_modules/yaml/browser/dist/compose/resolve-flow-collection.js +207 -0
  56. package/node_modules/yaml/browser/dist/compose/resolve-flow-scalar.js +226 -0
  57. package/node_modules/yaml/browser/dist/compose/resolve-props.js +146 -0
  58. package/node_modules/yaml/browser/dist/compose/util-contains-newline.js +34 -0
  59. package/node_modules/yaml/browser/dist/compose/util-empty-scalar-position.js +26 -0
  60. package/node_modules/yaml/browser/dist/compose/util-flow-indent-check.js +15 -0
  61. package/node_modules/yaml/browser/dist/compose/util-map-includes.js +13 -0
  62. package/node_modules/yaml/browser/dist/doc/Document.js +335 -0
  63. package/node_modules/yaml/browser/dist/doc/anchors.js +71 -0
  64. package/node_modules/yaml/browser/dist/doc/applyReviver.js +55 -0
  65. package/node_modules/yaml/browser/dist/doc/createNode.js +88 -0
  66. package/node_modules/yaml/browser/dist/doc/directives.js +176 -0
  67. package/node_modules/yaml/browser/dist/errors.js +57 -0
  68. package/node_modules/yaml/browser/dist/index.js +17 -0
  69. package/node_modules/yaml/browser/dist/log.js +11 -0
  70. package/node_modules/yaml/browser/dist/nodes/Alias.js +118 -0
  71. package/node_modules/yaml/browser/dist/nodes/Collection.js +147 -0
  72. package/node_modules/yaml/browser/dist/nodes/Node.js +38 -0
  73. package/node_modules/yaml/browser/dist/nodes/Pair.js +36 -0
  74. package/node_modules/yaml/browser/dist/nodes/Scalar.js +24 -0
  75. package/node_modules/yaml/browser/dist/nodes/YAMLMap.js +144 -0
  76. package/node_modules/yaml/browser/dist/nodes/YAMLSeq.js +113 -0
  77. package/node_modules/yaml/browser/dist/nodes/addPairToJSMap.js +63 -0
  78. package/node_modules/yaml/browser/dist/nodes/identity.js +36 -0
  79. package/node_modules/yaml/browser/dist/nodes/toJS.js +37 -0
  80. package/node_modules/yaml/browser/dist/parse/cst-scalar.js +214 -0
  81. package/node_modules/yaml/browser/dist/parse/cst-stringify.js +61 -0
  82. package/node_modules/yaml/browser/dist/parse/cst-visit.js +97 -0
  83. package/node_modules/yaml/browser/dist/parse/cst.js +98 -0
  84. package/node_modules/yaml/browser/dist/parse/lexer.js +721 -0
  85. package/node_modules/yaml/browser/dist/parse/line-counter.js +39 -0
  86. package/node_modules/yaml/browser/dist/parse/parser.js +975 -0
  87. package/node_modules/yaml/browser/dist/public-api.js +102 -0
  88. package/node_modules/yaml/browser/dist/schema/Schema.js +37 -0
  89. package/node_modules/yaml/browser/dist/schema/common/map.js +17 -0
  90. package/node_modules/yaml/browser/dist/schema/common/null.js +15 -0
  91. package/node_modules/yaml/browser/dist/schema/common/seq.js +17 -0
  92. package/node_modules/yaml/browser/dist/schema/common/string.js +14 -0
  93. package/node_modules/yaml/browser/dist/schema/core/bool.js +19 -0
  94. package/node_modules/yaml/browser/dist/schema/core/float.js +43 -0
  95. package/node_modules/yaml/browser/dist/schema/core/int.js +38 -0
  96. package/node_modules/yaml/browser/dist/schema/core/schema.js +23 -0
  97. package/node_modules/yaml/browser/dist/schema/json/schema.js +62 -0
  98. package/node_modules/yaml/browser/dist/schema/tags.js +96 -0
  99. package/node_modules/yaml/browser/dist/schema/yaml-1.1/binary.js +58 -0
  100. package/node_modules/yaml/browser/dist/schema/yaml-1.1/bool.js +26 -0
  101. package/node_modules/yaml/browser/dist/schema/yaml-1.1/float.js +46 -0
  102. package/node_modules/yaml/browser/dist/schema/yaml-1.1/int.js +71 -0
  103. package/node_modules/yaml/browser/dist/schema/yaml-1.1/merge.js +67 -0
  104. package/node_modules/yaml/browser/dist/schema/yaml-1.1/omap.js +74 -0
  105. package/node_modules/yaml/browser/dist/schema/yaml-1.1/pairs.js +78 -0
  106. package/node_modules/yaml/browser/dist/schema/yaml-1.1/schema.js +39 -0
  107. package/node_modules/yaml/browser/dist/schema/yaml-1.1/set.js +93 -0
  108. package/node_modules/yaml/browser/dist/schema/yaml-1.1/timestamp.js +101 -0
  109. package/node_modules/yaml/browser/dist/stringify/foldFlowLines.js +146 -0
  110. package/node_modules/yaml/browser/dist/stringify/stringify.js +129 -0
  111. package/node_modules/yaml/browser/dist/stringify/stringifyCollection.js +153 -0
  112. package/node_modules/yaml/browser/dist/stringify/stringifyComment.js +20 -0
  113. package/node_modules/yaml/browser/dist/stringify/stringifyDocument.js +85 -0
  114. package/node_modules/yaml/browser/dist/stringify/stringifyNumber.js +25 -0
  115. package/node_modules/yaml/browser/dist/stringify/stringifyPair.js +150 -0
  116. package/node_modules/yaml/browser/dist/stringify/stringifyString.js +336 -0
  117. package/node_modules/yaml/browser/dist/util.js +11 -0
  118. package/node_modules/yaml/browser/dist/visit.js +233 -0
  119. package/node_modules/yaml/browser/index.js +5 -0
  120. package/node_modules/yaml/browser/package.json +3 -0
  121. package/node_modules/yaml/dist/cli.d.ts +8 -0
  122. package/node_modules/yaml/dist/cli.mjs +201 -0
  123. package/node_modules/yaml/dist/compose/compose-collection.d.ts +11 -0
  124. package/node_modules/yaml/dist/compose/compose-collection.js +90 -0
  125. package/node_modules/yaml/dist/compose/compose-doc.d.ts +7 -0
  126. package/node_modules/yaml/dist/compose/compose-doc.js +45 -0
  127. package/node_modules/yaml/dist/compose/compose-node.d.ts +29 -0
  128. package/node_modules/yaml/dist/compose/compose-node.js +112 -0
  129. package/node_modules/yaml/dist/compose/compose-scalar.d.ts +5 -0
  130. package/node_modules/yaml/dist/compose/compose-scalar.js +88 -0
  131. package/node_modules/yaml/dist/compose/composer.d.ts +63 -0
  132. package/node_modules/yaml/dist/compose/composer.js +224 -0
  133. package/node_modules/yaml/dist/compose/resolve-block-map.d.ts +6 -0
  134. package/node_modules/yaml/dist/compose/resolve-block-map.js +117 -0
  135. package/node_modules/yaml/dist/compose/resolve-block-scalar.d.ts +11 -0
  136. package/node_modules/yaml/dist/compose/resolve-block-scalar.js +200 -0
  137. package/node_modules/yaml/dist/compose/resolve-block-seq.d.ts +6 -0
  138. package/node_modules/yaml/dist/compose/resolve-block-seq.js +51 -0
  139. package/node_modules/yaml/dist/compose/resolve-end.d.ts +6 -0
  140. package/node_modules/yaml/dist/compose/resolve-end.js +39 -0
  141. package/node_modules/yaml/dist/compose/resolve-flow-collection.d.ts +7 -0
  142. package/node_modules/yaml/dist/compose/resolve-flow-collection.js +209 -0
  143. package/node_modules/yaml/dist/compose/resolve-flow-scalar.d.ts +10 -0
  144. package/node_modules/yaml/dist/compose/resolve-flow-scalar.js +228 -0
  145. package/node_modules/yaml/dist/compose/resolve-props.d.ts +23 -0
  146. package/node_modules/yaml/dist/compose/resolve-props.js +148 -0
  147. package/node_modules/yaml/dist/compose/util-contains-newline.d.ts +2 -0
  148. package/node_modules/yaml/dist/compose/util-contains-newline.js +36 -0
  149. package/node_modules/yaml/dist/compose/util-empty-scalar-position.d.ts +2 -0
  150. package/node_modules/yaml/dist/compose/util-empty-scalar-position.js +28 -0
  151. package/node_modules/yaml/dist/compose/util-flow-indent-check.d.ts +3 -0
  152. package/node_modules/yaml/dist/compose/util-flow-indent-check.js +17 -0
  153. package/node_modules/yaml/dist/compose/util-map-includes.d.ts +4 -0
  154. package/node_modules/yaml/dist/compose/util-map-includes.js +15 -0
  155. package/node_modules/yaml/dist/doc/Document.d.ts +141 -0
  156. package/node_modules/yaml/dist/doc/Document.js +337 -0
  157. package/node_modules/yaml/dist/doc/anchors.d.ts +24 -0
  158. package/node_modules/yaml/dist/doc/anchors.js +76 -0
  159. package/node_modules/yaml/dist/doc/applyReviver.d.ts +9 -0
  160. package/node_modules/yaml/dist/doc/applyReviver.js +57 -0
  161. package/node_modules/yaml/dist/doc/createNode.d.ts +17 -0
  162. package/node_modules/yaml/dist/doc/createNode.js +90 -0
  163. package/node_modules/yaml/dist/doc/directives.d.ts +49 -0
  164. package/node_modules/yaml/dist/doc/directives.js +178 -0
  165. package/node_modules/yaml/dist/errors.d.ts +21 -0
  166. package/node_modules/yaml/dist/errors.js +62 -0
  167. package/node_modules/yaml/dist/index.d.ts +25 -0
  168. package/node_modules/yaml/dist/index.js +50 -0
  169. package/node_modules/yaml/dist/log.d.ts +3 -0
  170. package/node_modules/yaml/dist/log.js +19 -0
  171. package/node_modules/yaml/dist/nodes/Alias.d.ts +29 -0
  172. package/node_modules/yaml/dist/nodes/Alias.js +120 -0
  173. package/node_modules/yaml/dist/nodes/Collection.d.ts +73 -0
  174. package/node_modules/yaml/dist/nodes/Collection.js +151 -0
  175. package/node_modules/yaml/dist/nodes/Node.d.ts +53 -0
  176. package/node_modules/yaml/dist/nodes/Node.js +40 -0
  177. package/node_modules/yaml/dist/nodes/Pair.d.ts +22 -0
  178. package/node_modules/yaml/dist/nodes/Pair.js +39 -0
  179. package/node_modules/yaml/dist/nodes/Scalar.d.ts +47 -0
  180. package/node_modules/yaml/dist/nodes/Scalar.js +27 -0
  181. package/node_modules/yaml/dist/nodes/YAMLMap.d.ts +53 -0
  182. package/node_modules/yaml/dist/nodes/YAMLMap.js +147 -0
  183. package/node_modules/yaml/dist/nodes/YAMLSeq.d.ts +60 -0
  184. package/node_modules/yaml/dist/nodes/YAMLSeq.js +115 -0
  185. package/node_modules/yaml/dist/nodes/addPairToJSMap.d.ts +4 -0
  186. package/node_modules/yaml/dist/nodes/addPairToJSMap.js +65 -0
  187. package/node_modules/yaml/dist/nodes/identity.d.ts +23 -0
  188. package/node_modules/yaml/dist/nodes/identity.js +53 -0
  189. package/node_modules/yaml/dist/nodes/toJS.d.ts +29 -0
  190. package/node_modules/yaml/dist/nodes/toJS.js +39 -0
  191. package/node_modules/yaml/dist/options.d.ts +350 -0
  192. package/node_modules/yaml/dist/parse/cst-scalar.d.ts +64 -0
  193. package/node_modules/yaml/dist/parse/cst-scalar.js +218 -0
  194. package/node_modules/yaml/dist/parse/cst-stringify.d.ts +8 -0
  195. package/node_modules/yaml/dist/parse/cst-stringify.js +63 -0
  196. package/node_modules/yaml/dist/parse/cst-visit.d.ts +39 -0
  197. package/node_modules/yaml/dist/parse/cst-visit.js +99 -0
  198. package/node_modules/yaml/dist/parse/cst.d.ts +109 -0
  199. package/node_modules/yaml/dist/parse/cst.js +112 -0
  200. package/node_modules/yaml/dist/parse/lexer.d.ts +87 -0
  201. package/node_modules/yaml/dist/parse/lexer.js +723 -0
  202. package/node_modules/yaml/dist/parse/line-counter.d.ts +22 -0
  203. package/node_modules/yaml/dist/parse/line-counter.js +41 -0
  204. package/node_modules/yaml/dist/parse/parser.d.ts +84 -0
  205. package/node_modules/yaml/dist/parse/parser.js +980 -0
  206. package/node_modules/yaml/dist/public-api.d.ts +44 -0
  207. package/node_modules/yaml/dist/public-api.js +107 -0
  208. package/node_modules/yaml/dist/schema/Schema.d.ts +17 -0
  209. package/node_modules/yaml/dist/schema/Schema.js +39 -0
  210. package/node_modules/yaml/dist/schema/common/map.d.ts +2 -0
  211. package/node_modules/yaml/dist/schema/common/map.js +19 -0
  212. package/node_modules/yaml/dist/schema/common/null.d.ts +4 -0
  213. package/node_modules/yaml/dist/schema/common/null.js +17 -0
  214. package/node_modules/yaml/dist/schema/common/seq.d.ts +2 -0
  215. package/node_modules/yaml/dist/schema/common/seq.js +19 -0
  216. package/node_modules/yaml/dist/schema/common/string.d.ts +2 -0
  217. package/node_modules/yaml/dist/schema/common/string.js +16 -0
  218. package/node_modules/yaml/dist/schema/core/bool.d.ts +4 -0
  219. package/node_modules/yaml/dist/schema/core/bool.js +21 -0
  220. package/node_modules/yaml/dist/schema/core/float.d.ts +4 -0
  221. package/node_modules/yaml/dist/schema/core/float.js +47 -0
  222. package/node_modules/yaml/dist/schema/core/int.d.ts +4 -0
  223. package/node_modules/yaml/dist/schema/core/int.js +42 -0
  224. package/node_modules/yaml/dist/schema/core/schema.d.ts +1 -0
  225. package/node_modules/yaml/dist/schema/core/schema.js +25 -0
  226. package/node_modules/yaml/dist/schema/json/schema.d.ts +2 -0
  227. package/node_modules/yaml/dist/schema/json/schema.js +64 -0
  228. package/node_modules/yaml/dist/schema/json-schema.d.ts +69 -0
  229. package/node_modules/yaml/dist/schema/tags.d.ts +48 -0
  230. package/node_modules/yaml/dist/schema/tags.js +99 -0
  231. package/node_modules/yaml/dist/schema/types.d.ts +92 -0
  232. package/node_modules/yaml/dist/schema/yaml-1.1/binary.d.ts +2 -0
  233. package/node_modules/yaml/dist/schema/yaml-1.1/binary.js +70 -0
  234. package/node_modules/yaml/dist/schema/yaml-1.1/bool.d.ts +7 -0
  235. package/node_modules/yaml/dist/schema/yaml-1.1/bool.js +29 -0
  236. package/node_modules/yaml/dist/schema/yaml-1.1/float.d.ts +4 -0
  237. package/node_modules/yaml/dist/schema/yaml-1.1/float.js +50 -0
  238. package/node_modules/yaml/dist/schema/yaml-1.1/int.d.ts +5 -0
  239. package/node_modules/yaml/dist/schema/yaml-1.1/int.js +76 -0
  240. package/node_modules/yaml/dist/schema/yaml-1.1/merge.d.ts +9 -0
  241. package/node_modules/yaml/dist/schema/yaml-1.1/merge.js +71 -0
  242. package/node_modules/yaml/dist/schema/yaml-1.1/omap.d.ts +22 -0
  243. package/node_modules/yaml/dist/schema/yaml-1.1/omap.js +77 -0
  244. package/node_modules/yaml/dist/schema/yaml-1.1/pairs.d.ts +10 -0
  245. package/node_modules/yaml/dist/schema/yaml-1.1/pairs.js +82 -0
  246. package/node_modules/yaml/dist/schema/yaml-1.1/schema.d.ts +1 -0
  247. package/node_modules/yaml/dist/schema/yaml-1.1/schema.js +41 -0
  248. package/node_modules/yaml/dist/schema/yaml-1.1/set.d.ts +28 -0
  249. package/node_modules/yaml/dist/schema/yaml-1.1/set.js +96 -0
  250. package/node_modules/yaml/dist/schema/yaml-1.1/timestamp.d.ts +6 -0
  251. package/node_modules/yaml/dist/schema/yaml-1.1/timestamp.js +105 -0
  252. package/node_modules/yaml/dist/stringify/foldFlowLines.d.ts +34 -0
  253. package/node_modules/yaml/dist/stringify/foldFlowLines.js +151 -0
  254. package/node_modules/yaml/dist/stringify/stringify.d.ts +21 -0
  255. package/node_modules/yaml/dist/stringify/stringify.js +132 -0
  256. package/node_modules/yaml/dist/stringify/stringifyCollection.d.ts +17 -0
  257. package/node_modules/yaml/dist/stringify/stringifyCollection.js +155 -0
  258. package/node_modules/yaml/dist/stringify/stringifyComment.d.ts +10 -0
  259. package/node_modules/yaml/dist/stringify/stringifyComment.js +24 -0
  260. package/node_modules/yaml/dist/stringify/stringifyDocument.d.ts +4 -0
  261. package/node_modules/yaml/dist/stringify/stringifyDocument.js +87 -0
  262. package/node_modules/yaml/dist/stringify/stringifyNumber.d.ts +2 -0
  263. package/node_modules/yaml/dist/stringify/stringifyNumber.js +27 -0
  264. package/node_modules/yaml/dist/stringify/stringifyPair.d.ts +3 -0
  265. package/node_modules/yaml/dist/stringify/stringifyPair.js +152 -0
  266. package/node_modules/yaml/dist/stringify/stringifyString.d.ts +9 -0
  267. package/node_modules/yaml/dist/stringify/stringifyString.js +338 -0
  268. package/node_modules/yaml/dist/test-events.d.ts +4 -0
  269. package/node_modules/yaml/dist/test-events.js +134 -0
  270. package/node_modules/yaml/dist/util.d.ts +16 -0
  271. package/node_modules/yaml/dist/util.js +28 -0
  272. package/node_modules/yaml/dist/visit.d.ts +102 -0
  273. package/node_modules/yaml/dist/visit.js +236 -0
  274. package/node_modules/yaml/package.json +97 -0
  275. package/node_modules/yaml/util.js +2 -0
  276. package/package.json +54 -0
  277. package/profiles/card.md +65 -0
  278. package/profiles/pillars.md +31 -0
  279. package/profiles/system.md +56 -0
  280. package/schemas/card.schema.json +30 -0
  281. package/skills/gcf-adopt/SKILL.md +41 -0
  282. package/skills/gcf-audit/SKILL.md +27 -0
  283. package/skills/gcf-card/SKILL.md +35 -0
  284. package/skills/gcf-debate/SKILL.md +33 -0
  285. package/skills/gcf-ingest/SKILL.md +38 -0
  286. package/skills/gcf-init/SKILL.md +32 -0
  287. package/skills/gcf-verdict/SKILL.md +32 -0
  288. package/skills/gcf-vision/SKILL.md +33 -0
  289. package/templates/PILLARS.md +8 -0
  290. package/templates/backlog.md +4 -0
  291. package/templates/card.md +34 -0
  292. package/templates/cnlp.config.json +8 -0
  293. package/templates/config.yml +8 -0
  294. package/templates/system.md +22 -0
@@ -0,0 +1,625 @@
1
+ # Changelog
2
+
3
+ The format has its own version from here on. It used to be stamped with the release number of
4
+ an ADR extension, which made a breaking change to the format invisible inside that project's
5
+ patch release.
6
+
7
+ ## 3.4.1
8
+
9
+ A record-list of multi-key records read as a wall. The only boundary between 2 records was a line
10
+ opening with `- ` rather than with 2 spaces, so finding where the third record ended meant scanning
11
+ forward for the next one. A blank line makes that boundary visible at the block level, and the old
12
+ boundary stays, so nothing that reads a document today reads it worse.
13
+
14
+ The parser was already indifferent: `itemsOf` drops a blank line and runs to the next top-level key,
15
+ so `readRecords` never sees one. Both spellings report the same issues, parse the same records, and
16
+ resolve the same references. What was missing was a sentence saying so.
17
+
18
+ ### Added
19
+
20
+ - **§3 states what a blank line does.** It separates records for a reader, carries no meaning, and
21
+ belongs between records that run to 2 lines or more; a list of one-line records stays tight. The
22
+ standard said nothing about blank lines anywhere, which left the behaviour undefined for the
23
+ second implementation `docs/BACKLOG.md` item 3 wants.
24
+ - **`renderBody` emits the separator**, so a scaffolded document is spelled the way a hand-written
25
+ one is.
26
+
27
+ ### Changed
28
+
29
+ - **The corpus is reformatted** — 239 blank lines over 41 files: the 9 profiles, the 21 pages of the
30
+ 2 worked docsets, and the Nano ID set outside this repository. Driven by the checker's own parser
31
+ rather than by a pattern over `- `, because a bullet-list item opens the same way and only the
32
+ profile says which blocks are record-lists. Content is unchanged: over `examples/`, 126 lines
33
+ added, 0 deleted, and 0 of the additions carry a character.
34
+ - **`docs/DOCSETS.md` measurements re-measured**, and 1 row had drifted before this change reached
35
+ it: `examples/dragonecs/index.md` was recorded at 10114 against a file of 9746. Nothing re-reads
36
+ those numbers, which is `docs/BACKLOG.md` item 8 arriving at the measurements instead of the pages.
37
+
38
+ ## 3.4.0
39
+
40
+ Producing a document set and adopting one turned out to be 2 modes wearing 1 name, and only the
41
+ second was built. The first real run outside this repository wrote 12 documentation files and 13
42
+ files of project scaffolding around them — a `package.json`, a lockfile, a `node_modules`, a
43
+ `cnlp.config.json`, an empty profiles directory, and a copy of both packaged skills under 2 agent
44
+ directories. The operator asked for an output folder and got a project.
45
+
46
+ `skills/cnlp-docset/SKILL.md` prescribed every bit of it: `preconditions:` required `cnlp-kit` to be
47
+ a dependency of *this repository* and a `cnlp.config.json` to carry a `docsets` key. Exactly 1 piece
48
+ of that scaffolding did any work — the config, because `cnlp check` could not start without one and
49
+ `readConfig` takes its root from the directory a config sits in, so a config cannot be kept outside
50
+ the tree it describes.
51
+
52
+ ### Added
53
+
54
+ - **`cnlp check <dir>` reads a directory by path**, with no config file and no project around it. A
55
+ directory carrying an `index.md` is 1 set; a directory whose subdirectories carry one is the root
56
+ of several; anything else falls back to the layouts `cnlp init` already knows. `checkProject`
57
+ already took a plain object, so `configForPath` in `src/config.js` synthesizes one and no internal
58
+ changed.
59
+ - **`docsetCorpus(base)`** in `src/config.js` writes the 4 entries of a set once. `CANDIDATES` spelled
60
+ those globs literally for `docs/docsets` and now reuses it.
61
+
62
+ ### Changed
63
+
64
+ - **`skills/cnlp-docset/SKILL.md` names an output directory**, not a project. `inputs:` takes
65
+ `output_directory` in place of `set_name`, `preconditions:` asks for neither a dependency nor a
66
+ config, and `scope:` states 2 rules that were missing: write nothing into that directory but the
67
+ set, and stop at authoring — a repository that will hold the set among its own documents runs
68
+ `cnlp init` and names it in `docsets:`, which is adoption and a second act by a second party.
69
+ - **A synthesized corpus drops an entry matching no file; a written one still refuses it.** Those
70
+ read as the same rule and are not: a glob a project typed and no file answers is a mistake, which
71
+ is what 2.6.0 added the refusal for, and a glob guessed from a directory names a folder a set
72
+ being written may not have yet. This also retires the friction the Nano ID run recorded, where
73
+ `cnlp check` on a freshly scaffolded index reported the empty `concepts/` glob rather than the
74
+ blocks the index still owed.
75
+ - **`README.md` splits producing from adopting** under "Document a library or a framework", and the
76
+ command table carries the path form.
77
+
78
+ ### Added to the record
79
+
80
+ - **`docs/PROBE-nanoid.md`** — the first set built for a library nobody here had read, from prose
81
+ alone at weight 3, with the declarations withheld until it was finished and then compared. 1
82
+ capability of 8 was lost to prose, plus 6 contract-level losses, every one an omission and none an
83
+ invention: the 3.2.0 prohibition held. `docs/BACKLOG.md` item 9's criterion is met.
84
+
85
+ ## 3.3.0
86
+
87
+ The mechanical half of authoring moved off the agent, and a docset stopped being a one-shot
88
+ artifact. Three commands' worth of work rested on one question — what does a document remember
89
+ about where it came from — and the answer turned out to be 1 optional key on a record rather than
90
+ the frontmatter reader `docs/BACKLOG.md` item 6 proposed. Drift is a property of a capability, and
91
+ a capability already had a record to carry it.
92
+
93
+ ### Added
94
+
95
+ - **`cnlp scaffold <profile> <data.json>`** writes a document from data, in the blocks and the forms
96
+ the profile declares. It reads the profile and nothing else, so it branches on no document kind:
97
+ the same command emits a docset index and an ADR, frontmatter and headings included, and a
98
+ project's local profile shadows the packaged one here as everywhere else.
99
+ - **A block the data does not carry is left out, never filled.** A skeleton that conformed by
100
+ inventing content would claim a completeness nobody wrote. What `cnlp check` then reports as
101
+ missing is the list of what the author still owes — the same honesty `status: source` gives a
102
+ capability with no page.
103
+ - **`cnlp diff <profile> <document.md> <data.json>`** reports what moved between a document and a
104
+ fresh read of its sources: a record added, a record removed, a key whose value moved. Audit and
105
+ refresh are the same comparison, so this reports and the author decides which pages to rewrite.
106
+ A record the data can compare and the document cannot is reported rather than skipped: a run
107
+ covering fewer records than it claims is the failure the run exists to catch.
108
+ - **`fingerprint:` on a `catalog:` record**, the optional value that changes when the source does.
109
+ Without it a set can report a capability that appeared and one that vanished, and cannot report
110
+ one that stood still under a signature that moved.
111
+ - **`record_values:` on a `sections:` record** closes a record key to a vocabulary, written
112
+ `status = covered, source, avoid`. The checker holds every record of that block to it, in a
113
+ record-list and a keyed-block alike, and a key left out of it stays open.
114
+
115
+ ### Fixed
116
+
117
+ - **`status:` no longer fails open.** A value outside `covered`, `source` and `avoid` read as
118
+ `covered`, which sent a reader to a `page:` that is not there, with nothing reporting it. It is
119
+ an error now. `relation:` is closed the same way on all 3 page profiles. Both were `note:` prose
120
+ that nothing read, and both are struck off `docs/BACKLOG.md` item 1 — which keeps the drivers
121
+ that are a line *shape* rather than a key *value*, and those still want `item_pattern:`.
122
+ - **3 documents named a check that now exists.** `profiles/docset.md` `enforcement:`, and 2 places
123
+ in `skills/cnlp-docset/SKILL.md`, said the vocabularies are caught by review.
124
+
125
+ ## 3.2.0
126
+
127
+ The docset sub-tool stopped assuming one shape of input. `skills/cnlp-docset/SKILL.md` declared
128
+ `library_source` and `library_documentation` and its step 4 required the capability list to come
129
+ from the sources rather than from the existing documentation — which holds for a library you can
130
+ clone and holds for nothing else. A library arrives as a specification, as a documentation site with
131
+ no readable source, as a closed-source package, as a pile of markdown an operator collected by hand,
132
+ or as a vendor file written for an agent to swallow whole. Every one of those was outside the skill.
133
+
134
+ The generalization cost no change to the checker and no change to a profile, which is the criterion
135
+ `AGENTS.md` states for one: `identity:` already carried the optional `derived_from` key, added
136
+ because "a page written from prose carries less weight than one written from a signature".
137
+
138
+ ### Added
139
+
140
+ - **A source weight, from 1 to 5, and the rule that a contract comes from the strongest source that
141
+ states it.** Declarations, then a specification written for a machine, then prose the library
142
+ publishes, then the examples and the tests it ships, then a file derived from a source nobody
143
+ read. The weights are `inputs:` of the skill, because they describe what the operator hands it.
144
+ - **`derived_from:` carries the sources and their weights**, filled in its own step, so a reader can
145
+ tell a set written from declarations from a set written from prose before trusting a signature on
146
+ any page of it.
147
+ - **A prohibition on promoting a claim past its source.** "Do not invent a signature" already
148
+ covered invention; it did not cover writing a prose claim as though a declaration stated it, which
149
+ is the failure a mixed pile of sources introduces and the one a reader cannot detect.
150
+
151
+ ### Changed
152
+
153
+ - **`inputs:` is a source list**, replacing `library_source` and `library_documentation`, and
154
+ `invocation:` names `<sources>` in all 3 agent forms.
155
+ - **`preconditions:` binds every source to a fixed revision or a fixed version**, not the library
156
+ source alone. A set states what 1 release says whatever it read that release from.
157
+ - **Step 3 lists the sources and reports the strongest weight the list holds**, before any page is
158
+ written, because that weight bounds what every page below can claim.
159
+ - **Step 7 lets `read:` name a document and an anchor**, not a file alone: a capability left at
160
+ `status: source` in a set built from prose has no file to send the reader to.
161
+ - **`README.md` says the skill takes any mix of sources** and explains what each weight proves.
162
+
163
+ ## 3.1.3
164
+
165
+ ### Changed
166
+
167
+ - **The Node floor is `>=22.14`, where the APIs it rests on are stable.** The floor was `>=22`,
168
+ which is where `fs.promises.glob` first appeared — the function `src/config.js` expands the
169
+ corpus and finds document sets with. It stayed experimental until 22.14.0, and `fs.promises.cp`,
170
+ which `cnlp init` copies agent files with, until 22.3.0, so a run on a 22.0–22.13 runtime printed
171
+ an `ExperimentalWarning` the project cannot silence for its callers. The format, the profiles,
172
+ and the checker are unchanged.
173
+
174
+ ## 3.1.2
175
+
176
+ First version published to the npm registry. `npm i -g cnlp-kit` replaces the GitHub tarball
177
+ install, so a consuming repository pins a semver range rather than a git ref. Nothing about the
178
+ format, the profiles, or the checker changes with it: the package has no build step and no runtime
179
+ dependency, and ships the same files it always did apart from `CHANGELOG.md`, which now travels
180
+ with the package so the npm page carries its own history. The source repository stays private —
181
+ what is public is the package, so the README carries no link to a place a reader cannot reach.
182
+
183
+ ### Fixed
184
+
185
+ - **`cnlp --help` exits 0.** The usage text was printed with the exit code of a missing command,
186
+ so asking for help failed a shell that checks the status. A missing command still exits 1: an
187
+ invocation that names nothing is an error, and a request for the usage is not.
188
+ - **An API page stated a size the reference does not hold.** `entlong-unpack.md` claimed a handle
189
+ costs 8 bytes against 4 for an id and turned that into advice about loops; the claim is not in
190
+ the library's own documentation, and a worked example that ships as proof of the profiles states
191
+ only what its source states.
192
+ - **A pitfall named operations instead of the reason.** `concepts/component.md` listed a tag pool's
193
+ methods where the pitfall's own point is that a tag holds no value to read.
194
+ - **The broken fixture's description names the count it breaks.** It said 3 rules and breaks 2.
195
+
196
+ ## 3.1.1
197
+
198
+ ### Changed
199
+
200
+ - **the block `cnlp init` prints for an agent file is 3 lines, and was 5** — an installed skill
201
+ announces its own task through its `description:`, so the line naming the `cnlp-docset` and
202
+ `cnlp-migrate` skills stated what an agent already reads when a session starts. The
203
+ `profiles/<name>.md` line went with it: `npx cnlp print format`, which the line above it names,
204
+ is what delivers that. What is left is what no skill can carry, because a standing rule answers
205
+ to no task description.
206
+
207
+ ## 3.1.0
208
+
209
+ A consistency pass: every rule the review found living outside `cnlp-format.md` moves in, and
210
+ `cnlp init` stops contradicting its own printed instructions.
211
+
212
+ ### Changed
213
+
214
+ - **§7 states the `sections:` ordering rule.** "A record's `heading:` never names a heading
215
+ earlier than the heading of the record before it" was enforced by `test/profile.test.js` and
216
+ stated only in a `profiles/profile.md` note — a rule that escaped the standard. The note now
217
+ points at §7.
218
+ - **§5 records the `handle` split.** The deny-list row stands, but the checker's `DENY` pattern
219
+ does not read the word: the noun is an established domain term — an entity handle — that a
220
+ word-level pattern cannot tell from the verb, so the verb is left to review. The one verb use
221
+ in the example corpus is rewritten.
222
+ - **The docset enforcement line carries its condition everywhere.** `profiles/api.md`,
223
+ `concept.md` and `task.md` claimed reference resolution unconditionally; all three now state
224
+ "once the project declares `docsets:`", as `docset.md` already did.
225
+
226
+ ### Fixed
227
+
228
+ - **`cnlp init` no longer recreates a deleted docsets directory.** It printed "a project
229
+ documenting no library deletes `docsets` and that directory", then recreated the directory on
230
+ the next run. An update run now creates it only when the config still carries the key.
231
+ - **A recorded empty agent choice repeats.** `"agents": []` read as "unrecorded", so a no-TTY
232
+ update run installed skills for every agent. An empty list is a choice and now repeats like
233
+ any other; only a missing config or key falls back to every agent.
234
+ - **The first-run message matches what the corpus can do.** When no known layout matched, `init`
235
+ wrote an example corpus and still printed "Next: run `cnlp check`" — a step that fails, since
236
+ the checker refuses a glob matching no file. The printed next step is now the edit.
237
+ - `AGENTS.md` step 4, `README.md` and `quality-rules.md` corrected where they misstated the
238
+ check's coverage, the adr block count, where the docset corpus entries go, and a byte-identity
239
+ test that never shipped.
240
+
241
+ ## 3.0.0
242
+
243
+ Adoption is 1 command. 2.6.0 split it in 2 and got the default backwards: `cnlp skills` kept an
244
+ existing copy unless `--force` said otherwise, which made *stale* the normal outcome — and a skill
245
+ is versioned with the standard it teaches, so a copy from 2.6.0 instructs an agent in rules this
246
+ version changed. The skills also assumed 1 runtime, while both of them carry a Codex `invocation:`
247
+ line.
248
+
249
+ ### Removed
250
+
251
+ - **`cnlp skills`.** Its work belongs to `cnlp init`, which is the breaking change this major
252
+ version is for. Nobody wants a config with no skills, or skills with no config.
253
+
254
+ ### Added
255
+
256
+ - **`cnlp init` installs and updates.** It stops refusing when a config exists: on a second run it
257
+ rewrites the `agents` key it wrote itself, replaces every installed skill with the packaged one,
258
+ and leaves the corpus alone. Re-running it after an upgrade is what brings a project current.
259
+ - **A terminal menu of agent runtimes**, from `node:readline` and nothing else, ported from
260
+ `pure-typescript-reviewer`. Claude Code writes to `.claude/skills/`, Codex to `.agents/skills/`;
261
+ a runtime is 1 record in `AGENTS` in `src/config.js` and no branch anywhere else. The choice is
262
+ recorded in `cnlp.config.json`, so the next run is Enter.
263
+ - **A resolution order that never stops to ask when nothing can answer**: `--agents claude-code,codex`,
264
+ then the menu, then the recorded choice, then every agent. Git Bash under MinTTY reports no TTY
265
+ and neither does CI, so a run there repeats what the config holds rather than hanging on a menu
266
+ nothing can draw.
267
+ - **`cnlp check` reports skills an upgrade left behind**, reading the `.cnlp-version` stamp each
268
+ agent's skills directory carries. It reports and does not decide the exit code: a stale copy is
269
+ not a defect in a document the corpus names. The stamp is a sidecar file and never frontmatter —
270
+ `profiles/skill.md` declares the 2 fields a `SKILL.md` carries, and a third would fail the check
271
+ of any project whose corpus globs its own skills.
272
+
273
+ ### Changed
274
+
275
+ - **`.claude/skills/*/SKILL.md` is no longer a corpus candidate.** With `init` writing this kit's
276
+ own skills there, proposing an entry over them would make a project check files it does not own
277
+ against its own local profile.
278
+ - **`README.md` states where the ownership line falls.** The package owns the skills and replaces
279
+ every copy; the project owns the config, its `custom_sections` and any local profile, and no
280
+ command here rewrites those. Without that sentence the new behaviour contradicts the rule.
281
+
282
+ ## 2.6.0
283
+
284
+ Adoption stopped being a manual copy. 2.5.0 shipped 2 skills inside the package, where no agent
285
+ looks and no name resolves, and told the operator to copy them by hand — the same failure the zip
286
+ exporter had, arriving through a different door. `cnlp init` wrote a corpus naming files a project
287
+ may not have, so `cnlp check` failed on the first run and every adopter edited the config before
288
+ ever seeing it pass. And `cnlp-migrate` claimed to migrate a corpus while its body named skill
289
+ bodies in every block, so 8 of the 9 profiles had no skill at all.
290
+
291
+ ### Added
292
+
293
+ - **`cnlp skills [--to <dir>] [--force]`** copies the packaged skills into `.claude/skills/`. It
294
+ keeps a copy already there unless `--force` says otherwise: the copy is the project's from the
295
+ moment it lands, and an upgrade of the package under it does not reach the operator's edits.
296
+ - **`cnlp init` reads the layout before it writes the corpus.** `proposeCorpus` in `src/config.js`
297
+ keeps the candidate entries that match a file — `AGENTS.md`, `CLAUDE.md`, `skills/*/SKILL.md`,
298
+ `docs/adr/*.md`, `docs/references/*.md`, the 4 docset globs — and names the count it found for
299
+ each. `checkProject` refuses a glob matching no file, so an entry no file answers is a config
300
+ that fails on its first run. Path convention only, never content: a decision record filed under
301
+ `docs/references/` reads as a reference until a human says otherwise.
302
+
303
+ ### Changed
304
+
305
+ - **`cnlp-migrate` migrates any kind of document**, not a `SKILL.md`. Its body named skill bodies
306
+ in `purpose:`, `scope:` and every step, while §8's procedure is general and 8 other profiles
307
+ ship. It now groups documents by kind, reads the packaged profile nearest each kind, and writes
308
+ a new profile for a kind none of them fits — which is the profile contract's own promise that a
309
+ new kind of document costs 1 file and no code change.
310
+ - **`README.md` carries a guide**: install global against dev-dependency and when each one is
311
+ right, the 3 commands in order, the 2 scenarios end to end — convert what you have, document a
312
+ library — and a table of every command.
313
+
314
+ ## 2.5.0
315
+
316
+ The kit stops serving 1 library. Everything since 2.1.0 was proven by hand-writing 21 pages for one
317
+ framework, and the rules that work produced reached the standard and the profiles in 2.4.0 — which
318
+ is what let the skill be written against the kit rather than against what its author remembered. A
319
+ docset skill written before that would have encoded the example.
320
+
321
+ ### Added
322
+
323
+ - **`skills/cnlp-docset/SKILL.md`** — the skill that turns a library's sources and its existing
324
+ documentation into a conforming document set. It points at the standard and the 4 profiles rather
325
+ than restating their rules, and its order is the one the worked corpus was actually built in: the
326
+ closed catalog before any page, the running example's names before any example, `canonical_use:`
327
+ before the pages it routes to. No config or packaging change: `cnlp.config.json` already globs
328
+ `skills/*/SKILL.md` and `package.json` already ships `skills`.
329
+ - **`cnlp init` prints the block a project pastes into its agent file** — the lines pointing an
330
+ agent at `cnlp print format`, at `cnlp check` before a commit, at `cnlp docs`, and at the 2
331
+ skills. Printed and not written: `init` refuses to overwrite the config, and an agent file is the
332
+ same kind of file. This is the second half of backlog item 9, in its cheapest form.
333
+ - **`write` joins the canonical verb set in §5**, on the record as that section requires:
334
+ 4 of the docset skill's steps open with it, and the set carried no verb for authoring a document.
335
+
336
+ ### Changed
337
+
338
+ - **`test/profile.test.js` holds every packaged skill**, not 1 named one. A consumer's corpus checks
339
+ its own skills and never the ones inside `node_modules`, so this test is where a shipped skill
340
+ body is held.
341
+ - **`README.md`** gains both skills with what each one is for, and its install line pins the version
342
+ this entry ships. It pinned `v2.4.0` while no tag existed at all, so the documented install
343
+ command failed for every adopter.
344
+
345
+ ## 2.4.1
346
+
347
+ The front door caught up. `README.md` had described the 2.0.0 package since 2.0.0: it pinned that
348
+ version in its install line, listed 5 shipped profiles where there are 9, named 4 commands without
349
+ `cnlp docs`, and said nothing about document sets — which is what every version since 2.1.0 added.
350
+ Merging that would have shipped a package contradicting its own contents. Documentation only; no
351
+ rule, profile or check changes.
352
+
353
+ ### Changed
354
+
355
+ - **`README.md`** gains the 4 docset profiles in its table, a section on document sets naming the
356
+ `docsets` config key and `npx cnlp docs`, and a corrected account of its own corpus. Its "not here
357
+ yet" list now says `item_pattern:` carries 6 drivers rather than 2, and names the 3 rules of §9 a
358
+ review holds, so an unenforced rule reads as one without a trip to the backlog.
359
+ - **`cnlp init` writes a `docsets` key and creates the directory.** A key absent from the starter
360
+ reads as a capability that does not exist. `readConfig` rejects a `docsets` key naming a missing
361
+ directory, so writing one without the other would have produced a config that fails on first run.
362
+ - **`AGENTS.md` `read_first:` names `docs/DOCSETS.md`**, which has been the second working note an
363
+ editor of this repository needs since 2.1.0.
364
+
365
+ ## 2.4.0
366
+
367
+ 2.3.0 fixed a docset. It did not fix most of the rules that say how one is built: 5 of the 9 lessons
368
+ that work produced lived only as content under `examples/`, or only in `docs/DOCSETS.md`, which says
369
+ of itself that it is a working note. `examples/dragonecs/` had become the specification, which is
370
+ the failure this repository already rejected once when it dropped the zip exporter — a copy cannot
371
+ be upgraded, only overwritten. Nothing in `src/` or `examples/` changes: the corpus already obeyed
372
+ every rule written down here, which is the point. The rules were copied out of it.
373
+
374
+ ### Added
375
+
376
+ - **§9 gains the rules a review holds**, beside the 4 a checker holds, the way §5 already splits the
377
+ enforced half of a limit from the reviewed half. A fact stated on one page of a set is not
378
+ restated on another, which is §6 reaching past the file it stops at. A set has 1 running example.
379
+ A name the entry document routes on reaches exactly 1 page. All 3 were found by reading a set: a
380
+ duplicated fact, 7 unrelated sets of type names, and 1 name routed to 3 pages.
381
+ - **`profiles/docset.md` says what `read_protocol:` has to contain** — the common case is written
382
+ from `canonical_use:`, a page opens for any call whose contract the reader lacks, and a step
383
+ telling the reader to stop reading is the defect. That sentence had to be deleted twice from a
384
+ written index and nothing had stopped it coming back.
385
+ - **`profiles/docset.md` says when a companion is loaded** — `when:` is "always" once the
386
+ companion's index carries `overrides:`, since a reader loading it on demand misses a correction to
387
+ a page it did not know was wrong.
388
+ - **The 3 page profiles require the set's names.** An `example:` is written in the names the set's
389
+ running example uses, so several pages compose into 1 program.
390
+
391
+ ### Fixed
392
+
393
+ - **A deferred item restored.** The `status` vocabulary is review-only and fails open: an
394
+ unrecognised status reads as `covered` and sends a reader to a page that is absent. It was written
395
+ at 2.1.0 and lost when `docs/BACKLOG.md` was renumbered at 2.2.0. `docs/BACKLOG.md` item 1 now
396
+ carries it and the 3 other line-grammar rules the docset work added, so its 6 drivers are on the
397
+ record rather than implied.
398
+ - **`docs/DOCSETS.md` stops being the specification.** Every decision names the file that holds it
399
+ as a rule. A decision with no such pointer is now visible as a defect.
400
+
401
+ ## 2.3.0
402
+
403
+ An index was a table of contents, which is enough for nothing. A reader holding one still had to
404
+ open most of the corpus before it knew the shape of a program, so the progression did not progress.
405
+ Breaking for a docset: an index without the 2 new blocks no longer conforms. Nothing else changes.
406
+
407
+ ### Added
408
+
409
+ - **`canonical_use:` on the index** — 1 complete working use of the library, carrying every
410
+ load-bearing element. The common case is now written from the index alone. This is the block that
411
+ turns a routing document into a sufficient one.
412
+ - **`walkthrough:` on the index** — each part of that program and the page owning its detail. A
413
+ record-list and not comments inside the fence, because §3 makes a fence opaque, so a link written
414
+ there reaches no reader and no check.
415
+ - **`cnlp docs [<set>]`** — writes the index of every document set, the overridden set first.
416
+ Loading a companion stops being a second action anybody can forget, which is the failure the
417
+ `IEcsFixedRun` case showed costs a system that compiles, builds and never runs. A set is active
418
+ because it is present: a project vendors what it uses, so no second config key can disagree with
419
+ the files on disk.
420
+ - **`docsetsOf` and `readingOrder` in `src/config.js`.** `companions:` runs both ways and fixes no
421
+ order; `overrides:` does, so a set correcting another's pages is written after it.
422
+
423
+ ### Changed
424
+
425
+ - **`read_protocol:` stops optimizing against reading.** It said "open the page the catalog names,
426
+ and open no other page" — a rule aimed at reading less, written when cost was still the goal. It
427
+ now says: write the common case from the index, open a page for any call whose contract you do not
428
+ hold, and **do not write a call whose contract you have not read**. An agent that stops reading too
429
+ early is the defect, not one that reads a second page.
430
+ - **`examples/dragonecs/api/pool-access.md` is merged into `api/pool-mutate.md`.** Reaching a pool
431
+ and changing a component through it is 1 flow, and the split had put the same fact in 2 files:
432
+ `concepts/component.md` and the deleted page both stated that `GetPool<T>` binds by marker
433
+ interface. §6 catches that inside a document and nothing catches it across one.
434
+ - **The catalog routes 1 symbol to 1 page.** `EcsPool<T>` had appeared in 3 records pointing at 3
435
+ pages, so an agent scanning for the most used type in the framework got 3 hits and no rule to
436
+ choose between them.
437
+ - **1 running example per docset.** Every fenced example is now a zoom into the program in
438
+ `canonical_use:`, with the same type and field names. They were 7 unrelated fragments that a
439
+ reader had to reconcile before writing anything.
440
+ - **`api/query.md` states the iteration hazard correctly.** It had claimed every structural change
441
+ invalidates an `EcsSpan`, which contradicts the framework's own examples. A span is a snapshot: a
442
+ change altering what the aspect matches is the hazard, and deleting entities is never safe.
443
+
444
+ ## 2.2.0
445
+
446
+ §9, and the checker pass that holds it. The rules above were all about 1 document; this is the
447
+ first that needs a whole corpus at once. Additive: a project with no `docsets:` key in its
448
+ `cnlp.config.json` has no document set, and nothing about its run changes.
449
+
450
+ ### Added
451
+
452
+ - **§9 page references.** A document set is a directory of documents that link to each other, a
453
+ page id is `<set>:<name>`, a bare name is local and a prefixed one crosses. `page:`, `by:` and
454
+ `docset:` are the only forms a reference takes: a name inside prose is a mention, and nothing
455
+ resolves it.
456
+ - **`pageRefs` in `src/cnlp.js`**, which reads references through the existing parser, so a `page:`
457
+ line inside a fenced example stays what §3 says it is — opaque content, not a link.
458
+ - **`linkIssues` and `pageIdOf` in `src/config.js`**, the corpus pass: every reference resolves,
459
+ every `docset:` names a set that exists, a `by:` value carries no prefix, and every page except a
460
+ set's `index` is reached by at least 1 reference. It runs over the files `checkProject` already
461
+ read, so it costs no second pass over the disk.
462
+ - **the `docsets` key in `cnlp.config.json`**, naming the directory whose immediate subdirectories
463
+ are 1 set each. Without it none of §9 applies, which is what keeps the change additive.
464
+
465
+ ### Fixed
466
+
467
+ - **`examples/dragonecs/` routed a reader into a document set that does not exist.** The first run
468
+ of the new pass reported it: the index named DragonECS-AutoInjections under `companions:`, which
469
+ means "load this", while no docset covers that package. It moved to `excluded:`, which means "not
470
+ covered here, and this is where to look instead". The distinction only became visible once
471
+ something resolved the name.
472
+
473
+ ## 2.1.0
474
+
475
+ 4 profiles for library documentation an agent reads, and the first worked corpus written against
476
+ them. No rule changed and no branch entered the checker, which is what the profile contract
477
+ promised: a new kind of document costs 1 profile. A document conforming to 2.0.0 still conforms.
478
+
479
+ ### Added
480
+
481
+ - **`profiles/docset.md`, `concept.md`, `api.md` and `task.md`** — the 4 page kinds of a docset,
482
+ which is the documentation of 1 library, written for an agent that loads a page at a time rather
483
+ than a file that holds everything.
484
+ - **`catalog:` on the index — the closed list of what a library offers.** Every capability carries a
485
+ record, and `read_protocol:` tells the reader that a symbol absent from it is a symbol the library
486
+ does not have. That is what the block is for: a reader who cannot tell absence from omission
487
+ invents the call it wanted.
488
+ - **`status:` on a catalog record**, one of `covered`, `source` or `avoid`. Trimming a library's
489
+ offering is marking, never deleting: a capability removed from the documentation gets invented
490
+ again or found in the source and used anyway, while one marked `avoid` carries an `instead:`
491
+ naming what to write. Nothing checks the vocabulary yet; `docs/BACKLOG.md` item 1 carries it.
492
+ - **`companions:` on the index**, naming another docset, when to load it, and what it owns. A
493
+ library that is engine-agnostic in its core and used through an integration package in practice
494
+ would otherwise leave a reader to write the integration from nothing.
495
+ - **`supersedes` in the `see_also` relations**, for the page of a companion docset that replaces a
496
+ page of the one it extends.
497
+ - **`overrides:` on the index**, which `examples/dragonecs-unity/` forced. `supersedes` sits on the
498
+ replacing page, and the reader who needs the correction most is the one who never opens that page:
499
+ a system written against the core pipeline page compiles, builds and never runs under Unity,
500
+ because that page states 1 run call and Unity needs 3. The correction has to sit in the index,
501
+ which is loaded whether or not the task looks engine-related.
502
+ - **`tasks:` on the index.** A catalog keyed on capability routes a reader holding a symbol. A
503
+ reader holding a goal had nowhere to start, and 1 task page in the first docset turned out to be
504
+ reachable from nothing at all.
505
+ - **`concepts:` and `tasks:` are record-lists**, so every link in a docset is a `page:` value. A
506
+ resolver picking page names out of backticks inside a bullet is guessing.
507
+ - **the page name rule**: a name crossing a docset carries the docset prefix and a bare name is
508
+ local, so an `overrides:` `page:` is always prefixed and its `by:` never is.
509
+ - **`excluded:` on the index**, for a whole region no page covers, with the reason.
510
+ - **`derived_from:` in `identity:`**, because a page written from prose documentation carries less
511
+ weight than one written from a signature, and a reader is entitled to know which it has.
512
+ - **`read_protocol:` on the index**, the block the rest rests on: it forbids inferring an overload,
513
+ a property or a default the pages do not state, and routes the reader to the source or to a
514
+ companion for everything the pages do not carry.
515
+ - **`choose:` on an API page**, the rule for picking 1 symbol out of a group. The worked corpus
516
+ needed it immediately — its subject declares 21 unpack calls that are 1 decision.
517
+ - **`see_also:` with a relation and a reason on every page**, so a reader decides whether to open a
518
+ page without opening it. Nothing resolves a page name to a file yet, so a broken link is caught by
519
+ review; `docs/BACKLOG.md` carries the item.
520
+ - **`examples/dragonecs/`**, 14 pages holding a real C# framework, and
521
+ **`examples/dragonecs-unity/`**, 8 pages holding the integration package that extends it. Both are
522
+ checked by the same `npx cnlp check` as everything else. The second one exists because a companion
523
+ package is where the design was wrong: `overrides:`, `tasks:` and the page name rule above all
524
+ came out of writing it, and none of the 3 was visible from the core docset alone. Neither corpus
525
+ ships — `files:` in `package.json` names neither.
526
+
527
+ ### Fixed
528
+
529
+ - **a keyed-block declaring no `record_keys` is valid**, which `test/profile.test.js` rejected. §3
530
+ gives a keyed-block a second form — one verbatim fenced block, which carries no sub-keys — and the
531
+ standard's own `report_format:` example uses it. The checker always handled the form; no shipped
532
+ profile had used it, so the assertion outlived the rule it came from.
533
+
534
+ ## 2.0.0
535
+
536
+ The §5 lexicon gains 4 rules, 2 of them mechanical. A document that conformed to 1.0.0 can fail
537
+ 2.0.0, and that is what the major number is for: the format carries its own version so a change to
538
+ what conforms is visible from outside the project that ships it.
539
+
540
+ ### Added
541
+
542
+ - **the active voice, in an imperative document only.** `mood:` was a register the checker never
543
+ read. It now gates 1 rule: a form of `be` with an `-ed` participle names no actor, and an imperative
544
+ body is addressed to whoever executes it. A `declarative` body is left alone, because the actor of
545
+ `a reference file is loaded by path` is genuinely nobody, and a participle naming a state —
546
+ `is required`, `is unchanged` — is exempt.
547
+ - **the light-verb construction.** `make a decision` is `decide` carrying 2 extra words and no verb of
548
+ its own. It is the shape prose keeps when a migration converts it a line at a time, so the rule
549
+ faces incoming documents rather than the corpus here, which never carried one.
550
+ - **one part of speech per term**, as a rule for review. `check the corpus` and `run the check` read
551
+ as 1 term and are 2. Telling a verb from a noun needs a parser and the checker is regular
552
+ expressions over lines, so §5 says so rather than implying the checker holds it. The first document
553
+ the rule caught was the standard itself — see Changed.
554
+ - **a growth policy for the canonical verbs**, and the 10 verbs the missing policy had cost. The set
555
+ was authored for 1 kind of document and this repository's own steps had already outrun it by `copy`,
556
+ `list`, `map`, `fill`, `pick`, `make`, `rewrite`, `tick`, `measure` and `repeat`. The set binds a
557
+ step's opening word, and nothing enforces it yet: the opener is an intra-block line grammar, which
558
+ is the `item_pattern:` item in `docs/BACKLOG.md` — now with a second driver.
559
+
560
+ ### Changed
561
+
562
+ - the standard says `the checker` for the program everywhere: `the check` as a noun was the first
563
+ catch of the one-part-of-speech rule, in the file that added the rule. `npx cnlp check` stays
564
+ untouched — a quoted command is data. `the list` went the same way once `list` joined the canonical
565
+ verbs, so the collection those paragraphs name is `the set`.
566
+ - `skills/cnlp-migrate/SKILL.md` lost 2 bullets that restated a rule another block owns (§6): the
567
+ behaviour boundary lived in `scope:` and in `forbidden_behaviors:` at once, and the one-skill-first
568
+ order lived in `forbidden_behaviors:` and in `workflow:` step 8 at once.
569
+ - `lexiconIssues(lines, mood)` takes the register. `bodyIssues` passes `profile.mood`; a caller
570
+ reaching `lexiconIssues` directly and passing nothing gets every rule that holds in either register.
571
+ - §7 lists `mood` among the values the checker reads, and `profiles/profile.md` says the same in its
572
+ `note:`. Both used to state that the checker never reads it.
573
+ - `AGENTS.md` and `skills/cnlp-migrate/SKILL.md` lost 10 agentless passives, each a step or a
574
+ prohibition that now names who acts, plus the 2 bullets above — the 2 files together shrank by 172
575
+ characters, so the rules cost the documents they govern nothing to satisfy.
576
+ - the standard grew 59 lines: 4 rules with their reasons, 1 table of replacements, and the
577
+ participles the active-voice rule leaves to review.
578
+
579
+ ## 1.0.0
580
+
581
+ First release as a standalone repository.
582
+
583
+ ### Where it came from
584
+
585
+ - the standard, the checker, and the `profile`, `skill` and `adr` profiles —
586
+ `ai-factory-adr-extension` 2.2.0, where CNL-P was written
587
+ - the `guide` and `reference` profiles — `pure-typescript-reviewer`, which authored them on top
588
+ of the 1.18.0 export and proved the format extends without touching the checker
589
+
590
+ ### Added
591
+
592
+ - `cnlp.config.json` and `cnlp check`. A project's corpus used to be constants at the top of a
593
+ test file the exporter overwrote, so every adopter edited a file it did not own.
594
+ - `cnlp print <doc> [--path]`, the runtime-neutral way to reach the standard from a project.
595
+ It replaces `ai-factory adr format`, which only existed inside one extension.
596
+ - `cnlp init`.
597
+ - local profile resolution: a profile in the directory `cnlp.config.json` names resolves before
598
+ the packaged one, so a project's `custom_sections` survive every upgrade.
599
+
600
+ ### Changed
601
+
602
+ - `resolveDoc(name, { roots })` takes the roots to search. The zip exporter used to rewrite two
603
+ path expressions in the checker with `String.replace` to retarget it.
604
+ - `loadProfile` caches on the resolved path, not the name, so a local and a packaged profile of
605
+ the same name are 2 entries.
606
+ - the standard no longer names `ai-factory` anywhere: the profile roster, the enforcer path, the
607
+ `format:` paragraph and every example were project-bound.
608
+ - `profiles/adr.md` states its severity as a policy a project applies, not as one CLI.
609
+ - `profiles/skill.md`, `guide.md` and `reference.md` ship with `custom_sections: - none`.
610
+ - `quality-rules.md` dropped its `[adr]` markers; the 3 marked lines are now written generically.
611
+
612
+ ### Fixed
613
+
614
+ - `profiles/profile.md` pointed at `docs/cnlp-format.md` and a test that the export never
615
+ carried, so in the one repository that adopted it the file named a directory that did not
616
+ exist while its 3 siblings named the right one.
617
+ - the `bullet-list` example in §3 of the standard had been blanked and showed nothing.
618
+
619
+ ### Not carried over
620
+
621
+ - `transitions:` and `status_footer:` in the skill profile, and its 24 ADR `custom_sections` —
622
+ lifecycle conventions of the project the format came from.
623
+ - the ADR template sentinels in `profiles/adr.md`'s `enforcement:`, which belong to that
624
+ project's template rather than to the profile.
625
+ - the zip exporter and its conformance test. A package replaces both.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 VirtualMaestro
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.