unknown-knowledge 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE +5 -0
- package/README.md +167 -0
- package/cli/.gitkeep +0 -0
- package/cli/commands/init-copy.js +90 -0
- package/cli/commands/init.js +386 -0
- package/cli/init-copy.js +24 -0
- package/cli/init.js +24 -0
- package/cli/kit.manifest.yaml +256 -0
- package/cli/lib/copy-payload.js +334 -0
- package/cli/lib/generate-wrappers.js +162 -0
- package/package.json +36 -0
- package/payload/adapter-fixtures/README.md +53 -0
- package/payload/adapter-fixtures/html/EXPECTED.yaml +50 -0
- package/payload/adapter-fixtures/html/sample.html +38 -0
- package/payload/adapter-fixtures/md/EXPECTED.yaml +65 -0
- package/payload/adapter-fixtures/md/sample.md +32 -0
- package/payload/adapter-fixtures/pdf/EXPECTED.yaml +45 -0
- package/payload/adapter-fixtures/pdf/sample.pdf +0 -0
- package/payload/adapter-fixtures/txt/EXPECTED.yaml +31 -0
- package/payload/adapter-fixtures/txt/sample.txt +18 -0
- package/payload/docs/README.md +102 -0
- package/payload/docs/boundaries.md +60 -0
- package/payload/docs/ci-wiring.md +109 -0
- package/payload/docs/steward-guide.md +238 -0
- package/payload/engine/audit.js +34 -0
- package/payload/engine/commands/audit.js +289 -0
- package/payload/engine/commands/derive.js +334 -0
- package/payload/engine/commands/ingest.js +124 -0
- package/payload/engine/commands/log-entry.js +85 -0
- package/payload/engine/commands/phoenix.js +206 -0
- package/payload/engine/commands/preflight.js +530 -0
- package/payload/engine/commands/resolve.js +1678 -0
- package/payload/engine/commands/survey-map.js +351 -0
- package/payload/engine/commands/validate-values.js +315 -0
- package/payload/engine/commands/validate.js +1426 -0
- package/payload/engine/derive.js +34 -0
- package/payload/engine/ingest.js +34 -0
- package/payload/engine/lib/anchor-signatures.js +126 -0
- package/payload/engine/lib/boot.js +39 -0
- package/payload/engine/lib/call-numbers.js +133 -0
- package/payload/engine/lib/cli.js +147 -0
- package/payload/engine/lib/coverage.js +849 -0
- package/payload/engine/lib/decomposition.js +225 -0
- package/payload/engine/lib/derived.js +494 -0
- package/payload/engine/lib/engine-refusal.js +40 -0
- package/payload/engine/lib/exit-codes.js +14 -0
- package/payload/engine/lib/extractor-kinds.js +955 -0
- package/payload/engine/lib/format-adapters.js +802 -0
- package/payload/engine/lib/id-grammars.js +178 -0
- package/payload/engine/lib/iso-date.js +55 -0
- package/payload/engine/lib/kit-root.js +101 -0
- package/payload/engine/lib/load-stores.js +1624 -0
- package/payload/engine/lib/log-entry.js +196 -0
- package/payload/engine/lib/phoenix.js +628 -0
- package/payload/engine/lib/scoring.js +150 -0
- package/payload/engine/lib/suppressions.js +172 -0
- package/payload/engine/lib/time-verdicts.js +282 -0
- package/payload/engine/lib/usage-error.js +14 -0
- package/payload/engine/lib/validate-record.js +504 -0
- package/payload/engine/log-entry.js +34 -0
- package/payload/engine/phoenix.js +39 -0
- package/payload/engine/preflight.js +34 -0
- package/payload/engine/resolve.js +34 -0
- package/payload/engine/survey-map.js +34 -0
- package/payload/engine/validate-values.js +34 -0
- package/payload/engine/validate.js +34 -0
- package/payload/extractor-fixtures/.gitkeep +0 -0
- package/payload/extractor-fixtures/README.md +29 -0
- package/payload/extractor-fixtures/swift/strings-keys/EXPECTED.yaml +8 -0
- package/payload/extractor-fixtures/swift/strings-keys/sample.strings +15 -0
- package/payload/extractor-fixtures/swift/swift-const-array/EXPECTED.yaml +7 -0
- package/payload/extractor-fixtures/swift/swift-const-array/sample.swift +21 -0
- package/payload/extractor-fixtures/swift/swift-enum/EXPECTED.yaml +8 -0
- package/payload/extractor-fixtures/swift/swift-enum/sample.swift +30 -0
- package/payload/extractor-fixtures/swift/yaml-keys/EXPECTED.yaml +6 -0
- package/payload/extractor-fixtures/swift/yaml-keys/sample.yaml +23 -0
- package/payload/extractor-fixtures/swift/yaml-map-keys/EXPECTED.yaml +7 -0
- package/payload/extractor-fixtures/swift/yaml-map-keys/sample.yaml +15 -0
- package/payload/extractor-fixtures/ts/dir-modules/EXPECTED.yaml +12 -0
- package/payload/extractor-fixtures/ts/dir-modules/sample-modules/alpha.widget.ts +1 -0
- package/payload/extractor-fixtures/ts/dir-modules/sample-modules/beta.widget.ts +1 -0
- package/payload/extractor-fixtures/ts/dir-modules/sample-modules/gamma.widget.ts +1 -0
- package/payload/extractor-fixtures/ts/dir-modules/sample-modules/helpers/format.ts +3 -0
- package/payload/extractor-fixtures/ts/dir-modules/sample-modules/widgets.test.ts +2 -0
- package/payload/extractor-fixtures/ts/json-keys/EXPECTED.yaml +7 -0
- package/payload/extractor-fixtures/ts/json-keys/sample.json +5 -0
- package/payload/extractor-fixtures/ts/json-map-keys/EXPECTED.yaml +7 -0
- package/payload/extractor-fixtures/ts/json-map-keys/sample.json +13 -0
- package/payload/extractor-fixtures/ts/ts-const-array/EXPECTED.yaml +6 -0
- package/payload/extractor-fixtures/ts/ts-const-array/sample.ts +13 -0
- package/payload/extractor-fixtures/ts/ts-enum/EXPECTED.yaml +7 -0
- package/payload/extractor-fixtures/ts/ts-enum/sample.ts +11 -0
- package/payload/extractor-fixtures/ts/ts-object-keys/EXPECTED.yaml +6 -0
- package/payload/extractor-fixtures/ts/ts-object-keys/sample.tsx +23 -0
- package/payload/extractor-fixtures/ts/ts-union/EXPECTED.yaml +5 -0
- package/payload/extractor-fixtures/ts/ts-union/sample.ts +9 -0
- package/payload/hooks/pre-commit +37 -0
- package/payload/hooks/reverse-lookup +66 -0
- package/payload/package.json +3 -0
- package/payload/protocol/.gitkeep +0 -0
- package/payload/protocol/AGENTS.md +239 -0
- package/payload/protocol/derived-layer.md +174 -0
- package/payload/protocol/new-kind-pipeline.md +179 -0
- package/payload/protocol/registry-warrant.md +162 -0
- package/payload/protocol/skills/kb-build.md +303 -0
- package/payload/protocol/skills/knowledge-audit.md +183 -0
- package/payload/protocol/skills/knowledge-bootstrap.md +229 -0
- package/payload/protocol/skills/knowledge-reflect.md +397 -0
- package/payload/schemas/catalog.schema.json +32 -0
- package/payload/schemas/decision-entry.schema.json +122 -0
- package/payload/schemas/finding.schema.json +77 -0
- package/payload/schemas/gap.schema.json +52 -0
- package/payload/schemas/graduation-categories.schema.json +64 -0
- package/payload/schemas/knowledge-leaf.schema.json +194 -0
- package/payload/schemas/miss.schema.json +45 -0
- package/payload/schemas/ontology-concept.schema.json +115 -0
- package/payload/schemas/phoenix-event.schema.json +76 -0
- package/payload/schemas/registry.schema.json +57 -0
- package/payload/schemas/rules.schema.json +14 -0
- package/payload/schemas/survey-scope.schema.json +23 -0
- package/payload/templates/decisions/_catalog.yaml +7 -0
- package/payload/templates/decisions/_registries/graduation-categories.yaml +42 -0
- package/payload/templates/decisions/phoenix-event.yaml +74 -0
- package/payload/templates/decisions/reflect-mint-proposal.yaml +100 -0
- package/payload/templates/decisions/registry-minting.yaml +58 -0
- package/payload/templates/decisions/trust-graduation.yaml +120 -0
- package/payload/templates/decisions/trust-revocation.yaml +106 -0
- package/payload/templates/knowledge/_catalog.yaml +9 -0
- package/payload/templates/knowledge/_registries/anchor.yaml +42 -0
- package/payload/templates/knowledge/_registries/authority-tiers.yaml +32 -0
- package/payload/templates/knowledge/_registries/domains.yaml +43 -0
- package/payload/templates/knowledge/_registries/form.yaml +38 -0
- package/payload/templates/knowledge/_registries/jurisdictions.yaml +20 -0
- package/payload/templates/knowledge/_registries/operations.yaml +18 -0
- package/payload/templates/knowledge/_registries/stage.yaml +53 -0
- package/payload/templates/knowledge/_rules.yaml +6 -0
- package/payload/templates/new-kind/README.md +107 -0
- package/payload/templates/new-kind/descriptor.example.yaml +18 -0
- package/payload/templates/new-kind/fixture/EXPECTED.yaml +6 -0
- package/payload/templates/new-kind/fixture/demo-anchor.list +2 -0
- package/payload/templates/new-kind/fixture/sample.list +7 -0
- package/payload/templates/new-kind/parser.example.js +98 -0
- package/payload/templates/ontology/_catalog.yaml +6 -0
- package/payload/templates/ontology/_rules.yaml +6 -0
- package/payload/wrappers/cursor.mdc +15 -0
- package/payload/wrappers/pointer.md +10 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query decomposition (UCS-1152) — turning an ask into joins against the
|
|
3
|
+
* governed vocabularies, and saying what did not join.
|
|
4
|
+
*
|
|
5
|
+
* The deterministic core of the resolution pipeline. A query is decomposed
|
|
6
|
+
* along three axes, each joining a DIFFERENT governed vocabulary, and none of
|
|
7
|
+
* them guessing:
|
|
8
|
+
*
|
|
9
|
+
* verb -> the `knowledge/operations` registry ("add a tool" -> add-tool)
|
|
10
|
+
* noun -> concept terms and aliases ("tool" -> K-101)
|
|
11
|
+
* place -> the `knowledge/jurisdictions` registry ("eu eaa" -> eu-eaa)
|
|
12
|
+
*
|
|
13
|
+
* What makes this the deterministic core rather than a search box is that every
|
|
14
|
+
* axis lands in a MINTED vocabulary value. The operations registry says which
|
|
15
|
+
* verbs exist; the ontology says which nouns do; the jurisdictions registry
|
|
16
|
+
* says which places do. A token that matches none of them is not silently
|
|
17
|
+
* dropped and not fuzzily coerced into the nearest thing — it is RESIDUE, named
|
|
18
|
+
* as such, with the context that did resolve attached, so the gap is a finding
|
|
19
|
+
* somebody can close rather than a bad answer nobody can trace.
|
|
20
|
+
*
|
|
21
|
+
* Three outputs no search box produces, and each exists because its absence is
|
|
22
|
+
* a specific failure the pipeline had:
|
|
23
|
+
*
|
|
24
|
+
* exclusions a leaf whose `applies.jurisdictions` excludes the query's place
|
|
25
|
+
* is EXCLUDED WITH ITS REASON, never silently absent. Silence
|
|
26
|
+
* here is indistinguishable from "no such knowledge exists", and
|
|
27
|
+
* the two demand opposite conduct from the reader.
|
|
28
|
+
* near-miss a vocabulary entry that shares tokens with the query but did
|
|
29
|
+
* not clear the match threshold. The answer that was nearly
|
|
30
|
+
* right is exactly what a reader needs to see when the right one
|
|
31
|
+
* is missing — and hiding it is how a store's vocabulary drifts
|
|
32
|
+
* from its users' without anyone noticing.
|
|
33
|
+
* residue the unconsumed non-stopword tokens. The store's own record of
|
|
34
|
+
* what it does not yet know.
|
|
35
|
+
*
|
|
36
|
+
* MATCH SEMANTICS. A vocabulary entry matches when EVERY word of its phrase is
|
|
37
|
+
* present in the query, each consuming a distinct token. Distinctness matters:
|
|
38
|
+
* "tool tool" must not satisfy a two-word phrase from one token. Words match
|
|
39
|
+
* with a naive singular/plural fold (`tool` ~ `tools`) and nothing else — no
|
|
40
|
+
* stemmer, no edit distance, no synonym expansion. That is a deliberate floor,
|
|
41
|
+
* not an unfinished feature: aliases are the governed, warranted mechanism for
|
|
42
|
+
* "these words mean the same thing", and a stemmer that quietly joined `tooling`
|
|
43
|
+
* to `tool` would be an ungoverned vocabulary decision made by a regex.
|
|
44
|
+
*
|
|
45
|
+
* NEAR-MISS is the same test relaxed from every-word to any-word, over entries
|
|
46
|
+
* that did NOT match. It reports the overlap, so a reader sees which word
|
|
47
|
+
* carried it.
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The pinned stopword list.
|
|
52
|
+
*
|
|
53
|
+
* PROVENANCE: the list is fixed rather than re-derived per store, because the
|
|
54
|
+
* residue output built on it is what the goldens mirror, and a list that
|
|
55
|
+
* drifted would make the fixtures disagree with the behavior they pin.
|
|
56
|
+
*
|
|
57
|
+
* PINNED AND NOT CONFIGURABLE, for the same reason the volatility thresholds
|
|
58
|
+
* are (UCS-1150): residue is a governance signal — it is what gets logged as a
|
|
59
|
+
* retrieval-miss and eventually minted by literary warrant — and a per-store
|
|
60
|
+
* stopword list would make "unresolved" mean something different in every repo.
|
|
61
|
+
* A token's absence from residue must mean "this word carries no query intent
|
|
62
|
+
* anywhere", not "somebody's config happened to hide it here".
|
|
63
|
+
*
|
|
64
|
+
* MINIMAL on purpose. It holds articles, prepositions, auxiliaries, first-person
|
|
65
|
+
* pronouns, and the handful of process words that appear in asks without
|
|
66
|
+
* narrowing them ("process", "launch"). It deliberately does NOT hold domain
|
|
67
|
+
* words: a store that stopworded its own vocabulary would report clean
|
|
68
|
+
* resolution for asks it never understood, which is precisely the silent miss
|
|
69
|
+
* this ticket exists to make impossible. Over-inclusion is the dangerous
|
|
70
|
+
* direction, so the list errs short — a false residue token is a finding a
|
|
71
|
+
* steward reads and dismisses, while a wrongly stopworded one is a gap nobody
|
|
72
|
+
* ever sees.
|
|
73
|
+
*
|
|
74
|
+
* @type {ReadonlySet<string>}
|
|
75
|
+
*/
|
|
76
|
+
export const STOPWORDS = Object.freeze(new Set([
|
|
77
|
+
'a', 'an', 'and', 'at', 'do', 'for', 'how', 'i', 'in', 'is', 'launch', 'my',
|
|
78
|
+
'of', 'on', 'our', 'process', 'should', 'the', 'this', 'to', 'we', 'with',
|
|
79
|
+
]));
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Split a query into tokens.
|
|
83
|
+
*
|
|
84
|
+
* The character class keeps `/`, `.`, `_` and `-` INSIDE a token, so
|
|
85
|
+
* `src/registry/export-formats.ts` survives as one token rather than
|
|
86
|
+
* shattering into five. That is what lets the resolver notice a path-shaped
|
|
87
|
+
* ask; splitting it first would destroy the only evidence that it was one.
|
|
88
|
+
*
|
|
89
|
+
* @param {string} query the raw query text
|
|
90
|
+
* @returns {string[]} lowercased tokens, in query order, duplicates kept
|
|
91
|
+
*/
|
|
92
|
+
export const tokenize = (query) => (String(query).toLowerCase().match(/[a-z0-9./_-]+/g) ?? []);
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Do a query token and a vocabulary word name the same thing?
|
|
96
|
+
*
|
|
97
|
+
* Exact, or differing by a single trailing `s`. That fold is the whole of the
|
|
98
|
+
* morphology here — see the module header for why it stops there.
|
|
99
|
+
*
|
|
100
|
+
* @param {string} token a query token
|
|
101
|
+
* @param {string} word a word from a vocabulary phrase
|
|
102
|
+
* @returns {boolean}
|
|
103
|
+
*/
|
|
104
|
+
export const sameWord = (token, word) => token === word || token === `${word}s` || `${token}s` === word;
|
|
105
|
+
|
|
106
|
+
/** Split a vocabulary phrase ("eu eaa", "Blend mode") into its words. */
|
|
107
|
+
export const phraseWords = (phrase) => String(phrase).toLowerCase().split(/\s+/).filter(Boolean);
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Which query tokens satisfy this phrase, or null when it is not satisfied.
|
|
111
|
+
*
|
|
112
|
+
* Every word must find a DISTINCT OCCURRENCE — the returned array is the tokens
|
|
113
|
+
* consumed, which is what makes residue computable: a token that satisfied some
|
|
114
|
+
* phrase is by definition not unresolved.
|
|
115
|
+
*
|
|
116
|
+
* Distinctness is tracked by INDEX, not by token text, and that is the whole
|
|
117
|
+
* subtlety. A query can legitimately repeat a word, and two occurrences of
|
|
118
|
+
* "tool" are two things the user typed — matching them by value would let the
|
|
119
|
+
* first occurrence be found again and rejected as already-used, so a phrase
|
|
120
|
+
* needing two would fail against a query that actually supplied two. Indexing
|
|
121
|
+
* also forecloses the opposite error: one occurrence can never satisfy two
|
|
122
|
+
* words, because its index is consumed the first time it is taken.
|
|
123
|
+
*
|
|
124
|
+
* Greedy first-fit, which is sound because vocabulary phrases are short. Where
|
|
125
|
+
* it cannot satisfy a phrase it returns null rather than backtracking, and that
|
|
126
|
+
* conservative direction is deliberate: under-matching leaves residue a steward
|
|
127
|
+
* can see, while over-matching silently swallows tokens nothing resolved.
|
|
128
|
+
*
|
|
129
|
+
* @param {string[]} phrase the vocabulary phrase's words
|
|
130
|
+
* @param {string[]} tokens the query's tokens
|
|
131
|
+
* @returns {string[]|null} the tokens consumed, in phrase order, or null
|
|
132
|
+
*/
|
|
133
|
+
export function phraseHit(phrase, tokens) {
|
|
134
|
+
if (!phrase.length) return null; // an empty phrase matches nothing, never everything
|
|
135
|
+
const takenIndexes = new Set();
|
|
136
|
+
const used = [];
|
|
137
|
+
for (const word of phrase) {
|
|
138
|
+
const index = tokens.findIndex((t, i) => !takenIndexes.has(i) && sameWord(t, word));
|
|
139
|
+
if (index === -1) return null;
|
|
140
|
+
takenIndexes.add(index);
|
|
141
|
+
used.push(tokens[index]);
|
|
142
|
+
}
|
|
143
|
+
return used;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* The tokens a phrase OVERLAPS, for near-miss reporting.
|
|
148
|
+
*
|
|
149
|
+
* The match test relaxed from every-word to any-word. An entry with overlap but
|
|
150
|
+
* no match is the near-miss: it shares vocabulary with the ask and still did not
|
|
151
|
+
* clear the threshold, which is exactly the case a reader needs to see when the
|
|
152
|
+
* right answer is missing.
|
|
153
|
+
*
|
|
154
|
+
* @param {string[]} phrase the vocabulary phrase's words
|
|
155
|
+
* @param {string[]} tokens the query's tokens
|
|
156
|
+
* @returns {string[]} the overlapping tokens, de-duplicated, in query order
|
|
157
|
+
*/
|
|
158
|
+
export function phraseOverlap(phrase, tokens) {
|
|
159
|
+
const overlap = [];
|
|
160
|
+
for (const token of tokens) {
|
|
161
|
+
if (!overlap.includes(token) && phrase.some((word) => sameWord(token, word))) overlap.push(token);
|
|
162
|
+
}
|
|
163
|
+
return overlap;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* The minted values of one registry, sorted (UCS-1148).
|
|
168
|
+
*
|
|
169
|
+
* SUPPRESSED VALUES ARE NOT JOINED. A suppressed value is one a steward
|
|
170
|
+
* explicitly refused, and joining an ask to it would resolve a query through
|
|
171
|
+
* vocabulary the store has disowned. It is not treated as unknown either: the
|
|
172
|
+
* registry accounted for it, which is a different fact from never having heard
|
|
173
|
+
* of it, and a near-miss is where that distinction can be shown without acting
|
|
174
|
+
* on it.
|
|
175
|
+
*
|
|
176
|
+
* A registry the store does not carry yields an empty list rather than throwing.
|
|
177
|
+
* Registry absence is the whole installed base (UCS-1148) — a store that governs
|
|
178
|
+
* no operations simply resolves no verbs, and demanding the file would fail
|
|
179
|
+
* every store written before this ticket.
|
|
180
|
+
*
|
|
181
|
+
* @param {object} model the loaded store model
|
|
182
|
+
* @param {string} key the registry key, e.g. 'knowledge/operations'
|
|
183
|
+
* @returns {string[]} minted values, lexicographically sorted
|
|
184
|
+
*/
|
|
185
|
+
export function mintedValues(model, key) {
|
|
186
|
+
const registry = model.registries?.get(key);
|
|
187
|
+
return registry ? [...registry.minted].sort() : [];
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Suppressed values of one registry, sorted — the disowned vocabulary.
|
|
192
|
+
*
|
|
193
|
+
* @param {object} model the loaded store model
|
|
194
|
+
* @param {string} key the registry key
|
|
195
|
+
* @returns {string[]}
|
|
196
|
+
*/
|
|
197
|
+
export function suppressedValues(model, key) {
|
|
198
|
+
const registry = model.registries?.get(key);
|
|
199
|
+
return registry ? [...registry.suppressed].sort() : [];
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* The phrases a registry value answers to.
|
|
204
|
+
*
|
|
205
|
+
* A minted value is an identifier, and identifiers are written for machines:
|
|
206
|
+
* `add-tool`, `eu-eaa`. So a value contributes TWO phrases — the value itself
|
|
207
|
+
* as one word, and the value with its separators opened into spaces, which is
|
|
208
|
+
* what a human types. "add tool" reaching `add-tool` is not fuzzy matching;
|
|
209
|
+
* it is reading the identifier's own internal structure, which the author put
|
|
210
|
+
* there precisely to be legible.
|
|
211
|
+
*
|
|
212
|
+
* Both are returned so the caller can report WHICH spelling matched.
|
|
213
|
+
*
|
|
214
|
+
* @param {string} value a registry value
|
|
215
|
+
* @returns {Array<{spelling: string, words: string[]}>}
|
|
216
|
+
*/
|
|
217
|
+
export function valuePhrases(value) {
|
|
218
|
+
const lower = String(value).toLowerCase();
|
|
219
|
+
const opened = lower.split(/[-_/.]+/).filter(Boolean);
|
|
220
|
+
const phrases = [{ spelling: lower, words: [lower] }];
|
|
221
|
+
if (opened.length > 1 || opened[0] !== lower) {
|
|
222
|
+
phrases.push({ spelling: opened.join(' '), words: opened });
|
|
223
|
+
}
|
|
224
|
+
return phrases;
|
|
225
|
+
}
|