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,162 @@
|
|
|
1
|
+
# Registries: warrant-minting and suppression (UCS-1148)
|
|
2
|
+
|
|
3
|
+
> Paths in this document are client-relative — relative to the vendored kit
|
|
4
|
+
> root after init (`schemas/…`, `templates/…`, `engine/…`, `protocol/…`). In
|
|
5
|
+
> the kit repo itself these live under `payload/`.
|
|
6
|
+
|
|
7
|
+
A **registry** is a governed vocabulary file: the closed set of values one
|
|
8
|
+
facet of a Store may draw from. Registries live at `<store>/_registries/<name>.yaml`
|
|
9
|
+
— underscore-prefixed like `_catalog.yaml` and `_rules.yaml`, and for the same
|
|
10
|
+
reason: they are governed store meta, not records.
|
|
11
|
+
|
|
12
|
+
The knowledge store's four registries:
|
|
13
|
+
|
|
14
|
+
| Registry | File | Shape | Governs |
|
|
15
|
+
|---|---|---|---|
|
|
16
|
+
| domains | `knowledge/_registries/domains.yaml` | hierarchical | `facets.domain` — the subject spine |
|
|
17
|
+
| operations | `knowledge/_registries/operations.yaml` | flat | `operations[]` — the verbs a leaf lets a reader do |
|
|
18
|
+
| jurisdictions | `knowledge/_registries/jurisdictions.yaml` | flat | `applies.jurisdictions[]` — where the claim holds |
|
|
19
|
+
| authority tiers | `knowledge/_registries/authority-tiers.yaml` | flat | `citations[].authority` — how far a source can be trusted |
|
|
20
|
+
|
|
21
|
+
## Why a registry and not a schema enum
|
|
22
|
+
|
|
23
|
+
Membership could have been a JSON Schema `enum`, and deliberately is not.
|
|
24
|
+
|
|
25
|
+
An enum is **kit-vendored code**. Under D-001 (seeded once, then owned) a
|
|
26
|
+
seeded repo has no update channel, so a vocabulary living in the schema would
|
|
27
|
+
be frozen at seed time for the life of that repo — a Store could never name a
|
|
28
|
+
subject its own material actually covers. A registry is **client data**: it
|
|
29
|
+
sits in the client zone, is reviewed as code like every other Store file, and
|
|
30
|
+
grows by steward decision without an engine release.
|
|
31
|
+
|
|
32
|
+
The engine therefore holds no opinion whatsoever about which values exist. It
|
|
33
|
+
enforces exactly one rule — *a governed value must be minted in its registry* —
|
|
34
|
+
and the registry alone says what is minted. This is what the acceptance
|
|
35
|
+
criterion "the domains top level is open" means concretely: the engine's only
|
|
36
|
+
notion of a top-level domain class is "a value with no parent segment", so
|
|
37
|
+
adding one is a registry edit plus a Decisions entry, with no schema change and
|
|
38
|
+
no engine change. There is no allocation table anywhere, and never a fixed
|
|
39
|
+
list of top-level classes to petition for a slot in.
|
|
40
|
+
|
|
41
|
+
## Literary warrant — the minting rule
|
|
42
|
+
|
|
43
|
+
> **A value is minted only when material exists to fill it.**
|
|
44
|
+
|
|
45
|
+
This is *literary warrant*, borrowed from classification practice: a class
|
|
46
|
+
earns its place in the scheme because documents exist that belong in it, never
|
|
47
|
+
because it seems like a category somebody might one day need. A registry minted
|
|
48
|
+
ahead of its material is speculative shelving — it invites authors to file
|
|
49
|
+
knowledge under a heading nobody chose deliberately, and the vocabulary drifts
|
|
50
|
+
into a taxonomy of guesses.
|
|
51
|
+
|
|
52
|
+
The `warrant:` field on every registry value is where the material is named,
|
|
53
|
+
and it is **required**. If it cannot be filled with something concrete — a leaf,
|
|
54
|
+
a document, a body of material that exists *now* — the value is not ready to be
|
|
55
|
+
minted.
|
|
56
|
+
|
|
57
|
+
### Conduct: minting a value
|
|
58
|
+
|
|
59
|
+
1. **Find the warrant.** Name the material that needs this value. If the answer
|
|
60
|
+
is "we'll need it later", stop: that is the case the rule refuses.
|
|
61
|
+
2. **Check for a suppression.** If the value is already listed with
|
|
62
|
+
`status: suppressed`, it was proposed and refused before. Re-minting is
|
|
63
|
+
legitimate but it is a *reversal*: read the suppressing decision first, and
|
|
64
|
+
record why the refusal no longer holds.
|
|
65
|
+
3. **Choose the level.** For the hierarchical domains registry, mint every
|
|
66
|
+
segment on the path. A child may not hang off an unminted parent — the
|
|
67
|
+
validator reports the missing segment, not the whole path, because the
|
|
68
|
+
segment is the edit you can actually make.
|
|
69
|
+
4. **Draft the Decisions entry** from `templates/decisions/registry-minting.yaml`.
|
|
70
|
+
Every minting is a governed act with a written rationale (§3.3): the entry
|
|
71
|
+
records the warrant, the value, and who decided.
|
|
72
|
+
5. **Edit the registry**, citing the decision id in the value's `decision:`
|
|
73
|
+
field. This is required and it is checked: a value citing no decision fails
|
|
74
|
+
the schema, and one citing an id no Decisions entry answers to fails as an
|
|
75
|
+
unresolved ref.
|
|
76
|
+
6. **Open one PR** carrying the registry edit, the Decisions entry, and the
|
|
77
|
+
material that supplied the warrant. Agents draft; humans approve.
|
|
78
|
+
|
|
79
|
+
### Conduct: suppressing a value
|
|
80
|
+
|
|
81
|
+
A value that is proposed and **rejected** is not deleted — it is recorded with
|
|
82
|
+
`status: suppressed` and left in the registry.
|
|
83
|
+
|
|
84
|
+
Deleting it would lose the decision. The next author to reach for the same term
|
|
85
|
+
would find nothing, propose it again, and the vocabulary question would be
|
|
86
|
+
re-litigated from scratch with no memory of why it went the way it did. A
|
|
87
|
+
suppression makes the refusal durable and visible: the term is on the shelf,
|
|
88
|
+
marked refused, with a decision id pointing at the reasoning.
|
|
89
|
+
|
|
90
|
+
It also changes what an author is told. Using a suppressed value is a
|
|
91
|
+
`suppressed-value` finding that says the term was *refused*, not the far less
|
|
92
|
+
useful "not in the registry" — which reads like a typo and invites the author
|
|
93
|
+
to fix their spelling rather than read the decision.
|
|
94
|
+
|
|
95
|
+
Suppression follows the same conduct as minting: a Decisions entry, then the
|
|
96
|
+
registry edit citing it, in one reviewed PR.
|
|
97
|
+
|
|
98
|
+
## What the engine checks
|
|
99
|
+
|
|
100
|
+
Registry membership is a **structural-validator** check (`engine/commands/validate.js`),
|
|
101
|
+
not a schema check. The hand-rolled schema subset cannot express "this value
|
|
102
|
+
appears in that file", and hierarchical segment membership is not a JSON Schema
|
|
103
|
+
shape at all.
|
|
104
|
+
|
|
105
|
+
| Finding | Means |
|
|
106
|
+
|---|---|
|
|
107
|
+
| `unregistered-value` | the value is not minted in its registry |
|
|
108
|
+
| `unminted-segment` | a hierarchical path whose named segment is not minted |
|
|
109
|
+
| `suppressed-value` | the value is listed as refused |
|
|
110
|
+
| `missing-registry` | the record cites a governed facet whose registry the store does not carry |
|
|
111
|
+
| `registry-shape-mismatch` | the registry's `hierarchical` flag disagrees with the facet it governs |
|
|
112
|
+
|
|
113
|
+
Every one of them names **both the value and the registry file**, so the finding
|
|
114
|
+
points at the edit rather than at the symptom.
|
|
115
|
+
|
|
116
|
+
The loader refuses a registry file outright — exit 2, before any membership is
|
|
117
|
+
judged — when it contradicts itself: a value declared twice, a value declared
|
|
118
|
+
both minted *and* suppressed (`duplicate-registry-value`), a declared `registry`
|
|
119
|
+
or `store` disagreeing with the file's own path (`registry-name-mismatch`,
|
|
120
|
+
`registry-store-mismatch`), or a `decision` naming no Decisions entry
|
|
121
|
+
(`unresolved-ref`). None of these can be settled by the engine: picking a winner
|
|
122
|
+
by file order would be a governance decision nobody made.
|
|
123
|
+
|
|
124
|
+
Four engine conducts are worth stating outright, because each is the difference
|
|
125
|
+
between a governed vocabulary and a decorative one:
|
|
126
|
+
|
|
127
|
+
**Every value cites a decision, and the citation is checked.** `decision` is a
|
|
128
|
+
*required* field, and it resolves through the same cross-store ref graph as
|
|
129
|
+
every other citation — an id naming no Decisions entry is an ordinary
|
|
130
|
+
`unresolved-ref` error. "Each minting a Decisions entry" is therefore enforced,
|
|
131
|
+
not merely encouraged: a vocabulary change nobody signed cannot reach the store.
|
|
132
|
+
|
|
133
|
+
**A malformed registry is a hard error, never an empty one.** Unparseable YAML
|
|
134
|
+
or a schema defect in a registry file is a loader error that gates every
|
|
135
|
+
surface to exit 2. Degrading to "the registry loaded as empty" would fail every
|
|
136
|
+
value that *was* minted — a check that never ran, wearing the exit code of a
|
|
137
|
+
check that ran and found problems (PRD §5).
|
|
138
|
+
|
|
139
|
+
**A registry's shape must match the facet it governs.** The `hierarchical` flag
|
|
140
|
+
is what turns on segment-by-segment membership, so a domains registry that lost
|
|
141
|
+
it would judge a whole path as one opaque string — the segment rule switched
|
|
142
|
+
off by an omitted line, at exit 0. The engine therefore declares the shape each
|
|
143
|
+
facet requires and refuses a registry that disagrees
|
|
144
|
+
(`registry-shape-mismatch`), reported once against the registry file.
|
|
145
|
+
|
|
146
|
+
**An absent registry surfaces where it can mean something.** A Store that
|
|
147
|
+
carries no registries is complete and valid: registries are opt-in governance,
|
|
148
|
+
and demanding them of every Store would fail every repo seeded before this
|
|
149
|
+
layer existed. Absence therefore surfaces at the point a record actually
|
|
150
|
+
*claims* a governed value — a leaf naming `facets.domain` in a Store with no
|
|
151
|
+
domains registry is an explicit `missing-registry` finding. That is never a
|
|
152
|
+
silent pass: the value went unjudged, and the finding says so in those terms.
|
|
153
|
+
The alternative conducts were both worse. Warning at load on every registry-less
|
|
154
|
+
Store would train stewards to ignore the warning; hard-erroring at load would
|
|
155
|
+
break every existing Store for a feature it never opted into.
|
|
156
|
+
|
|
157
|
+
## Where registries are not the answer
|
|
158
|
+
|
|
159
|
+
A registry governs a **facet** — a small, stable, shared vocabulary that
|
|
160
|
+
readers navigate by. It is not a place to park free text. If a value would be
|
|
161
|
+
minted once and used once, it is content, not vocabulary: it belongs in the
|
|
162
|
+
leaf's prose or its `terms`, where nothing has to govern it.
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# /kb-build — the sole knowledge write path (PRD §3.2, D-019)
|
|
2
|
+
|
|
3
|
+
> Paths in this document are client-relative — relative to the vendored kit
|
|
4
|
+
> root after init (`ontology/…`, `engine/…`, `protocol/…`). In the kit repo
|
|
5
|
+
> itself these live under `payload/`. Commands are written to run from the
|
|
6
|
+
> **repo root** with the kit dir at its default name `unknown-knowledge/`;
|
|
7
|
+
> substitute your chosen kit dir name if it differs.
|
|
8
|
+
|
|
9
|
+
The knowledge store's truth anchor is the world, not the code — and this
|
|
10
|
+
skill is its **sole write path**: every leaf under `knowledge/` lands
|
|
11
|
+
through this procedure, drafted by an agent and approved by a human through
|
|
12
|
+
the normal PR gate (agents draft; humans approve). You operate under
|
|
13
|
+
`protocol/AGENTS.md` throughout — every gate rule there binds here. Run
|
|
14
|
+
this when someone brings an item worth keeping: a regulation, an industry
|
|
15
|
+
rule, a research result, an operational fact the code cannot testify to.
|
|
16
|
+
|
|
17
|
+
**The leading rule: citations required — an unsourced claim is not
|
|
18
|
+
promotable.** A claim with no traceable source never becomes a leaf; it
|
|
19
|
+
parks as a gap-log entry (step 2) so the demand signal survives without the
|
|
20
|
+
store vouching for it.
|
|
21
|
+
|
|
22
|
+
## This skill is thin orchestration
|
|
23
|
+
|
|
24
|
+
Every mechanical step below **names the engine command that performs it**.
|
|
25
|
+
The commands compute; this skill sequences them and stops on their exit
|
|
26
|
+
codes. Where a step says "run", run it — do not reproduce its answer from
|
|
27
|
+
memory, and do not decide an outcome the engine reports.
|
|
28
|
+
|
|
29
|
+
Your discretion is limited to three **judgment fills**, and they are the
|
|
30
|
+
only free-form work in the procedure:
|
|
31
|
+
|
|
32
|
+
| Judgment fill | Where | What it means |
|
|
33
|
+
| --- | --- | --- |
|
|
34
|
+
| **Prose bodies** | step 4 | the leaf's markdown body — written, not generated |
|
|
35
|
+
| **Candidate confirmation** | steps 1–2 | confirming a proposed classification or citation against the source, which is a read no command can do for you |
|
|
36
|
+
| **Mint proposals with warrant evidence** | step 3 | proposing a governed vocabulary value, carrying its literary warrant |
|
|
37
|
+
|
|
38
|
+
Everything else — locating coverage, minting the accession, checking facet
|
|
39
|
+
values against their registries, checking the catalog, the final gate — is
|
|
40
|
+
the engine's. **Protocol compliance is a property of the mechanism, not of
|
|
41
|
+
agent obedience**: the hooks in `hooks/` run the blocking validation and
|
|
42
|
+
the reverse lookup whether or not anyone remembers to, and they propagate
|
|
43
|
+
the engine's exit codes unchanged.
|
|
44
|
+
|
|
45
|
+
Two `--root` conventions, stated once (same as AGENTS.md):
|
|
46
|
+
|
|
47
|
+
- Store-reading CLIs (`resolve.js`, `validate.js`) take `--root` as the
|
|
48
|
+
**repo root** (default: cwd); the stores are auto-located at
|
|
49
|
+
`<root>/unknown-knowledge/`.
|
|
50
|
+
- `log-entry.js` takes `--root` as the **kit dir** (the directory
|
|
51
|
+
containing `logs/`), e.g. `--root unknown-knowledge`.
|
|
52
|
+
|
|
53
|
+
## The five steps
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
1. CLASSIFY item → one facet-set home, via resolve.js
|
|
57
|
+
2. CITE every claim carries a citation, or it parks via log-entry.js
|
|
58
|
+
3. FACET fill the governed facets from the registries
|
|
59
|
+
4. DRAFT the leaf file: §3.2 governance frontmatter + body, at draft stage
|
|
60
|
+
5. VALIDATE validate.js green, then the human gate
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 1. CLASSIFY — one subject home
|
|
64
|
+
|
|
65
|
+
Enter through the store's navigational grammar (AGENTS.md): read
|
|
66
|
+
`knowledge/_catalog.yaml`, then `knowledge/_rules.yaml` — the
|
|
67
|
+
domain spine the bootstrap interview wrote. Then ask the engine what
|
|
68
|
+
already exists near the item:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
node unknown-knowledge/engine/resolve.js "svg asset export precision" --json --root .
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`resolve.js` is what answers "does the store already cover this". Read its
|
|
75
|
+
`decomposition` (which operations, concepts and jurisdictions joined) and
|
|
76
|
+
its `residue` (the tokens nothing consumed) — residue is the store telling
|
|
77
|
+
you where its vocabulary runs out, and it is the raw material a later
|
|
78
|
+
`mint-proposal` is built from. Read any leaf it names before deciding
|
|
79
|
+
placement (the map is never the fact): that read is **candidate
|
|
80
|
+
confirmation**, a judgment fill, and no command substitutes for it.
|
|
81
|
+
|
|
82
|
+
Decide, in this order:
|
|
83
|
+
|
|
84
|
+
- **An existing leaf already covers the item** → this run is a *revision*
|
|
85
|
+
of that leaf: its accession is its identity and never changes (§3.5), so
|
|
86
|
+
keep it and append a `revision` note in step 4.
|
|
87
|
+
- **The spine names a home** → a new leaf. Classification is a
|
|
88
|
+
`facets.domain` value, not a position: the subject path says what the leaf
|
|
89
|
+
is about, and the leaf's identity is a fresh **accession** minted in step
|
|
90
|
+
4. Nothing has to be looked up to find "the next free" anything — an
|
|
91
|
+
accession is opaque and drawn from a sequence, so two authors classifying
|
|
92
|
+
into one domain never contend for a number, and the classification you
|
|
93
|
+
choose here constrains nothing about the identity you get.
|
|
94
|
+
Where the classification was contestable (the item could plausibly file
|
|
95
|
+
under two domains), record the call as a `class-here` note on the leaf.
|
|
96
|
+
- **The spine has no home for it** → the spine is the human's (it came from
|
|
97
|
+
the bootstrap interview): hand the item back with the domains you
|
|
98
|
+
considered and ask whether `knowledge/_rules.yaml` should grow — never
|
|
99
|
+
invent a domain silently.
|
|
100
|
+
|
|
101
|
+
**Done when** exactly one of the three outcomes holds: one subject home
|
|
102
|
+
settled for a new leaf, one existing leaf identified for revision, or the
|
|
103
|
+
item handed back for a spine decision. Two plausible homes you cannot
|
|
104
|
+
separate is the third outcome, not a coin flip.
|
|
105
|
+
|
|
106
|
+
### 2. CITE — the promotion gate
|
|
107
|
+
|
|
108
|
+
Inventory every claim the drafted item makes — each sentence that asserts
|
|
109
|
+
something about the world. Each claim must end this step in exactly one
|
|
110
|
+
state:
|
|
111
|
+
|
|
112
|
+
- **Cited**: a `source` (+ `accessed` date) a reviewer can follow to the
|
|
113
|
+
world — a regulation, a standard, a published document, a dated research
|
|
114
|
+
artifact. The citation supports the claim as written, not the topic in
|
|
115
|
+
general. Confirming that is **candidate confirmation**: open the source
|
|
116
|
+
and read it, because a citation nobody followed is a claim about a
|
|
117
|
+
citation.
|
|
118
|
+
- **Dropped**: reworded out or removed — the leaf says less and stays true.
|
|
119
|
+
- **Parked**: worth keeping as demand but unsourced. An unsourced claim is
|
|
120
|
+
not promotable — it goes to the gap log, never into a leaf, and
|
|
121
|
+
`log-entry.js` is the only write path into `logs/`:
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
node unknown-knowledge/engine/log-entry.js create --log gaps --date 2026-07-09 \
|
|
125
|
+
--root unknown-knowledge \
|
|
126
|
+
--entry '{"summary":"kb-build item not promotable: export-precision claim lacks any citation; nearest leaf L-000100","consulted":{"leaves":["L-000100"]}}'
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
`--date` is injected, never wall-clock; the summary carries leaf ids,
|
|
130
|
+
concept IDs, and file paths only — never verbatim user text or secrets
|
|
131
|
+
(§3.4). `consulted.leaves` cites each leaf by its accession id — the only
|
|
132
|
+
spelling that resolves — and the summary should name that same id, so a
|
|
133
|
+
reader can look up what the entry consulted.
|
|
134
|
+
|
|
135
|
+
**Done when** zero uncited claims remain in the draft. If citing
|
|
136
|
+
and dropping empties the item, park what remains and end the run here — a
|
|
137
|
+
parked item is a recorded demand signal, not a failure.
|
|
138
|
+
|
|
139
|
+
### 3. FACET — fill the governed facets from the registries
|
|
140
|
+
|
|
141
|
+
`facets` is the classification block, and **every value must already be
|
|
142
|
+
minted in its registry** under `knowledge/_registries/`. Read the registry
|
|
143
|
+
file and take the value from it; a value the registry does not carry is a
|
|
144
|
+
blocking `unregistered-value` finding at step 5, which is the mechanism
|
|
145
|
+
refusing an ad-hoc string rather than trusting you not to write one.
|
|
146
|
+
|
|
147
|
+
| Facet | Registry | What it records |
|
|
148
|
+
| --- | --- | --- |
|
|
149
|
+
| `domain` | `_registries/domains.yaml` | the hierarchical subject path — every segment minted |
|
|
150
|
+
| `form` | `_registries/form.yaml` | what KIND of knowledge this is |
|
|
151
|
+
| `anchor` | `_registries/anchor.yaml` | which truth anchor settles the claim (artifact, world, team — D-003) |
|
|
152
|
+
| `stage` | `_registries/stage.yaml` | where the leaf sits in the promotion path |
|
|
153
|
+
|
|
154
|
+
Two adjacent governed lists are filled the same way, from the same kind of
|
|
155
|
+
file: `operations` (the verbs this leaf lets a reader DO,
|
|
156
|
+
`_registries/operations.yaml`) and `applies.jurisdictions`
|
|
157
|
+
(`_registries/jurisdictions.yaml` — EMPTY means universal, which is a
|
|
158
|
+
claim, so leave it empty only when the knowledge really does hold
|
|
159
|
+
everywhere). Each `citations` entry carries an `authority` tier from
|
|
160
|
+
`_registries/authority-tiers.yaml`: the tier records how far the source can
|
|
161
|
+
be trusted, and without it a regulator's text and a hallway conversation
|
|
162
|
+
read identically.
|
|
163
|
+
|
|
164
|
+
**If no minted value fits, that is the signal to propose a minting, not to
|
|
165
|
+
invent a spelling.** A mint proposal is the third **judgment fill**, and it
|
|
166
|
+
is a governed act with a written rationale: draft it from
|
|
167
|
+
`templates/decisions/registry-minting.yaml` and carry its **literary
|
|
168
|
+
warrant** — the material that already exists for the value to hold. Warrant
|
|
169
|
+
is evidence, not intention: a value minted ahead of its material is
|
|
170
|
+
speculative shelving (`protocol/registry-warrant.md`). Where the proposal
|
|
171
|
+
comes from a corroborated residue cluster instead of a single item, it is
|
|
172
|
+
reflect's `mint-proposal` shape and belongs on the reflect queue —
|
|
173
|
+
`protocol/skills/knowledge-reflect.md` owns that path. Either way the
|
|
174
|
+
proposal goes to the human; this skill never edits a registry.
|
|
175
|
+
|
|
176
|
+
**Done when** every facet, operation, jurisdiction and authority tier the
|
|
177
|
+
draft will carry is a value its registry already mints, or the run is
|
|
178
|
+
paused on a mint proposal awaiting the human.
|
|
179
|
+
|
|
180
|
+
### 4. DRAFT — §3.2 governance frontmatter + body
|
|
181
|
+
|
|
182
|
+
The frontmatter shape is `schemas/knowledge-leaf.schema.json` — the single
|
|
183
|
+
source of truth; `validate.js` enforces it in step 5. The governance calls
|
|
184
|
+
this skill makes on top of the schema:
|
|
185
|
+
|
|
186
|
+
- **`id`** — the accession (`L-NNNNNN`): **required on every leaf**, opaque,
|
|
187
|
+
never reused, never positional. It is the leaf's identity, what the loader
|
|
188
|
+
indexes by, and the only spelling other leaves, the catalog, decisions and
|
|
189
|
+
log fragments may cite it as. Mint the next value in the sequence; because
|
|
190
|
+
it says nothing about where the leaf sits, refiling the leaf later leaves
|
|
191
|
+
it untouched and breaks no citation. A collision is a hard error at step 5,
|
|
192
|
+
never a silently shared identity.
|
|
193
|
+
- **`facets.stage`** — start at **`draft`**. Every agent-authored entry
|
|
194
|
+
enters at draft stage; this is not a courtesy, it is where the moderation
|
|
195
|
+
pipeline picks the leaf up. A draft leaf is downranked in resolver output and
|
|
196
|
+
verdicted `unknown` by preflight, which is correct and not a defect:
|
|
197
|
+
nothing has certified it yet. Promotion is a moderator's act after the
|
|
198
|
+
citations are checked, never the author's.
|
|
199
|
+
- **`notes`** — every leaf carries a `scope` note (what it covers and
|
|
200
|
+
pointedly does not) and every write appends a `revision` note with
|
|
201
|
+
`date` (initial entry, or what changed); add `class-here` when step 1
|
|
202
|
+
flagged the classification as contestable.
|
|
203
|
+
- **`cross-references`** — `class-elsewhere` and `see-also` must resolve to
|
|
204
|
+
leaves the catalog declares. Cite the target's accession id (`L-NNNNNN`),
|
|
205
|
+
which is the only legal spelling. `including` is standing room —
|
|
206
|
+
candidate topics parked under the heading, not authoritative, never
|
|
207
|
+
citable as fact.
|
|
208
|
+
- **`facets`**, **`operations`**, **`applies.jurisdictions`**,
|
|
209
|
+
**`citations[].authority`** — the step-3 values, verbatim. Nothing minted
|
|
210
|
+
here that step 3 did not settle.
|
|
211
|
+
- **`citations`** — the step-2 survivors, verbatim; at least one.
|
|
212
|
+
- **`terms`** — the words a future resolve should hit; write them for the
|
|
213
|
+
searcher, not the author.
|
|
214
|
+
- **`concepts`** — the ontology concepts (`K-NNN`) this leaf is knowledge
|
|
215
|
+
ABOUT. Declare them even when `terms` already names the concept's term: the
|
|
216
|
+
concept edge is STRUCTURAL, so it keeps working when the concept is renamed
|
|
217
|
+
or when your leaf uses different words than the ontology does. `terms` is a
|
|
218
|
+
text match between two authors' vocabularies; this is a claim. Each must
|
|
219
|
+
resolve — a concept id nothing mints is a blocking finding.
|
|
220
|
+
- **`paths`** — the repo-relative files or directories this leaf governs. A
|
|
221
|
+
directory covers its subtree. This is what makes the leaf surface in the
|
|
222
|
+
reverse lookup, so the files in a diff surface the knowledge that governs
|
|
223
|
+
them BEFORE the edit — and it is what the `hooks/reverse-lookup` hook
|
|
224
|
+
reads. Every path must name something that exists INSIDE this repo: a path
|
|
225
|
+
pointing at nothing governs nothing, one that escapes the repo root
|
|
226
|
+
(`../elsewhere`, or an absolute path) is not this store's to claim, and
|
|
227
|
+
`.` — the repo root — attributes nothing by attributing to everything. All
|
|
228
|
+
three are blocking findings.
|
|
229
|
+
- **`relates`** — typed leaf-to-leaf edges, and the type carries the meaning,
|
|
230
|
+
so choose it rather than defaulting to `see-also`:
|
|
231
|
+
`depends-on` (this leaf's claim is only usable once the target's is),
|
|
232
|
+
`see-also` (worth reading alongside — no dependency, no conflict),
|
|
233
|
+
`contradicts` (the two claims cannot both hold — recorded, not resolved, so a
|
|
234
|
+
human can settle it), and `supersedes` (this leaf replaces the target's
|
|
235
|
+
claim — the disagreement is already settled). A resolver hit carries its
|
|
236
|
+
neighborhood one hop out, labeled by kind, so these are what an agent reads
|
|
237
|
+
next. Targets are leaf refs and each must resolve: cite the target's
|
|
238
|
+
accession, as with `cross-references`.
|
|
239
|
+
- **`provenance`** — `author` and `skill-version`, so a systematic drafting
|
|
240
|
+
defect can be traced to the vintage that introduced it. The skill is
|
|
241
|
+
versioned and its changes are gated; record the version you ran.
|
|
242
|
+
- **Body** — the markdown below the frontmatter is the content, and it is
|
|
243
|
+
the first **judgment fill**: each claim reads back to a listed citation.
|
|
244
|
+
**Open with a topic sentence**: there is no `description` field (retired
|
|
245
|
+
in v2), and display prose is DERIVED from the body's first sentence
|
|
246
|
+
wherever a one-liner is shown. Write it as the sentence you would want to
|
|
247
|
+
read in a search result.
|
|
248
|
+
|
|
249
|
+
What the deriver actually does, so the guidance is not a guess: it skips
|
|
250
|
+
leading markdown structure line by line — headings, list items, block
|
|
251
|
+
quotes, fenced code, table rows — and takes the first prose line it finds,
|
|
252
|
+
joining hard-wrapped continuation lines. It ends the excerpt at the first
|
|
253
|
+
`.`, `!`, or `?` followed by whitespace, so `§4.2` and `v3.2` do not cut it
|
|
254
|
+
short. Prose with no terminator is shown whole rather than dropped. The
|
|
255
|
+
only body with nothing to show is one that is *entirely* structure — all
|
|
256
|
+
heading, all list, all code — so the failure mode to avoid is opening with
|
|
257
|
+
a bare list or a code block, not writing a fragment.
|
|
258
|
+
|
|
259
|
+
Then add the catalog row to `knowledge/_catalog.yaml`: `id` (the leaf's
|
|
260
|
+
accession, the same value as its `id` field, and the only legal spelling),
|
|
261
|
+
`title` (the heading, kept in sync on revision), `file` (the leaf path
|
|
262
|
+
relative to `knowledge/`). Leaf files are sharded by accession prefix —
|
|
263
|
+
`knowledge/<L-NN>/<accession>-<slug>.md`, where the prefix is `L-` plus the
|
|
264
|
+
first two digits of the accession's numeric part (`L-000101` files under
|
|
265
|
+
`knowledge/L-00/`). The shard is a fanout device for directory size and
|
|
266
|
+
**carries no meaning**: it makes no claim about the leaf's subject, and
|
|
267
|
+
nothing reads it. `validate.js`'s `index-drift` and `orphan` checks are what
|
|
268
|
+
verify the row against the file — do not audit that pairing by eye.
|
|
269
|
+
|
|
270
|
+
**Done when** the leaf file and its catalog row both exist, the body opens
|
|
271
|
+
with a topic sentence, `facets.stage` is `draft`, and every value in the
|
|
272
|
+
frontmatter came from step 2 or step 3.
|
|
273
|
+
|
|
274
|
+
### 5. VALIDATE — green, then the human gate
|
|
275
|
+
|
|
276
|
+
```
|
|
277
|
+
node unknown-knowledge/engine/validate.js --root .
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
This is the same command the `hooks/pre-commit` hook runs, so a commit that
|
|
281
|
+
would fail here is refused before it exists — running it now is how you see
|
|
282
|
+
the findings first, not a substitute for the hook.
|
|
283
|
+
|
|
284
|
+
- **Exit 0** — done drafting. Hand the change to the human gate: the leaf,
|
|
285
|
+
the catalog row, and any gap fragments ride one PR; knowledge writes are
|
|
286
|
+
human-gated, and the merge IS the approval.
|
|
287
|
+
- **Exit 1** — the findings name the defect (`orphan`, `index-drift`,
|
|
288
|
+
`missing-citation` — an unsourced claim is not promotable;
|
|
289
|
+
`unregistered-value` — step 3 was skipped or a value was invented): fix
|
|
290
|
+
the draft, re-run.
|
|
291
|
+
- **Exit 2** — **stop and fix**: the check never ran (an unresolved
|
|
292
|
+
cross-reference lands here), and a check that never ran is a blocking
|
|
293
|
+
defect, never a silent pass. Re-run until the run itself completes.
|
|
294
|
+
|
|
295
|
+
Then attribute what you touched, which the `hooks/reverse-lookup` hook does
|
|
296
|
+
automatically over the staged diff and you can run directly:
|
|
297
|
+
|
|
298
|
+
```
|
|
299
|
+
node unknown-knowledge/engine/resolve.js --paths knowledge/L-00/L-000110-svg-asset-export-precision.md --json --root .
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
The skill declares done only on an exit-0 run that saw the final draft —
|
|
303
|
+
a verdict is per-run, never carried (D-011).
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# /knowledge-audit — the on-demand health check (PRD §8, D-019)
|
|
2
|
+
|
|
3
|
+
> Paths in this document are client-relative — relative to the vendored kit
|
|
4
|
+
> root after init (`ontology/…`, `engine/…`, `protocol/…`). In the kit repo
|
|
5
|
+
> itself these live under `payload/`. Commands are written to run from the
|
|
6
|
+
> **repo root** with the kit dir at its default name `unknown-knowledge/`;
|
|
7
|
+
> substitute your chosen kit dir name if it differs.
|
|
8
|
+
|
|
9
|
+
Run this when someone asks how healthy the map is — on demand, before a
|
|
10
|
+
reflect cycle, or when the loop has gone quiet. The audit is **read-only**:
|
|
11
|
+
it runs the engine's checks in a fixed order, sweeps the two lifecycles the
|
|
12
|
+
engine does not compute, and files one human-readable report. It never
|
|
13
|
+
mutates stores — everything it finds is *routed*, not fixed inline:
|
|
14
|
+
validator findings to the owning concepts' normal PR path, reverse-audit
|
|
15
|
+
drafts to the steward (proposal-first), fragments to reflect. You operate
|
|
16
|
+
under `protocol/AGENTS.md` throughout.
|
|
17
|
+
|
|
18
|
+
Dates are injected, never wall-clock: the invoker supplies today's date
|
|
19
|
+
once (`<TODAY>` below) and every step reuses it.
|
|
20
|
+
|
|
21
|
+
## The seven steps
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
1. STRUCTURE engine/validate.js — whole-store structural truth
|
|
25
|
+
2. VALUES engine/validate-values.js — enumerates vs source, both ways
|
|
26
|
+
3. REVERSE engine/audit.js — advisory (never blocking) proposals
|
|
27
|
+
4. KNOWLEDGE leaf sweep: citations, cross-refs, revision notes
|
|
28
|
+
5. DECISIONS lifecycle: aging proposed/accepted, orphaned relates-to
|
|
29
|
+
6. HEARTBEAT last-reflect stamp, open fragments, quarantined concepts
|
|
30
|
+
7. REPORT the fixed report shape, filled from the outputs above
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
No step's outcome stops the audit. Exit 2 anywhere is itself the finding —
|
|
34
|
+
a check that never ran is a blocking defect, never a silent pass — so the
|
|
35
|
+
report records that verdict as **CHECK NEVER RAN** (never as a pass) and
|
|
36
|
+
the audit continues, keeping the report whole.
|
|
37
|
+
|
|
38
|
+
### 1. STRUCTURE — the whole-store validator
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
node unknown-knowledge/engine/validate.js --root .
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Run unfiltered — the audit is a whole-store instrument, never a `--concepts`
|
|
45
|
+
spot check. Capture verbatim: the exit code, the summary line, the
|
|
46
|
+
`checks run:` line (so a green verdict names what actually ran), and every
|
|
47
|
+
finding. Unresolved cross-store references — including a knowledge
|
|
48
|
+
cross-reference or a decision `relates-to` that points at nothing — surface
|
|
49
|
+
here as loader errors at exit 2. **Done when** the exit code and the full
|
|
50
|
+
finding list (or the clean two-liner) are captured for the report.
|
|
51
|
+
|
|
52
|
+
### 2. VALUES — enumerates vs source
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
node unknown-knowledge/engine/validate-values.js --root .
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Capture verbatim: the counts line, every HARD ERROR (out-of-envelope
|
|
59
|
+
descriptors — on those concepts the check never ran, and the report must
|
|
60
|
+
say so), and every finding (`value-not-in-source`, `source-value-missing`,
|
|
61
|
+
`wrong-pointer`). **Done when** exit code, counts line, hard errors, and
|
|
62
|
+
findings are all captured.
|
|
63
|
+
|
|
64
|
+
### 3. REVERSE — the advisory scan
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
node unknown-knowledge/engine/audit.js --root . --today 2026-07-09
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Always pass `--today <TODAY>` — without it the stale-last-verified check
|
|
71
|
+
reports itself skipped, and the heartbeat wants that check run. The reverse
|
|
72
|
+
audit is **advisory (never blocking)**: its findings are drafted proposals
|
|
73
|
+
for human review, so capture the header lines (candidates / matched /
|
|
74
|
+
findings, scope, stale check), the finding codes with their paths, and any
|
|
75
|
+
suppressed count — the draft YAML blocks go to the steward, not into the
|
|
76
|
+
report body. `--fail-on-findings` stays a human opt-in — never a CI
|
|
77
|
+
default, never part of this audit. **Done when** the header lines and the
|
|
78
|
+
per-finding one-liners are captured.
|
|
79
|
+
|
|
80
|
+
### 4. KNOWLEDGE — the leaf sweep
|
|
81
|
+
|
|
82
|
+
Citation *presence* and cross-reference *resolution* are engine checks —
|
|
83
|
+
they already ran in step 1 (`missing-citation` findings; unresolved refs at
|
|
84
|
+
exit 2). Never re-derive them by hand. This sweep reads every leaf the
|
|
85
|
+
knowledge catalog declares and records what the engine does not compute,
|
|
86
|
+
one row per leaf:
|
|
87
|
+
|
|
88
|
+
- **citations dated** — every citation carries an `accessed` date (an
|
|
89
|
+
undated source ages invisibly);
|
|
90
|
+
- **revision note present** — at least one `revision` note with a `date`,
|
|
91
|
+
and the newest one consistent with `edition` (an edition bump with no
|
|
92
|
+
note is an unexplained change);
|
|
93
|
+
- **standing room pressure** — `including` topics that sessions keep
|
|
94
|
+
needing are kb-build candidates; name them.
|
|
95
|
+
|
|
96
|
+
**Done when** every catalog-declared leaf appears in the sweep table with
|
|
97
|
+
all three columns filled — a leaf skipped is a check that never ran.
|
|
98
|
+
|
|
99
|
+
### 5. DECISIONS — the lifecycle check
|
|
100
|
+
|
|
101
|
+
Orphaned `relates-to` references are engine-checked (step 1, exit 2) —
|
|
102
|
+
record here any that fired; never re-derive resolution by hand. This sweep
|
|
103
|
+
computes the ages the engine does not: for every entry in
|
|
104
|
+
`decisions/entries/`, days from its `date` to `<TODAY>`, then flag:
|
|
105
|
+
|
|
106
|
+
- **aging `proposed`** — older than 30 days: a proposal nobody gated. A
|
|
107
|
+
provisional date-suffixed id (`D-YYYY-MM-DD-<slug>`) still `proposed`
|
|
108
|
+
past the window means the steward never minted the final `D-NNN` — name
|
|
109
|
+
it.
|
|
110
|
+
- **aging `accepted`** — older than 90 days and never moved to
|
|
111
|
+
`addressed`/`archived`: accepted words with no follow-through.
|
|
112
|
+
|
|
113
|
+
The thresholds are report headings, not verdicts — aging entries route to
|
|
114
|
+
the steward for triage. **Done when** every catalog-declared decision
|
|
115
|
+
appears with its status and age, and the aging list is exhaustive over that
|
|
116
|
+
table.
|
|
117
|
+
|
|
118
|
+
### 6. HEARTBEAT — the loop's vital signs (§8)
|
|
119
|
+
|
|
120
|
+
Three instruments; every one produces a report line — a lapsed steward
|
|
121
|
+
rotation is **visible, never silent**.
|
|
122
|
+
|
|
123
|
+
**Days since last reflect.** The reflect skill stamps a `last-reflect`
|
|
124
|
+
state file at the kit root:
|
|
125
|
+
|
|
126
|
+
```sh
|
|
127
|
+
cat unknown-knowledge/last-reflect.yaml
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Present → report `<TODAY>` minus the stamped date as
|
|
131
|
+
days-since-last-reflect. Absent (`No such file or directory`) → the report
|
|
132
|
+
line reads **no reflect has run yet** — degrade gracefully; the absence IS
|
|
133
|
+
the datum, and it still prints.
|
|
134
|
+
|
|
135
|
+
**Open fragments per log.**
|
|
136
|
+
|
|
137
|
+
```sh
|
|
138
|
+
for log in findings misses gaps; do
|
|
139
|
+
printf '%s open: ' "$log"
|
|
140
|
+
grep -rl '^status: open' "unknown-knowledge/logs/$log" 2>/dev/null | wc -l
|
|
141
|
+
done
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Top-N quarantined concepts** (N = 5). List the quarantine-trigger
|
|
145
|
+
fragments, read each one's `consulted.concepts`, count per concept, rank:
|
|
146
|
+
|
|
147
|
+
```sh
|
|
148
|
+
grep -rl '^trigger: quarantine' unknown-knowledge/logs/findings 2>/dev/null
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Report concept IDs and counts only — fragment summaries stay in the
|
|
152
|
+
fragments (§3.4 rides into reports too). **Done when** all three heartbeat
|
|
153
|
+
lines exist, each carrying a real number or the explicit absence line.
|
|
154
|
+
|
|
155
|
+
### 7. REPORT — the fixed shape
|
|
156
|
+
|
|
157
|
+
One markdown report, sections in this order, **every section present even
|
|
158
|
+
when empty** — "none" is a real answer; a missing section is a check that
|
|
159
|
+
never ran:
|
|
160
|
+
|
|
161
|
+
```markdown
|
|
162
|
+
# knowledge-audit report — <TODAY>
|
|
163
|
+
|
|
164
|
+
## Verdicts
|
|
165
|
+
| step | command | exit | reading |
|
|
166
|
+
(structure, values, reverse audit — one row each; exit 2 reads CHECK NEVER RAN)
|
|
167
|
+
|
|
168
|
+
## Structural findings
|
|
169
|
+
## Value findings
|
|
170
|
+
## Reverse audit proposals (advisory — never blocking)
|
|
171
|
+
## Knowledge leaves
|
|
172
|
+
## Decisions lifecycle
|
|
173
|
+
## Heartbeat
|
|
174
|
+
- days since last reflect: <n> (or: no reflect has run yet)
|
|
175
|
+
- open fragments: findings <n>, misses <n>, gaps <n>
|
|
176
|
+
- top quarantined concepts: K-NNN (<count>), … (or: none)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Fill every line from the outputs captured in steps 1–6 — never from memory
|
|
180
|
+
of a previous run: trust is per-run (D-011). Deliver the report in the
|
|
181
|
+
conversation; the audit commits nothing and edits nothing — anything worth
|
|
182
|
+
fixing routes to its owning path (concept PRs, kb-build, reflect, the
|
|
183
|
+
steward).
|