naive-framework 0.1.0 → 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 (254) hide show
  1. package/AGENTS.md +2 -1
  2. package/docs/decisions/decisions.json +27 -0
  3. package/docs/reference/ROUTES.md +36 -37
  4. package/governance/layer.json +2 -1
  5. package/governance/venture-template/roles/venture-roles.json +62 -0
  6. package/interface/acting.mjs +83 -0
  7. package/interface/adapters/claude-code.json +16 -0
  8. package/interface/adapters/codex.json +14 -0
  9. package/interface/adapters/cursor.json +16 -0
  10. package/interface/adapters.mjs +182 -0
  11. package/interface/api/server.mjs +4 -2
  12. package/interface/boundaries.mjs +218 -0
  13. package/interface/brand.mjs +214 -0
  14. package/interface/cli/freshness.mjs +59 -0
  15. package/interface/cli/guard.mjs +6 -0
  16. package/interface/cli/mentura.mjs +78 -8
  17. package/interface/cli/naive.mjs +33 -8
  18. package/interface/context.mjs +524 -0
  19. package/interface/demo/board.mjs +1 -1
  20. package/interface/dev/setup.mjs +84 -0
  21. package/interface/gate-hooks.mjs +36 -0
  22. package/interface/harness/evals.mjs +3 -3
  23. package/interface/harness/run.mjs +4 -4
  24. package/interface/instrumentation.mjs +86 -0
  25. package/interface/kit-boundary.mjs +73 -0
  26. package/interface/layer.json +8 -2
  27. package/interface/mcp/server.mjs +47 -7
  28. package/interface/package-routes.mjs +196 -0
  29. package/interface/provenance.mjs +24 -1
  30. package/interface/reads.mjs +173 -0
  31. package/interface/release-card.mjs +42 -0
  32. package/interface/router.mjs +101 -28
  33. package/interface/skills/naive-setup/SKILL.md +71 -0
  34. package/interface/skills/naive-setup/artifact.html +83 -0
  35. package/interface/vitals.mjs +115 -0
  36. package/interface/writes.mjs +190 -0
  37. package/knowledge/freshness.json +85 -0
  38. package/knowledge/layer.json +11 -3
  39. package/knowledge/templates/glossary.md +23 -0
  40. package/operations/layer.json +10 -3
  41. package/operations/templates/marketing-brand.md +46 -0
  42. package/operations/templates/public-assets.md +39 -0
  43. package/package.json +3 -1
  44. package/packages/catalog.json +8 -0
  45. package/packages/customers/package.json +21 -1
  46. package/packages/deals/package.json +27 -0
  47. package/packages/decisions/package.json +12 -1
  48. package/packages/finance/frames/fund-without-ceding-control.frame.json +177 -0
  49. package/packages/foundation/package.json +8 -1
  50. package/packages/fund/package.json +48 -0
  51. package/packages/marketing/package.json +10 -4
  52. package/packages/money/package.json +24 -3
  53. package/packages/validation/package.json +13 -0
  54. package/platform/README.md +6 -0
  55. package/platform/adapter.json +15 -0
  56. package/platform/integrations/remote-image.mjs +79 -0
  57. package/platform/integrations/rho.mjs +7 -6
  58. package/platform/kits/README.md +8 -1
  59. package/platform/kits/agent-upgrade/kit.json +15 -0
  60. package/platform/kits/agent-upgrade/run.mjs +82 -0
  61. package/platform/kits/agent-upgrade/stand-in-agent.mjs +32 -0
  62. package/platform/kits/validation-kickoff/kit.json +29 -0
  63. package/platform/webhooks/server.mjs +70 -0
  64. package/purpose/frameworks/idea-map/ideamap.mjs +4 -2
  65. package/schema/README.md +1 -0
  66. package/schema/access.mjs +57 -0
  67. package/schema/adapter.schema.json +33 -0
  68. package/schema/assets.mjs +212 -0
  69. package/schema/brand.mjs +373 -0
  70. package/schema/build-release.mjs +61 -0
  71. package/schema/caching.mjs +505 -0
  72. package/schema/check-assets.mjs +24 -0
  73. package/schema/check-brand.mjs +24 -0
  74. package/schema/check-config.mjs +110 -0
  75. package/schema/check-nextjs-status.mjs +3 -1
  76. package/schema/check-people.mjs +70 -0
  77. package/schema/check-sources.mjs +9 -1
  78. package/schema/data-model.json +334 -8
  79. package/schema/deal.schema.json +80 -0
  80. package/schema/decisions.mjs +7 -1
  81. package/schema/examples/frames/judge.mjs +10 -0
  82. package/schema/examples/venture-type/jev.mjs +12 -0
  83. package/schema/examples/workspace/ventures/acme-labs/AGENTS.md +17 -0
  84. package/schema/examples/workspace/ventures/acme-labs/accounts/.gitkeep +0 -0
  85. package/schema/examples/workspace/ventures/acme-labs/decisions/discovery-goal.decision.json +23 -0
  86. package/schema/examples/workspace/ventures/acme-labs/decisions/statement-icp.decision.json +22 -0
  87. package/schema/examples/workspace/ventures/acme-labs/decisions/statement-problem.decision.json +22 -0
  88. package/schema/examples/workspace/ventures/acme-labs/decisions/venture.team.decision.json +37 -0
  89. package/schema/examples/workspace/ventures/acme-labs/knowledge/README.md +3 -0
  90. package/schema/examples/workspace/ventures/acme-labs/knowledge/sources.json +46 -0
  91. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000001.json +12 -0
  92. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000002.json +12 -0
  93. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000003.json +12 -0
  94. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000004.json +12 -0
  95. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000005.json +12 -0
  96. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000006.json +12 -0
  97. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000007.json +12 -0
  98. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000008.json +12 -0
  99. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000009.json +12 -0
  100. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000010.json +12 -0
  101. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000011.json +12 -0
  102. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000012.json +12 -0
  103. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000013.json +12 -0
  104. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000014.json +12 -0
  105. package/schema/examples/workspace/ventures/acme-labs/money/_streams/transactions/stream.json +5 -0
  106. package/schema/examples/workspace/ventures/acme-labs/money/_summary.json +30 -0
  107. package/schema/examples/workspace/ventures/acme-labs/operations/departments/customer-service/README.md +5 -0
  108. package/schema/examples/workspace/ventures/acme-labs/operations/departments/customer-service/department.json +5 -0
  109. package/schema/examples/workspace/ventures/acme-labs/operations/departments/finance/README.md +5 -0
  110. package/schema/examples/workspace/ventures/acme-labs/operations/departments/finance/department.json +5 -0
  111. package/schema/examples/workspace/ventures/acme-labs/operations/departments/human-capital/README.md +5 -0
  112. package/schema/examples/workspace/ventures/acme-labs/operations/departments/human-capital/department.json +5 -0
  113. package/schema/examples/workspace/ventures/acme-labs/operations/departments/it/README.md +5 -0
  114. package/schema/examples/workspace/ventures/acme-labs/operations/departments/it/department.json +5 -0
  115. package/schema/examples/workspace/ventures/acme-labs/operations/departments/marketing-and-sales/README.md +5 -0
  116. package/schema/examples/workspace/ventures/acme-labs/operations/departments/marketing-and-sales/department.json +5 -0
  117. package/schema/examples/workspace/ventures/acme-labs/operations/departments/products/README.md +5 -0
  118. package/schema/examples/workspace/ventures/acme-labs/operations/departments/products/department.json +5 -0
  119. package/schema/examples/workspace/ventures/acme-labs/operations/departments/strategy/README.md +5 -0
  120. package/schema/examples/workspace/ventures/acme-labs/operations/departments/strategy/department.json +5 -0
  121. package/schema/examples/workspace/ventures/acme-labs/people/founders/maya-chen.json +15 -0
  122. package/schema/examples/workspace/ventures/acme-labs/people/people.json +22 -0
  123. package/schema/examples/workspace/ventures/acme-labs/pillars/brand.md +5 -0
  124. package/schema/examples/workspace/ventures/acme-labs/pillars/business.md +5 -0
  125. package/schema/examples/workspace/ventures/acme-labs/pillars/product.md +5 -0
  126. package/schema/examples/workspace/ventures/acme-labs/products/.gitkeep +0 -0
  127. package/schema/examples/workspace/ventures/acme-labs/products/decisions/product.core-product.decision.json +28 -0
  128. package/schema/examples/workspace/ventures/acme-labs/products/decisions/product.exists.decision.json +38 -0
  129. package/schema/examples/workspace/ventures/acme-labs/products/decisions/product.flagship.decision.json +27 -0
  130. package/schema/examples/workspace/ventures/acme-labs/profile.md +12 -0
  131. package/schema/examples/workspace/ventures/acme-labs/provenance.jsonl +12 -0
  132. package/schema/examples/workspace/ventures/acme-labs/raw/dump.md +6 -0
  133. package/schema/examples/workspace/ventures/acme-labs/venture.json +27 -0
  134. package/schema/examples/workspace/ventures/northstar/AGENTS.md +17 -0
  135. package/schema/examples/workspace/ventures/northstar/accounts/.gitkeep +0 -0
  136. package/schema/examples/workspace/ventures/northstar/deals/ductline.json +8 -0
  137. package/schema/examples/workspace/ventures/northstar/deals/kilnworks.json +14 -0
  138. package/schema/examples/workspace/ventures/northstar/decisions/venture.team.decision.json +31 -0
  139. package/schema/examples/workspace/ventures/northstar/evidence/README.md +3 -0
  140. package/schema/examples/workspace/ventures/northstar/fund/decisions/terms.decision.json +27 -0
  141. package/schema/examples/workspace/ventures/northstar/fund/decisions/terms.first-close.decision.json +27 -0
  142. package/schema/examples/workspace/ventures/northstar/fund/decisions/thesis.decision.json +26 -0
  143. package/schema/examples/workspace/ventures/northstar/fund/terms.json +22 -0
  144. package/schema/examples/workspace/ventures/northstar/fund/thesis.json +22 -0
  145. package/schema/examples/workspace/ventures/northstar/governance/README.md +3 -0
  146. package/schema/examples/workspace/ventures/northstar/governance/departments/external-relationships/charter.md +5 -0
  147. package/schema/examples/workspace/ventures/northstar/governance/departments/external-relationships/department.json +5 -0
  148. package/schema/examples/workspace/ventures/northstar/governance/departments/finance/charter.md +5 -0
  149. package/schema/examples/workspace/ventures/northstar/governance/departments/finance/department.json +5 -0
  150. package/schema/examples/workspace/ventures/northstar/governance/departments/human-capital/charter.md +5 -0
  151. package/schema/examples/workspace/ventures/northstar/governance/departments/human-capital/department.json +5 -0
  152. package/schema/examples/workspace/ventures/northstar/governance/departments/risk-and-compliance/charter.md +5 -0
  153. package/schema/examples/workspace/ventures/northstar/governance/departments/risk-and-compliance/department.json +5 -0
  154. package/schema/examples/workspace/ventures/northstar/governance/departments/strategy/charter.md +5 -0
  155. package/schema/examples/workspace/ventures/northstar/governance/departments/strategy/department.json +5 -0
  156. package/schema/examples/workspace/ventures/northstar/knowledge/README.md +3 -0
  157. package/schema/examples/workspace/ventures/northstar/operations/README.md +3 -0
  158. package/schema/examples/workspace/ventures/northstar/operations/departments/external-relationships/README.md +5 -0
  159. package/schema/examples/workspace/ventures/northstar/operations/departments/external-relationships/department.json +5 -0
  160. package/schema/examples/workspace/ventures/northstar/operations/departments/finance/README.md +5 -0
  161. package/schema/examples/workspace/ventures/northstar/operations/departments/finance/department.json +5 -0
  162. package/schema/examples/workspace/ventures/northstar/operations/departments/human-capital/README.md +5 -0
  163. package/schema/examples/workspace/ventures/northstar/operations/departments/human-capital/department.json +5 -0
  164. package/schema/examples/workspace/ventures/northstar/operations/departments/risk-and-compliance/README.md +5 -0
  165. package/schema/examples/workspace/ventures/northstar/operations/departments/risk-and-compliance/department.json +5 -0
  166. package/schema/examples/workspace/ventures/northstar/operations/departments/strategy/README.md +5 -0
  167. package/schema/examples/workspace/ventures/northstar/operations/departments/strategy/department.json +5 -0
  168. package/schema/examples/workspace/ventures/northstar/people/founders/ana-ruiz.json +13 -0
  169. package/schema/examples/workspace/ventures/northstar/people/founders/ben-okafor.json +7 -0
  170. package/schema/examples/workspace/ventures/northstar/people/people.json +27 -0
  171. package/schema/examples/workspace/ventures/northstar/pillars/brand.md +5 -0
  172. package/schema/examples/workspace/ventures/northstar/pillars/business.md +5 -0
  173. package/schema/examples/workspace/ventures/northstar/pillars/product.md +5 -0
  174. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/AGENTS.md +17 -0
  175. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/accounts/.gitkeep +0 -0
  176. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/decisions/venture.team.decision.json +31 -0
  177. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/knowledge/README.md +3 -0
  178. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/customer-service/README.md +5 -0
  179. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/customer-service/department.json +5 -0
  180. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/finance/README.md +5 -0
  181. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/finance/department.json +5 -0
  182. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/human-capital/README.md +5 -0
  183. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/human-capital/department.json +5 -0
  184. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/it/README.md +5 -0
  185. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/it/department.json +5 -0
  186. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/marketing-and-sales/README.md +5 -0
  187. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/marketing-and-sales/department.json +5 -0
  188. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/products/README.md +5 -0
  189. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/products/department.json +5 -0
  190. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/strategy/README.md +5 -0
  191. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/strategy/department.json +5 -0
  192. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/pillars/brand.md +5 -0
  193. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/pillars/business.md +5 -0
  194. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/pillars/product.md +5 -0
  195. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/products/.gitkeep +0 -0
  196. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/products/decisions/product.core-product.decision.json +28 -0
  197. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/products/decisions/product.exists.decision.json +32 -0
  198. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/products/decisions/product.flagship.decision.json +27 -0
  199. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/profile.md +5 -0
  200. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/venture.json +27 -0
  201. package/schema/examples/workspace/ventures/northstar/products/.gitkeep +0 -0
  202. package/schema/examples/workspace/ventures/northstar/profile.md +5 -0
  203. package/schema/examples/workspace/ventures/northstar/provenance.jsonl +3 -0
  204. package/schema/examples/workspace/ventures/northstar/purpose/README.md +3 -0
  205. package/schema/examples/workspace/ventures/northstar/venture.json +49 -0
  206. package/schema/founder.schema.json +72 -0
  207. package/schema/frame.schema.json +240 -0
  208. package/schema/frames.mjs +228 -0
  209. package/schema/freshness-log.schema.json +40 -0
  210. package/schema/freshness-profiles.schema.json +44 -0
  211. package/schema/freshness.mjs +473 -0
  212. package/schema/fund-terms.schema.json +107 -0
  213. package/schema/fund-thesis.schema.json +87 -0
  214. package/schema/gate-drafts.mjs +130 -0
  215. package/schema/gate.mjs +105 -11
  216. package/schema/glossary.schema.json +25 -0
  217. package/schema/init-venture.mjs +38 -8
  218. package/schema/judgment.schema.json +38 -0
  219. package/schema/kit.schema.json +47 -0
  220. package/schema/kits.mjs +24 -0
  221. package/schema/knowledge-sources.schema.json +145 -15
  222. package/schema/layer.json +16 -3
  223. package/schema/marketing-brand.schema.json +116 -0
  224. package/schema/migrations/kit-to-package.mjs +94 -0
  225. package/schema/migrations/package-layout.mjs +86 -0
  226. package/schema/model-steps.mjs +717 -0
  227. package/schema/money-summary.schema.json +138 -0
  228. package/schema/naive-config.mjs +165 -0
  229. package/schema/naive-config.schema.json +268 -0
  230. package/schema/need-now.json +171 -0
  231. package/schema/need-now.mjs +3 -2
  232. package/schema/packages.mjs +10 -5
  233. package/schema/people.schema.json +86 -0
  234. package/schema/public-assets.schema.json +76 -0
  235. package/schema/release-read.mjs +111 -0
  236. package/schema/releases.mjs +497 -0
  237. package/schema/setup.mjs +164 -0
  238. package/schema/stale.mjs +111 -0
  239. package/schema/start-release.mjs +41 -0
  240. package/schema/structure.mjs +186 -0
  241. package/schema/systems-catalog.json +126 -0
  242. package/schema/systems-catalog.schema.json +78 -0
  243. package/schema/trigger.schema.json +44 -0
  244. package/schema/triggers.mjs +237 -0
  245. package/schema/upgrade-registry.schema.json +60 -0
  246. package/schema/upgrade-venture.mjs +96 -118
  247. package/schema/upgrades.json +69 -0
  248. package/schema/upgrades.mjs +385 -0
  249. package/schema/validate.py +19 -10
  250. package/schema/venture-role.schema.json +64 -0
  251. package/schema/venture-type.mjs +62 -0
  252. package/schema/venture-types.json +346 -0
  253. package/schema/venture-types.schema.json +129 -0
  254. package/schema/venture.schema.json +53 -0
@@ -0,0 +1,240 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "frame.schema.json",
4
+ "title": "Frame (decision library)",
5
+ "description": "One recurring venture problem, as a shape, at packages/<function>/frames/<id>.frame.json. A frame is to Naive what a component is to a React component library. It holds the goal, the decisions hidden in the founder's sentence, the premises that sentence assumes and the moves to attack them, and what current information a lookup must supply. It never holds an answer: no instrument, vendor, term or market norm, because those go stale and can be wrong. schema/frames.mjs matches a frame to the founder's words, reads the props from the venture's records, has a model judge each premise yes, no or unknown, and proposes the frame's decisions with open options for the founder to decide.",
6
+ "type": "object",
7
+ "required": [
8
+ "id",
9
+ "title",
10
+ "functions",
11
+ "triggers",
12
+ "goal",
13
+ "premises",
14
+ "attacks",
15
+ "reframe",
16
+ "props",
17
+ "freshness",
18
+ "reasoning",
19
+ "emits"
20
+ ],
21
+ "additionalProperties": false,
22
+ "properties": {
23
+ "id": {
24
+ "type": "string",
25
+ "pattern": "^[a-z0-9-]+$"
26
+ },
27
+ "title": {
28
+ "type": "string"
29
+ },
30
+ "functions": {
31
+ "type": "array",
32
+ "minItems": 1,
33
+ "items": {
34
+ "type": "string",
35
+ "pattern": "^[a-z0-9-]+$"
36
+ },
37
+ "description": "The venture functions the problem belongs to; the first is the package the frame lives in"
38
+ },
39
+ "triggers": {
40
+ "type": "array",
41
+ "minItems": 1,
42
+ "items": {
43
+ "type": "string"
44
+ },
45
+ "description": "Sentences a founder says when they have this problem, in a founder's words"
46
+ },
47
+ "goal": {
48
+ "type": "string",
49
+ "description": "The end the decisions serve; {prop} placeholders are filled from the venture"
50
+ },
51
+ "premises": {
52
+ "type": "array",
53
+ "minItems": 1,
54
+ "items": {
55
+ "type": "object",
56
+ "required": [
57
+ "id",
58
+ "claim",
59
+ "attack"
60
+ ],
61
+ "additionalProperties": false,
62
+ "properties": {
63
+ "id": {
64
+ "type": "string",
65
+ "pattern": "^[a-z0-9-]+$"
66
+ },
67
+ "claim": {
68
+ "type": "string",
69
+ "description": "What the founder's sentence assumes, as a yes/no proposition about this venture"
70
+ },
71
+ "attack": {
72
+ "type": "string",
73
+ "description": "The premise attack applied to it, one of schema/frames.mjs ATTACKS"
74
+ },
75
+ "reads": {
76
+ "type": "array",
77
+ "items": {
78
+ "type": "string"
79
+ },
80
+ "description": "The props the judgment of this premise needs"
81
+ }
82
+ }
83
+ },
84
+ "description": "The chain the founder's sentence assumes, in order"
85
+ },
86
+ "attacks": {
87
+ "type": "array",
88
+ "minItems": 1,
89
+ "items": {
90
+ "type": "string"
91
+ },
92
+ "description": "The premise attacks the frame uses (the hooks of the library)"
93
+ },
94
+ "dichotomy": {
95
+ "type": "string",
96
+ "description": "The trade the founder's sentence forces, asked as: is it false, a real trade-off, or a sequence?"
97
+ },
98
+ "reframe": {
99
+ "type": "string",
100
+ "description": "The better question the frame leaves the founder with; {prop} placeholders are filled from the venture"
101
+ },
102
+ "composes": {
103
+ "type": "array",
104
+ "items": {
105
+ "type": "string"
106
+ },
107
+ "description": "Smaller frames this one is built from"
108
+ },
109
+ "props": {
110
+ "type": "array",
111
+ "items": {
112
+ "type": "string"
113
+ },
114
+ "description": "The venture facts the frame reads, never stores: phase, goal, runway, revenue, cap_table, jurisdiction, control_rights"
115
+ },
116
+ "freshness": {
117
+ "type": "object",
118
+ "required": [
119
+ "look_for",
120
+ "max_age_days",
121
+ "cite"
122
+ ],
123
+ "additionalProperties": false,
124
+ "properties": {
125
+ "look_for": {
126
+ "type": "array",
127
+ "minItems": 1,
128
+ "items": {
129
+ "type": "string"
130
+ },
131
+ "description": "What a lookup must find, described as a problem, never as a named answer"
132
+ },
133
+ "filter_by": {
134
+ "type": "array",
135
+ "items": {
136
+ "type": "string"
137
+ }
138
+ },
139
+ "max_age_days": {
140
+ "type": "integer",
141
+ "minimum": 1
142
+ },
143
+ "cite": {
144
+ "type": "boolean",
145
+ "const": true
146
+ }
147
+ },
148
+ "description": "What current information the frame needs and how fresh it must be. The lookup itself is a kit's skill; the frame says only what to look for."
149
+ },
150
+ "reasoning": {
151
+ "type": "array",
152
+ "minItems": 1,
153
+ "items": {
154
+ "type": "string"
155
+ },
156
+ "description": "What a model that fetches the frame must do, in order"
157
+ },
158
+ "emits": {
159
+ "type": "array",
160
+ "minItems": 1,
161
+ "items": {
162
+ "type": "object",
163
+ "required": [
164
+ "id",
165
+ "question"
166
+ ],
167
+ "additionalProperties": false,
168
+ "properties": {
169
+ "id": {
170
+ "type": "string",
171
+ "pattern": "^[a-z0-9-]+$"
172
+ },
173
+ "question": {
174
+ "type": "string"
175
+ },
176
+ "options": {
177
+ "type": "array",
178
+ "items": {
179
+ "type": "string"
180
+ },
181
+ "description": "Options that describe the problem's own parts, never a named answer; options from a lookup are added at run time with their date and source"
182
+ },
183
+ "options_from": {
184
+ "enum": [
185
+ "frame",
186
+ "lookup"
187
+ ],
188
+ "default": "frame"
189
+ },
190
+ "layer": {
191
+ "enum": [
192
+ "purpose",
193
+ "knowledge",
194
+ "operations",
195
+ "evidence",
196
+ "governance",
197
+ "interface"
198
+ ]
199
+ },
200
+ "needed_in": {
201
+ "enum": [
202
+ "discovery",
203
+ "validation",
204
+ "beachhead",
205
+ "scale",
206
+ "platform"
207
+ ]
208
+ }
209
+ }
210
+ },
211
+ "description": "The decisions the frame proposes, each open for the founder to decide"
212
+ },
213
+ "cases": {
214
+ "type": "array",
215
+ "items": {
216
+ "type": "object",
217
+ "required": [
218
+ "id",
219
+ "facts",
220
+ "expect"
221
+ ],
222
+ "additionalProperties": false,
223
+ "properties": {
224
+ "id": {
225
+ "type": "string"
226
+ },
227
+ "facts": {
228
+ "type": "object",
229
+ "description": "The props of a worked venture"
230
+ },
231
+ "expect": {
232
+ "type": "object",
233
+ "description": "The premise verdicts and dichotomy a good judgment reaches for these facts"
234
+ }
235
+ }
236
+ },
237
+ "description": "Worked cases, to evaluate a model's judgments against"
238
+ }
239
+ }
240
+ }
@@ -0,0 +1,228 @@
1
+ #!/usr/bin/env node
2
+ // The decision library: frames (schema/frame.schema.json). A frame is a recurring venture problem as a
3
+ // shape, the way a component is a reusable piece of UI. It holds no answer. This module:
4
+ //
5
+ // match finds the frames whose triggers the founder's words fit (code, by word overlap)
6
+ // props reads the facts a frame needs from the venture's records, never from the frame
7
+ // request asks a model to judge each premise yes, no or unknown, and whether the trade is false, a
8
+ // real trade-off or a sequence (one typed question each, the Jev protocol)
9
+ // run settles the verdicts in code and proposes the frame's decisions, open, beside the venture's
10
+ // other decisions; options come from the frame's own parts or from a dated, cited lookup
11
+ // check a frame matches its schema's rules and names no instrument as an answer
12
+ // eval judges the frame's worked cases and compares the verdicts with what they expect
13
+ //
14
+ // Judgments go through the judgment cache (schema/caching.mjs) with the command in NAIVE_JUDGE_CMD,
15
+ // else Jev when TYPESAFE_API_KEY is set. Lookups are a kit's job: run reads one from --lookup.
16
+ //
17
+ // node schema/frames.mjs list
18
+ // node schema/frames.mjs match "<the founder's words>"
19
+ // node schema/frames.mjs check
20
+ // node schema/frames.mjs run <venture dir> [<frame id>] [--text "<the founder's words>"] [--lookup <file>]
21
+ // node schema/frames.mjs eval <frame id>
22
+
23
+ import { existsSync, readdirSync, readFileSync } from "node:fs";
24
+ import { tmpdir } from "node:os";
25
+ import { join, resolve } from "node:path";
26
+
27
+ const repo = new URL("..", import.meta.url).pathname;
28
+ const load = (p) => JSON.parse(readFileSync(p, "utf8"));
29
+ export const YES = 0.7, NO = 0.3, MATCH = 0.34;
30
+
31
+ /** The premise attacks: the reusable reasoning moves frames call, as hooks are called by components. */
32
+ export const ATTACKS = {
33
+ "test-the-goal": "Make the goal concrete (a number and a date) and check whether the problem serves it at all.",
34
+ "split-the-dimension": "Break a bundled thing (control, ownership, price) into the parts that can move separately.",
35
+ "name-the-control": "Name the specific right that matters: direction, votes, board seats, vetoes, day-to-day authority or the mission.",
36
+ "false-dichotomy": "Ask whether the founder can have both. Answer false, a real trade-off, or a sequence.",
37
+ "sequence-not-choose": "Ask whether both can happen in order, and which comes first.",
38
+ "invert": "Ask what would guarantee the bad outcome, and avoid that first.",
39
+ "who-solved-this": "Find ventures that faced the same shape, through a dated lookup, without copying their answer.",
40
+ };
41
+
42
+ // Words that would make a frame an answer: named instruments, which go stale and can be wrong. A frame
43
+ // that says "use a SAFE" carries the error that a SAFE gives up no equity; it converts at a later round.
44
+ export const NEVER = ["safe", "convertible note", "revenue-based financing", "venture debt", "dual-class", "preferred stock", "crowdfunding", "bootstrap", "term sheet", "series a"];
45
+
46
+ const framesDir = (pkg) => join(repo, "packages", pkg, "frames");
47
+ export function frames() {
48
+ if (!existsSync(join(repo, "packages"))) return [];
49
+ return readdirSync(join(repo, "packages")).filter((p) => existsSync(framesDir(p))).flatMap((p) =>
50
+ readdirSync(framesDir(p)).filter((f) => f.endsWith(".frame.json")).map((f) => ({ ...load(join(framesDir(p), f)), package: p, file: `packages/${p}/frames/${f}` })));
51
+ }
52
+ export const frameOf = (id) => frames().find((f) => f.id === id) ?? null;
53
+
54
+ // ---- check ----
55
+
56
+ const placeholders = (s) => [...String(s).matchAll(/\{([a-z_]+)\}/g)].map((m) => m[1]);
57
+ export function check(f) {
58
+ const errors = [];
59
+ const text = JSON.stringify({ ...f, cases: undefined }).toLowerCase();
60
+ for (const w of NEVER) if (new RegExp(`\\b${w.replace(/[-]/g, "[- ]")}\\b`).test(text)) errors.push(`${f.id}: names "${w}", an answer; a frame describes the problem and a lookup supplies current options`);
61
+ for (const a of f.attacks) if (!ATTACKS[a]) errors.push(`${f.id}: unknown attack ${a}`);
62
+ for (const p of f.premises) {
63
+ if (!f.attacks.includes(p.attack)) errors.push(`${f.id}: premise ${p.id} uses ${p.attack}, which the frame does not list in attacks`);
64
+ for (const r of p.reads ?? []) if (!f.props.includes(r)) errors.push(`${f.id}: premise ${p.id} reads ${r}, which is not one of its props`);
65
+ }
66
+ for (const s of [f.goal, f.reframe]) for (const ph of placeholders(s)) if (!f.props.includes(ph)) errors.push(`${f.id}: {${ph}} is not one of its props`);
67
+ if (f.package && f.package !== f.functions[0]) errors.push(`${f.id}: lives in packages/${f.package} but its first function is ${f.functions[0]}`);
68
+ for (const e of f.emits) if ((e.options_from ?? "frame") === "frame" && !e.options?.length) errors.push(`${f.id}: ${e.id} takes its options from the frame but lists none`);
69
+ for (const c of f.cases ?? []) for (const k of Object.keys(c.expect)) if (k !== "dichotomy" && !f.premises.some((p) => p.id === k)) errors.push(`${f.id}: case ${c.id} expects a verdict for ${k}, which is not a premise`);
70
+ return errors;
71
+ }
72
+
73
+ // ---- match ----
74
+
75
+ const words = (s) => new Set(String(s).toLowerCase().replace(/[^a-z0-9' ]+/g, " ").split(/\s+/).filter((w) => w.length > 2 && !STOP.has(w)));
76
+ const STOP = new Set(["the", "and", "but", "want", "need", "don't", "dont", "not", "can", "how", "what", "with", "for", "that", "this", "too", "much", "have", "get", "give", "away", "without", "keep", "lose", "losing", "my", "our", "you"]);
77
+ /** Frames whose triggers the founder's words fit, best first: the share of a trigger's words they use. */
78
+ export function match(text) {
79
+ const said = words(text);
80
+ return frames().map((f) => {
81
+ const best = Math.max(...f.triggers.map((t) => { const w = words(t); return w.size ? [...w].filter((x) => said.has(x)).length / w.size : 0; }));
82
+ return { id: f.id, title: f.title, score: Math.round(best * 100) / 100 };
83
+ }).filter((m) => m.score >= MATCH).sort((a, b) => b.score - a.score);
84
+ }
85
+
86
+ // ---- props ----
87
+
88
+ const NONE = "not on record";
89
+ const money = (m) => (m ? `${(m.amount / 100).toLocaleString("en-US", { maximumFractionDigits: 0 })} ${m.currency}` : null);
90
+ /** The facts a frame reads, from the venture's records; a fact the records do not hold is "not on record". */
91
+ export async function props(dir) {
92
+ const { decisions } = await import("./decisions.mjs");
93
+ const v = load(join(dir, "venture.json"));
94
+ const ds = decisions(dir).decisions;
95
+ const answer = (id) => { const d = ds.find((x) => x.id === id); return d?.status === "decided" ? d.answer : null; };
96
+ const sum = existsSync(join(dir, "money/_summary.json")) ? load(join(dir, "money/_summary.json")) : null;
97
+ const own = existsSync(join(dir, "governance/ownership.json")) ? load(join(dir, "governance/ownership.json")) : null;
98
+ const people = existsSync(join(dir, "people/people.json")) ? load(join(dir, "people/people.json")) : null;
99
+ const out = {
100
+ phase: v.phase,
101
+ goal: answer("discovery-goal") ?? NONE,
102
+ revenue: sum ? `${money(sum.monthly_inflow)} a month in, as of ${sum.as_of.slice(0, 10)} (${sum.source})` : NONE,
103
+ runway: sum ? (sum.runway_months == null ? `cash ${money(sum.cash)}, net cash flow ${money(sum.monthly_net)} a month, so no runway limit (${sum.source}, as of ${sum.as_of.slice(0, 10)})` : `${sum.runway_months} months (${sum.source}, as of ${sum.as_of.slice(0, 10)})`) : NONE,
104
+ cap_table: own ? own.holders.map((h) => h.name ?? h.id).join(", ") : people ? `${people.people.map((p) => p.name).join(", ")}; no ownership record yet` : NONE,
105
+ control_rights: answer("which-control-matters") ?? NONE,
106
+ jurisdiction: v.profile?.jurisdiction ?? v.form?.jurisdiction ?? NONE,
107
+ };
108
+ return { facts: out, sources: { revenue: sum ? "money/_summary.json" : null, runway: sum ? "money/_summary.json" : null, goal: answer("discovery-goal") ? "decisions: discovery-goal" : null } };
109
+ }
110
+ const fill = (s, facts) => String(s).replace(/\{([a-z_]+)\}/g, (_, k) => (facts[k] && facts[k] !== NONE ? facts[k] : `the venture's ${k.replace(/_/g, " ")}`));
111
+
112
+ // ---- request and verdicts ----
113
+
114
+ const DICHOTOMY = { false: "a false choice: the founder can have both", "trade-off": "a real trade-off: gaining one costs the other", sequence: "a sequence: both, one after the other" };
115
+ /** The typed request: one noul question per premise, and one per reading of the trade. */
116
+ export function request(f, facts) {
117
+ const questions = {};
118
+ for (const p of f.premises) questions[`premise:${p.id}`] = { type: "noul", instructions: `Given only the facts in \`venture\` (a fact that says "${NONE}" is unknown), is this true: ${p.claim}`, criteria: { true: "Yes: the facts show it is true for this venture", false: "No: the facts show it is false for this venture" } };
119
+ if (f.dichotomy) for (const [k, d] of Object.entries(DICHOTOMY)) questions[`dichotomy:${k}`] = { type: "noul", instructions: `The founder's sentence forces this trade: "${f.dichotomy}" Given only the facts in \`venture\`, is that trade ${d}?`, criteria: { true: "Yes", false: "No" } };
120
+ return { state: { guidelines: "Judge each question against the venture's facts alone, as an experienced founder and investor would. Do not assume facts that are not given.", venture: facts, frame: { problem: f.title, goal: fill(f.goal, facts) } }, model: "jev-latest", questions };
121
+ }
122
+ const p = (a) => (typeof a?.noul === "number" ? a.noul : a?.noul === true ? 1 : a?.noul === false ? 0 : null);
123
+ /** Code settles the verdicts: yes at 0.7 or above, no at 0.3 or below, unknown between or unanswered. */
124
+ // When every fact a premise reads is missing from the records, the verdict is unknown whatever the model
125
+ // said: code wins over a judgment the facts cannot support.
126
+ export function verdicts(f, answers, facts = null) {
127
+ const out = {};
128
+ for (const x of f.premises) {
129
+ const v = p(answers[`premise:${x.id}`]);
130
+ const blind = facts && x.reads?.length && x.reads.every((r) => !facts[r] || facts[r] === NONE);
131
+ out[x.id] = { claim: x.claim, attack: x.attack, move: ATTACKS[x.attack], p: v, verdict: blind || v == null ? "unknown" : v >= YES ? "yes" : v <= NO ? "no" : "unknown", ...(blind ? { overruled: `the records hold none of: ${x.reads.join(", ")}` } : {}) };
132
+ }
133
+ let dichotomy = null;
134
+ if (f.dichotomy) {
135
+ const ranked = Object.keys(DICHOTOMY).map((k) => ({ k, p: p(answers[`dichotomy:${k}`]) ?? 0 })).sort((a, b) => b.p - a.p);
136
+ dichotomy = { trade: f.dichotomy, reading: ranked[0].p >= YES ? ranked[0].k : "unknown", p: ranked[0].p };
137
+ }
138
+ return { premises: out, dichotomy };
139
+ }
140
+
141
+ function judgeCmd() {
142
+ if (process.env.NAIVE_JUDGE_CMD) return process.env.NAIVE_JUDGE_CMD;
143
+ if (process.env.TYPESAFE_API_KEY || process.env.TYPESAFEAI_API_KEY) return `node ${join(repo, "platform/integrations/jev.mjs")}`;
144
+ return null;
145
+ }
146
+ async function ask(dir, req) {
147
+ const cmd = judgeCmd();
148
+ if (!cmd) throw new Error("no judge: set NAIVE_JUDGE_CMD (a command that answers the Jev protocol) or TYPESAFE_API_KEY");
149
+ const { judge } = await import("./caching.mjs");
150
+ return judge(dir, req, { cmd, packages: [req.package].filter(Boolean) });
151
+ }
152
+
153
+ // ---- run ----
154
+
155
+ /** Options a lookup found, kept only when dated within the frame's freshness and cited. */
156
+ export function fresh(f, lookup, now = Date.now()) {
157
+ const max = f.freshness.max_age_days * 864e5;
158
+ const list = (lookup?.options ?? lookup ?? []);
159
+ const kept = list.filter((o) => o.option && o.source && o.as_of && now - Date.parse(o.as_of) <= max);
160
+ return { kept, dropped: list.length - kept.length };
161
+ }
162
+
163
+ /** Match (or take) a frame, judge its premises against the venture, and propose its decisions, open. */
164
+ export async function run(dir, { id, text, lookup, now = Date.now(), agentId = "frames", harness, model } = {}) {
165
+ const f = id ? frameOf(id) : (text ? frameOf(match(text)[0]?.id) : null);
166
+ if (!f) return { ok: false, error: id ? `no frame ${id}` : `no frame fits "${text ?? ""}"; node schema/frames.mjs list shows them` };
167
+ const bad = check(f);
168
+ if (bad.length) return { ok: false, error: bad.join("\n") };
169
+ const { facts, sources } = await props(dir);
170
+ const req = request(f, facts);
171
+ let judged;
172
+ try { judged = await ask(dir, req); } catch (e) { return { ok: false, error: e.message, request: req }; }
173
+ const v = verdicts(f, judged.answers, facts);
174
+ const reframe = fill(f.reframe, facts);
175
+ const { propose, decisions } = await import("./decisions.mjs");
176
+ const said = text ? `The founder said: "${text}". ` : "";
177
+ const summary = Object.entries(v.premises).map(([k, x]) => `${k} ${x.verdict}`).join("; ");
178
+ const proposed = [], skipped = [];
179
+ for (const e of f.emits) {
180
+ const existing = decisions(dir).decisions.find((d) => d.id === e.id);
181
+ if (existing?.status === "decided") { skipped.push({ id: e.id, why: "decided already" }); continue; }
182
+ const looked = (e.options_from ?? "frame") === "lookup" ? fresh(f, lookup, now) : null;
183
+ const options = looked ? looked.kept.map((o) => `${o.option} (${o.source}, ${o.as_of.slice(0, 10)})`) : e.options;
184
+ const note = `${said}From the frame ${f.id}: ${reframe} Premises: ${summary}${v.dichotomy ? `; the trade reads as ${v.dichotomy.reading}` : ""}.${looked && !looked.kept.length ? ` Options come from a dated, cited lookup for: ${f.freshness.look_for.join("; ")} (no more than ${f.freshness.max_age_days} days old); none is on file yet.` : ""}`;
185
+ const r = propose(dir, { id: e.id, question: e.question, ...(options?.length ? { options } : {}), ...(e.layer ? { layer: e.layer } : {}), ...(e.needed_in ? { needed_in: e.needed_in } : {}), note }, { agentId, via: "mcp", harness, model: judged.model ?? model });
186
+ if (!r.ok) return { ok: false, error: r.error };
187
+ proposed.push({ id: e.id, question: e.question, options: options ?? [], awaiting: "the founder" });
188
+ }
189
+ return { ok: true, result: { frame: f.id, title: f.title, goal: fill(f.goal, facts), facts, sources, verdicts: v.premises, dichotomy: v.dichotomy, reframe, proposed, skipped, judge: { model: judged.model, cache: judged.cache.status } } };
190
+ }
191
+
192
+ // ---- eval ----
193
+
194
+ /** Judge each worked case and compare the verdicts with what the case expects. */
195
+ // Its judgments are cached outside the repository, so an eval never writes into it.
196
+ export async function evaluate(id, { dir = join(tmpdir(), "naive-frame-evals") } = {}) {
197
+ const f = frameOf(id);
198
+ if (!f) return { ok: false, error: `no frame ${id}` };
199
+ const rows = [];
200
+ for (const c of f.cases ?? []) {
201
+ const { answers, model } = await ask(dir, request(f, c.facts));
202
+ const v = verdicts(f, answers, c.facts);
203
+ const got = { ...Object.fromEntries(Object.entries(v.premises).map(([k, x]) => [k, x.verdict])), ...(v.dichotomy ? { dichotomy: v.dichotomy.reading } : {}) };
204
+ const right = Object.entries(c.expect).filter(([k, x]) => got[k] === x).length;
205
+ rows.push({ case: c.id, model, right, of: Object.keys(c.expect).length, got, expect: c.expect });
206
+ }
207
+ const right = rows.reduce((s, r) => s + r.right, 0), of = rows.reduce((s, r) => s + r.of, 0);
208
+ return { ok: true, result: { frame: id, cases: rows, accuracy: of ? Math.round((right / of) * 100) / 100 : null } };
209
+ }
210
+
211
+ if (process.argv[1] && resolve(process.argv[1]) === new URL(import.meta.url).pathname) {
212
+ const [cmd, ...rest] = process.argv.slice(2);
213
+ const flag = (n) => { const i = rest.indexOf(`--${n}`); if (i < 0) return undefined; const v = rest[i + 1]; rest.splice(i, 2); return v; };
214
+ const show = (r) => { console.log(JSON.stringify(r.ok === undefined ? r : r.ok ? r.result : { error: r.error }, null, 2)); process.exit(r.ok === false ? 1 : 0); };
215
+ if (cmd === "list") show(frames().map((f) => ({ id: f.id, title: f.title, package: f.package, triggers: f.triggers })));
216
+ else if (cmd === "match") show(match(rest.join(" ")));
217
+ else if (cmd === "check") {
218
+ const errs = frames().flatMap(check);
219
+ if (errs.length) { console.error(errs.join("\n")); process.exit(1); }
220
+ console.log(`${frames().length} frame(s): each describes a problem and names no answer.`);
221
+ } else if (cmd === "run") {
222
+ const text = flag("text"), lk = flag("lookup");
223
+ const [dirArg, id] = rest;
224
+ if (!dirArg || !existsSync(join(dirArg, "venture.json"))) { console.error("usage: node schema/frames.mjs run <venture dir> [<frame id>] [--text ...] [--lookup <file>]"); process.exit(2); }
225
+ show(await run(resolve(dirArg), { id, text, lookup: lk ? load(lk) : null }));
226
+ } else if (cmd === "eval") show(await evaluate(rest[0]));
227
+ else { console.error("usage: node schema/frames.mjs list|match|check|run|eval"); process.exit(2); }
228
+ }
@@ -0,0 +1,40 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "freshness-log.schema.json",
4
+ "title": "Freshness log entry",
5
+ "description": "One line of a venture's freshness log (<venture>/knowledge/freshness.jsonl, Revalidating V-1, V-2, V-5, V-7): an on-demand revalidation (a tag, a folder path or a package marked stale, like revalidateTag and revalidatePath), a check that a record is still right without changing it (verify), or a phase change. Append-only; each append is also a line in the provenance log. schema/freshness.mjs writes and reads it.",
6
+ "type": "object",
7
+ "required": ["at", "event", "by"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "at": { "type": "string", "format": "date-time" },
11
+ "event": { "enum": ["revalidate", "verify", "phase"], "description": "revalidate: mark stale on demand. verify: a record was checked and is still right; its age starts again. phase: the venture changed phase" },
12
+ "target": {
13
+ "type": "object",
14
+ "required": ["kind", "value"],
15
+ "additionalProperties": false,
16
+ "description": "revalidate and verify: what is marked. tag: one record file and everything that depends on it. path: every record under a folder. package: every record of a package's record types",
17
+ "properties": {
18
+ "kind": { "enum": ["tag", "path", "package"] },
19
+ "value": { "type": "string", "pattern": "^(?!/)(?!.*\\.\\./).+$" }
20
+ }
21
+ },
22
+ "from": { "type": "string", "description": "phase: the phase before" },
23
+ "to": { "type": "string", "description": "phase: the phase after" },
24
+ "reason": { "type": "string" },
25
+ "pivot": { "type": "boolean", "description": "A revalidate of the validation package because the venture pivoted" },
26
+ "by": {
27
+ "type": "object",
28
+ "required": ["kind", "via"],
29
+ "additionalProperties": false,
30
+ "properties": {
31
+ "kind": { "enum": ["person", "agent"] },
32
+ "id": { "type": "string" },
33
+ "model": { "type": "string" },
34
+ "session": { "type": "string" },
35
+ "harness": { "type": "string" },
36
+ "via": { "enum": ["cli", "mcp", "api", "router"] }
37
+ }
38
+ }
39
+ }
40
+ }
@@ -0,0 +1,44 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "freshness-profiles.schema.json",
4
+ "title": "Freshness profiles",
5
+ "description": "How long records stay fresh (Revalidating, V-1 to V-3), after Next.js cacheLife profiles (stale, revalidate, expire) plus two Naive adds: per_phase (stale once the venture changes phase) and live (never frozen into a release; a live hole). The framework's defaults are knowledge/freshness.json; a venture overrides profiles and record assignments under freshness in its naive.config.json. schema/freshness.mjs reads both.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "$schema": { "type": "string" },
10
+ "note": { "type": "string" },
11
+ "version": { "type": "string" },
12
+ "default": { "type": "string", "description": "The profile a record type gets when records names none" },
13
+ "profiles": {
14
+ "type": "object",
15
+ "additionalProperties": { "$ref": "#/$defs/profile" }
16
+ },
17
+ "records": {
18
+ "type": "object",
19
+ "description": "Profile name by record type id, or by route prefix (validation, foundation/problem); a route prefix wins over the record type, and the longest prefix wins",
20
+ "additionalProperties": { "type": "string" }
21
+ }
22
+ },
23
+ "$defs": {
24
+ "duration": {
25
+ "description": "Seconds, or a number followed by s, m, h, d or w",
26
+ "oneOf": [
27
+ { "type": "integer", "minimum": 0 },
28
+ { "type": "string", "pattern": "^[0-9]+(s|m|h|d|w)$" }
29
+ ]
30
+ },
31
+ "profile": {
32
+ "type": "object",
33
+ "additionalProperties": false,
34
+ "properties": {
35
+ "stale": { "$ref": "#/$defs/duration", "description": "How long an agent may reuse what it read without reading it again" },
36
+ "revalidate": { "$ref": "#/$defs/duration", "description": "After this long since it was last checked, the record is stale: readable with a stale flag, to be checked or redone" },
37
+ "expire": { "$ref": "#/$defs/duration", "description": "After this long it is expired: not relied on, and not frozen into a release" },
38
+ "per_phase": { "type": "boolean", "description": "Stale once the venture changes phase after the record was last checked" },
39
+ "live": { "type": "boolean", "description": "A fast-changing record (pipeline, money, streams): never frozen into a release, it stays a live hole" },
40
+ "note": { "type": "string" }
41
+ }
42
+ }
43
+ }
44
+ }