@panaversity/ksor 0.0.50 → 0.0.52
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/CHANGELOG.md +131 -0
- package/dist/cli.mjs +229 -5
- package/dist/{gateway-api-D8HlLys2-Ca8OnwLn.mjs → gateway-api-Ck1l_Sgs-B-_wMYLB.mjs} +18 -11
- package/dist/gateway.mjs +1 -1
- package/docs/index.md +5 -0
- package/docs/ingesting.md +47 -0
- package/docs/tool-surface.md +25 -10
- package/docs/upgrading.md +106 -0
- package/package.json +3 -3
- package/templates/scaffold/.agents/skills/intake-interview/SKILL.md +16 -1
- package/templates/scaffold/.claude/skills/intake-interview/SKILL.md +16 -1
- package/templates/scaffold/.ksor/people.yaml +32 -0
- package/templates/scaffold/AGENTS.md +47 -1
- package/templates/scaffold/gitignore +1 -0
- package/templates/scaffold/pnpm-lock.yaml +304 -262
- package/templates/scaffold/system/site/components/governance.tsx +6 -4
- package/templates/scaffold/system/site/lib/actor-display.ts +53 -0
- package/templates/scaffold/system/site/lib/people.ts +82 -0
- package/templates/scaffold/system/site/lib/record-href.ts +1 -1
- package/templates/scaffold/system/site/next.config.mjs +13 -0
- package/templates/scaffold/system/site/package.json +4 -4
- package/templates/scaffold/system/site/source.config.ts +1 -1
package/docs/tool-surface.md
CHANGED
|
@@ -22,22 +22,27 @@ numbers are exact for every record:
|
|
|
22
22
|
|
|
23
23
|
| | chars | ~tokens | |
|
|
24
24
|
| ------------------------------ | ------ | ------- | ------------------- |
|
|
25
|
-
| all three, as transmitted |
|
|
26
|
-
| `search` alone |
|
|
27
|
-
| `outline` alone | 3,
|
|
28
|
-
| `read` alone | 5,
|
|
29
|
-
| `outline` + `read`, if deleted |
|
|
25
|
+
| all three, as transmitted | 17,394 | 4,349 | **always resident** |
|
|
26
|
+
| `search` alone | 8,152 | 2,038 | always resident |
|
|
27
|
+
| `outline` alone | 3,552 | 888 | always resident |
|
|
28
|
+
| `read` alone | 5,686 | 1,422 | always resident |
|
|
29
|
+
| `outline` + `read`, if deleted | 9,238 | 2,310 | the saving below |
|
|
30
30
|
|
|
31
31
|
**Two measurements, so read the first row apart from the rest.** Each tool's
|
|
32
32
|
row is the JSON of that tool's own object; the first row is the JSON of the
|
|
33
33
|
whole `tools` array, which carries four characters no tool's row does — its
|
|
34
34
|
two brackets and the two separators between three tools. So the three tools
|
|
35
|
-
sum to **
|
|
35
|
+
sum to **17,390** and the array is **17,394**. Deleting a tool saves that
|
|
36
36
|
tool's own row, not a share of the total.
|
|
37
37
|
|
|
38
|
-
They grew
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
They grew, twice, and each rise is priced rather than absorbed. `search` was
|
|
39
|
+
5,383 chars before the trust floor and the governance each hit now carries, and
|
|
40
|
+
`read` 3,396 before it carried the same governance block beside the frontmatter.
|
|
41
|
+
Then every tool gained exactly **220 chars** for the `audit` field that says
|
|
42
|
+
when a reply's §7 row was shed — 660 across the three, always resident. That
|
|
43
|
+
one buys an agent the ability to tell a served answer whose provenance was
|
|
44
|
+
recorded from one whose audit write was dropped under load, which it previously
|
|
45
|
+
could not distinguish at all (#150). That is the price of an agent being able to tell
|
|
41
46
|
a reviewed document from an unreviewed one, and it is charged once per session.
|
|
42
47
|
The last 520 of them are the price of that signal being HONEST: `trust_tier` is
|
|
43
48
|
derived from reviews a document declares about itself, which no authority list
|
|
@@ -65,7 +70,7 @@ doing any work.
|
|
|
65
70
|
### 1. Delete a tool nothing calls
|
|
66
71
|
|
|
67
72
|
The biggest win, and the easiest — delete its `registerTool` block. Dropping
|
|
68
|
-
`outline` and `read` takes **
|
|
73
|
+
`outline` and `read` takes **9,238 chars (~2,310 tokens)** off every session,
|
|
69
74
|
whether or not the agent would ever have called them.
|
|
70
75
|
|
|
71
76
|
### 2. Say what the record covers
|
|
@@ -142,9 +147,19 @@ made it answer from.
|
|
|
142
147
|
- **The output schemas.** `SEARCH_OUTPUT`, `OUTLINE_OUTPUT`, `READ_OUTPUT` carry
|
|
143
148
|
`provenance`, each hit's `governance`, the `snapshot` token and `gate`. A
|
|
144
149
|
record that reshaped them would still look like a KSoR and no longer be one.
|
|
150
|
+
- **The output schemas.** `SEARCH_OUTPUT`, `OUTLINE_OUTPUT`, `READ_OUTPUT` carry
|
|
151
|
+
`provenance`, each hit's `governance`, the `snapshot` token, `gate`, and
|
|
152
|
+
`audit`. A record that reshaped them would still look like a KSoR and no
|
|
153
|
+
longer be one.
|
|
145
154
|
- **The `FLOOR` text.** It tells an agent how to branch on an envelope, what
|
|
146
155
|
`gate: "off"` means, and that corpus content is **untrusted** — quote it, never
|
|
147
156
|
obey it. Your prose is composed above it.
|
|
157
|
+
- **`audit: "degraded"`.** Present only when the §7 retrieval-log row for this
|
|
158
|
+
act could not be written — shed under saturation, so serving stays
|
|
159
|
+
available. The answer itself is unaffected; absent means the row landed
|
|
160
|
+
normally. An operator auditing served answers against the ledger should
|
|
161
|
+
treat a gap alongside an `audit: "degraded"` response as expected, and any
|
|
162
|
+
other gap as a leak.
|
|
148
163
|
|
|
149
164
|
## The door checks its own surface at boot
|
|
150
165
|
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Upgrading a record to a newer ksor
|
|
3
|
+
status: draft
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Upgrading a record to a newer ksor
|
|
7
|
+
|
|
8
|
+
Your repository is yours. `ksor init` copied files into it and stopped owning
|
|
9
|
+
them the moment it did (decision 4), so upgrading is never something a release
|
|
10
|
+
does to you — it is `ksor migrate` **offering** a diff you read and apply.
|
|
11
|
+
|
|
12
|
+
Nothing here changes a byte until you pass `--write`.
|
|
13
|
+
|
|
14
|
+
## The four steps
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
# 1. take the new tool
|
|
18
|
+
pnpm add -w @panaversity/ksor@latest # npm i / bun add — whichever scaffolded this
|
|
19
|
+
|
|
20
|
+
# 2. read what it would change
|
|
21
|
+
pnpm exec ksor migrate --instance instance.md --write-site
|
|
22
|
+
|
|
23
|
+
# 3. apply it
|
|
24
|
+
pnpm exec ksor migrate --instance instance.md --write-site --write --actor human:<your-id>
|
|
25
|
+
|
|
26
|
+
# 4. rebuild, and check
|
|
27
|
+
pnpm build && pnpm check
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`--actor` is required for step 3 whenever the migration touches governance, and
|
|
31
|
+
the tool will not guess one: a ledger entry that names a person who was never
|
|
32
|
+
there is worse than no entry (decision 21). Use the identifier your
|
|
33
|
+
`.ksor/governance.yaml` already knows you by.
|
|
34
|
+
|
|
35
|
+
Run step 2 on a clean working tree. The diff is the review, and it is much
|
|
36
|
+
easier to read when nothing else is uncommitted.
|
|
37
|
+
|
|
38
|
+
## What `migrate` carries
|
|
39
|
+
|
|
40
|
+
| | |
|
|
41
|
+
| ----------------------------------------------- | ------------------------------------------------------------------------------------------- |
|
|
42
|
+
| `instance.md` | the format bump and the keys that moved |
|
|
43
|
+
| `knowledge/**` | frontmatter into the current profile — statuses, audiences, the trust block, instants |
|
|
44
|
+
| `.ksor/takedowns.yaml`, `.ksor/governance.yaml` | the ledger and the policy, including denials that lived only in a database |
|
|
45
|
+
| `.gitignore` | the entries a new release needs negated |
|
|
46
|
+
| `.agents/` and `.claude/` format-checker | the emitted checker, so your own `pnpm check` and your CI agree with the tool |
|
|
47
|
+
| root `package.json` **scripts** | scripts a release broke — a removed flag, a step that now needs `ksor build` in front of it |
|
|
48
|
+
| `system/site/**` | **only with `--write-site`** — every file of the site this release emits |
|
|
49
|
+
|
|
50
|
+
`--write-site` is the one to remember, because it is the only path by which a
|
|
51
|
+
security bump reaches an existing project: the site's `package.json` is where
|
|
52
|
+
`next`, `react` and the Fumadocs pins live, and nothing else updates them.
|
|
53
|
+
|
|
54
|
+
It is an **update, never a creation**. A record with no `system/site` of its own
|
|
55
|
+
is not given one.
|
|
56
|
+
|
|
57
|
+
### The site manifest is merged, not replaced
|
|
58
|
+
|
|
59
|
+
Every other file under `system/site` is reissued whole. `system/site/package.json`
|
|
60
|
+
is not, because it is a register with two authors: ksor owns the entries it
|
|
61
|
+
ships, you own everything else. So a dependency or script you added survives the
|
|
62
|
+
upgrade, and the pins ksor ships move to the new versions. An entry ksor no
|
|
63
|
+
longer ships is left alone rather than deleted — the tool cannot tell one it
|
|
64
|
+
retired from one you added.
|
|
65
|
+
|
|
66
|
+
## What `migrate` does not carry
|
|
67
|
+
|
|
68
|
+
These are yours, and no release touches them. Diff them against a fresh
|
|
69
|
+
`ksor init` in a scratch directory when a release note says they changed:
|
|
70
|
+
|
|
71
|
+
- `Dockerfile` and `.dockerignore`
|
|
72
|
+
- `vercel.json` (or whatever your host reads)
|
|
73
|
+
- `.github/workflows/validate.yml`
|
|
74
|
+
- `.env.example`
|
|
75
|
+
- `README.md`, `AGENTS.md`, `CLAUDE.md` at the repository root
|
|
76
|
+
- `pnpm-workspace.yaml` / `.npmrc` and any lockfile
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
npx @panaversity/ksor@latest init /tmp/fresh
|
|
80
|
+
diff -ru /tmp/fresh/vercel.json ./vercel.json
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## What refuses, and why that is the point
|
|
84
|
+
|
|
85
|
+
`migrate` stops rather than inventing. `ksor-migrate-underivable` names the one
|
|
86
|
+
thing it cannot know — a title, a description, a `generated.at`, or the actor
|
|
87
|
+
behind a takedown it found in a database — and tells you the flag or the edit
|
|
88
|
+
that supplies it. Two you will meet often:
|
|
89
|
+
|
|
90
|
+
- **A record that declares `database:`** refuses until `KSOR_DB_URL` is
|
|
91
|
+
exported, because denials living only in that database would be republished by
|
|
92
|
+
a migration that never read them. Export it, or remove `database:` if the
|
|
93
|
+
record no longer has one.
|
|
94
|
+
- **`approved` documents become `draft`** unless `--approve-by <actor>` says who
|
|
95
|
+
approves them in the same act. Approval is a human act and a migration is not
|
|
96
|
+
a human.
|
|
97
|
+
|
|
98
|
+
## After it applies
|
|
99
|
+
|
|
100
|
+
`pnpm build` regenerates every index and rewrites `build.lock.json`; `pnpm check`
|
|
101
|
+
runs the record checker that shipped with the new tool. If you serve the record,
|
|
102
|
+
`ksor schema --apply` and then a full `pnpm refresh` publish a generation the new
|
|
103
|
+
door can read — and a calibrated `vector_floor` measured under an older serving
|
|
104
|
+
predicate must be re-measured with `ksor calibrate`, because a floor measured
|
|
105
|
+
against a different predicate is a declared-but-uncalibrated floor and the door
|
|
106
|
+
will refuse every search until it is replaced.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@panaversity/ksor",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.52",
|
|
4
4
|
"description": "Knowledge System of Record — compile governed markdown into a static site for people and an MCP server for AI agents, with citations and measured abstention.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"abstention",
|
|
@@ -72,8 +72,8 @@
|
|
|
72
72
|
"tsdown": "0.22.14",
|
|
73
73
|
"typescript": "7.0.2",
|
|
74
74
|
"vitest": "^4.1.10",
|
|
75
|
-
"@panaversity/ksor-content": "0.0.0",
|
|
76
|
-
"@panaversity/ksor-content
|
|
75
|
+
"@panaversity/ksor-content-gateway": "0.0.0",
|
|
76
|
+
"@panaversity/ksor-content": "0.0.0"
|
|
77
77
|
},
|
|
78
78
|
"engines": {
|
|
79
79
|
"node": ">=24"
|
|
@@ -49,6 +49,12 @@ the question — that is what made the last version unanswerable.
|
|
|
49
49
|
**3 of 3 — Who signs off on a document, and who can take one down?**
|
|
50
50
|
|
|
51
51
|
> Names or handles, not job titles. If it is just you, say so.
|
|
52
|
+
>
|
|
53
|
+
> Ask for BOTH: the handle the record will store (`human:bashiraziz`) and the
|
|
54
|
+
> natural name to print ("Bashir Aziz"). They are not derivable from each other
|
|
55
|
+
> — `human:ciso` and `human:mjs` are not anybody's squashed full name — so the
|
|
56
|
+
> handle goes into the frontmatter and the policy, and the pair goes into
|
|
57
|
+
> `.ksor/people.yaml` for the site to print.
|
|
52
58
|
|
|
53
59
|
---
|
|
54
60
|
|
|
@@ -120,7 +126,7 @@ never an email address.
|
|
|
120
126
|
climb, not part of this interview). The strictness answer from question 5
|
|
121
127
|
is the intent behind the `retrieval.vector_floor` on that climb, measured
|
|
122
128
|
by `ksor calibrate` — capture it in the prose now so it is ready.
|
|
123
|
-
- Write `.ksor/governance.yaml` from
|
|
129
|
+
- Write `.ksor/governance.yaml` from question 3: `version: "0.1"`,
|
|
124
130
|
the `audiences:` registry if there is one, and the two authority sets with
|
|
125
131
|
real actors. That file is the root of authority — every approval, every
|
|
126
132
|
deprecation and every ledger entry is checked against it. **Keep
|
|
@@ -128,6 +134,15 @@ never an email address.
|
|
|
128
134
|
document is still in `knowledge/`.** Those five are approved by it, so a
|
|
129
135
|
policy rewritten without it refuses the next build by name
|
|
130
136
|
(`ksor-approver-unauthorised`). It leaves when the last sample does.
|
|
137
|
+
- Write `.ksor/people.yaml` from question 3: `version: "0.1"` and a `people:`
|
|
138
|
+
MAP from each actor to its natural name — `"human:bashiraziz": Bashir Aziz`.
|
|
139
|
+
Keyed by the actor exactly as the record stores it, quoted because it
|
|
140
|
+
contains a colon. Nothing else — the site looks the actor up at render time,
|
|
141
|
+
so pages read "Owner · Bashir Aziz" instead of "Owner · human:bashiraziz". Every skill that records a governance
|
|
142
|
+
act (this one, add-sources for `verified:` entries, `ksor takedown` for
|
|
143
|
+
withdrawals) asks the owner for a natural name whenever it is about to write
|
|
144
|
+
an actor that isn't in `people.yaml` yet — the owner is the only source of a
|
|
145
|
+
display name, never a convention-based guess.
|
|
131
146
|
- **Offer to start replacing the starter documents — they are already
|
|
132
147
|
published.** All five ship `status: stable`, approved by
|
|
133
148
|
`ksor-starter/KSOR-STAMP-VERSION`, so the site and `llms.txt` carry them from
|
|
@@ -49,6 +49,12 @@ the question — that is what made the last version unanswerable.
|
|
|
49
49
|
**3 of 3 — Who signs off on a document, and who can take one down?**
|
|
50
50
|
|
|
51
51
|
> Names or handles, not job titles. If it is just you, say so.
|
|
52
|
+
>
|
|
53
|
+
> Ask for BOTH: the handle the record will store (`human:bashiraziz`) and the
|
|
54
|
+
> natural name to print ("Bashir Aziz"). They are not derivable from each other
|
|
55
|
+
> — `human:ciso` and `human:mjs` are not anybody's squashed full name — so the
|
|
56
|
+
> handle goes into the frontmatter and the policy, and the pair goes into
|
|
57
|
+
> `.ksor/people.yaml` for the site to print.
|
|
52
58
|
|
|
53
59
|
---
|
|
54
60
|
|
|
@@ -120,7 +126,7 @@ never an email address.
|
|
|
120
126
|
climb, not part of this interview). The strictness answer from question 5
|
|
121
127
|
is the intent behind the `retrieval.vector_floor` on that climb, measured
|
|
122
128
|
by `ksor calibrate` — capture it in the prose now so it is ready.
|
|
123
|
-
- Write `.ksor/governance.yaml` from
|
|
129
|
+
- Write `.ksor/governance.yaml` from question 3: `version: "0.1"`,
|
|
124
130
|
the `audiences:` registry if there is one, and the two authority sets with
|
|
125
131
|
real actors. That file is the root of authority — every approval, every
|
|
126
132
|
deprecation and every ledger entry is checked against it. **Keep
|
|
@@ -128,6 +134,15 @@ never an email address.
|
|
|
128
134
|
document is still in `knowledge/`.** Those five are approved by it, so a
|
|
129
135
|
policy rewritten without it refuses the next build by name
|
|
130
136
|
(`ksor-approver-unauthorised`). It leaves when the last sample does.
|
|
137
|
+
- Write `.ksor/people.yaml` from question 3: `version: "0.1"` and a `people:`
|
|
138
|
+
MAP from each actor to its natural name — `"human:bashiraziz": Bashir Aziz`.
|
|
139
|
+
Keyed by the actor exactly as the record stores it, quoted because it
|
|
140
|
+
contains a colon. Nothing else — the site looks the actor up at render time,
|
|
141
|
+
so pages read "Owner · Bashir Aziz" instead of "Owner · human:bashiraziz". Every skill that records a governance
|
|
142
|
+
act (this one, add-sources for `verified:` entries, `ksor takedown` for
|
|
143
|
+
withdrawals) asks the owner for a natural name whenever it is about to write
|
|
144
|
+
an actor that isn't in `people.yaml` yet — the owner is the only source of a
|
|
145
|
+
display name, never a convention-based guess.
|
|
131
146
|
- **Offer to start replacing the starter documents — they are already
|
|
132
147
|
published.** All five ship `status: stable`, approved by
|
|
133
148
|
`ksor-starter/KSOR-STAMP-VERSION`, so the site and `llms.txt` carry them from
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Natural names for the actors this record cites. The site looks an actor up
|
|
2
|
+
# here at render time and prints the name in its place — so a page reads
|
|
3
|
+
# "Owner · Bashir Aziz" instead of "Owner · human:bashiraziz".
|
|
4
|
+
#
|
|
5
|
+
# A MAP, keyed by the actor exactly as the record stores it. Not a derivation:
|
|
6
|
+
# there is no rule that turns "Bashir Aziz" into `mjs`, `ciso` or `audit-lead`,
|
|
7
|
+
# and most handles in a real record are not somebody's squashed full name. The
|
|
8
|
+
# key is the identifier, the value is what to print, and nothing is guessed.
|
|
9
|
+
#
|
|
10
|
+
# people:
|
|
11
|
+
# "human:bashiraziz": Bashir Aziz
|
|
12
|
+
# "human:ciso": Ayesha Khan
|
|
13
|
+
# "team:legal-ops": Legal Operations
|
|
14
|
+
#
|
|
15
|
+
# ONE-WAY. The identifier is what the record STORES, cites, and checks against
|
|
16
|
+
# `.ksor/governance.yaml`; the name here is only what a page prints. Nothing
|
|
17
|
+
# reads this file back into an actor, and no authority follows from appearing
|
|
18
|
+
# in it (which is why it is not part of the policy).
|
|
19
|
+
#
|
|
20
|
+
# NOT the same list as `.ksor/governance.yaml`. That file says who MAY approve
|
|
21
|
+
# or withdraw; this one says what to print for anyone the record cites. An
|
|
22
|
+
# approver is usually in both, for two different reasons; a document's owner and
|
|
23
|
+
# a `verified:` entry's actor are only ever here, because neither carries
|
|
24
|
+
# authority. Nothing cross-checks the two, on purpose: someone who leaves the
|
|
25
|
+
# authority list is still the recorded approver of what they approved, and their
|
|
26
|
+
# name has to keep rendering on those acts.
|
|
27
|
+
#
|
|
28
|
+
# Optional. An actor with no entry renders exactly as stored, as it did before
|
|
29
|
+
# this file existed. The intake and add-sources skills offer to add one; the
|
|
30
|
+
# owner can also edit this file by hand — it is theirs.
|
|
31
|
+
version: "0.1"
|
|
32
|
+
people: {}
|
|
@@ -33,6 +33,36 @@ written by `ksor takedown` — every entry's actor is checked against the
|
|
|
33
33
|
policy, so a line appended by hand is refused exactly as the verb would refuse
|
|
34
34
|
it, and a deleted line is refused by `ksor build` against the file's history.
|
|
35
35
|
|
|
36
|
+
Display names for those actors live in `.ksor/people.yaml`, a small phone book
|
|
37
|
+
mapping each actor to the name a page should print — `"human:bashiraziz": Bashir
|
|
38
|
+
Aziz` — so a page reads "Owner · Bashir Aziz" instead of "Owner ·
|
|
39
|
+
human:bashiraziz". The two are not derivable from each other (`human:ciso` is
|
|
40
|
+
nobody's squashed full name), which is why both are written down.
|
|
41
|
+
|
|
42
|
+
It is a SEPARATE file from `.ksor/governance.yaml` deliberately: the policy is
|
|
43
|
+
the root of authority, its key set is closed so that nothing sits there without
|
|
44
|
+
being enforced, and its digest is hashed into `build.lock.json` — so a display
|
|
45
|
+
name living there would mean correcting the spelling of somebody's name refused
|
|
46
|
+
your next build. Appearing in `people.yaml` confers no authority whatsoever; it
|
|
47
|
+
only changes what is printed.
|
|
48
|
+
|
|
49
|
+
An actor with no entry renders exactly as stored, and the governance skills
|
|
50
|
+
offer to add one when they are about to write an actor the file does not know.
|
|
51
|
+
|
|
52
|
+
**The two files list different things, and neither is derived from the other.**
|
|
53
|
+
`governance.yaml` names who MAY act — an actor must be in `approval_authorities`
|
|
54
|
+
to approve a document, or in `takedown_authorities` to withdraw one.
|
|
55
|
+
`people.yaml` names what to PRINT for any actor the record cites. An approver
|
|
56
|
+
usually appears in both, for two different reasons. A document's `ksor.owner`
|
|
57
|
+
and a `verified:` entry's actor appear only in `people.yaml`, because neither
|
|
58
|
+
carries authority — the policy has no verification family at all. And an
|
|
59
|
+
authority whose handle already reads fine needs no entry at all.
|
|
60
|
+
|
|
61
|
+
Nothing cross-checks them, deliberately: a person who leaves the authority list
|
|
62
|
+
is still the recorded approver of everything they approved, and their name must
|
|
63
|
+
keep rendering on those acts. A governance act is history; the policy is
|
|
64
|
+
current state.
|
|
65
|
+
|
|
36
66
|
## Critical rules
|
|
37
67
|
|
|
38
68
|
1. **The site never contains authored content.** Knowledge goes in
|
|
@@ -215,6 +245,22 @@ Stand it up in this order (each step's errors explain how to fix themselves):
|
|
|
215
245
|
the intent to gate WITHOUT a measurement, and every serve refuses until a
|
|
216
246
|
number replaces it; that is the fail-closed posture, not a starting point.
|
|
217
247
|
|
|
248
|
+
**The same applies across TIME, not only across corpora.** A floor measured
|
|
249
|
+
against 5 documents is a copied constant once the record holds 200, and it
|
|
250
|
+
weakens in silence: questions that used to be out-of-corpus start scoring
|
|
251
|
+
above a fixed number, so the record answers what it used to refuse.
|
|
252
|
+
|
|
253
|
+
```sh
|
|
254
|
+
pnpm exec ksor calibrate --instance instance.md --check
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
reads the record's own logged searches and reports how the declared floor is
|
|
258
|
+
holding — no provider key, no LLM, one query, and it always exits 0. Run it
|
|
259
|
+
on a schedule; when it says WATCH, re-run `ksor calibrate` to get a new
|
|
260
|
+
number. It is a monitor, not a measurement: it can say the floor has gone
|
|
261
|
+
permissive against real traffic, never that it is too strict for questions
|
|
262
|
+
nobody asked.
|
|
263
|
+
|
|
218
264
|
```sh
|
|
219
265
|
pnpm schema # apply the DDL (once)
|
|
220
266
|
pnpm grant # authorize ingest for this corpus (once)
|
|
@@ -333,7 +379,7 @@ governance block every hit now carries:
|
|
|
333
379
|
|
|
334
380
|
| | |
|
|
335
381
|
| -------------------------------- | ------------------------------ |
|
|
336
|
-
| all three tool definitions | ~4,
|
|
382
|
+
| all three tool definitions | ~4,349 tokens, always resident |
|
|
337
383
|
| one `search` at `k=10` (default) | ~4,196 tokens per call |
|
|
338
384
|
| one `search` at `k=5` | ~2,330 tokens per call |
|
|
339
385
|
|