unknown-knowledge 2.1.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 (147) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +5 -0
  3. package/README.md +167 -0
  4. package/cli/.gitkeep +0 -0
  5. package/cli/commands/init-copy.js +90 -0
  6. package/cli/commands/init.js +386 -0
  7. package/cli/init-copy.js +24 -0
  8. package/cli/init.js +24 -0
  9. package/cli/kit.manifest.yaml +256 -0
  10. package/cli/lib/copy-payload.js +334 -0
  11. package/cli/lib/generate-wrappers.js +162 -0
  12. package/package.json +36 -0
  13. package/payload/adapter-fixtures/README.md +53 -0
  14. package/payload/adapter-fixtures/html/EXPECTED.yaml +50 -0
  15. package/payload/adapter-fixtures/html/sample.html +38 -0
  16. package/payload/adapter-fixtures/md/EXPECTED.yaml +65 -0
  17. package/payload/adapter-fixtures/md/sample.md +32 -0
  18. package/payload/adapter-fixtures/pdf/EXPECTED.yaml +45 -0
  19. package/payload/adapter-fixtures/pdf/sample.pdf +0 -0
  20. package/payload/adapter-fixtures/txt/EXPECTED.yaml +31 -0
  21. package/payload/adapter-fixtures/txt/sample.txt +18 -0
  22. package/payload/docs/README.md +102 -0
  23. package/payload/docs/boundaries.md +60 -0
  24. package/payload/docs/ci-wiring.md +109 -0
  25. package/payload/docs/steward-guide.md +238 -0
  26. package/payload/engine/audit.js +34 -0
  27. package/payload/engine/commands/audit.js +289 -0
  28. package/payload/engine/commands/derive.js +334 -0
  29. package/payload/engine/commands/ingest.js +124 -0
  30. package/payload/engine/commands/log-entry.js +85 -0
  31. package/payload/engine/commands/phoenix.js +206 -0
  32. package/payload/engine/commands/preflight.js +530 -0
  33. package/payload/engine/commands/resolve.js +1678 -0
  34. package/payload/engine/commands/survey-map.js +351 -0
  35. package/payload/engine/commands/validate-values.js +315 -0
  36. package/payload/engine/commands/validate.js +1426 -0
  37. package/payload/engine/derive.js +34 -0
  38. package/payload/engine/ingest.js +34 -0
  39. package/payload/engine/lib/anchor-signatures.js +126 -0
  40. package/payload/engine/lib/boot.js +39 -0
  41. package/payload/engine/lib/call-numbers.js +133 -0
  42. package/payload/engine/lib/cli.js +147 -0
  43. package/payload/engine/lib/coverage.js +849 -0
  44. package/payload/engine/lib/decomposition.js +225 -0
  45. package/payload/engine/lib/derived.js +494 -0
  46. package/payload/engine/lib/engine-refusal.js +40 -0
  47. package/payload/engine/lib/exit-codes.js +14 -0
  48. package/payload/engine/lib/extractor-kinds.js +955 -0
  49. package/payload/engine/lib/format-adapters.js +802 -0
  50. package/payload/engine/lib/id-grammars.js +178 -0
  51. package/payload/engine/lib/iso-date.js +55 -0
  52. package/payload/engine/lib/kit-root.js +101 -0
  53. package/payload/engine/lib/load-stores.js +1624 -0
  54. package/payload/engine/lib/log-entry.js +196 -0
  55. package/payload/engine/lib/phoenix.js +628 -0
  56. package/payload/engine/lib/scoring.js +150 -0
  57. package/payload/engine/lib/suppressions.js +172 -0
  58. package/payload/engine/lib/time-verdicts.js +282 -0
  59. package/payload/engine/lib/usage-error.js +14 -0
  60. package/payload/engine/lib/validate-record.js +504 -0
  61. package/payload/engine/log-entry.js +34 -0
  62. package/payload/engine/phoenix.js +39 -0
  63. package/payload/engine/preflight.js +34 -0
  64. package/payload/engine/resolve.js +34 -0
  65. package/payload/engine/survey-map.js +34 -0
  66. package/payload/engine/validate-values.js +34 -0
  67. package/payload/engine/validate.js +34 -0
  68. package/payload/extractor-fixtures/.gitkeep +0 -0
  69. package/payload/extractor-fixtures/README.md +29 -0
  70. package/payload/extractor-fixtures/swift/strings-keys/EXPECTED.yaml +8 -0
  71. package/payload/extractor-fixtures/swift/strings-keys/sample.strings +15 -0
  72. package/payload/extractor-fixtures/swift/swift-const-array/EXPECTED.yaml +7 -0
  73. package/payload/extractor-fixtures/swift/swift-const-array/sample.swift +21 -0
  74. package/payload/extractor-fixtures/swift/swift-enum/EXPECTED.yaml +8 -0
  75. package/payload/extractor-fixtures/swift/swift-enum/sample.swift +30 -0
  76. package/payload/extractor-fixtures/swift/yaml-keys/EXPECTED.yaml +6 -0
  77. package/payload/extractor-fixtures/swift/yaml-keys/sample.yaml +23 -0
  78. package/payload/extractor-fixtures/swift/yaml-map-keys/EXPECTED.yaml +7 -0
  79. package/payload/extractor-fixtures/swift/yaml-map-keys/sample.yaml +15 -0
  80. package/payload/extractor-fixtures/ts/dir-modules/EXPECTED.yaml +12 -0
  81. package/payload/extractor-fixtures/ts/dir-modules/sample-modules/alpha.widget.ts +1 -0
  82. package/payload/extractor-fixtures/ts/dir-modules/sample-modules/beta.widget.ts +1 -0
  83. package/payload/extractor-fixtures/ts/dir-modules/sample-modules/gamma.widget.ts +1 -0
  84. package/payload/extractor-fixtures/ts/dir-modules/sample-modules/helpers/format.ts +3 -0
  85. package/payload/extractor-fixtures/ts/dir-modules/sample-modules/widgets.test.ts +2 -0
  86. package/payload/extractor-fixtures/ts/json-keys/EXPECTED.yaml +7 -0
  87. package/payload/extractor-fixtures/ts/json-keys/sample.json +5 -0
  88. package/payload/extractor-fixtures/ts/json-map-keys/EXPECTED.yaml +7 -0
  89. package/payload/extractor-fixtures/ts/json-map-keys/sample.json +13 -0
  90. package/payload/extractor-fixtures/ts/ts-const-array/EXPECTED.yaml +6 -0
  91. package/payload/extractor-fixtures/ts/ts-const-array/sample.ts +13 -0
  92. package/payload/extractor-fixtures/ts/ts-enum/EXPECTED.yaml +7 -0
  93. package/payload/extractor-fixtures/ts/ts-enum/sample.ts +11 -0
  94. package/payload/extractor-fixtures/ts/ts-object-keys/EXPECTED.yaml +6 -0
  95. package/payload/extractor-fixtures/ts/ts-object-keys/sample.tsx +23 -0
  96. package/payload/extractor-fixtures/ts/ts-union/EXPECTED.yaml +5 -0
  97. package/payload/extractor-fixtures/ts/ts-union/sample.ts +9 -0
  98. package/payload/hooks/pre-commit +37 -0
  99. package/payload/hooks/reverse-lookup +66 -0
  100. package/payload/package.json +3 -0
  101. package/payload/protocol/.gitkeep +0 -0
  102. package/payload/protocol/AGENTS.md +239 -0
  103. package/payload/protocol/derived-layer.md +174 -0
  104. package/payload/protocol/new-kind-pipeline.md +179 -0
  105. package/payload/protocol/registry-warrant.md +162 -0
  106. package/payload/protocol/skills/kb-build.md +303 -0
  107. package/payload/protocol/skills/knowledge-audit.md +183 -0
  108. package/payload/protocol/skills/knowledge-bootstrap.md +229 -0
  109. package/payload/protocol/skills/knowledge-reflect.md +397 -0
  110. package/payload/schemas/catalog.schema.json +32 -0
  111. package/payload/schemas/decision-entry.schema.json +122 -0
  112. package/payload/schemas/finding.schema.json +77 -0
  113. package/payload/schemas/gap.schema.json +52 -0
  114. package/payload/schemas/graduation-categories.schema.json +64 -0
  115. package/payload/schemas/knowledge-leaf.schema.json +194 -0
  116. package/payload/schemas/miss.schema.json +45 -0
  117. package/payload/schemas/ontology-concept.schema.json +115 -0
  118. package/payload/schemas/phoenix-event.schema.json +76 -0
  119. package/payload/schemas/registry.schema.json +57 -0
  120. package/payload/schemas/rules.schema.json +14 -0
  121. package/payload/schemas/survey-scope.schema.json +23 -0
  122. package/payload/templates/decisions/_catalog.yaml +7 -0
  123. package/payload/templates/decisions/_registries/graduation-categories.yaml +42 -0
  124. package/payload/templates/decisions/phoenix-event.yaml +74 -0
  125. package/payload/templates/decisions/reflect-mint-proposal.yaml +100 -0
  126. package/payload/templates/decisions/registry-minting.yaml +58 -0
  127. package/payload/templates/decisions/trust-graduation.yaml +120 -0
  128. package/payload/templates/decisions/trust-revocation.yaml +106 -0
  129. package/payload/templates/knowledge/_catalog.yaml +9 -0
  130. package/payload/templates/knowledge/_registries/anchor.yaml +42 -0
  131. package/payload/templates/knowledge/_registries/authority-tiers.yaml +32 -0
  132. package/payload/templates/knowledge/_registries/domains.yaml +43 -0
  133. package/payload/templates/knowledge/_registries/form.yaml +38 -0
  134. package/payload/templates/knowledge/_registries/jurisdictions.yaml +20 -0
  135. package/payload/templates/knowledge/_registries/operations.yaml +18 -0
  136. package/payload/templates/knowledge/_registries/stage.yaml +53 -0
  137. package/payload/templates/knowledge/_rules.yaml +6 -0
  138. package/payload/templates/new-kind/README.md +107 -0
  139. package/payload/templates/new-kind/descriptor.example.yaml +18 -0
  140. package/payload/templates/new-kind/fixture/EXPECTED.yaml +6 -0
  141. package/payload/templates/new-kind/fixture/demo-anchor.list +2 -0
  142. package/payload/templates/new-kind/fixture/sample.list +7 -0
  143. package/payload/templates/new-kind/parser.example.js +98 -0
  144. package/payload/templates/ontology/_catalog.yaml +6 -0
  145. package/payload/templates/ontology/_rules.yaml +6 -0
  146. package/payload/wrappers/cursor.mdc +15 -0
  147. package/payload/wrappers/pointer.md +10 -0
@@ -0,0 +1,122 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "urn:unknown-knowledge:schema:decision-entry",
4
+ "title": "Decision entry (PRD §3.3)",
5
+ "description": "One ADR-style record in decisions/entries/. Truth anchor: the team. Append-mostly: status transitions never rewrite context/decision/consequences. Drafted with provisional date-suffixed ids (D-YYYY-MM-DD-slug); the steward assigns the final D-NNN at acceptance (§3.5). Chain resolution and acyclicity are structural-validator checks (KK-05). Schema evolution is additive-only (§3.5, D-013).",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["id", "title", "category", "status", "date", "deciders", "context", "decision"],
9
+ "properties": {
10
+ "id": {
11
+ "$ref": "#/$defs/decisionRef",
12
+ "description": "Final D-NNN (immutable once published) or provisional date-suffixed draft id (§3.5)."
13
+ },
14
+ "title": { "type": "string" },
15
+ "category": {
16
+ "enum": ["architecture", "governance", "scope", "process", "trust"]
17
+ },
18
+ "status": {
19
+ "enum": ["proposed", "accepted", "addressed", "archived", "rejected", "superseded"],
20
+ "description": "Lifecycle: proposed → accepted → addressed → archived (+ rejected, superseded)."
21
+ },
22
+ "date": { "$ref": "#/$defs/isoDate" },
23
+ "deciders": { "type": "array", "minItems": 1, "items": { "type": "string" } },
24
+ "context": {
25
+ "type": "string",
26
+ "description": "Append-mostly: transitions never rewrite recorded reasoning."
27
+ },
28
+ "decision": { "type": "string" },
29
+ "consequences": { "type": "string" },
30
+ "supersedes": {
31
+ "type": "array",
32
+ "items": { "$ref": "#/$defs/decisionRef" },
33
+ "description": "Chains must resolve and be acyclic (structural validator)."
34
+ },
35
+ "superseded-by": {
36
+ "type": "array",
37
+ "items": { "$ref": "#/$defs/decisionRef" }
38
+ },
39
+ "relates-to": {
40
+ "type": "object",
41
+ "additionalProperties": false,
42
+ "description": "Sideways typed refs to concepts and leaves; never embedded content across store lines (PRD §3).",
43
+ "properties": {
44
+ "concepts": { "type": "array", "items": { "$ref": "#/$defs/conceptRef" } },
45
+ "leaves": { "type": "array", "items": { "$ref": "#/$defs/leafRef" } },
46
+ "decisions": { "type": "array", "items": { "$ref": "#/$defs/decisionRef" } }
47
+ }
48
+ },
49
+ "graduation": {
50
+ "$ref": "#/$defs/graduation",
51
+ "description": "OPTIONAL typed block marking this entry as a trust graduation or revocation (UCS-1155). Present only on the entries that move the trust boundary; an ordinary decision omits it. Deliberately a BLOCK on the existing record rather than a forked record kind: a graduation IS an ADR — it has context, a decision, consequences, deciders and a date, and it supersedes and is superseded like any other — so forking the kind would duplicate the whole envelope to add three fields, and split the decisions store into two things a steward has to know apart. The validator holds this block against the graduation category table (graduation-categories.schema.json)."
52
+ },
53
+ "provenance": {
54
+ "$ref": "#/$defs/provenance",
55
+ "description": "Who authored this entry and with which skill revision (UCS-1149's leaf provenance, applied to decision entries by UCS-1155). Optional, so the installed base and every fixture written before it stay valid. It is what makes a defect traceable: when a graduated category produces a bad change, the question is not only which entry was wrong but which AUTHOR and which SKILL VERSION produced it — a bad skill revision is then traceable like any other defect, and every entry it touched is findable rather than guessed at."
56
+ }
57
+ },
58
+ "$defs": {
59
+ "graduation": {
60
+ "type": "object",
61
+ "additionalProperties": false,
62
+ "required": ["action", "category"],
63
+ "description": "A move of the trust boundary: this entry either GRADUATES a change category from full inspection to sampling, or REVOKES a graduation and returns the category to full inspection (UCS-1155). Both directions are the same shape because both are the same governed act — a recorded, reviewable, reversible statement about how much reading a class of change gets — and giving revocation a lesser shape would make un-earning trust cheaper to record than earning it, which is backwards.",
64
+ "properties": {
65
+ "action": {
66
+ "enum": ["graduate", "revoke"],
67
+ "description": "`graduate` — the category moves from full inspection to sampling. `revoke` — a graduation is withdrawn and the category returns to full inspection. Revocation is AUTOMATIC on any defect found in a graduated category (conduct, documented in the steward guide): the steward records it, the mechanism does not wait for a judgment call about whether this particular defect was bad enough."
68
+ },
69
+ "category": {
70
+ "type": "string",
71
+ "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
72
+ "description": "The change category being graduated or revoked — must name a row in the graduation category table (decisions/_registries/). An entry naming an absent category is a validator finding, as is a graduation for a permanently gated one: autonomy that cites no declared category is autonomy nobody scoped."
73
+ },
74
+ "observed-cycles": {
75
+ "type": "integer",
76
+ "minimum": 0,
77
+ "description": "The count of consecutive approved-unmodified cycles the moderator OBSERVED for this category, as recorded by reflect. v1 DOES NOT COMPUTE OR VERIFY THIS NUMBER — the analytics stay manual, and this field is the steward's written record of what they judged against the table's threshold, not an engine-derived total. Recording it is what makes the judgment reviewable after the fact: a reader can ask whether the number was met, even though no code asserts the number itself. REQUIRED on a `graduate` (a `graduation-field-shape` finding otherwise) — a grant with no written count is exactly the unreviewable judgment the manual-analytics stance depends on not existing. Meaningless but tolerated on a `revoke`, which is triggered by a defect rather than by a count. The action-conditional rules are enforced by the structural validator rather than here, because this document is interpreted by the engine's own validator, whose keyword subset has no conditional."
78
+ },
79
+ "revokes": {
80
+ "$ref": "#/$defs/decisionRef",
81
+ "description": "On a `revoke`, the graduation entry being withdrawn. When present it is resolved like any other cross-store ref, so an id naming no decision is an unresolved-ref error — and the structural validator additionally checks WHAT it names: the target must carry a graduation block, with action `graduate`, for this entry's own category, since resolution alone cannot tell a grant from an unrelated ADR (`disconnected-revocation`). REFUSED on a `graduate`, which grants rather than withdraws (`graduation-field-shape`). REQUIRED WHENEVER A GRADUATION FOR THE SAME CATEGORY EXISTS in the store — otherwise the store asserts both a graduation and its revocation with nothing linking them, and a reader cannot tell whether the graduation still stands (a `disconnected-revocation` finding). It stays OPTIONAL when no graduation for the category exists, which is the standing-position case: recording that a never-graduated category remains at full inspection is legitimate and has nothing to point at. That conditional is enforced by the structural validator rather than here, because this document is interpreted by the engine's own validator, whose keyword subset has no conditional — and a rule stated in a keyword nothing enforces is contract drift wearing the appearance of a check."
82
+ },
83
+ "defect": {
84
+ "type": "string",
85
+ "description": "On a `revoke`, what went wrong — the defect that triggered it. Prose, because the point is that a human can read why trust was withdrawn; the machine-checkable half is that a revocation exists and names something. REQUIRED on a `revoke` and REFUSED on a `graduate` (a `graduation-field-shape` finding either way): revocation is automatic ON A DEFECT, so a revocation naming none records that trust was withdrawn for no stated reason and leaves the next graduation of that category with nothing to have fixed — while a defect on a GRANT is withdrawal vocabulary on an entry moving the other direction. Validator-enforced, per the note on `observed-cycles`."
86
+ }
87
+ }
88
+ },
89
+ "provenance": {
90
+ "type": "object",
91
+ "additionalProperties": false,
92
+ "description": "Who wrote this entry and with which authoring skill (UCS-1149's leaf shape, applied to decision entries by UCS-1155). Recorded, never judged: no registry governs it, because an author name and a skill version are facts about how the entry came to exist rather than governed vocabulary. Surfaced in validator and resolver output so a defect is traceable to both.",
93
+ "properties": {
94
+ "author": {
95
+ "type": "string",
96
+ "description": "Who authored the entry — a human steward or the agent that drafted it."
97
+ },
98
+ "skill-version": {
99
+ "type": "string",
100
+ "description": "The version of the authoring skill that produced the entry, so a systematic drafting defect can be traced to the vintage that introduced it — the property that makes a bad skill revision recallable rather than merely regrettable."
101
+ }
102
+ }
103
+ },
104
+ "conceptRef": { "type": "string", "pattern": "^K-[0-9]+$" },
105
+ "decisionRef": {
106
+ "type": "string",
107
+ "pattern": "^D-([0-9]+|[0-9]{4}-[0-9]{2}-[0-9]{2}-[a-z0-9-]+)$"
108
+ },
109
+ "leafRef": { "type": "string", "pattern": "^L-[0-9]{6}$" },
110
+ "isoDate": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$" },
111
+ "storeFile": {
112
+ "type": "object",
113
+ "additionalProperties": false,
114
+ "required": ["schema-version", "entries"],
115
+ "description": "Decision entries-file envelope. Every store file carries schema-version (§3.5); evolution is additive-only.",
116
+ "properties": {
117
+ "schema-version": { "type": "integer", "minimum": 1 },
118
+ "entries": { "type": "array", "items": { "$ref": "#" } }
119
+ }
120
+ }
121
+ }
122
+ }
@@ -0,0 +1,77 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "urn:unknown-knowledge:schema:finding",
4
+ "title": "Finding log fragment (PRD §3.4)",
5
+ "description": "One agent-appended finding in logs/findings/ — ONE FILE PER ENTRY (D-010), so concurrent sessions never merge-conflict; the fragment is the store file and carries schema-version (§3.5). Raw signal, no judgment at capture time. Capture content policy: concept IDs and file paths only — never verbatim user text or secrets; committed fragments are permanent git history. Lifecycle open → proposed → resolved/rejected; recurrences re-open the same entry (never duplicate), appending to occurrences. The reflect skill (KK-22) consolidates fragments and prunes resolved ones; uncorroborated entries age out to archived with a rollup note. Sibling logs live in logs/misses/ (miss.schema.json) and logs/gaps/ (gap.schema.json). Schema evolution is additive-only (§3.5, D-013).",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["schema-version", "date", "trigger", "summary", "status"],
9
+ "properties": {
10
+ "schema-version": { "type": "integer", "minimum": 1 },
11
+ "date": { "$ref": "#/$defs/isoDate" },
12
+ "trigger": {
13
+ "enum": ["correction", "recurrence", "retrieval-struggle", "retrieval-miss", "quarantine"],
14
+ "description": "The five capture triggers; quarantine is engine-attributed."
15
+ },
16
+ "session": {
17
+ "type": "string",
18
+ "description": "Platform/session hint."
19
+ },
20
+ "summary": {
21
+ "type": "string",
22
+ "description": "Concept IDs and file paths only — never verbatim user text or secrets."
23
+ },
24
+ "consulted": {
25
+ "type": "object",
26
+ "additionalProperties": false,
27
+ "properties": {
28
+ "concepts": { "type": "array", "items": { "$ref": "#/$defs/conceptRef" } },
29
+ "leaves": { "type": "array", "items": { "$ref": "#/$defs/leafRef" } }
30
+ }
31
+ },
32
+ "residue": {
33
+ "type": "array",
34
+ "items": { "type": "string" },
35
+ "description": "The unresolved terms this finding is about (UCS-1160) — resolve's `decomposition.residue` for a query, or a ranked candidate's term for a document. Terms are the store's own tokens, never quoted user prose (capture content policy)."
36
+ },
37
+ "resolved-context": {
38
+ "type": "array",
39
+ "items": { "type": "string" },
40
+ "description": "What DID resolve in the same ask (UCS-1160) — resolve's `decomposition.resolved-context`: the operations, concept ids, and jurisdictions the query landed in. A bare unresolved token is a finding nobody can act on; the context localizes the gap precisely enough that the minting decision writes itself."
41
+ },
42
+ "section": {
43
+ "type": "object",
44
+ "additionalProperties": false,
45
+ "description": "Where a DOCUMENT candidate was found (UCS-1160) — the section locator from the --doc coverage map, so reflect can open the section just-in-time rather than re-reading the document. Absent on query residue, which has no document to address. EXACTLY ONE of line/page is required: coverage emits {line, endLine} for line-addressed sources and {page, object} for pdf, never both. Neither is an underspecified locator (the coordinate-free claim the locator exists to replace); both is contradictory. That rule is enforced by the VALIDATOR as the `locator-shape` convention, not by this document, because the engine's JSON Schema subset has no conditional keywords (no oneOf/anyOf/allOf/not) — writing one here would promise a rule nothing checks.",
46
+ "required": ["document", "address"],
47
+ "properties": {
48
+ "document": { "type": "string", "description": "Repo-relative path of the document the candidate fell out of." },
49
+ "address": { "type": "string", "description": "The section's heading text — the coverage map's own address for it." },
50
+ "line": { "type": "integer", "minimum": 1, "description": "First line of the section's range; absent for page-addressed sources (pdf). Exactly one of line/page — see the `locator-shape` convention above." },
51
+ "page": { "type": "integer", "minimum": 1, "description": "Page number for page-addressed sources (pdf); absent for line-addressed ones. Exactly one of line/page — see the `locator-shape` convention above." }
52
+ }
53
+ },
54
+ "status": {
55
+ "enum": ["open", "proposed", "resolved", "rejected"],
56
+ "description": "Lifecycle: open → proposed → resolved/rejected; re-open-not-duplicate."
57
+ },
58
+ "verified": {
59
+ "$ref": "#/$defs/isoDate",
60
+ "description": "Stamped by the transition helper when the entry resolves (validator re-run passed); removed on re-open."
61
+ },
62
+ "reason": {
63
+ "type": "string",
64
+ "description": "Required on rejection — rejections record the reason (§8)."
65
+ },
66
+ "occurrences": {
67
+ "type": "array",
68
+ "items": { "$ref": "#/$defs/isoDate" },
69
+ "description": "Re-open dates: recurrences re-open the same entry, never duplicate (§8)."
70
+ }
71
+ },
72
+ "$defs": {
73
+ "conceptRef": { "type": "string", "pattern": "^K-[0-9]+$" },
74
+ "leafRef": { "type": "string", "pattern": "^L-[0-9]{6}$" },
75
+ "isoDate": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$" }
76
+ }
77
+ }
@@ -0,0 +1,52 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "urn:unknown-knowledge:schema:gap",
4
+ "title": "Gap-log fragment (PRD §3.4)",
5
+ "description": "One request no protocol/skill could route, recorded in logs/gaps/ — ONE FILE PER ENTRY (D-010), so concurrent sessions never merge-conflict; the fragment is the store file and carries schema-version (§3.5). Capture content policy: concept IDs and file paths only — never verbatim user text or secrets; committed fragments are permanent git history. Lifecycle open → proposed → resolved/rejected; recurrences re-open the same entry (never duplicate), appending to occurrences. The reflect skill (KK-22) consolidates fragments and prunes resolved ones; uncorroborated entries age out to archived with a rollup note. Schema evolution is additive-only (§3.5, D-013).",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["schema-version", "date", "summary", "status"],
9
+ "properties": {
10
+ "schema-version": { "type": "integer", "minimum": 1 },
11
+ "date": { "$ref": "#/$defs/isoDate" },
12
+ "summary": {
13
+ "type": "string",
14
+ "description": "What could not be routed, by concept IDs and file paths only — never verbatim user text or secrets."
15
+ },
16
+ "session": {
17
+ "type": "string",
18
+ "description": "Opaque platform/session hint — an ID, never quoted session content."
19
+ },
20
+ "consulted": {
21
+ "type": "object",
22
+ "additionalProperties": false,
23
+ "description": "Nearest concepts/leaves consulted before declaring the gap.",
24
+ "properties": {
25
+ "concepts": { "type": "array", "items": { "$ref": "#/$defs/conceptRef" } },
26
+ "leaves": { "type": "array", "items": { "$ref": "#/$defs/leafRef" } }
27
+ }
28
+ },
29
+ "status": {
30
+ "enum": ["open", "proposed", "resolved", "rejected"],
31
+ "description": "Lifecycle: open → proposed → resolved/rejected; re-open-not-duplicate."
32
+ },
33
+ "verified": {
34
+ "$ref": "#/$defs/isoDate",
35
+ "description": "Stamped by the transition helper when the entry resolves (validator re-run passed); removed on re-open."
36
+ },
37
+ "reason": {
38
+ "type": "string",
39
+ "description": "Required on rejection — rejections record the reason (§8)."
40
+ },
41
+ "occurrences": {
42
+ "type": "array",
43
+ "items": { "$ref": "#/$defs/isoDate" },
44
+ "description": "Re-open dates: recurrences re-open the same entry, never duplicate (§8)."
45
+ }
46
+ },
47
+ "$defs": {
48
+ "conceptRef": { "type": "string", "pattern": "^K-[0-9]+$" },
49
+ "leafRef": { "type": "string", "pattern": "^L-[0-9]{6}$" },
50
+ "isoDate": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$" }
51
+ }
52
+ }
@@ -0,0 +1,64 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "urn:unknown-knowledge:schema:graduation-categories",
4
+ "title": "Trust graduation category table (decisions/_registries/graduation-categories.yaml)",
5
+ "description": "The governed table declaring which CHANGE CATEGORIES may ever graduate from full inspection to sampling, and which are permanently gated (PRD §2 'autonomy earned per category', UCS-1155). Autonomy is per category and never per leaf: a category is the unit because a mechanical change class (alias additions, verified bumps, paths edges, see-also links) can accumulate evidence about ITSELF, while an individual record cannot — one leaf approved ten times says nothing about the eleventh leaf. Two eligibilities, and the split is the whole mechanism: `eligible` categories name an integer threshold N of approved-unmodified cycles after which a steward MAY graduate them, and `gated` categories (new domain classes, contradicts/supersedes edges, authority assignments, anything citation-bearing) can never graduate at all — a judgment call does not become mechanical by being made correctly N times. Graduating an eligible category and revoking any graduation are both Decisions entries carrying the typed `graduation:` block (decision-entry.schema.json); the validator holds those entries against this table, so an entry naming a category absent here, or graduating a gated one, is a finding rather than a silent pass. v1 DOES NOT COMPUTE the approved-unmodified counts: the threshold is what the moderator judges the recorded counts against by hand, and the analytics stay manual (steward-guide.md). This schema governs the table file itself. Schema evolution is additive-only (§3.5, D-013).",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["schema-version", "store", "table", "categories"],
9
+ "properties": {
10
+ "schema-version": { "type": "integer", "minimum": 1 },
11
+ "store": {
12
+ "enum": ["decisions"],
13
+ "description": "Always `decisions`. The table governs the change PROCESS — who may write without full inspection — which is the team's truth anchor (D-003), not the artifact's or the world's. A graduation table filed under knowledge/ would be claiming the world decides how this repo is reviewed."
14
+ },
15
+ "table": {
16
+ "type": "string",
17
+ "description": "The table's name — must equal the file's basename, so the file a finding names is the table it names (a loader check, mirroring registries)."
18
+ },
19
+ "categories": {
20
+ "type": "array",
21
+ "items": { "$ref": "#/$defs/category" },
22
+ "description": "The declared change categories. Order is the steward's; the engine compares as a set."
23
+ }
24
+ },
25
+ "$defs": {
26
+ "isoDate": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$" },
27
+ "decisionRef": { "type": "string", "pattern": "^D-([0-9]+|[0-9]{4}-[0-9]{2}-[0-9]{2}-[a-z0-9-]+)$" },
28
+ "category": {
29
+ "type": "object",
30
+ "additionalProperties": false,
31
+ "required": ["category", "eligibility", "warrant", "decision"],
32
+ "properties": {
33
+ "category": {
34
+ "type": "string",
35
+ "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
36
+ "description": "The change category's name: lowercase kebab, e.g. `alias-additions`. Names a CLASS OF EDIT, never a record — 'alias additions' is a category, 'L-000117' is not."
37
+ },
38
+ "eligibility": {
39
+ "enum": ["eligible", "gated"],
40
+ "description": "`eligible` — this category MAY graduate once its threshold of approved-unmodified cycles is met and a steward records the graduation. `gated` — permanently gated: it may never graduate, whatever the evidence. The distinction is mechanical-versus-judgment, not easy-versus-hard: an alias addition is checkable by looking at it, while an authority assignment encodes how far a source can be trusted, and being right about that N times running is not evidence that the N+1th needs no reading."
41
+ },
42
+ "threshold": {
43
+ "type": "integer",
44
+ "minimum": 1,
45
+ "description": "N — the consecutive approved-unmodified cycles this category must accumulate before a steward may graduate it. REQUIRED for an `eligible` category and REFUSED for a `gated` one; both halves of that rule are the loader's (a `graduation-threshold-shape` diagnostic), because this engine's schema subset has no conditional keyword and a rule stated in a keyword nothing enforces is contract drift wearing the appearance of a check. An eligible category with no threshold would be graduation-eligible against no bar at all."
46
+ },
47
+ "gloss": {
48
+ "type": "string",
49
+ "description": "What edits fall in this category — prose is navigation, never the fact."
50
+ },
51
+ "warrant": {
52
+ "type": "string",
53
+ "pattern": "\\S",
54
+ "description": "Why this category carries this eligibility. For a `gated` category this is the substance: name what judgment the edit requires that no streak of correct instances removes. Must carry actual text, not whitespace."
55
+ },
56
+ "decision": {
57
+ "$ref": "#/$defs/decisionRef",
58
+ "description": "REQUIRED — the Decisions entry that declared this row (§3.3). The table governs the trust boundary, so a row nobody signed is exactly the ungoverned autonomy the mechanism exists to prevent. Resolved like any other cross-store ref: an id naming no decision is an unresolved-ref error."
59
+ },
60
+ "declared": { "$ref": "#/$defs/isoDate" }
61
+ }
62
+ }
63
+ }
64
+ }
@@ -0,0 +1,194 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "urn:unknown-knowledge:schema:knowledge-leaf",
4
+ "title": "Knowledge leaf front matter (PRD §3.2)",
5
+ "description": "The YAML front matter of one knowledge leaf file; the markdown body below it holds the actual knowledge content. Truth anchor: the world — citation-anchored, human-gated writes only. One leaf per file, so the front matter is the store file and carries schema-version (§3.5) — v2-shape leaves stamp schema-version: 2 (UCS-1147). Every leaf carries an opaque accession id (id: L-NNNNNN), minted at PR time and never reused: it is the leaf's identity, what the loader indexes by, and the ONLY shape a citation of a leaf may take. The dotted `notation` is demoted to an optional legacy display label that nothing treats as identity (UCS-1147, retiring the dual-shape citation contract UCS-1144 opened). Because identity is opaque rather than positional, a leaf file may be moved — between prefix shards, between directories — without invalidating a single citation: position on disk carries no meaning. Cross-reference resolution and catalog-index consistency are structural-validator checks (KK-05). Schema evolution is additive-only (§3.5, D-013), with one sanctioned exception: frontmatter v2 RETIRED the free-prose `description` field (UCS-1149). A leaf now opens its body with a topic sentence and display prose is DERIVED from it, so the one-line summary can never drift from the content it summarizes. Under additionalProperties:false a leaf still carrying `description` fails as an unknown property — a deliberate break, and the major release D-021 defines for exactly this.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["schema-version", "id", "domain", "heading", "citations"],
9
+ "properties": {
10
+ "schema-version": { "type": "integer", "minimum": 1 },
11
+ "id": {
12
+ "$ref": "#/$defs/accession",
13
+ "description": "Accession id — opaque, minted at PR time, never reused, never positional (L-NNNNNN). REQUIRED: it is the leaf's identity, the key the loader indexes by, and the only spelling any record may cite this leaf as (UCS-1147). A leaf without one has no identity, so its absence is a missing-required finding and the remedy is to assign one."
14
+ },
15
+ "notation": {
16
+ "$ref": "#/$defs/notation",
17
+ "description": "OPTIONAL LEGACY display label — the leaf's old position in the per-project tree (e.g. \"362.1\"), kept so a reader who knows the tree still recognizes the leaf. It is NOT an identity: nothing indexes by it, no citation resolves through it, and moving the leaf's file does not invalidate it. Still validated by pattern when present, because a malformed label is a defect even though nothing resolves through it. Quote it — unquoted it parses as a number."
18
+ },
19
+ "domain": {
20
+ "type": "string",
21
+ "description": "LEGACY navigational domain — a free string naming the tree branch this leaf files under, paired with `division` and mirrored in the notation spine (§3.2). Ungoverned: nothing checks it against a vocabulary. Distinct from `facets.domain`, which is the REGISTRY-GOVERNED subject path (UCS-1148) whose every segment must be minted. The two coexist while v2 lands; UCS-1149 settles which survives."
22
+ },
23
+ "division": {
24
+ "type": "string",
25
+ "description": "Legacy navigational subdivision under `domain`, ungoverned in the same way. See the note on `domain`."
26
+ },
27
+ "heading": { "type": "string" },
28
+ "notes": {
29
+ "type": "array",
30
+ "items": { "$ref": "#/$defs/note" },
31
+ "description": "Governance notes required by the build skill: scope/class-here."
32
+ },
33
+ "cross-references": {
34
+ "type": "object",
35
+ "additionalProperties": false,
36
+ "properties": {
37
+ "class-elsewhere": {
38
+ "type": "array",
39
+ "items": { "$ref": "#/$defs/leafRef" },
40
+ "description": "Redirects — must resolve. Cite the target leaf by its accession id (L-NNNNNN)."
41
+ },
42
+ "see-also": {
43
+ "type": "array",
44
+ "items": { "$ref": "#/$defs/leafRef" },
45
+ "description": "Related context — must resolve. Cite the target leaf by its accession id (L-NNNNNN)."
46
+ },
47
+ "including": {
48
+ "type": "array",
49
+ "items": { "type": "string" },
50
+ "description": "Standing room: candidate topics, not authoritative."
51
+ }
52
+ }
53
+ },
54
+ "citations": {
55
+ "type": "array",
56
+ "minItems": 1,
57
+ "items": { "$ref": "#/$defs/citation" },
58
+ "description": "REQUIRED — an unsourced claim is not promotable."
59
+ },
60
+ "facets": {
61
+ "type": "object",
62
+ "additionalProperties": false,
63
+ "description": "Governed facets: values drawn from the store's registries (UCS-1148). Membership is a structural-validator check, never a schema enum — the vocabulary is minted by literary warrant under steward review, so it grows by a registry edit plus a Decisions entry rather than by an engine release.",
64
+ "properties": {
65
+ "domain": {
66
+ "type": "string",
67
+ "description": "Hierarchical domain path from the domains registry, '/'-joined. Valid only when EVERY segment is minted — a child cannot hang off an unminted parent. This is the GOVERNED subject path, not the legacy top-level `domain` free string: membership here is a structural-validator check against knowledge/_registries/domains.yaml, and the top level of that registry is open (a new class is a registry edit plus a Decisions entry)."
68
+ },
69
+ "form": {
70
+ "type": "string",
71
+ "description": "What KIND of knowledge this leaf is — reference, recipe, runbook, constraint (UCS-1149). Flat value from the form registry. Ships EMPTY like domains: which forms a project recognizes is a judgement about its own material, so the vocabulary is minted by warrant rather than shipped as an enum."
72
+ },
73
+ "anchor": {
74
+ "type": "string",
75
+ "description": "The truth anchor this leaf's claim answers to — artifact, world, or team (D-003). Flat value from the anchor registry. That vocabulary is FIXED by the kit rather than chosen per project — the three anchors are the kit's own architecture, and a project minting a fourth would be describing a store this engine does not have — but the registry still ships EMPTY, because every value must cite a Decisions entry that resolves and a seeded repo's decisions store starts empty (D-001). The bootstrap interview mints the three with an entry of the project's own; the registry template's header names them."
76
+ },
77
+ "stage": {
78
+ "type": "string",
79
+ "description": "Where this leaf sits in its promotion lifecycle — draft until a moderator promotes it, verified once they have (UCS-1149). Flat value from the stage registry: draft, proposed, verified. That vocabulary is FIXED by the kit rather than chosen per project, because the same values drive the shared pre-promotion predicate (isPrePromotionStatus) — a project that renamed them would have a resolver downrank and a preflight verdict disagreeing about which leaves are provisional — but the registry still ships EMPTY, since every value must cite a Decisions entry that resolves and a seeded repo's decisions store starts empty (D-001). A draft or proposed leaf is downranked in resolver output and verdicted unknown by preflight, through that one predicate. There is deliberately no deprecated stage yet: no leaf surface implements the demotion the concept lifecycle gives that word, so the term would govern nothing."
80
+ }
81
+ }
82
+ },
83
+ "verified": {
84
+ "$ref": "#/$defs/isoDate",
85
+ "description": "When this leaf's claim was last checked against its citations — the Time facet's date half (UCS-1150). TOP-LEVEL, alongside `volatility`, not under `facets`: a facet is a governed classification of what the leaf IS, drawn from a registry, while this is a governance fact about the record's own upkeep. Paired with `volatility` to produce a pinned trusted/stale verdict, computed ONLY against an injected `--today` — the engine never reads the wall clock (D-012), and without an injected date the check reports itself skipped rather than passing silently. Same calendar-date pattern as every other date in this schema; a date matching the pattern but naming no real day (2026-02-30) is a structural-validator finding, because an age measured from a day that does not exist is a number nobody's calendar agrees with."
86
+ },
87
+ "volatility": {
88
+ "enum": ["static", "stable", "volatile"],
89
+ "description": "How fast this leaf's subject moves — the Time facet's rate half (UCS-1150). Governs when the leaf stales: `static` never, `stable` after 365 days, `volatile` after 90, measured from `verified`. A SCHEMA ENUM rather than a registry, which is the opposite of how form/anchor/stage are governed and deliberately so: those registries hold values the engine only compares, so a project may mint its own, whereas each value here is a KEY INTO A PINNED NUMERIC TABLE in engine/lib/time-verdicts.js. A project that minted a fourth class by registry edit would produce leaves with no threshold at all — a governed field silently ungoverned, which is the failure class this engine exists to prevent. Extending the vocabulary means shipping a threshold for it, so it is an engine release with a Decisions entry, and the schema is where that is said. ABSENT means the leaf is EXEMPT from time governance, not that it defaults to a class: the facet arrived in v2 and stores are mid-migration, so defaulting would stale every un-migrated leaf in the store at once on the first run that passed --today. Exempt is reported as its own verdict class, never as `trusted` — a leaf nothing governs has not passed a check."
90
+ },
91
+ "provenance": {
92
+ "type": "object",
93
+ "additionalProperties": false,
94
+ "description": "Who wrote this leaf and with which authoring skill (UCS-1149). Recorded, never judged: no registry governs it, because an author name and a skill version are facts about how the entry came to exist rather than governed vocabulary. Round-trips untouched through resolver and validator output.",
95
+ "properties": {
96
+ "author": {
97
+ "type": "string",
98
+ "description": "Who authored the entry — a human steward or the agent that drafted it."
99
+ },
100
+ "skill-version": {
101
+ "type": "string",
102
+ "description": "The version of the authoring skill that produced the entry, so a systematic drafting defect can be traced to the vintage that introduced it."
103
+ }
104
+ }
105
+ },
106
+ "operations": {
107
+ "type": "array",
108
+ "items": { "type": "string" },
109
+ "description": "Verbs from the operations registry — what this leaf lets a reader DO."
110
+ },
111
+ "applies": {
112
+ "type": "object",
113
+ "additionalProperties": false,
114
+ "description": "Where this leaf's claim holds.",
115
+ "properties": {
116
+ "jurisdictions": {
117
+ "type": "array",
118
+ "items": { "type": "string" },
119
+ "description": "Values from the jurisdictions registry."
120
+ }
121
+ }
122
+ },
123
+ "concepts": {
124
+ "type": "array",
125
+ "items": { "$ref": "#/$defs/conceptRef" },
126
+ "description": "Ontology concepts this leaf is knowledge ABOUT (UCS-1151). The edge lives leaf-side because deciding what a leaf is about is curatorial, and the leaf is what sits under the human write gate. It is derived BIDIRECTIONALLY at load: the loader builds concept -> leaves from these declarations, so resolving a concept surfaces its declaring leaves structurally, with no dependence on whether the leaf's `terms` happen to spell the concept's term. Targets must resolve — an unresolvable id is the ordinary unresolved-ref finding, declared in the ref-field table like every other typed edge."
127
+ },
128
+ "paths": {
129
+ "type": "array",
130
+ "items": { "type": "string" },
131
+ "description": "Repo-relative file or directory paths this leaf governs (UCS-1151). NOT an id space: these name the working tree, so they are checked against the filesystem as a missing-path finding — the same mechanism concept source-of-truth pointers already ride — rather than through the ref graph, which only knows how to ask whether an ID resolves. Each entry must name something INSIDE this repo that exists: a path resolving outside the repo root (`../elsewhere`, or an absolute path) is refused, because a store may only point at its own repo and an escaping pointer would be judged against a file the store has no claim on. So is a path naming the repo root itself — a pointer at everything attributes nothing. Reverse lookup (resolve --paths) joins over these alongside concept pointers, so the files in a diff surface the knowledge that governs them before an edit."
132
+ },
133
+ "relates": {
134
+ "type": "object",
135
+ "additionalProperties": false,
136
+ "description": "Typed leaf-to-leaf edges (UCS-1151). Four kinds, each a distinct claim about how two leaves stand to one another, and each a declared row in the ref-field table targeting the leaf space. The resolver expands exactly ONE hop over these from any hit, labeled by kind, so a hit carries its structural neighborhood without a second lookup. Targets are leaf refs, which since UCS-1147 means accession ids and nothing else: the dotted notation is a legacy display label and no longer resolves.",
137
+ "properties": {
138
+ "depends-on": {
139
+ "type": "array",
140
+ "items": { "$ref": "#/$defs/leafRef" },
141
+ "description": "This leaf's claim is only usable once the target's is — a prerequisite, not a suggestion."
142
+ },
143
+ "see-also": {
144
+ "type": "array",
145
+ "items": { "$ref": "#/$defs/leafRef" },
146
+ "description": "Related context worth reading alongside. The weakest of the four: no dependency, no conflict."
147
+ },
148
+ "contradicts": {
149
+ "type": "array",
150
+ "items": { "$ref": "#/$defs/leafRef" },
151
+ "description": "The two leaves make claims that cannot both hold. Recorded rather than resolved — surfacing the conflict is what lets a human settle it, and a store that hid it would let a reader cite either one unaware."
152
+ },
153
+ "supersedes": {
154
+ "type": "array",
155
+ "items": { "$ref": "#/$defs/leafRef" },
156
+ "description": "This leaf replaces the target's claim. Distinct from contradicts: the disagreement is already settled, and this leaf is the settlement."
157
+ }
158
+ }
159
+ },
160
+ "terms": { "type": "array", "items": { "type": "string" } },
161
+ "edition": { "type": "integer", "minimum": 1 },
162
+ "contributors": { "type": "array", "items": { "type": "string" } }
163
+ },
164
+ "$defs": {
165
+ "notation": { "type": "string", "pattern": "^[0-9]+(\\.[0-9]+)*$" },
166
+ "accession": { "type": "string", "pattern": "^L-[0-9]{6}$" },
167
+ "conceptRef": { "type": "string", "pattern": "^K-[0-9]+$" },
168
+ "leafRef": { "type": "string", "pattern": "^L-[0-9]{6}$" },
169
+ "isoDate": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$" },
170
+ "note": {
171
+ "type": "object",
172
+ "additionalProperties": false,
173
+ "required": ["type", "text"],
174
+ "properties": {
175
+ "type": { "enum": ["scope", "class-here", "revision"] },
176
+ "text": { "type": "string" },
177
+ "date": { "$ref": "#/$defs/isoDate" }
178
+ }
179
+ },
180
+ "citation": {
181
+ "type": "object",
182
+ "additionalProperties": false,
183
+ "required": ["source"],
184
+ "properties": {
185
+ "source": { "type": "string" },
186
+ "accessed": { "$ref": "#/$defs/isoDate" },
187
+ "authority": {
188
+ "type": "string",
189
+ "description": "The source's authority tier, from the authority-tiers registry (UCS-1148). A tier is a governed value, not an enum: which tiers a project recognizes is its own to mint."
190
+ }
191
+ }
192
+ }
193
+ }
194
+ }
@@ -0,0 +1,45 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "urn:unknown-knowledge:schema:miss",
4
+ "title": "Miss-log fragment (PRD §3.4, §5.2)",
5
+ "description": "One unextractable anchor recorded in logs/misses/ — ONE FILE PER ENTRY (D-010), so concurrent sessions never merge-conflict; the fragment is the store file and carries schema-version (§3.5). The demand-driven extractor backlog: a shape description, no parser yet. Capture content policy: concept IDs and file paths only — never verbatim user text or secrets; committed fragments are permanent git history. Lifecycle open → proposed → resolved/rejected; recurrences re-open the same entry (never duplicate), appending to occurrences. The reflect skill (KK-22) consolidates fragments and prunes resolved ones; uncorroborated entries age out to archived with a rollup note. Schema evolution is additive-only (§3.5, D-013).",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["schema-version", "date", "path", "shape", "status"],
9
+ "properties": {
10
+ "schema-version": { "type": "integer", "minimum": 1 },
11
+ "date": { "$ref": "#/$defs/isoDate" },
12
+ "path": {
13
+ "type": "string",
14
+ "description": "Root-relative path of the anchor no extractor kind can read."
15
+ },
16
+ "shape": {
17
+ "type": "string",
18
+ "description": "Shape description of the unextractable anchor — enough for the 6-step new-kind pipeline (§5.2) to draft a parser; paths and structure only, never file contents verbatim."
19
+ },
20
+ "session": {
21
+ "type": "string",
22
+ "description": "Opaque platform/session hint — an ID, never quoted session content."
23
+ },
24
+ "status": {
25
+ "enum": ["open", "proposed", "resolved", "rejected"],
26
+ "description": "Lifecycle: open → proposed → resolved/rejected; re-open-not-duplicate."
27
+ },
28
+ "verified": {
29
+ "$ref": "#/$defs/isoDate",
30
+ "description": "Stamped by the transition helper when the entry resolves (validator re-run passed); removed on re-open."
31
+ },
32
+ "reason": {
33
+ "type": "string",
34
+ "description": "Required on rejection — rejections record the reason (§8)."
35
+ },
36
+ "occurrences": {
37
+ "type": "array",
38
+ "items": { "$ref": "#/$defs/isoDate" },
39
+ "description": "Re-open dates: recurrences re-open the same entry, never duplicate (§8)."
40
+ }
41
+ },
42
+ "$defs": {
43
+ "isoDate": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$" }
44
+ }
45
+ }