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,60 @@
|
|
|
1
|
+
# Guarantees and boundaries
|
|
2
|
+
|
|
3
|
+
What the kit promises, what it deliberately does not, and which of its rules
|
|
4
|
+
are yours to change. Each section names the decision that pinned it — the
|
|
5
|
+
full record is in the kit's decision log, and the seeded copy of every rule
|
|
6
|
+
below lives in `protocol/AGENTS.md`.
|
|
7
|
+
|
|
8
|
+
## What the kit will never catch (D-008)
|
|
9
|
+
|
|
10
|
+
The kit catches **conceptual drift**: names, value sets, and pointers — the
|
|
11
|
+
map disagreeing with the artifact. A registry gained a value no concept
|
|
12
|
+
knows; a concept enumerates a value the source dropped; a pointer dangles at
|
|
13
|
+
a file that moved.
|
|
14
|
+
|
|
15
|
+
It will **never** catch **behavioral drift**: logic bugs, inverted
|
|
16
|
+
conditions, a wrong calculation behind a correctly-named function, a
|
|
17
|
+
registry whose values are all present and all handled badly. Behavior is
|
|
18
|
+
your test suite's job. Budget your trust accordingly: a green validator run
|
|
19
|
+
means the map matches the code, not that the code is right.
|
|
20
|
+
|
|
21
|
+
## The engine never executes your code (D-014)
|
|
22
|
+
|
|
23
|
+
The engine only ever **reads your files lexically**. It never imports,
|
|
24
|
+
evals, or runs repo content; JSON and YAML are parsed as data, never
|
|
25
|
+
loaded as code; it makes no network calls. The one child process the
|
|
26
|
+
engine spawns is `git` (in `survey-map.js`, to list tracked files) — it
|
|
27
|
+
reads git's index, never your code. This is the answer to "does this tool
|
|
28
|
+
run our code in CI?": no — guaranteed by design and pinned by a grep test
|
|
29
|
+
in the kit's own CI. Any future adapter that would break it (e.g. a
|
|
30
|
+
remote-config fetch at validate time) must be explicitly opt-in.
|
|
31
|
+
|
|
32
|
+
## Findings privacy — the capture content policy
|
|
33
|
+
|
|
34
|
+
Findings, misses, and gaps are committed YAML fragments: permanent git
|
|
35
|
+
history **in your repo**, reviewable in PRs like any other change — and
|
|
36
|
+
they never leave it. The kit has no runtime and no telemetry; nothing is
|
|
37
|
+
collected or sent anywhere.
|
|
38
|
+
|
|
39
|
+
The capture policy is what keeps the fragments safe to commit: summaries
|
|
40
|
+
carry **concept IDs and file paths only** — never verbatim user text,
|
|
41
|
+
quoted session content, or secrets; the `session` field is an opaque ID.
|
|
42
|
+
This strips context by design — a finding is a signal that something
|
|
43
|
+
disagreed, not a transcript of the disagreement. The SSOT is the artifact
|
|
44
|
+
the finding points at; anyone judging a finding follows the pointer and
|
|
45
|
+
reads the source.
|
|
46
|
+
|
|
47
|
+
## Preflight conduct is yours to set (D-011)
|
|
48
|
+
|
|
49
|
+
Verdicts are deterministic engine facts; **what a session does about a
|
|
50
|
+
verdict is policy in markdown you own**. The place to edit is the
|
|
51
|
+
CLIENT-EDITABLE conduct table in `protocol/AGENTS.md`
|
|
52
|
+
("Conduct-on-verdict policy"): the recommended default is
|
|
53
|
+
quarantine-and-continue, and a stricter shop may edit `quarantined` to
|
|
54
|
+
fail-stop — that is the sanctioned edit, made by normal PR through your
|
|
55
|
+
steward gate.
|
|
56
|
+
|
|
57
|
+
The non-editable floor: the engine's verdicts, exit codes, and evidence are
|
|
58
|
+
computed facts, not policy — and no policy edit may tell an agent to bypass
|
|
59
|
+
a gate, trust a quarantined concept's claims, or treat exit 2 (a check that
|
|
60
|
+
never ran) as anything but a stop.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# CI wiring — validators in CI, attribution on PRs
|
|
2
|
+
|
|
3
|
+
> Commands run from the **repo root** with the kit dir at its default name
|
|
4
|
+
> `unknown-knowledge/`; substitute your chosen name if it differs. The CI
|
|
5
|
+
> snippets below are honest templates: written to be correct, **not executed
|
|
6
|
+
> against every CI product** — adapt runners, images, and paths to your
|
|
7
|
+
> setup, then watch the first run.
|
|
8
|
+
|
|
9
|
+
The kit never wires CI at init (D-006) — CI systems churn; your pipeline is
|
|
10
|
+
yours. But at team scale CI stops being optional in practice: session-level
|
|
11
|
+
preflight is a sufficient gate for a small team, not for hundreds of
|
|
12
|
+
engineers. Wire the two validators in.
|
|
13
|
+
|
|
14
|
+
## What may gate, and what never does
|
|
15
|
+
|
|
16
|
+
- `engine/validate.js` and `engine/validate-values.js` are blocking-grade
|
|
17
|
+
and MAY gate a merge. Exit codes: 0 = clean, 1 = findings, 2 = the check
|
|
18
|
+
never ran. Fail the job on both 1 and 2 — **a check that never ran is a
|
|
19
|
+
blocking defect, never a silent pass** (a non-zero exit fails the job by
|
|
20
|
+
default in every system below, so the templates need no special casing).
|
|
21
|
+
- `engine/preflight.js` with no `--concepts` checks store health only — add
|
|
22
|
+
it as a third gating step if you want the store verdict pinned in CI.
|
|
23
|
+
- `engine/audit.js` is advisory (never blocking): it drafts proposals for
|
|
24
|
+
human review, and presenting it as a required check would flip the whole
|
|
25
|
+
protocol from proposal-first to gate-first. Keep it out of CI. Its
|
|
26
|
+
`--fail-on-findings` flag exists for a human's local run — never a CI
|
|
27
|
+
default.
|
|
28
|
+
|
|
29
|
+
The engine needs Node ≥ 22 and its one library dependency, `js-yaml`,
|
|
30
|
+
resolvable in the checkout (see the seeded README) — the templates below
|
|
31
|
+
install dependencies for that reason. It reads your files lexically — it
|
|
32
|
+
never executes your code and never touches the network
|
|
33
|
+
(`docs/boundaries.md`) — so the jobs need no secrets, tokens, or extra
|
|
34
|
+
permissions.
|
|
35
|
+
|
|
36
|
+
## GitHub Actions
|
|
37
|
+
|
|
38
|
+
```yaml
|
|
39
|
+
# .github/workflows/knowledge-gates.yml — untested template, adapt.
|
|
40
|
+
name: knowledge-gates
|
|
41
|
+
on: pull_request
|
|
42
|
+
jobs:
|
|
43
|
+
validate:
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
steps:
|
|
46
|
+
- uses: actions/checkout@v4
|
|
47
|
+
- uses: actions/setup-node@v4
|
|
48
|
+
with:
|
|
49
|
+
node-version: 22
|
|
50
|
+
- run: npm ci # js-yaml must resolve; use `npm install js-yaml` if you keep no lockfile
|
|
51
|
+
- run: node unknown-knowledge/engine/validate.js --root .
|
|
52
|
+
- run: node unknown-knowledge/engine/validate-values.js --root .
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## GitLab CI
|
|
56
|
+
|
|
57
|
+
```yaml
|
|
58
|
+
# .gitlab-ci.yml fragment — untested template, adapt.
|
|
59
|
+
knowledge-gates:
|
|
60
|
+
image: node:22
|
|
61
|
+
rules:
|
|
62
|
+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
63
|
+
script:
|
|
64
|
+
- npm ci # js-yaml must resolve; use `npm install js-yaml` if you keep no lockfile
|
|
65
|
+
- node unknown-knowledge/engine/validate.js --root .
|
|
66
|
+
- node unknown-knowledge/engine/validate-values.js --root .
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Xcode Cloud
|
|
70
|
+
|
|
71
|
+
Xcode Cloud runs custom scripts from `ci_scripts/`; its images ship no Node
|
|
72
|
+
runtime, so the script installs one.
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
#!/bin/sh
|
|
76
|
+
# ci_scripts/ci_post_clone.sh — untested template, adapt.
|
|
77
|
+
set -e
|
|
78
|
+
brew install node
|
|
79
|
+
npm ci --prefix "$CI_PRIMARY_REPOSITORY_PATH" # js-yaml must resolve
|
|
80
|
+
node "$CI_PRIMARY_REPOSITORY_PATH/unknown-knowledge/engine/validate.js" --root "$CI_PRIMARY_REPOSITORY_PATH"
|
|
81
|
+
node "$CI_PRIMARY_REPOSITORY_PATH/unknown-knowledge/engine/validate-values.js" --root "$CI_PRIMARY_REPOSITORY_PATH"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## PR drift attribution (D-012) — whose findings are these?
|
|
85
|
+
|
|
86
|
+
Filtering validation down to the concepts a PR touched is rejected by
|
|
87
|
+
design: any gap in the reverse index (folder pointers, renames, module
|
|
88
|
+
adds/deletes) turns the filter into a false all-clear, which is worse than
|
|
89
|
+
no check. Attribution instead diffs **two honest whole-store runs** — the
|
|
90
|
+
finding set at the PR's merge-base against the set at HEAD. Both validators
|
|
91
|
+
emit stable, sorted JSON precisely so this diff means something.
|
|
92
|
+
|
|
93
|
+
```sh
|
|
94
|
+
git worktree add /tmp/kk-base "$(git merge-base HEAD origin/main)"
|
|
95
|
+
|
|
96
|
+
# Exit 1 just means findings exist — attribution wants the sets, not the gate.
|
|
97
|
+
node unknown-knowledge/engine/validate.js --json --root /tmp/kk-base > /tmp/base.json || true
|
|
98
|
+
node unknown-knowledge/engine/validate.js --json --root . > /tmp/head.json || true
|
|
99
|
+
|
|
100
|
+
# Right side only = drift this PR introduced; left side only = drift it fixed.
|
|
101
|
+
diff <(jq -S '.findings' /tmp/base.json) <(jq -S '.findings' /tmp/head.json)
|
|
102
|
+
|
|
103
|
+
git worktree remove /tmp/kk-base
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Run the same pair with `engine/validate-values.js` for value drift. In a CI
|
|
107
|
+
gate, fail on findings the diff attributes to the PR rather than on the raw
|
|
108
|
+
exit code — the baseline may legitimately be red while the map catches up,
|
|
109
|
+
and a PR should answer for its own drift, not the backlog's.
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# Steward guide — owning the loop
|
|
2
|
+
|
|
3
|
+
> Commands run from the **repo root** with the kit dir at its default name
|
|
4
|
+
> `unknown-knowledge/`; substitute your chosen name if it differs.
|
|
5
|
+
> Procedures live in the skills and in `protocol/AGENTS.md` — this guide
|
|
6
|
+
> tells you what the steward decides and points at where each procedure is
|
|
7
|
+
> defined; it never restates one.
|
|
8
|
+
|
|
9
|
+
## The role
|
|
10
|
+
|
|
11
|
+
A small group or rotation owns the improvement loop; the ordinary engineer
|
|
12
|
+
invokes nothing — the protocol rides along in their sessions. The steward:
|
|
13
|
+
|
|
14
|
+
- runs `/knowledge-reflect` on cadence — weekly, daily at high finding
|
|
15
|
+
volume (procedure: `protocol/skills/knowledge-reflect.md`);
|
|
16
|
+
- triages the reverse audit's drafted concepts — audit output is advisory
|
|
17
|
+
(never blocking), so every draft waits for your judgment;
|
|
18
|
+
- gates `/kb-build` promotions — the knowledge store's only write path is
|
|
19
|
+
cited and human-gated (`protocol/skills/kb-build.md`);
|
|
20
|
+
- accepts decision entries (final `D-NNN` assignment, below).
|
|
21
|
+
|
|
22
|
+
The heartbeat is `/knowledge-audit` (`protocol/skills/knowledge-audit.md`):
|
|
23
|
+
days-since-last-reflect, open-fragment counts, top quarantined concepts — a
|
|
24
|
+
lapsed rotation is visible instead of silent. The engine side of triage is
|
|
25
|
+
one command; `--today` is passed explicitly because diffable output never
|
|
26
|
+
reads the wall clock:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
node unknown-knowledge/engine/audit.js --root . --json --today 2026-07-09 --stale-days 90
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Reflect lands as a PR
|
|
33
|
+
|
|
34
|
+
Reflect emits a recommendation list — each item a concrete diff with its
|
|
35
|
+
corroborating findings attached; you approve or reject **per item**, and
|
|
36
|
+
approved diffs land as a normal PR. That is the design, not a convenience:
|
|
37
|
+
even the improvement loop's own changes pass the review and CI your org
|
|
38
|
+
already trusts, and rejections leave a recorded reason instead of a
|
|
39
|
+
disappeared suggestion.
|
|
40
|
+
|
|
41
|
+
## CODEOWNERS — scope the human gate
|
|
42
|
+
|
|
43
|
+
Gate the stores, the protocol, and the engine; leave the logs alone:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
# CODEOWNERS — steward review scoped to the governed surfaces.
|
|
47
|
+
/unknown-knowledge/ontology/ @your-org/knowledge-stewards
|
|
48
|
+
/unknown-knowledge/knowledge/ @your-org/knowledge-stewards
|
|
49
|
+
/unknown-knowledge/decisions/ @your-org/knowledge-stewards
|
|
50
|
+
/unknown-knowledge/protocol/ @your-org/knowledge-stewards
|
|
51
|
+
/unknown-knowledge/engine/ @your-org/knowledge-stewards
|
|
52
|
+
# logs/ is deliberately absent: findings ride nearly every agent-assisted
|
|
53
|
+
# PR. Requiring steward review there drowns the rotation in rubber-stamping
|
|
54
|
+
# — or teaches engineers to delete fragments to unblock merges, and capture
|
|
55
|
+
# dies. Logs must never require steward review.
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Suppressions hygiene
|
|
59
|
+
|
|
60
|
+
`unknown-knowledge/suppressions.yaml` silences known-noise audit findings.
|
|
61
|
+
Each entry is **strictly** `{ term, sourcePath, reason, date }`, exact match
|
|
62
|
+
only — no patterns, no expiry (D-013). Two properties to lean on:
|
|
63
|
+
|
|
64
|
+
- **Fails open.** A malformed entry (or an unparseable file) warns and
|
|
65
|
+
suppresses nothing, so the findings it would have hidden resurface — a
|
|
66
|
+
suppression can hide less than you meant, never more.
|
|
67
|
+
- **Exact match is self-expiring.** A suppression stops matching the moment
|
|
68
|
+
the file moves or the term changes; that is a feature, not fragility.
|
|
69
|
+
|
|
70
|
+
The JSON report carries the full suppressed list — sweep it on reflect
|
|
71
|
+
cadence and prune entries whose `reason` no longer holds.
|
|
72
|
+
|
|
73
|
+
## ID collision — two branches mint the same K-id
|
|
74
|
+
|
|
75
|
+
Published IDs are immutable — never renumbered (PRD §3.5). When two
|
|
76
|
+
branches both mint `K-210`, the merge is textually clean and the duplicate
|
|
77
|
+
surfaces on main; the **later-merging PR renumbers its own entry**, never
|
|
78
|
+
the one already published:
|
|
79
|
+
|
|
80
|
+
1. Rebase onto main and run the structural validator — it reports the
|
|
81
|
+
`duplicate-id` finding:
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
node unknown-knowledge/engine/validate.js --root .
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
2. Re-mint your entry at a free id within the owning class's range (mint
|
|
88
|
+
with gaps, per the store's `_rules.yaml`).
|
|
89
|
+
3. Update your branch's own inbound refs to the new id — `used-by`,
|
|
90
|
+
`relates-to`, and any `consulted:` refs in findings your branch appended.
|
|
91
|
+
4. Re-run both validators; green means the renumber is complete.
|
|
92
|
+
|
|
93
|
+
## Decisions authoring
|
|
94
|
+
|
|
95
|
+
The write path is the "Decisions-authoring path" in `protocol/AGENTS.md`:
|
|
96
|
+
anyone — agent or human — drafts a `proposed` entry with a provisional
|
|
97
|
+
date-suffixed id through the normal PR gate. Your half is acceptance: assign
|
|
98
|
+
the final `D-NNN` within range, and hold the append-mostly line — status
|
|
99
|
+
transitions never rewrite `context`/`decision`, and supersession chains must
|
|
100
|
+
resolve and stay acyclic.
|
|
101
|
+
|
|
102
|
+
## Phoenix events — re-filing a drifted subtree
|
|
103
|
+
|
|
104
|
+
Sometimes the material is fine and the shelf is wrong: one class holds two kinds
|
|
105
|
+
of thing that no longer share a reader, or a name stopped meaning what it says.
|
|
106
|
+
A phoenix event fixes that in bulk, under review, without breaking a single
|
|
107
|
+
citation.
|
|
108
|
+
|
|
109
|
+
It is a PR like any other, carrying four things: the Decisions entry that
|
|
110
|
+
sanctions it (copy `templates/decisions/phoenix-event.yaml`), the registry
|
|
111
|
+
mintings the new values need, the mapping at `knowledge/_phoenix/<event>.yaml`,
|
|
112
|
+
and the leaf rewrites — which you never make by hand:
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
node unknown-knowledge/engine/phoenix.js P-001 --root . # dry run: plan it, write nothing
|
|
116
|
+
node unknown-knowledge/engine/phoenix.js P-001 --root . --apply # write, only if the plan is clean
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
What to check when you review one:
|
|
120
|
+
|
|
121
|
+
- **The mapping is complete.** Every leaf in the declared scope must be mapped,
|
|
122
|
+
split, or explicitly carried forward. The engine refuses the event and names
|
|
123
|
+
the leaf otherwise — it will not half-apply, so a rejected event leaves the
|
|
124
|
+
store exactly as it found it.
|
|
125
|
+
- **Each row's `why` earns its move.** On a split this is the whole substance:
|
|
126
|
+
the class-level rule cannot say why L-000117 went to ingest and its neighbour
|
|
127
|
+
went to patterns, so the rows have to.
|
|
128
|
+
- **The diff is two lines per leaf.** `edition` and the one facet. If a leaf's
|
|
129
|
+
citations, body, or `id` appear in the diff, something is wrong — the engine
|
|
130
|
+
rewrites single frontmatter lines and copies every other byte through.
|
|
131
|
+
- **The mapping stays.** Do not delete it after the event lands. It is what lets
|
|
132
|
+
the validator confirm every edition above 1 was sanctioned, reading only the
|
|
133
|
+
working tree. A leaf's edition must equal `1 + the events that moved it`, and
|
|
134
|
+
`validate.js` reports `unaccounted-edition` when it does not.
|
|
135
|
+
|
|
136
|
+
Identity never moves. Accession ids are untouched, so every citation into the
|
|
137
|
+
subtree — decisions entries, catalog rows, leaf cross-references — stays valid
|
|
138
|
+
across the event. If a proposal needs an id renamed or reissued, it is not a
|
|
139
|
+
phoenix event.
|
|
140
|
+
|
|
141
|
+
## Findings are lossy, by design
|
|
142
|
+
|
|
143
|
+
Keep the corroboration math honest by knowing what the log is not:
|
|
144
|
+
|
|
145
|
+
- **Capture strips context deliberately.** Summaries carry concept IDs and
|
|
146
|
+
file paths only — never verbatim user text (see `docs/boundaries.md`).
|
|
147
|
+
The SSOT is the artifact the finding points at, never the finding's
|
|
148
|
+
prose: to judge a cluster, follow the pointers and read the source.
|
|
149
|
+
- **Findings travel only with merged PRs.** Abandoned branches lose theirs.
|
|
150
|
+
Corroboration tolerates a lossy denominator — treat finding counts as
|
|
151
|
+
signal, never as census.
|
|
152
|
+
|
|
153
|
+
## Trust graduation — narrowing inspection, and un-narrowing it
|
|
154
|
+
|
|
155
|
+
Autonomy is graduated per change-category, never global, never per leaf, and
|
|
156
|
+
never assumed (the gate rules in `protocol/AGENTS.md`). The category is the
|
|
157
|
+
unit because it is the only thing evidence can be about: "this leaf has been
|
|
158
|
+
right ten times" says nothing about the eleventh leaf, which is a different
|
|
159
|
+
claim by a different author, whereas "alias additions have been approved
|
|
160
|
+
unmodified ten cycles running" is evidence about a class of edit.
|
|
161
|
+
|
|
162
|
+
The observable basis is what reflect already records: **per-item approval
|
|
163
|
+
outcomes by category** (approved / approved-with-modification / rejected).
|
|
164
|
+
|
|
165
|
+
### The category table
|
|
166
|
+
|
|
167
|
+
`decisions/_registries/graduation-categories.yaml` declares every change
|
|
168
|
+
category and its eligibility. It is filed under `decisions/` because
|
|
169
|
+
graduation governs the change *process* — the team's truth anchor (D-003) —
|
|
170
|
+
not the knowledge itself. Two shapes:
|
|
171
|
+
|
|
172
|
+
- **`eligible`**, with a threshold **N**: mechanical categories, where the
|
|
173
|
+
edit is checkable by reading it and a clean run is evidence about the next
|
|
174
|
+
one. Alias additions, verified bumps, `paths` edges, see-also links.
|
|
175
|
+
- **`gated`**, permanently: judgment categories. New domain classes,
|
|
176
|
+
contradicts/supersedes edges, authority assignments, and **anything
|
|
177
|
+
citation-bearing**. These never graduate, however long the streak — the
|
|
178
|
+
streak answers a different question than the one they ask. A correct
|
|
179
|
+
authority assignment ten times over says the assigner has been careful, not
|
|
180
|
+
that the eleventh source's trustworthiness can go unread.
|
|
181
|
+
|
|
182
|
+
Every row carries a warrant and cites a Decisions entry, like any registry
|
|
183
|
+
value. A malformed table is a hard error (exit 2), not a finding: graduation
|
|
184
|
+
checks judged against a table the engine could not read are checks that never
|
|
185
|
+
ran.
|
|
186
|
+
|
|
187
|
+
### v1 analytics are MANUAL — the engine does not compute the counts
|
|
188
|
+
|
|
189
|
+
State this plainly to anyone reading a green validator: **the engine does not
|
|
190
|
+
compute approved-unmodified counts and never decides whether a threshold was
|
|
191
|
+
met.** It checks that the entry is well-formed, that its category is declared,
|
|
192
|
+
and that the category is not gated. *You* count the cycles and judge them
|
|
193
|
+
against N. The `observed-cycles` field is your written record of that count,
|
|
194
|
+
kept so a reviewer can weigh the judgment — no code asserts it. A clean
|
|
195
|
+
validation run is not agreement that a graduation was earned.
|
|
196
|
+
|
|
197
|
+
### Recording one
|
|
198
|
+
|
|
199
|
+
Copy `templates/decisions/trust-graduation.yaml`, and record the graduation as
|
|
200
|
+
a `decisions/` entry of category `trust`. The entry carries a typed
|
|
201
|
+
`graduation:` block naming the category and your observed count.
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
node unknown-knowledge/engine/validate.js --root .
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Revocation is automatic on ANY defect
|
|
208
|
+
|
|
209
|
+
**Any defect found in a graduated category revokes it.** Not "a serious
|
|
210
|
+
defect", not "a pattern of defects" — one is enough, and the response is
|
|
211
|
+
mechanical so it cannot be argued down. The warrant for sampling a category
|
|
212
|
+
was that it had stopped producing surprises; one surprise is the evidence that
|
|
213
|
+
it has not. Record it with `templates/decisions/trust-revocation.yaml`; the
|
|
214
|
+
category returns to full inspection and its streak restarts at zero.
|
|
215
|
+
|
|
216
|
+
Revoking is deliberately the cheapest entry in the store to write. Narrowing
|
|
217
|
+
inspection takes a counted streak and a written rationale; restoring it takes
|
|
218
|
+
noticing one defect. If revoking were as laborious as graduating, the
|
|
219
|
+
laborious thing would quietly not get done and the boundary would only ever
|
|
220
|
+
move one way. Revoking is always allowed — including for a gated category,
|
|
221
|
+
where it is a no-op that records the standing position. Only *graduating* a
|
|
222
|
+
gated category is refused.
|
|
223
|
+
|
|
224
|
+
### Citation spot-checks stay in the sampling plan at every trust level
|
|
225
|
+
|
|
226
|
+
Whatever a category has earned, **citation spot-checks continue at every trust
|
|
227
|
+
level**, including the most graduated. A citation is a claim about the world
|
|
228
|
+
that the store cannot check for itself; no streak of clean mechanical edits is
|
|
229
|
+
evidence that the citations are sound. Graduation only ever answers the
|
|
230
|
+
mechanical question.
|
|
231
|
+
|
|
232
|
+
### Provenance — tracing a bad skill revision
|
|
233
|
+
|
|
234
|
+
Entries carry `provenance` (`author`, `skill-version`), and the validator
|
|
235
|
+
surfaces it in both JSON and human output. When a defect turns out to come
|
|
236
|
+
from a bad skill vintage rather than a bad judgment, this is what makes every
|
|
237
|
+
entry that vintage wrote findable rather than guessed at — a bad skill
|
|
238
|
+
revision is traceable like any other defect.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* engine/audit.js — the entry shim (UCS-956).
|
|
4
|
+
*
|
|
5
|
+
* This file statically imports NOTHING. That is its entire job.
|
|
6
|
+
*
|
|
7
|
+
* Node exits 1 on an unhandled ES module load error, and exit 1 means FINDINGS
|
|
8
|
+
* (PRD §5). A SyntaxError in a lib/ module, or a missing `js-yaml`, must not
|
|
9
|
+
* tell an agent that the check ran and found problems. So the engine is reached
|
|
10
|
+
* only through `import()`, where a load failure is an ordinary catchable
|
|
11
|
+
* rejection rather than a process-level crash.
|
|
12
|
+
*
|
|
13
|
+
* Both specifiers are string literals naming the engine's own files. D-014
|
|
14
|
+
* forbids importing REPO CONTENT — the client's code — and nothing here can
|
|
15
|
+
* name it: there is no variable to point somewhere else.
|
|
16
|
+
*
|
|
17
|
+
* The command lives in commands/audit.js. Its invocation path is unchanged.
|
|
18
|
+
*/
|
|
19
|
+
try {
|
|
20
|
+
const [{ boot }, command] = await Promise.all([
|
|
21
|
+
import('./lib/boot.js'),
|
|
22
|
+
import('./commands/audit.js'),
|
|
23
|
+
]);
|
|
24
|
+
// exitCode, never process.exit(): exit() drops queued async stdout writes, so
|
|
25
|
+
// piped --json output would truncate at the pipe buffer — corrupt output
|
|
26
|
+
// wearing a clean exit code. Node exits on its own once stdout drains.
|
|
27
|
+
process.exitCode = await boot('audit', command);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
// The engine could not be loaded, so no check ran. Exit 2 — never 1.
|
|
30
|
+
// Hardcoded, because reading it from lib/exit-codes.js is the very thing
|
|
31
|
+
// that may have just failed.
|
|
32
|
+
process.stderr.write(`audit: internal failure — the engine could not be loaded\n${error?.stack ?? error}\n`);
|
|
33
|
+
process.exitCode = 2;
|
|
34
|
+
}
|