@knowledge-bus/opencode 0.5.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.
- package/LICENSE +21 -0
- package/index.js +12 -0
- package/package.json +30 -0
- package/references/agent-runtime.md +35 -0
- package/references/knowledge-bus-directory.md +53 -0
- package/references/knowledge-bus-protocol.yaml +432 -0
- package/references/product-development/type-guidance.kbp.yaml +711 -0
- package/references/product-development/universe.kbp.yaml +411 -0
- package/runtime/kbp.py +91 -0
- package/runtime/knowledge_bus-0.5.0-py3-none-any.whl +0 -0
- package/runtime/requirements.json +9 -0
- package/skills/kb-check/SKILL.md +30 -0
- package/skills/kb-evolve/SKILL.md +84 -0
- package/skills/kb-ingest/SKILL.md +59 -0
- package/skills/kb-uncover-decision/SKILL.md +32 -0
- package/skills/kb-uncover-question/SKILL.md +35 -0
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
universe:
|
|
2
|
+
id: product-development
|
|
3
|
+
label: Product development
|
|
4
|
+
version: 0.5
|
|
5
|
+
conforms_to: kbp/0.5
|
|
6
|
+
ordering_frame: phase
|
|
7
|
+
overview:
|
|
8
|
+
covers: >
|
|
9
|
+
The reasoning around deliberate work — what makes it worth doing, what it should
|
|
10
|
+
be, and whether it held up. The work may produce something made or put in place,
|
|
11
|
+
a service rendered, or something learned; for a recipient — including your own
|
|
12
|
+
later self — who simply receives it, free to take it or leave it, or paying
|
|
13
|
+
for it.
|
|
14
|
+
for: >
|
|
15
|
+
Whoever is accountable for that judgement or has to account for it later — one person
|
|
16
|
+
on one machine, a group, or an organisation.
|
|
17
|
+
excludes: >
|
|
18
|
+
Doing or delivering the work itself.
|
|
19
|
+
|
|
20
|
+
statuses: [conjecture, modelled, contracted, measured, adjudicated, superseded]
|
|
21
|
+
|
|
22
|
+
frames:
|
|
23
|
+
|
|
24
|
+
- id: phase
|
|
25
|
+
code: ft1k1
|
|
26
|
+
role: ordering # assigns every element its place in the sequence
|
|
27
|
+
set_by: universe # fixed in this file, by whoever authors the universe
|
|
28
|
+
attaches_to: element
|
|
29
|
+
values:
|
|
30
|
+
- { id: strategy, question: "Who are we, where are we going, and why that way?" }
|
|
31
|
+
- { id: discovery, question: "What is worth solving, for whom, and is it viable?" }
|
|
32
|
+
- { id: design, question: "What are we building and how does it behave?" }
|
|
33
|
+
- { id: validation, question: "How do we know it works?" }
|
|
34
|
+
- { id: architecture, question: "How does it technically hold together?" }
|
|
35
|
+
- { id: operate, question: "How is this carried out and kept working?" }
|
|
36
|
+
|
|
37
|
+
- id: time-separation
|
|
38
|
+
code: fn7cn
|
|
39
|
+
role: applicability # decides whether writing anything down is warranted
|
|
40
|
+
set_by: instance # per piece of work — this note, this effort
|
|
41
|
+
question: "Who has to reconstruct this reasoning without the author present?"
|
|
42
|
+
values: [none, across-sessions, across-people, across-organisations]
|
|
43
|
+
|
|
44
|
+
- id: reversibility
|
|
45
|
+
code: fzjkj
|
|
46
|
+
role: applicability
|
|
47
|
+
set_by: instance # a given step is reversible or not; asked each time
|
|
48
|
+
question: "What does proceeding foreclose?"
|
|
49
|
+
values: [reversible, costly, irreversible]
|
|
50
|
+
|
|
51
|
+
- id: uptake
|
|
52
|
+
code: f6shk
|
|
53
|
+
role: gating # switches elements and artifacts on or off
|
|
54
|
+
set_by: scope # declared at whatever scope asserts it; narrower scopes inherit or re-declare
|
|
55
|
+
question: "How does the outcome reach the people it's for?"
|
|
56
|
+
values:
|
|
57
|
+
- { id: given, question: "Does it arrive whether or not they'd choose it?" }
|
|
58
|
+
- { id: chosen, question: "Do they take it up only by deciding to, with nothing to pay?" }
|
|
59
|
+
- { id: bought, question: "Is paying how they take it up?" }
|
|
60
|
+
|
|
61
|
+
- id: authority
|
|
62
|
+
code: f6yr9
|
|
63
|
+
role: gating
|
|
64
|
+
set_by: scope
|
|
65
|
+
question: "Whose assent is a precondition?"
|
|
66
|
+
values: [none, discretionary, notify, approve, statutory]
|
|
67
|
+
|
|
68
|
+
- id: maturity
|
|
69
|
+
code: fcz7q
|
|
70
|
+
role: gating
|
|
71
|
+
set_by: scope # re-asked as the work matures: unproven, proven, scaling
|
|
72
|
+
question: "How settled is the bet this work rests on?"
|
|
73
|
+
values: [unproven, proven, scaling]
|
|
74
|
+
|
|
75
|
+
- id: outcome
|
|
76
|
+
code: fdhsz
|
|
77
|
+
role: gating
|
|
78
|
+
set_by: instance # per outcome-component: the chassis and the firmware answer differently
|
|
79
|
+
attaches_to: outcome-component
|
|
80
|
+
question: "What kind of thing does this work produce?"
|
|
81
|
+
facets:
|
|
82
|
+
form: [artifact, service, claim]
|
|
83
|
+
replication: [singular, serial, unbounded]
|
|
84
|
+
mutability: [fixed-at-delivery, field-updatable, continuously-deployed]
|
|
85
|
+
|
|
86
|
+
- id: audience
|
|
87
|
+
code: f80a5
|
|
88
|
+
role: selection # shapes the composition when an artifact crosses
|
|
89
|
+
set_by: instance # per crossing: this artifact, this recipient
|
|
90
|
+
values: [self, internal, counterparty, regulator, public]
|
|
91
|
+
|
|
92
|
+
empty_composition:
|
|
93
|
+
when: { time-separation: [none], reversibility: [reversible] }
|
|
94
|
+
|
|
95
|
+
relation_kinds:
|
|
96
|
+
- { id: presupposes, ordered: true }
|
|
97
|
+
- { id: distinct-from, ordered: false }
|
|
98
|
+
- { id: counterweight-to, ordered: false }
|
|
99
|
+
- { id: feeds, ordered: true }
|
|
100
|
+
- { id: split-signal, ordered: true }
|
|
101
|
+
- { id: descendant-of, ordered: true }
|
|
102
|
+
- { id: requires, ordered: true }
|
|
103
|
+
- { id: nests-under, ordered: true }
|
|
104
|
+
|
|
105
|
+
elements:
|
|
106
|
+
|
|
107
|
+
- { id: product-vision, code: emsdr, question: "What future are we committing to, and why is it worth wanting?", phase: strategy, cardinality: singleton }
|
|
108
|
+
- { id: positioning-statement, code: e9x77, question: "For whom, against what alternatives, why us?", phase: strategy, cardinality: per-segment, gate: { uptake: [chosen, bought] } }
|
|
109
|
+
- { id: customer-segments, code: ebvkm, question: "Who exactly is served, grouped how?", phase: discovery, cardinality: singleton }
|
|
110
|
+
- { id: value-proposition, code: edffx, question: "Why would a segment choose this over its alternatives?", phase: strategy, cardinality: per-segment, gate: { uptake: [bought] } }
|
|
111
|
+
- { id: case-for-change, code: eaddp, question: "Why is this worth doing at all, versus not doing it?", phase: strategy, cardinality: singleton }
|
|
112
|
+
- { id: problem-statement, code: eyhkm, question: "What pain, for whom, why now?", phase: discovery, cardinality: singleton }
|
|
113
|
+
- { id: solution-overview, code: eseq3, question: "What is the intended solution, in outline?", phase: design, cardinality: singleton }
|
|
114
|
+
- { id: goals-and-non-goals, code: ezw7x, question: "What outcomes is this aiming for — and pointedly not?", phase: design, cardinality: singleton }
|
|
115
|
+
- { id: channels, code: eeq3f, question: "How do we reach and deliver to each segment?", phase: strategy, cardinality: per-segment, gate: { uptake: [chosen, bought] } }
|
|
116
|
+
- { id: customer-relationships, code: e9h1v, question: "How is each segment acquired, retained, grown?", phase: strategy, cardinality: per-segment }
|
|
117
|
+
- { id: revenue-streams, code: ebs31, question: "How does delivered value convert to money?", phase: strategy, cardinality: per-stream, gate: { uptake: [bought] } }
|
|
118
|
+
- { id: funding-source, code: exzg8, question: "Where does the sustaining resource come from, with what conditions attached?", phase: strategy, cardinality: per-source }
|
|
119
|
+
- { id: cost-structure, code: ereet, question: "What does operating this cost, and what drives it?", phase: strategy, cardinality: singleton }
|
|
120
|
+
- { id: key-resources, code: e72wk, question: "What assets must be owned or controlled?", phase: strategy, cardinality: singleton }
|
|
121
|
+
- { id: key-activities, code: ea6q2, question: "What must be done ourselves, and done well?", phase: strategy, cardinality: singleton }
|
|
122
|
+
- { id: key-partnerships, code: er20v, question: "What is deliberately relied on others for?", phase: strategy, cardinality: per-partner }
|
|
123
|
+
- { id: unfair-advantage, code: e9g24, question: "What can't be easily copied or bought?", phase: strategy, cardinality: singleton, gate: { uptake: [bought] } }
|
|
124
|
+
- { id: trade-offs, code: e45f8, question: "What is deliberately not being done?", phase: strategy, cardinality: per-refusal }
|
|
125
|
+
- { id: growth-mechanism, code: evkfg, question: "How does usage compound?", phase: strategy, cardinality: singleton, gate: { uptake: [bought] } }
|
|
126
|
+
- { id: capabilities, code: eqsja, question: "What must we be able to do to execute?", phase: strategy, cardinality: singleton }
|
|
127
|
+
- { id: north-star-metric, code: ezg3v, question: "What single measure best proxies delivered value?", phase: validation, cardinality: singleton, gate: { uptake: [chosen, bought] } }
|
|
128
|
+
- { id: input-metrics, code: ehk97, question: "Which controllable measures drive the outcome?", phase: validation, cardinality: per-north-star }
|
|
129
|
+
- { id: guardrail-health-metrics, code: e2hrs, question: "What must not degrade while pushing forward?", phase: validation, cardinality: per-owner }
|
|
130
|
+
- { id: success-criteria, code: e0pge, question: "What observable result counts as 'it worked'?", phase: validation, cardinality: per-effort }
|
|
131
|
+
- { id: market-sizing, code: erw62, question: "How big is the addressable population, credibly?", phase: discovery, cardinality: singleton, gate: { uptake: [bought] } }
|
|
132
|
+
- { id: internal-strengths-weaknesses, code: ews8m, question: "Where are we strong or exposed, internally?", phase: strategy, cardinality: singleton }
|
|
133
|
+
- { id: external-opportunities-threats, code: egp69, question: "What outside forces help or endanger?", phase: strategy, cardinality: per-force, closable: false }
|
|
134
|
+
- { id: macro-environment-factors, code: earc7, question: "Which external forces shape the space?", phase: strategy, cardinality: per-lens, closable: true }
|
|
135
|
+
- { id: competitor-profile, code: e6fsz, question: "Who else solves this, how, and how well?", phase: discovery, cardinality: per-competitor, closable: false, gate: { uptake: [chosen, bought] } }
|
|
136
|
+
- { id: jobs-to-be-done, code: ev2wp, question: "What progress is being 'hired' for, in what circumstance?", phase: discovery, cardinality: per-job }
|
|
137
|
+
- { id: pains-and-gains, code: ekyn8, question: "What frustrates today, and what would better look like?", phase: discovery, cardinality: per-segment }
|
|
138
|
+
- { id: user-job-stories, code: ed6n5, question: "What behavior, in what situation, toward what outcome?", phase: design, cardinality: per-story }
|
|
139
|
+
- { id: stepwise-trace, code: e58p3, question: "What happens at each step, and what does each step hand to the next?", phase: design, cardinality: per-scenario }
|
|
140
|
+
- { id: risks-and-assumptions, code: edew6, question: "What must be true, what could break for us, and what's the response?", phase: discovery, cardinality: per-risk }
|
|
141
|
+
- { id: affected-and-interested-parties, code: eppxq, question: "Who is materially affected or burdened without owning this, and with what standing?", phase: discovery, cardinality: per-party }
|
|
142
|
+
- { id: decision-authority-and-approvals, code: eqj19, question: "Whose agreement is required for this to proceed, under what delegation?", phase: strategy, cardinality: per-gate }
|
|
143
|
+
- { id: consent-and-authority, code: e921t, question: "Under what authority is this permitted, from whom, obtained when, expiring when?", phase: strategy, cardinality: per-consent, gate: { authority: [discretionary, notify, approve, statutory] } }
|
|
144
|
+
- { id: scope-in-out, code: esk7t, question: "What is included now, deferred, or refused?", phase: design, cardinality: singleton }
|
|
145
|
+
- { id: constraints, code: emwtf, question: "What externally imposed fixed limits bound the work?", phase: design, cardinality: per-constraint }
|
|
146
|
+
- { id: as-built-survey, code: esy0b, question: "What is actually there, measured to what tolerance, observed when?", phase: discovery, cardinality: per-subject }
|
|
147
|
+
- { id: cross-cutting-concerns, code: eyn7j, question: "What system-wide obligations must the design uphold?", phase: design, cardinality: per-concern }
|
|
148
|
+
- { id: visual-identity-rules, code: ej174, question: "How must the brand be rendered, and what renderings are forbidden?", phase: design, cardinality: singleton }
|
|
149
|
+
- { id: verbal-identity-rules, code: ehpbb, question: "How must the brand be worded, and what wordings are forbidden?", phase: design, cardinality: singleton }
|
|
150
|
+
- { id: alternatives-considered, code: e7j8k, question: "What else could have been done, and why not?", phase: design, cardinality: per-decision }
|
|
151
|
+
- { id: decision-criteria, code: e32n2, question: "By what criteria are the options judged, and how are they traded off?", phase: design, cardinality: per-decision }
|
|
152
|
+
- { id: decision, code: e43c2, question: "What was decided, and on what reasoning?", phase: design, cardinality: per-decision }
|
|
153
|
+
- { id: accepted-consequences, code: er7ec, question: "What are we accepting as a consequence of this commitment?", phase: design, cardinality: per-decision }
|
|
154
|
+
- { id: reversal-condition, code: ebxtg, question: "What observable condition would reopen this?", phase: design, cardinality: per-decision }
|
|
155
|
+
- { id: hypothesis, code: eavvd, question: "What relation do we predict, and what observation would refute it?", phase: discovery, cardinality: per-hypothesis, gate: { outcome: { form: [claim] } } }
|
|
156
|
+
- { id: measurement-protocol, code: ewd2m, question: "By what prescribed procedure are data produced, and how is each construct operationalised into a measured quantity?", phase: validation, cardinality: per-construct, gate: { outcome: { form: [claim] } } }
|
|
157
|
+
- { id: prior-art, code: e0c8e, question: "How have others solved this, and what does that teach?", phase: design, cardinality: per-precedent }
|
|
158
|
+
- { id: rollout-and-phasing, code: erszc, question: "How does this reach reality, in graduated exposure, with kill criteria?", phase: operate, cardinality: singleton }
|
|
159
|
+
- { id: sequence-and-foreclosure, code: enbkd, question: "In what order must this be done, and what does each step foreclose?", phase: design, cardinality: singleton }
|
|
160
|
+
- { id: open-questions, code: edcxt, question: "What is knowingly unknown?", phase: design, cardinality: per-question }
|
|
161
|
+
- { id: system-boundary-and-context, code: ec73p, question: "What is inside the system, and what does it touch?", phase: architecture, cardinality: singleton }
|
|
162
|
+
- { id: components-and-responsibilities, code: eey7j, question: "What parts exist, each owning what?", phase: architecture, cardinality: per-component, gate: { outcome: { form: [artifact] } } }
|
|
163
|
+
- { id: data-flows-and-integrations, code: e11bw, question: "What moves where, over which contracts?", phase: architecture, cardinality: per-flow }
|
|
164
|
+
- { id: canonical-model, code: eenkt, question: "What named categories carve the domain, and what shape does each entry take?", phase: architecture, cardinality: singleton }
|
|
165
|
+
|
|
166
|
+
artifacts:
|
|
167
|
+
|
|
168
|
+
- id: product-strategy-canvas
|
|
169
|
+
code: aqfpn
|
|
170
|
+
enablement: { action: "commit to a direction and the refusals that make it real", actor: decision-makers, timing: before allocating a cycle's resources }
|
|
171
|
+
alias: { kind: none, reason: no-aligned-form }
|
|
172
|
+
disabled_when: { uptake: [given] }
|
|
173
|
+
composition:
|
|
174
|
+
core: [product-vision, customer-segments, value-proposition, cost-structure, trade-offs,
|
|
175
|
+
north-star-metric, growth-mechanism, capabilities, unfair-advantage]
|
|
176
|
+
situational: [positioning-statement, input-metrics, revenue-streams, case-for-change]
|
|
177
|
+
|
|
178
|
+
- id: business-model-canvas
|
|
179
|
+
code: af0pt
|
|
180
|
+
enablement: { action: "judge whether the business logic closes — value, delivery and money", actor: operator or backer, timing: before or during commitment }
|
|
181
|
+
alias: { kind: normative, form: "Business Model Canvas (Osterwalder)" }
|
|
182
|
+
disabled_when: { uptake: [given, chosen] }
|
|
183
|
+
composition:
|
|
184
|
+
core: [customer-segments, value-proposition, channels, customer-relationships,
|
|
185
|
+
revenue-streams, key-resources, key-activities, key-partnerships, cost-structure]
|
|
186
|
+
situational: []
|
|
187
|
+
|
|
188
|
+
- id: lean-canvas
|
|
189
|
+
code: ajw0x
|
|
190
|
+
enablement: { action: "judge whether an early-stage bet is worth testing next", actor: founder or sponsor, timing: before fit is established }
|
|
191
|
+
alias: { kind: normative, form: "Lean Canvas (Maurya)" }
|
|
192
|
+
disabled_when: { uptake: [given, chosen] }
|
|
193
|
+
composition:
|
|
194
|
+
core: [problem-statement, customer-segments, value-proposition, solution-overview,
|
|
195
|
+
channels, revenue-streams, cost-structure, input-metrics, unfair-advantage]
|
|
196
|
+
situational: []
|
|
197
|
+
|
|
198
|
+
- id: startup-canvas
|
|
199
|
+
code: awrrs
|
|
200
|
+
enablement: { action: "commit to a venture direction with its business logic attached", actor: founder and backer, timing: at formation }
|
|
201
|
+
alias: { kind: none, reason: no-aligned-form }
|
|
202
|
+
disabled_when: { uptake: [given, chosen] }
|
|
203
|
+
composition:
|
|
204
|
+
core: [product-vision, customer-segments, value-proposition, cost-structure, trade-offs,
|
|
205
|
+
north-star-metric, growth-mechanism, capabilities, unfair-advantage, revenue-streams]
|
|
206
|
+
situational: [positioning-statement, input-metrics]
|
|
207
|
+
|
|
208
|
+
- id: swot-analysis
|
|
209
|
+
code: a7ds8
|
|
210
|
+
enablement: { action: "orient on position before choosing a direction", actor: planning group, timing: before strategy is set }
|
|
211
|
+
alias: { kind: normative, form: "SWOT" }
|
|
212
|
+
composition:
|
|
213
|
+
core: [internal-strengths-weaknesses, external-opportunities-threats]
|
|
214
|
+
situational: [macro-environment-factors, competitor-profile]
|
|
215
|
+
|
|
216
|
+
- id: pestle-analysis
|
|
217
|
+
code: amr2m
|
|
218
|
+
enablement: { action: "orient on external forces before committing to a direction", actor: planning group, timing: before strategy is set }
|
|
219
|
+
alias: { kind: normative, form: "PESTLE" }
|
|
220
|
+
composition:
|
|
221
|
+
core: [macro-environment-factors]
|
|
222
|
+
situational: [external-opportunities-threats, risks-and-assumptions]
|
|
223
|
+
|
|
224
|
+
- id: competitor-analysis
|
|
225
|
+
code: az67c
|
|
226
|
+
enablement: { action: "position against the alternatives a chooser actually has", actor: "strategy, marketing and sales", timing: continuous }
|
|
227
|
+
alias: { kind: descriptive, form: "competitor analysis" }
|
|
228
|
+
disabled_when: { uptake: [given] }
|
|
229
|
+
composition:
|
|
230
|
+
core: [competitor-profile]
|
|
231
|
+
situational: [positioning-statement, external-opportunities-threats, market-sizing]
|
|
232
|
+
|
|
233
|
+
- id: persona-profile
|
|
234
|
+
code: a7rcy
|
|
235
|
+
enablement: { action: "design for a specific circumstance rather than an average", actor: "designers, researchers and product", timing: before solution design }
|
|
236
|
+
alias: { kind: descriptive, form: "persona profile" }
|
|
237
|
+
composition:
|
|
238
|
+
core: [jobs-to-be-done, pains-and-gains]
|
|
239
|
+
situational: [customer-segments, user-job-stories, channels]
|
|
240
|
+
|
|
241
|
+
- id: opportunity-assessment
|
|
242
|
+
code: a2cwq
|
|
243
|
+
enablement: { action: "decide whether to pursue this at all", actor: sponsor, timing: before committing build resources }
|
|
244
|
+
alias: { kind: descriptive, form: "product brief / one-pager" }
|
|
245
|
+
composition:
|
|
246
|
+
core:
|
|
247
|
+
- { element: problem-statement, mode: owns }
|
|
248
|
+
- { element: case-for-change, mode: owns }
|
|
249
|
+
- { element: customer-segments, mode: owns }
|
|
250
|
+
- { element: risks-and-assumptions, mode: owns }
|
|
251
|
+
- { element: consent-and-authority, mode: owns, when: { authority: [approve, statutory] } }
|
|
252
|
+
situational: [market-sizing, value-proposition, competitor-profile, success-criteria,
|
|
253
|
+
affected-and-interested-parties, decision-authority-and-approvals, funding-source]
|
|
254
|
+
|
|
255
|
+
- id: risk-assessment
|
|
256
|
+
code: abewy
|
|
257
|
+
enablement: { action: "decide what to mitigate, accept or watch, and who owns each", actor: accountable owner, timing: before and throughout }
|
|
258
|
+
alias: { kind: descriptive, form: "risk register" }
|
|
259
|
+
composition:
|
|
260
|
+
core: [risks-and-assumptions, affected-and-interested-parties, scope-in-out]
|
|
261
|
+
situational: [guardrail-health-metrics, open-questions]
|
|
262
|
+
|
|
263
|
+
- id: design-doc
|
|
264
|
+
code: a0czz
|
|
265
|
+
enablement: { action: "agree or object to a proposed approach", actor: reviewer, timing: before build }
|
|
266
|
+
alias: { kind: descriptive, form: "RFC / RFD" }
|
|
267
|
+
composition:
|
|
268
|
+
core:
|
|
269
|
+
- { element: problem-statement, mode: links }
|
|
270
|
+
- { element: goals-and-non-goals, mode: owns }
|
|
271
|
+
- { element: solution-overview, mode: owns }
|
|
272
|
+
- { element: alternatives-considered, mode: owns }
|
|
273
|
+
- { element: open-questions, mode: owns }
|
|
274
|
+
- { element: constraints, mode: owns, when: { authority: [approve, statutory] } }
|
|
275
|
+
- { element: cross-cutting-concerns, mode: owns, when: { authority: [approve, statutory] } }
|
|
276
|
+
- { element: risks-and-assumptions, mode: owns, when: { authority: [approve, statutory] } }
|
|
277
|
+
- { element: sequence-and-foreclosure, mode: owns, when: { reversibility: [costly, irreversible] } }
|
|
278
|
+
situational: [rollout-and-phasing, prior-art, scope-in-out, success-criteria, user-job-stories,
|
|
279
|
+
stepwise-trace, canonical-model, as-built-survey, consent-and-authority]
|
|
280
|
+
|
|
281
|
+
- id: brand-identity-guide
|
|
282
|
+
code: atm2v
|
|
283
|
+
enablement: { action: "render and voice the identity correctly without asking", actor: anyone producing expression, timing: continuous }
|
|
284
|
+
alias: { kind: descriptive, form: "brand guidelines / style guide / DESIGN.md" }
|
|
285
|
+
composition:
|
|
286
|
+
core:
|
|
287
|
+
- { element: visual-identity-rules, mode: owns }
|
|
288
|
+
- { element: verbal-identity-rules, mode: owns }
|
|
289
|
+
situational:
|
|
290
|
+
- { element: product-vision, mode: links }
|
|
291
|
+
- { element: positioning-statement, mode: links }
|
|
292
|
+
- { element: constraints, mode: owns }
|
|
293
|
+
- { element: prior-art, mode: owns }
|
|
294
|
+
- { element: open-questions, mode: owns }
|
|
295
|
+
|
|
296
|
+
- id: scenario-walkthrough
|
|
297
|
+
code: azetx
|
|
298
|
+
enablement: { action: "verify one concrete path resolves end to end", actor: reviewer, timing: before build }
|
|
299
|
+
alias: { kind: descriptive, form: "key path scenario" }
|
|
300
|
+
composition:
|
|
301
|
+
core: [stepwise-trace]
|
|
302
|
+
situational: [user-job-stories, data-flows-and-integrations, constraints]
|
|
303
|
+
|
|
304
|
+
- id: success-metrics
|
|
305
|
+
code: ar2vy
|
|
306
|
+
enablement: { action: "tell whether the thing is working, and what to push and protect", actor: operator, timing: continuous after launch }
|
|
307
|
+
alias: { kind: descriptive, form: "North Star framework" }
|
|
308
|
+
disabled_when: { uptake: [given] }
|
|
309
|
+
composition:
|
|
310
|
+
core: [north-star-metric, input-metrics, guardrail-health-metrics]
|
|
311
|
+
situational: [success-criteria]
|
|
312
|
+
|
|
313
|
+
- id: architecture-overview
|
|
314
|
+
code: a74pm
|
|
315
|
+
enablement: { action: "understand the shape well enough to change part of it safely", actor: engineer or architect, timing: on joining or before changing }
|
|
316
|
+
alias: { kind: descriptive, form: "C4 levels 1–2" }
|
|
317
|
+
composition:
|
|
318
|
+
core: [system-boundary-and-context, components-and-responsibilities, data-flows-and-integrations]
|
|
319
|
+
situational: [constraints, trade-offs, risks-and-assumptions, canonical-model, as-built-survey]
|
|
320
|
+
|
|
321
|
+
- id: system-context-diagram
|
|
322
|
+
code: avxcm
|
|
323
|
+
enablement: { action: "see the boundary and what crosses it", actor: anyone new to the system, timing: on first contact }
|
|
324
|
+
alias: { kind: normative, form: "C4 level 1" }
|
|
325
|
+
composition:
|
|
326
|
+
core: [system-boundary-and-context, data-flows-and-integrations]
|
|
327
|
+
situational: []
|
|
328
|
+
|
|
329
|
+
- id: decision-brief
|
|
330
|
+
code: a20v3
|
|
331
|
+
enablement: { action: "choose among live alternatives by a set date", actor: the person accountable for the choice, timing: before the decision is taken }
|
|
332
|
+
alias: { kind: descriptive, form: "options paper / decision document (DACI, SPADE)" }
|
|
333
|
+
composition:
|
|
334
|
+
core:
|
|
335
|
+
- { element: alternatives-considered, mode: owns }
|
|
336
|
+
- { element: decision-criteria, mode: owns }
|
|
337
|
+
- { element: decision-authority-and-approvals, mode: owns, when: { authority: [approve, statutory] } }
|
|
338
|
+
- { element: problem-statement, mode: links }
|
|
339
|
+
situational: [constraints, risks-and-assumptions, prior-art, open-questions, scope-in-out]
|
|
340
|
+
|
|
341
|
+
- id: decision-record
|
|
342
|
+
code: ayx0k
|
|
343
|
+
enablement: { action: "know whether this decision still stands, and reopen it correctly if not", actor: future reader, timing: any time after }
|
|
344
|
+
alias: { kind: descriptive, form: "ADR (Nygard) / MADR / record of decision" }
|
|
345
|
+
composition:
|
|
346
|
+
core:
|
|
347
|
+
- { element: decision, mode: owns }
|
|
348
|
+
- { element: accepted-consequences, mode: owns }
|
|
349
|
+
- { element: reversal-condition, mode: owns }
|
|
350
|
+
- { element: alternatives-considered, mode: owns }
|
|
351
|
+
- { element: risks-and-assumptions, mode: owns }
|
|
352
|
+
- { element: problem-statement, mode: links }
|
|
353
|
+
- { element: decision-criteria, mode: links, when: { authority: [approve, statutory] } }
|
|
354
|
+
situational: [constraints, prior-art, open-questions]
|
|
355
|
+
|
|
356
|
+
- id: working-note
|
|
357
|
+
code: axh9h
|
|
358
|
+
enablement: { action: "resume your own work after a gap without re-deriving it", actor: the author at a later time, timing: across sessions }
|
|
359
|
+
alias: { kind: none, reason: no-aligned-form }
|
|
360
|
+
disabled_when: { time-separation: [none] }
|
|
361
|
+
composition:
|
|
362
|
+
core: [constraints, scope-in-out, open-questions]
|
|
363
|
+
situational: [trade-offs, as-built-survey, success-criteria]
|
|
364
|
+
|
|
365
|
+
relations:
|
|
366
|
+
|
|
367
|
+
- { from: value-proposition, to: case-for-change, kind: distinct-from }
|
|
368
|
+
- { from: constraints, to: as-built-survey, kind: distinct-from }
|
|
369
|
+
- { from: constraints, to: trade-offs, kind: distinct-from }
|
|
370
|
+
- { from: goals-and-non-goals, to: scope-in-out, kind: distinct-from }
|
|
371
|
+
- { from: risks-and-assumptions, to: affected-and-interested-parties, kind: distinct-from }
|
|
372
|
+
- { from: hypothesis, to: success-criteria, kind: distinct-from }
|
|
373
|
+
- { from: hypothesis, to: risks-and-assumptions, kind: distinct-from }
|
|
374
|
+
- { from: rollout-and-phasing, to: sequence-and-foreclosure, kind: distinct-from }
|
|
375
|
+
- { from: key-activities, to: capabilities, kind: distinct-from }
|
|
376
|
+
- { from: components-and-responsibilities, to: canonical-model, kind: distinct-from }
|
|
377
|
+
- { from: customer-segments, to: canonical-model, kind: distinct-from }
|
|
378
|
+
- { from: prior-art, to: competitor-profile, kind: distinct-from }
|
|
379
|
+
- { from: accepted-consequences, to: trade-offs, kind: distinct-from }
|
|
380
|
+
- { from: alternatives-considered, to: decision, kind: distinct-from }
|
|
381
|
+
- { from: decision-criteria, to: goals-and-non-goals, kind: distinct-from }
|
|
382
|
+
- { from: decision-criteria, to: constraints, kind: distinct-from }
|
|
383
|
+
- { from: reversal-condition, to: risks-and-assumptions, kind: distinct-from }
|
|
384
|
+
- { from: goals-and-non-goals, to: trade-offs, kind: distinct-from }
|
|
385
|
+
- { from: visual-identity-rules, to: cross-cutting-concerns, kind: distinct-from }
|
|
386
|
+
- { from: verbal-identity-rules, to: positioning-statement, kind: distinct-from }
|
|
387
|
+
- { from: verbal-identity-rules, to: value-proposition, kind: distinct-from }
|
|
388
|
+
- { from: stepwise-trace, to: solution-overview, kind: distinct-from }
|
|
389
|
+
- { from: revenue-streams, to: funding-source, kind: distinct-from }
|
|
390
|
+
- { from: decision-authority-and-approvals, to: affected-and-interested-parties, kind: distinct-from }
|
|
391
|
+
- { from: constraints, to: consent-and-authority, kind: presupposes }
|
|
392
|
+
- { from: north-star-metric, to: input-metrics, kind: requires }
|
|
393
|
+
- { from: guardrail-health-metrics, to: input-metrics, kind: counterweight-to }
|
|
394
|
+
- { from: measurement-protocol, to: hypothesis, kind: presupposes }
|
|
395
|
+
- { from: external-opportunities-threats, to: macro-environment-factors, kind: feeds }
|
|
396
|
+
- { from: external-opportunities-threats, to: competitor-profile, kind: feeds }
|
|
397
|
+
- { from: as-built-survey, to: sequence-and-foreclosure, kind: feeds }
|
|
398
|
+
- { from: stepwise-trace, to: data-flows-and-integrations, kind: split-signal }
|
|
399
|
+
- { from: product-vision, to: product-vision, kind: nests-under, legality: permitted }
|
|
400
|
+
- { from: design-doc, to: opportunity-assessment, kind: presupposes }
|
|
401
|
+
- { from: persona-profile, to: problem-statement, kind: presupposes }
|
|
402
|
+
- { from: scenario-walkthrough, to: design-doc, kind: presupposes }
|
|
403
|
+
- { from: architecture-overview, to: design-doc, kind: presupposes }
|
|
404
|
+
- { from: success-metrics, to: north-star-metric, kind: requires }
|
|
405
|
+
- { from: success-criteria, to: trade-offs, kind: feeds, legality: permitted }
|
|
406
|
+
- { from: guardrail-health-metrics, to: decision, kind: feeds, legality: permitted, gate: { authority: approve } }
|
|
407
|
+
- { from: success-criteria, to: hypothesis, kind: feeds, legality: permitted-if-logged }
|
|
408
|
+
- { from: decision, to: scope-in-out, kind: feeds, freeze: baselined }
|
|
409
|
+
- { from: decision-criteria, to: decision, kind: feeds }
|
|
410
|
+
- { from: decision-record, to: design-doc, kind: distinct-from }
|
|
411
|
+
- { from: decision-brief, to: decision-record, kind: feeds }
|
package/runtime/kbp.py
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""Run the bundled checker without writing into the plugin or changing scope."""
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
import json
|
|
5
|
+
import os
|
|
6
|
+
import re
|
|
7
|
+
import shutil
|
|
8
|
+
import subprocess
|
|
9
|
+
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def command(arguments, runtime=None, environ=None):
|
|
14
|
+
"""Build an isolated checker invocation from verified bundled dependencies."""
|
|
15
|
+
runtime = (runtime or Path(__file__).resolve().parent).resolve()
|
|
16
|
+
env = dict(os.environ if environ is None else environ)
|
|
17
|
+
config = json.loads((runtime / "requirements.json").read_text())
|
|
18
|
+
requirement = config.get("requires_python", "")
|
|
19
|
+
match = re.fullmatch(r">=(\d+)\.(\d+)(?:\.(\d+))?", requirement)
|
|
20
|
+
if not match:
|
|
21
|
+
raise ValueError("Bundled Python requirement is missing or unsupported.")
|
|
22
|
+
minimum = tuple(int(part or 0) for part in match.groups())
|
|
23
|
+
if sys.version_info[:3] < minimum:
|
|
24
|
+
raise ValueError(
|
|
25
|
+
f"Knowledge Bus requires Python {requirement}; "
|
|
26
|
+
f"this interpreter is {'.'.join(map(str, sys.version_info[:3]))}."
|
|
27
|
+
)
|
|
28
|
+
uv = shutil.which("uv", path=env.get("PATH"))
|
|
29
|
+
if not uv:
|
|
30
|
+
raise ValueError("Knowledge Bus requires uv. See https://docs.astral.sh/uv/.")
|
|
31
|
+
wheel = runtime / config["wheel"]
|
|
32
|
+
if wheel.parent != runtime or not wheel.is_file():
|
|
33
|
+
raise ValueError("Bundled checker wheel is missing or outside the runtime.")
|
|
34
|
+
if hashlib.sha256(wheel.read_bytes()).hexdigest() != config["sha256"]:
|
|
35
|
+
raise ValueError("Bundled checker wheel does not match its recorded checksum.")
|
|
36
|
+
default = (
|
|
37
|
+
Path.home() / "Library/Caches"
|
|
38
|
+
if sys.platform == "darwin"
|
|
39
|
+
else Path(env.get("LOCALAPPDATA", str(Path.home() / "AppData/Local")))
|
|
40
|
+
if os.name == "nt"
|
|
41
|
+
else Path(env.get("XDG_CACHE_HOME", str(Path.home() / ".cache")))
|
|
42
|
+
)
|
|
43
|
+
cache = (
|
|
44
|
+
Path(env.get("KNOWLEDGE_BUS_CACHE_DIR", str(default / "knowledge-bus")))
|
|
45
|
+
.expanduser()
|
|
46
|
+
.resolve()
|
|
47
|
+
)
|
|
48
|
+
if cache == runtime.parent or runtime.parent in cache.parents:
|
|
49
|
+
raise ValueError("The runtime cache must be outside the installed plugin.")
|
|
50
|
+
env["UV_CACHE_DIR"] = str(cache)
|
|
51
|
+
env["UV_PYTHON_DOWNLOADS"] = "never"
|
|
52
|
+
env["PYTHONDONTWRITEBYTECODE"] = "1"
|
|
53
|
+
for key in (
|
|
54
|
+
"UV_PROJECT_ENVIRONMENT",
|
|
55
|
+
"UV_PROJECT",
|
|
56
|
+
"UV_WORKING_DIRECTORY",
|
|
57
|
+
"UV_CONFIG_FILE",
|
|
58
|
+
"UV_NO_SYNC",
|
|
59
|
+
"UV_FROZEN",
|
|
60
|
+
"VIRTUAL_ENV",
|
|
61
|
+
"PYTHONPATH",
|
|
62
|
+
"PYTHONHOME",
|
|
63
|
+
):
|
|
64
|
+
env.pop(key, None)
|
|
65
|
+
args = [
|
|
66
|
+
uv,
|
|
67
|
+
"run",
|
|
68
|
+
"--no-project",
|
|
69
|
+
"--no-config",
|
|
70
|
+
"--isolated",
|
|
71
|
+
"--python",
|
|
72
|
+
sys.executable,
|
|
73
|
+
"--with",
|
|
74
|
+
str(wheel),
|
|
75
|
+
]
|
|
76
|
+
for requirement in config["dependencies"]:
|
|
77
|
+
args.extend(["--with", requirement])
|
|
78
|
+
return args + ["python", "-I", "-m", "kbp_conform.cli", *arguments], env
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def main():
|
|
82
|
+
try:
|
|
83
|
+
args, env = command(sys.argv[1:])
|
|
84
|
+
return subprocess.run(args, env=env, check=False).returncode
|
|
85
|
+
except (ValueError, OSError, KeyError) as error:
|
|
86
|
+
print(f"Knowledge Bus: {error}", file=sys.stderr)
|
|
87
|
+
return 2
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
if __name__ == "__main__":
|
|
91
|
+
sys.exit(main())
|
|
Binary file
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: kb-check
|
|
3
|
+
description: Validate Knowledge Bus definitions and guidance after edits, and explain each failure and its fix.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Check Spec Files
|
|
7
|
+
|
|
8
|
+
**Purpose — answer "is this still valid?" with the clause that failed and the fix it calls for, never a bare pass/fail.**
|
|
9
|
+
|
|
10
|
+
## The flow
|
|
11
|
+
|
|
12
|
+
- **1. Locate.** The installed package supplies the checker and protocol. Explicit file or directory targets take precedence. Without a target, use the nearest `.knowledge-bus/` from the user's working directory upward. Pass the resolved absolute Knowledge Bus directory path when the agent host runs commands from a different directory. Never combine definitions from different Knowledge Bus directories. If no `.knowledge-bus/` exists, report it; checking never creates one. See [Knowledge Bus Directory](../../references/knowledge-bus-directory.md). The implementation checkout retains its bundled-example default when no `.knowledge-bus/` directory is found.
|
|
13
|
+
|
|
14
|
+
- **2. Run.** Follow [Checker for Agent Workflows](../../references/agent-runtime.md). Run the bundled checker with `--validate <resolved-target>`. The format self-check runs first; an unsound format stops the run.
|
|
15
|
+
|
|
16
|
+
- **3. Interpret.** Every refusal names its clause. Translate each into the edit it calls for; see [Checker for Agent Workflows](../../references/agent-runtime.md) for the clause families.
|
|
17
|
+
|
|
18
|
+
- **4. Report.** Per-file pass/fail, then refusals grouped by fix, not by file.
|
|
19
|
+
|
|
20
|
+
## Common failures
|
|
21
|
+
|
|
22
|
+
Each row is a registered refusal; every one has a corpus file that must fail for exactly this reason.
|
|
23
|
+
|
|
24
|
+
| Refusal contains | Fix |
|
|
25
|
+
| ------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
26
|
+
| `already carried by` | The code is taken. Mint a fresh one (`kbp --mint <kind> 1 <resolved-target>`); never reuse or reassign a code. |
|
|
27
|
+
| `missing required` | The declaration lacks a required key (`id`, `code`, its identity). Add it; the message names which. |
|
|
28
|
+
| `may not be referenced by a universe` | A `when:` predicate names a factor. Factors are unwired by design — predicate on a frame instead. |
|
|
29
|
+
| `composition refs unknown elements` | A composition entry names an element the spec never declares. Declare it or correct the id. |
|
|
30
|
+
| `does not match` | `conforms_to` disagrees with the format version. Update it deliberately, against the changelog. |
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: kb-evolve
|
|
3
|
+
description: Add or re-examine document types in a Knowledge Bus universe, grounding structural changes in evidence.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Evolve a Spec
|
|
7
|
+
|
|
8
|
+
**Purpose — add a type the spec does not carry, or deepen one it already declares, so that every declaration is earned by evidence, every refusal is recorded with its reason, and the framework stays cohesive rather than locally patched.**
|
|
9
|
+
|
|
10
|
+
Two entry points share one spine. Run the spine; take the branch that applies.
|
|
11
|
+
|
|
12
|
+
- **Path A — new type.** A form exists in the world and the spec does not carry it. Governing question: *does it enable something no declared type enables?*
|
|
13
|
+
- **Path B — re-evaluation.** A declared type is about to become load-bearing and its basis is unexamined. Governing question: *what in this type is inherited rather than earned?*
|
|
14
|
+
|
|
15
|
+
## Knowledge Bus Directory
|
|
16
|
+
|
|
17
|
+
Follow [Knowledge Bus Directory](../../references/knowledge-bus-directory.md). Use an explicit target when supplied; otherwise resolve the nearest `.knowledge-bus/` from the user's working directory. Inspect existing files before proposing changes and preserve existing definitions and decision history. Do not combine definitions from different Knowledge Bus directories. Write only inside the selected `.knowledge-bus/`; leave source files untouched. If definitions are absent, ask the user to select or explicitly create a set rather than inventing one silently.
|
|
18
|
+
|
|
19
|
+
## Standing constraints
|
|
20
|
+
|
|
21
|
+
- **Deepen by sharpening questions, splits and cross-connections — never by growing per-cell density.** A fattening cell means the essence is not grasped yet.
|
|
22
|
+
- **Re-evaluate every row the new knowledge touches**, revising earlier depictions the evidence has outgrown. Cohesion over local patching.
|
|
23
|
+
- **A refusal is an output.** Record what you declined to add and why, so it is not re-litigated.
|
|
24
|
+
- **Nothing about a downstream app enters either file**, in any form.
|
|
25
|
+
- **Surface, do not hack.** Where the model cannot express something honestly, say so and file it — do not bend a declaration to fit.
|
|
26
|
+
- **Codes are stable.** Renaming an `id` is free; reusing or reassigning a code is not.
|
|
27
|
+
|
|
28
|
+
## The flow
|
|
29
|
+
|
|
30
|
+
- **1. State the suspicion before searching.** Write down what you expect to find wrong, then go looking. This is what stops a first-hit lineage from being confirmed rather than tested.
|
|
31
|
+
- **A:** name the form and the gap it claims to fill.
|
|
32
|
+
- **B:** name what looks inherited — a word in the id, a single-tradition guidance base, a question doing more than one job, an enablement promising something no element delivers.
|
|
33
|
+
|
|
34
|
+
- **2. Group candidate sources by enablement, not by discipline.** Families are "what does this let someone *do*" — decide, know-what-stands, calibrate, follow-an-argument. Discipline groupings smuggle in the lineage you are trying to test.
|
|
35
|
+
|
|
36
|
+
- **3. Fetch primary sources. Record every failed or degraded fetch.** Paywalled, rescinded, image-only, redirected — say so, and carry the caveat into the citation itself rather than leaving it for a reader to discover.
|
|
37
|
+
|
|
38
|
+
- **4. Run the artifact test per family.** Identity is `(action, actor)`; add timing to break ties.
|
|
39
|
+
- **A:** if the enablement duplicates a declared type's, fold the form in as an alias — do not add a row.
|
|
40
|
+
- **B:** ask whether any *surveyed family* deserves a type the spec lacks. Refusing one is an output, not an omission — record why.
|
|
41
|
+
|
|
42
|
+
- **5. Run the element test on every candidate field, against every declared question.** Identity is the question. Name the collision for each candidate and rule *sharpen existing / new / refused*.
|
|
43
|
+
- **A:** decompose the external form into its documented sections; reconcile each — fold into an existing row, split one, or add. Never duplicate.
|
|
44
|
+
- **B:** additionally audit the type's **existing** elements. A question with two conjunctions is usually two questions. A clause the instance layer already answers is a leak between levels, not a field.
|
|
45
|
+
|
|
46
|
+
- **6. Derive strength; do not choose it.** Core iff the enabled action cannot be taken without it. Where a frame decides, express it as `when:` on a core entry rather than as a second row.
|
|
47
|
+
|
|
48
|
+
- **7. Check the relation graph.**
|
|
49
|
+
- **A:** add boundaries for the near-misses step 5 surfaced.
|
|
50
|
+
- **B:** **re-point every edge naming a renamed or split declaration**, and promote any boundary that exists only as guidance prose into a `distinct-from` edge.
|
|
51
|
+
|
|
52
|
+
- **8. Write the spec file.** See § Outputs.
|
|
53
|
+
- **A:** mint codes for everything new.
|
|
54
|
+
- **B:** **retain the code on any declaration keeping its identity**; mint only for genuinely new ones. A rename with a stable code costs nothing downstream — that is what codes are for.
|
|
55
|
+
|
|
56
|
+
- **9. Write the guidance file.** See § Outputs.
|
|
57
|
+
- **A:** guidance starts empty; author it.
|
|
58
|
+
- **B:** guidance already exists and is keyed on ids you may have changed. Rekey it, and re-home entries whose subject moved — a boundary claim follows the element it is about.
|
|
59
|
+
|
|
60
|
+
- **10. Verify mechanically.** Use [Checker for Agent Workflows](../../references/agent-runtime.md) for code minting and validation. Run the checker; expect it to catch the rekeying you missed. Grep for downstream leakage. Count codes and entries against expectation. Confirm the protocol version did not move unless you meant it to.
|
|
61
|
+
|
|
62
|
+
- **11. Record the decision — including the refusals.** One record: what changed, why, what was refused and on what grounds, what would reverse it, what stayed ambiguous.
|
|
63
|
+
|
|
64
|
+
- **12. Raise what you surfaced but did not solve.** A gap found and left unfiled becomes an assumption. File it as an item.
|
|
65
|
+
|
|
66
|
+
## Outputs, by file
|
|
67
|
+
|
|
68
|
+
**Spec file — carries only what something reads.**
|
|
69
|
+
|
|
70
|
+
- Declarations: elements, artifact types, frames, factors — each with `id`, `code`, and its identity (`question` for an element, `enablement` for an artifact).
|
|
71
|
+
- Composition: `core` / `situational`, each entry's `mode` (`owns` | `links`) and any `when:` predicate.
|
|
72
|
+
- Relations: edges with `kind`, plus `legality`, `gate` or `freeze` where they apply.
|
|
73
|
+
- The `alias` — the external form(s) the composition aligns with, and its kind.
|
|
74
|
+
- Nothing advisory. Nothing about any app built on the spec. Nothing a reader is meant to weigh rather than resolve.
|
|
75
|
+
|
|
76
|
+
**Guidance file — carries everything else, and is advisory by rule.**
|
|
77
|
+
|
|
78
|
+
- One entry per claim: `kind`, `claim`, `source`, optional `when:`.
|
|
79
|
+
- `convention` must cite a registry source; `pitfall`, `heuristic`, `empty`, `refresh`, `boundary` may be `asserted`.
|
|
80
|
+
- Register each new source with `cite`, `url` and `checked`. **Put sourcing caveats inside the `cite` string** — rescinded, paywalled, secondary, abstract-only.
|
|
81
|
+
- Give every `distinct-from` edge a `boundary` entry saying why the distinction holds.
|
|
82
|
+
- Give every element you added an `empty` entry saying what an honest empty answer means.
|
|
83
|
+
|
|
84
|
+
**Split rule:** a value belongs in the spec because something reads it; everything else belongs in guidance. A spec must stay valid with no guidance file present.
|