@panaversity/ksor 0.0.57 → 0.0.59
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 +205 -0
- package/README.md +19 -15
- package/dist/checker/check-main.mjs +142 -136
- package/dist/cli.mjs +812 -212
- package/dist/{gateway-api-C0vL3oOK-D24n786A.mjs → gateway-api-CEsb-e8z-Ch6oMaq2.mjs} +74 -7
- package/dist/gateway.d.mts +2 -2
- package/dist/gateway.mjs +1 -1
- package/docs/building.md +157 -0
- package/docs/deploying.md +17 -5
- package/docs/index.md +7 -3
- package/docs/ingesting.md +36 -6
- package/docs/tool-surface.md +0 -3
- package/docs/upgrading.md +16 -2
- package/package.json +1 -1
- package/templates/scaffold/.agents/skills/format-checker/check.mjs +140 -134
- package/templates/scaffold/.agents/skills/intake-interview/SKILL.md +6 -5
- package/templates/scaffold/.claude/skills/format-checker/check.mjs +140 -134
- package/templates/scaffold/.claude/skills/intake-interview/SKILL.md +6 -5
- package/templates/scaffold/.ksor/people.yaml +2 -2
- package/templates/scaffold/AGENTS.md +23 -8
- package/templates/scaffold/README.md +5 -2
- package/templates/scaffold/env.example +3 -0
- package/templates/scaffold/instance.md +2 -3
- package/templates/scaffold/system/site/next-no-telemetry.mjs +27 -0
- package/templates/scaffold/system/site/package.json +2 -2
- package/templates/scaffold/system/site/record/change-control.ts +319 -0
- package/templates/scaffold/system/site/record/index.ts +8 -0
- package/templates/scaffold/system/site/record/lock.ts +37 -0
- package/templates/scaffold/system/site/record/refusal.ts +1 -0
|
@@ -12672,6 +12672,139 @@ function nearMissOf(baseName) {
|
|
|
12672
12672
|
return null;
|
|
12673
12673
|
}
|
|
12674
12674
|
/**
|
|
12675
|
+
* The takedown ledger's OTHER baseline: every entry any COMMITTED version of
|
|
12676
|
+
* `.ksor/takedowns.yaml` has ever carried.
|
|
12677
|
+
*
|
|
12678
|
+
* The committed lock is a baseline too, and a good one — it holds each entry's
|
|
12679
|
+
* digest, so an entry retargeted in place is caught. What it cannot do is prove
|
|
12680
|
+
* that an entry was never deleted, because the lock travels in the SAME change
|
|
12681
|
+
* as the ledger: delete the row, recompute `ledger_sha256`, empty
|
|
12682
|
+
* `ledger_entries`, and the two agree with each other about a denial that is
|
|
12683
|
+
* gone. Only history remembers.
|
|
12684
|
+
*
|
|
12685
|
+
* The baseline may be INCOMPLETE only if it SAYS so: every version history
|
|
12686
|
+
* holds is read, or `entries` comes back null and the caller reports that it
|
|
12687
|
+
* could not verify. A version silently skipped would contribute neither
|
|
12688
|
+
* digests nor ids while the answer still read "verified"
|
|
12689
|
+
* (`git-ledger.integration.test.ts`).
|
|
12690
|
+
*
|
|
12691
|
+
* This lives in the record module because THREE surfaces need the same answer —
|
|
12692
|
+
* `ksor build`, the emitted checker, and the site's stage (decision 19: a
|
|
12693
|
+
* surface that refuses must refuse on both surfaces). Plain `git log` / `git
|
|
12694
|
+
* show`, so nothing here needs installing.
|
|
12695
|
+
*/
|
|
12696
|
+
const LEDGER = ".ksor/takedowns.yaml";
|
|
12697
|
+
/**
|
|
12698
|
+
* `spawnSync` defaults to a 1 MB stdout buffer, and past it the child is KILLED
|
|
12699
|
+
* — `status` comes back null, so the query reads as a failure. A ledger with a
|
|
12700
|
+
* few thousand entries, or one entry carrying a long reason, clears 1 MB
|
|
12701
|
+
* easily, and the version was then dropped from the baseline while the caller
|
|
12702
|
+
* was still told history had been verified. The ceiling stays finite on
|
|
12703
|
+
* purpose: past it this returns null, which is a state the caller SAYS.
|
|
12704
|
+
*/
|
|
12705
|
+
const MAX_BUFFER$1 = 67108864;
|
|
12706
|
+
/** One git query, read-only. Null on any non-zero exit, including no git at all. */
|
|
12707
|
+
function git(root, args) {
|
|
12708
|
+
const r = spawnSync("git", [...args], {
|
|
12709
|
+
cwd: root,
|
|
12710
|
+
encoding: "utf8",
|
|
12711
|
+
maxBuffer: MAX_BUFFER$1
|
|
12712
|
+
});
|
|
12713
|
+
return r.status === 0 ? r.stdout : null;
|
|
12714
|
+
}
|
|
12715
|
+
function historicLedger(root) {
|
|
12716
|
+
const inside = git(root, ["rev-parse", "--is-inside-work-tree"]);
|
|
12717
|
+
if (inside === null || inside.trim() !== "true") return {
|
|
12718
|
+
repository: false,
|
|
12719
|
+
shallow: false,
|
|
12720
|
+
entries: null,
|
|
12721
|
+
unreadable: null
|
|
12722
|
+
};
|
|
12723
|
+
const shallow = (git(root, ["rev-parse", "--is-shallow-repository"]) ?? "").trim() === "true";
|
|
12724
|
+
const born = git(root, [
|
|
12725
|
+
"rev-parse",
|
|
12726
|
+
"--verify",
|
|
12727
|
+
"--quiet",
|
|
12728
|
+
"HEAD"
|
|
12729
|
+
]) !== null;
|
|
12730
|
+
const entries = shallow ? null : born ? historicEntries(root) : [];
|
|
12731
|
+
return {
|
|
12732
|
+
repository: true,
|
|
12733
|
+
shallow,
|
|
12734
|
+
entries,
|
|
12735
|
+
unreadable: entries !== null ? null : shallow ? "shallow" : "unreadable"
|
|
12736
|
+
};
|
|
12737
|
+
}
|
|
12738
|
+
/**
|
|
12739
|
+
* Every id history has ever recorded, each with the text it carried the FIRST
|
|
12740
|
+
* time it was written. A version that parses contributes each entry's digest,
|
|
12741
|
+
* so an entry EDITED in place is caught, not only one deleted; a version that
|
|
12742
|
+
* no longer parses still contributes its ids, read permissively — the point
|
|
12743
|
+
* there is that an id once written never disappears.
|
|
12744
|
+
*
|
|
12745
|
+
* FIRST, not every: keying this by `id\tdigest` kept one baseline entry per
|
|
12746
|
+
* version an id ever had, so a tamper that was COMMITTED and then UNDONE left
|
|
12747
|
+
* two digests for one id, the restored entry matched only one of them, and
|
|
12748
|
+
* `ksor-ledger-amended` fired for good. The record became permanently
|
|
12749
|
+
* unbuildable — by a tamper that had already been put right — and the only
|
|
12750
|
+
* escape was rewriting git history, which is not a remedy a refusal may
|
|
12751
|
+
* demand (found in review, 2026-08-25).
|
|
12752
|
+
*
|
|
12753
|
+
* Taking the OLDEST is what makes the guarantee both enforceable and
|
|
12754
|
+
* escapable. It still refuses a committed tamper (the baseline is what the
|
|
12755
|
+
* entry said when it was written, so committing the edit does not launder
|
|
12756
|
+
* it), and the remedy it names — put the entry back — now actually clears
|
|
12757
|
+
* it. Taking the NEWEST would have done the opposite on both counts.
|
|
12758
|
+
*/
|
|
12759
|
+
function historicEntries(root) {
|
|
12760
|
+
const atRoot = `${(git(root, ["rev-parse", "--show-prefix"]) ?? "").trim()}${LEDGER}`;
|
|
12761
|
+
const commits = git(root, [
|
|
12762
|
+
"log",
|
|
12763
|
+
"--full-history",
|
|
12764
|
+
"--topo-order",
|
|
12765
|
+
"--format=%H",
|
|
12766
|
+
"--",
|
|
12767
|
+
LEDGER
|
|
12768
|
+
]);
|
|
12769
|
+
if (commits === null) return null;
|
|
12770
|
+
const seen = /* @__PURE__ */ new Map();
|
|
12771
|
+
for (const sha of commits.split("\n").filter((s) => s !== "")) {
|
|
12772
|
+
const text = git(root, ["show", `${sha}:${atRoot}`]);
|
|
12773
|
+
if (text === null) {
|
|
12774
|
+
const listed = git(root, [
|
|
12775
|
+
"ls-tree",
|
|
12776
|
+
"--full-tree",
|
|
12777
|
+
"--name-only",
|
|
12778
|
+
sha,
|
|
12779
|
+
"--",
|
|
12780
|
+
atRoot
|
|
12781
|
+
]);
|
|
12782
|
+
if (listed !== null && listed.trim() === "") continue;
|
|
12783
|
+
return null;
|
|
12784
|
+
}
|
|
12785
|
+
const where = sha.slice(0, 7);
|
|
12786
|
+
const parsed = parseLedger(text, LEDGER);
|
|
12787
|
+
if (parsed.ok) {
|
|
12788
|
+
for (const entry of parsed.ledger.entries) seen.set(entry.id, {
|
|
12789
|
+
id: entry.id,
|
|
12790
|
+
digest: entryDigest(entry),
|
|
12791
|
+
entry,
|
|
12792
|
+
where
|
|
12793
|
+
});
|
|
12794
|
+
continue;
|
|
12795
|
+
}
|
|
12796
|
+
for (const m of text.matchAll(/^\s*(?:-\s+)?id:\s*["']?([^\s"']+)/gm)) {
|
|
12797
|
+
const id = m[1] ?? "";
|
|
12798
|
+
if (!seen.has(id)) seen.set(id, {
|
|
12799
|
+
id,
|
|
12800
|
+
digest: null,
|
|
12801
|
+
where
|
|
12802
|
+
});
|
|
12803
|
+
}
|
|
12804
|
+
}
|
|
12805
|
+
return [...seen.values()].sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
|
|
12806
|
+
}
|
|
12807
|
+
/**
|
|
12675
12808
|
* The widening rule: a link, a `ksor.superseded_by` pointer or a companion
|
|
12676
12809
|
* body may reach a target whose audience contains `public` or contains every
|
|
12677
12810
|
* identifier in the source's — then every reader of the source can read the
|
|
@@ -13537,6 +13670,11 @@ function checkAgainstPolicy(concept, policy, refusals) {
|
|
|
13537
13670
|
}
|
|
13538
13671
|
const hex64 = string().regex(/^[0-9a-f]{64}$/, "a sha256 hex digest");
|
|
13539
13672
|
const viewerList = array(string().min(1));
|
|
13673
|
+
const bundleEntry = object({
|
|
13674
|
+
viewer: string().min(1),
|
|
13675
|
+
sha256: hex64,
|
|
13676
|
+
files: number().int().nonnegative()
|
|
13677
|
+
}).strict();
|
|
13540
13678
|
const lockSchema = object({
|
|
13541
13679
|
format: literal(1),
|
|
13542
13680
|
build_id: string().regex(/^sha256:[0-9a-f]{64}$/),
|
|
@@ -13584,7 +13722,8 @@ const lockSchema = object({
|
|
|
13584
13722
|
indexes: array(object({
|
|
13585
13723
|
path: string().min(1),
|
|
13586
13724
|
sha256: hex64
|
|
13587
|
-
}).strict())
|
|
13725
|
+
}).strict()),
|
|
13726
|
+
bundles: array(bundleEntry)
|
|
13588
13727
|
}).strict();
|
|
13589
13728
|
function parseLock(text) {
|
|
13590
13729
|
let value;
|
|
@@ -13609,139 +13748,6 @@ function parseLock(text) {
|
|
|
13609
13748
|
lock: parsed.data
|
|
13610
13749
|
};
|
|
13611
13750
|
}
|
|
13612
|
-
/**
|
|
13613
|
-
* The takedown ledger's OTHER baseline: every entry any COMMITTED version of
|
|
13614
|
-
* `.ksor/takedowns.yaml` has ever carried.
|
|
13615
|
-
*
|
|
13616
|
-
* The committed lock is a baseline too, and a good one — it holds each entry's
|
|
13617
|
-
* digest, so an entry retargeted in place is caught. What it cannot do is prove
|
|
13618
|
-
* that an entry was never deleted, because the lock travels in the SAME change
|
|
13619
|
-
* as the ledger: delete the row, recompute `ledger_sha256`, empty
|
|
13620
|
-
* `ledger_entries`, and the two agree with each other about a denial that is
|
|
13621
|
-
* gone. Only history remembers.
|
|
13622
|
-
*
|
|
13623
|
-
* The baseline may be INCOMPLETE only if it SAYS so: every version history
|
|
13624
|
-
* holds is read, or `entries` comes back null and the caller reports that it
|
|
13625
|
-
* could not verify. A version silently skipped would contribute neither
|
|
13626
|
-
* digests nor ids while the answer still read "verified"
|
|
13627
|
-
* (`git-ledger.integration.test.ts`).
|
|
13628
|
-
*
|
|
13629
|
-
* This lives in the record module because THREE surfaces need the same answer —
|
|
13630
|
-
* `ksor build`, the emitted checker, and the site's stage (decision 19: a
|
|
13631
|
-
* surface that refuses must refuse on both surfaces). Plain `git log` / `git
|
|
13632
|
-
* show`, so nothing here needs installing.
|
|
13633
|
-
*/
|
|
13634
|
-
const LEDGER = ".ksor/takedowns.yaml";
|
|
13635
|
-
/**
|
|
13636
|
-
* `spawnSync` defaults to a 1 MB stdout buffer, and past it the child is KILLED
|
|
13637
|
-
* — `status` comes back null, so the query reads as a failure. A ledger with a
|
|
13638
|
-
* few thousand entries, or one entry carrying a long reason, clears 1 MB
|
|
13639
|
-
* easily, and the version was then dropped from the baseline while the caller
|
|
13640
|
-
* was still told history had been verified. The ceiling stays finite on
|
|
13641
|
-
* purpose: past it this returns null, which is a state the caller SAYS.
|
|
13642
|
-
*/
|
|
13643
|
-
const MAX_BUFFER = 67108864;
|
|
13644
|
-
/** One git query, read-only. Null on any non-zero exit, including no git at all. */
|
|
13645
|
-
function git(root, args) {
|
|
13646
|
-
const r = spawnSync("git", [...args], {
|
|
13647
|
-
cwd: root,
|
|
13648
|
-
encoding: "utf8",
|
|
13649
|
-
maxBuffer: MAX_BUFFER
|
|
13650
|
-
});
|
|
13651
|
-
return r.status === 0 ? r.stdout : null;
|
|
13652
|
-
}
|
|
13653
|
-
function historicLedger(root) {
|
|
13654
|
-
const inside = git(root, ["rev-parse", "--is-inside-work-tree"]);
|
|
13655
|
-
if (inside === null || inside.trim() !== "true") return {
|
|
13656
|
-
repository: false,
|
|
13657
|
-
shallow: false,
|
|
13658
|
-
entries: null,
|
|
13659
|
-
unreadable: null
|
|
13660
|
-
};
|
|
13661
|
-
const shallow = (git(root, ["rev-parse", "--is-shallow-repository"]) ?? "").trim() === "true";
|
|
13662
|
-
const born = git(root, [
|
|
13663
|
-
"rev-parse",
|
|
13664
|
-
"--verify",
|
|
13665
|
-
"--quiet",
|
|
13666
|
-
"HEAD"
|
|
13667
|
-
]) !== null;
|
|
13668
|
-
const entries = shallow ? null : born ? historicEntries(root) : [];
|
|
13669
|
-
return {
|
|
13670
|
-
repository: true,
|
|
13671
|
-
shallow,
|
|
13672
|
-
entries,
|
|
13673
|
-
unreadable: entries !== null ? null : shallow ? "shallow" : "unreadable"
|
|
13674
|
-
};
|
|
13675
|
-
}
|
|
13676
|
-
/**
|
|
13677
|
-
* Every id history has ever recorded, each with the text it carried the FIRST
|
|
13678
|
-
* time it was written. A version that parses contributes each entry's digest,
|
|
13679
|
-
* so an entry EDITED in place is caught, not only one deleted; a version that
|
|
13680
|
-
* no longer parses still contributes its ids, read permissively — the point
|
|
13681
|
-
* there is that an id once written never disappears.
|
|
13682
|
-
*
|
|
13683
|
-
* FIRST, not every: keying this by `id\tdigest` kept one baseline entry per
|
|
13684
|
-
* version an id ever had, so a tamper that was COMMITTED and then UNDONE left
|
|
13685
|
-
* two digests for one id, the restored entry matched only one of them, and
|
|
13686
|
-
* `ksor-ledger-amended` fired for good. The record became permanently
|
|
13687
|
-
* unbuildable — by a tamper that had already been put right — and the only
|
|
13688
|
-
* escape was rewriting git history, which is not a remedy a refusal may
|
|
13689
|
-
* demand (found in review, 2026-08-25).
|
|
13690
|
-
*
|
|
13691
|
-
* Taking the OLDEST is what makes the guarantee both enforceable and
|
|
13692
|
-
* escapable. It still refuses a committed tamper (the baseline is what the
|
|
13693
|
-
* entry said when it was written, so committing the edit does not launder
|
|
13694
|
-
* it), and the remedy it names — put the entry back — now actually clears
|
|
13695
|
-
* it. Taking the NEWEST would have done the opposite on both counts.
|
|
13696
|
-
*/
|
|
13697
|
-
function historicEntries(root) {
|
|
13698
|
-
const atRoot = `${(git(root, ["rev-parse", "--show-prefix"]) ?? "").trim()}${LEDGER}`;
|
|
13699
|
-
const commits = git(root, [
|
|
13700
|
-
"log",
|
|
13701
|
-
"--full-history",
|
|
13702
|
-
"--topo-order",
|
|
13703
|
-
"--format=%H",
|
|
13704
|
-
"--",
|
|
13705
|
-
LEDGER
|
|
13706
|
-
]);
|
|
13707
|
-
if (commits === null) return null;
|
|
13708
|
-
const seen = /* @__PURE__ */ new Map();
|
|
13709
|
-
for (const sha of commits.split("\n").filter((s) => s !== "")) {
|
|
13710
|
-
const text = git(root, ["show", `${sha}:${atRoot}`]);
|
|
13711
|
-
if (text === null) {
|
|
13712
|
-
const listed = git(root, [
|
|
13713
|
-
"ls-tree",
|
|
13714
|
-
"--full-tree",
|
|
13715
|
-
"--name-only",
|
|
13716
|
-
sha,
|
|
13717
|
-
"--",
|
|
13718
|
-
atRoot
|
|
13719
|
-
]);
|
|
13720
|
-
if (listed !== null && listed.trim() === "") continue;
|
|
13721
|
-
return null;
|
|
13722
|
-
}
|
|
13723
|
-
const where = sha.slice(0, 7);
|
|
13724
|
-
const parsed = parseLedger(text, LEDGER);
|
|
13725
|
-
if (parsed.ok) {
|
|
13726
|
-
for (const entry of parsed.ledger.entries) seen.set(entry.id, {
|
|
13727
|
-
id: entry.id,
|
|
13728
|
-
digest: entryDigest(entry),
|
|
13729
|
-
entry,
|
|
13730
|
-
where
|
|
13731
|
-
});
|
|
13732
|
-
continue;
|
|
13733
|
-
}
|
|
13734
|
-
for (const m of text.matchAll(/^\s*(?:-\s+)?id:\s*["']?([^\s"']+)/gm)) {
|
|
13735
|
-
const id = m[1] ?? "";
|
|
13736
|
-
if (!seen.has(id)) seen.set(id, {
|
|
13737
|
-
id,
|
|
13738
|
-
digest: null,
|
|
13739
|
-
where
|
|
13740
|
-
});
|
|
13741
|
-
}
|
|
13742
|
-
}
|
|
13743
|
-
return [...seen.values()].sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
|
|
13744
|
-
}
|
|
13745
13751
|
/** The inputs a projection reads; nothing else moves `source_commit` (the lock itself included). */
|
|
13746
13752
|
const INPUTS = [
|
|
13747
13753
|
"knowledge",
|
|
@@ -146,11 +146,12 @@ never an email address.
|
|
|
146
146
|
MAP from each actor to its natural name — `"human:bashiraziz": Bashir Aziz`.
|
|
147
147
|
Keyed by the actor exactly as the record stores it, quoted because it
|
|
148
148
|
contains a colon. Nothing else — the site looks the actor up at render time,
|
|
149
|
-
so pages read "Owner · Bashir Aziz" instead of "Owner · human:bashiraziz".
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
149
|
+
so pages read "Owner · Bashir Aziz" instead of "Owner · human:bashiraziz". This
|
|
150
|
+
is the skill that writes actors into the policy, so it is the one that asks
|
|
151
|
+
the owner for a natural name for each — the owner is the only source of a
|
|
152
|
+
display name, never a convention-based guess. An actor that arrives later
|
|
153
|
+
(an owner named in a document, an approver added by hand) gets its entry
|
|
154
|
+
when the owner adds one; the site prints the identifier until then.
|
|
154
155
|
- **Offer to start replacing the starter documents — they are already
|
|
155
156
|
published.** All five ship `status: stable`, approved by
|
|
156
157
|
`ksor-starter/KSOR-STAMP-VERSION`, so the site and `llms.txt` carry them from
|
|
@@ -12672,6 +12672,139 @@ function nearMissOf(baseName) {
|
|
|
12672
12672
|
return null;
|
|
12673
12673
|
}
|
|
12674
12674
|
/**
|
|
12675
|
+
* The takedown ledger's OTHER baseline: every entry any COMMITTED version of
|
|
12676
|
+
* `.ksor/takedowns.yaml` has ever carried.
|
|
12677
|
+
*
|
|
12678
|
+
* The committed lock is a baseline too, and a good one — it holds each entry's
|
|
12679
|
+
* digest, so an entry retargeted in place is caught. What it cannot do is prove
|
|
12680
|
+
* that an entry was never deleted, because the lock travels in the SAME change
|
|
12681
|
+
* as the ledger: delete the row, recompute `ledger_sha256`, empty
|
|
12682
|
+
* `ledger_entries`, and the two agree with each other about a denial that is
|
|
12683
|
+
* gone. Only history remembers.
|
|
12684
|
+
*
|
|
12685
|
+
* The baseline may be INCOMPLETE only if it SAYS so: every version history
|
|
12686
|
+
* holds is read, or `entries` comes back null and the caller reports that it
|
|
12687
|
+
* could not verify. A version silently skipped would contribute neither
|
|
12688
|
+
* digests nor ids while the answer still read "verified"
|
|
12689
|
+
* (`git-ledger.integration.test.ts`).
|
|
12690
|
+
*
|
|
12691
|
+
* This lives in the record module because THREE surfaces need the same answer —
|
|
12692
|
+
* `ksor build`, the emitted checker, and the site's stage (decision 19: a
|
|
12693
|
+
* surface that refuses must refuse on both surfaces). Plain `git log` / `git
|
|
12694
|
+
* show`, so nothing here needs installing.
|
|
12695
|
+
*/
|
|
12696
|
+
const LEDGER = ".ksor/takedowns.yaml";
|
|
12697
|
+
/**
|
|
12698
|
+
* `spawnSync` defaults to a 1 MB stdout buffer, and past it the child is KILLED
|
|
12699
|
+
* — `status` comes back null, so the query reads as a failure. A ledger with a
|
|
12700
|
+
* few thousand entries, or one entry carrying a long reason, clears 1 MB
|
|
12701
|
+
* easily, and the version was then dropped from the baseline while the caller
|
|
12702
|
+
* was still told history had been verified. The ceiling stays finite on
|
|
12703
|
+
* purpose: past it this returns null, which is a state the caller SAYS.
|
|
12704
|
+
*/
|
|
12705
|
+
const MAX_BUFFER$1 = 67108864;
|
|
12706
|
+
/** One git query, read-only. Null on any non-zero exit, including no git at all. */
|
|
12707
|
+
function git(root, args) {
|
|
12708
|
+
const r = spawnSync("git", [...args], {
|
|
12709
|
+
cwd: root,
|
|
12710
|
+
encoding: "utf8",
|
|
12711
|
+
maxBuffer: MAX_BUFFER$1
|
|
12712
|
+
});
|
|
12713
|
+
return r.status === 0 ? r.stdout : null;
|
|
12714
|
+
}
|
|
12715
|
+
function historicLedger(root) {
|
|
12716
|
+
const inside = git(root, ["rev-parse", "--is-inside-work-tree"]);
|
|
12717
|
+
if (inside === null || inside.trim() !== "true") return {
|
|
12718
|
+
repository: false,
|
|
12719
|
+
shallow: false,
|
|
12720
|
+
entries: null,
|
|
12721
|
+
unreadable: null
|
|
12722
|
+
};
|
|
12723
|
+
const shallow = (git(root, ["rev-parse", "--is-shallow-repository"]) ?? "").trim() === "true";
|
|
12724
|
+
const born = git(root, [
|
|
12725
|
+
"rev-parse",
|
|
12726
|
+
"--verify",
|
|
12727
|
+
"--quiet",
|
|
12728
|
+
"HEAD"
|
|
12729
|
+
]) !== null;
|
|
12730
|
+
const entries = shallow ? null : born ? historicEntries(root) : [];
|
|
12731
|
+
return {
|
|
12732
|
+
repository: true,
|
|
12733
|
+
shallow,
|
|
12734
|
+
entries,
|
|
12735
|
+
unreadable: entries !== null ? null : shallow ? "shallow" : "unreadable"
|
|
12736
|
+
};
|
|
12737
|
+
}
|
|
12738
|
+
/**
|
|
12739
|
+
* Every id history has ever recorded, each with the text it carried the FIRST
|
|
12740
|
+
* time it was written. A version that parses contributes each entry's digest,
|
|
12741
|
+
* so an entry EDITED in place is caught, not only one deleted; a version that
|
|
12742
|
+
* no longer parses still contributes its ids, read permissively — the point
|
|
12743
|
+
* there is that an id once written never disappears.
|
|
12744
|
+
*
|
|
12745
|
+
* FIRST, not every: keying this by `id\tdigest` kept one baseline entry per
|
|
12746
|
+
* version an id ever had, so a tamper that was COMMITTED and then UNDONE left
|
|
12747
|
+
* two digests for one id, the restored entry matched only one of them, and
|
|
12748
|
+
* `ksor-ledger-amended` fired for good. The record became permanently
|
|
12749
|
+
* unbuildable — by a tamper that had already been put right — and the only
|
|
12750
|
+
* escape was rewriting git history, which is not a remedy a refusal may
|
|
12751
|
+
* demand (found in review, 2026-08-25).
|
|
12752
|
+
*
|
|
12753
|
+
* Taking the OLDEST is what makes the guarantee both enforceable and
|
|
12754
|
+
* escapable. It still refuses a committed tamper (the baseline is what the
|
|
12755
|
+
* entry said when it was written, so committing the edit does not launder
|
|
12756
|
+
* it), and the remedy it names — put the entry back — now actually clears
|
|
12757
|
+
* it. Taking the NEWEST would have done the opposite on both counts.
|
|
12758
|
+
*/
|
|
12759
|
+
function historicEntries(root) {
|
|
12760
|
+
const atRoot = `${(git(root, ["rev-parse", "--show-prefix"]) ?? "").trim()}${LEDGER}`;
|
|
12761
|
+
const commits = git(root, [
|
|
12762
|
+
"log",
|
|
12763
|
+
"--full-history",
|
|
12764
|
+
"--topo-order",
|
|
12765
|
+
"--format=%H",
|
|
12766
|
+
"--",
|
|
12767
|
+
LEDGER
|
|
12768
|
+
]);
|
|
12769
|
+
if (commits === null) return null;
|
|
12770
|
+
const seen = /* @__PURE__ */ new Map();
|
|
12771
|
+
for (const sha of commits.split("\n").filter((s) => s !== "")) {
|
|
12772
|
+
const text = git(root, ["show", `${sha}:${atRoot}`]);
|
|
12773
|
+
if (text === null) {
|
|
12774
|
+
const listed = git(root, [
|
|
12775
|
+
"ls-tree",
|
|
12776
|
+
"--full-tree",
|
|
12777
|
+
"--name-only",
|
|
12778
|
+
sha,
|
|
12779
|
+
"--",
|
|
12780
|
+
atRoot
|
|
12781
|
+
]);
|
|
12782
|
+
if (listed !== null && listed.trim() === "") continue;
|
|
12783
|
+
return null;
|
|
12784
|
+
}
|
|
12785
|
+
const where = sha.slice(0, 7);
|
|
12786
|
+
const parsed = parseLedger(text, LEDGER);
|
|
12787
|
+
if (parsed.ok) {
|
|
12788
|
+
for (const entry of parsed.ledger.entries) seen.set(entry.id, {
|
|
12789
|
+
id: entry.id,
|
|
12790
|
+
digest: entryDigest(entry),
|
|
12791
|
+
entry,
|
|
12792
|
+
where
|
|
12793
|
+
});
|
|
12794
|
+
continue;
|
|
12795
|
+
}
|
|
12796
|
+
for (const m of text.matchAll(/^\s*(?:-\s+)?id:\s*["']?([^\s"']+)/gm)) {
|
|
12797
|
+
const id = m[1] ?? "";
|
|
12798
|
+
if (!seen.has(id)) seen.set(id, {
|
|
12799
|
+
id,
|
|
12800
|
+
digest: null,
|
|
12801
|
+
where
|
|
12802
|
+
});
|
|
12803
|
+
}
|
|
12804
|
+
}
|
|
12805
|
+
return [...seen.values()].sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
|
|
12806
|
+
}
|
|
12807
|
+
/**
|
|
12675
12808
|
* The widening rule: a link, a `ksor.superseded_by` pointer or a companion
|
|
12676
12809
|
* body may reach a target whose audience contains `public` or contains every
|
|
12677
12810
|
* identifier in the source's — then every reader of the source can read the
|
|
@@ -13537,6 +13670,11 @@ function checkAgainstPolicy(concept, policy, refusals) {
|
|
|
13537
13670
|
}
|
|
13538
13671
|
const hex64 = string().regex(/^[0-9a-f]{64}$/, "a sha256 hex digest");
|
|
13539
13672
|
const viewerList = array(string().min(1));
|
|
13673
|
+
const bundleEntry = object({
|
|
13674
|
+
viewer: string().min(1),
|
|
13675
|
+
sha256: hex64,
|
|
13676
|
+
files: number().int().nonnegative()
|
|
13677
|
+
}).strict();
|
|
13540
13678
|
const lockSchema = object({
|
|
13541
13679
|
format: literal(1),
|
|
13542
13680
|
build_id: string().regex(/^sha256:[0-9a-f]{64}$/),
|
|
@@ -13584,7 +13722,8 @@ const lockSchema = object({
|
|
|
13584
13722
|
indexes: array(object({
|
|
13585
13723
|
path: string().min(1),
|
|
13586
13724
|
sha256: hex64
|
|
13587
|
-
}).strict())
|
|
13725
|
+
}).strict()),
|
|
13726
|
+
bundles: array(bundleEntry)
|
|
13588
13727
|
}).strict();
|
|
13589
13728
|
function parseLock(text) {
|
|
13590
13729
|
let value;
|
|
@@ -13609,139 +13748,6 @@ function parseLock(text) {
|
|
|
13609
13748
|
lock: parsed.data
|
|
13610
13749
|
};
|
|
13611
13750
|
}
|
|
13612
|
-
/**
|
|
13613
|
-
* The takedown ledger's OTHER baseline: every entry any COMMITTED version of
|
|
13614
|
-
* `.ksor/takedowns.yaml` has ever carried.
|
|
13615
|
-
*
|
|
13616
|
-
* The committed lock is a baseline too, and a good one — it holds each entry's
|
|
13617
|
-
* digest, so an entry retargeted in place is caught. What it cannot do is prove
|
|
13618
|
-
* that an entry was never deleted, because the lock travels in the SAME change
|
|
13619
|
-
* as the ledger: delete the row, recompute `ledger_sha256`, empty
|
|
13620
|
-
* `ledger_entries`, and the two agree with each other about a denial that is
|
|
13621
|
-
* gone. Only history remembers.
|
|
13622
|
-
*
|
|
13623
|
-
* The baseline may be INCOMPLETE only if it SAYS so: every version history
|
|
13624
|
-
* holds is read, or `entries` comes back null and the caller reports that it
|
|
13625
|
-
* could not verify. A version silently skipped would contribute neither
|
|
13626
|
-
* digests nor ids while the answer still read "verified"
|
|
13627
|
-
* (`git-ledger.integration.test.ts`).
|
|
13628
|
-
*
|
|
13629
|
-
* This lives in the record module because THREE surfaces need the same answer —
|
|
13630
|
-
* `ksor build`, the emitted checker, and the site's stage (decision 19: a
|
|
13631
|
-
* surface that refuses must refuse on both surfaces). Plain `git log` / `git
|
|
13632
|
-
* show`, so nothing here needs installing.
|
|
13633
|
-
*/
|
|
13634
|
-
const LEDGER = ".ksor/takedowns.yaml";
|
|
13635
|
-
/**
|
|
13636
|
-
* `spawnSync` defaults to a 1 MB stdout buffer, and past it the child is KILLED
|
|
13637
|
-
* — `status` comes back null, so the query reads as a failure. A ledger with a
|
|
13638
|
-
* few thousand entries, or one entry carrying a long reason, clears 1 MB
|
|
13639
|
-
* easily, and the version was then dropped from the baseline while the caller
|
|
13640
|
-
* was still told history had been verified. The ceiling stays finite on
|
|
13641
|
-
* purpose: past it this returns null, which is a state the caller SAYS.
|
|
13642
|
-
*/
|
|
13643
|
-
const MAX_BUFFER = 67108864;
|
|
13644
|
-
/** One git query, read-only. Null on any non-zero exit, including no git at all. */
|
|
13645
|
-
function git(root, args) {
|
|
13646
|
-
const r = spawnSync("git", [...args], {
|
|
13647
|
-
cwd: root,
|
|
13648
|
-
encoding: "utf8",
|
|
13649
|
-
maxBuffer: MAX_BUFFER
|
|
13650
|
-
});
|
|
13651
|
-
return r.status === 0 ? r.stdout : null;
|
|
13652
|
-
}
|
|
13653
|
-
function historicLedger(root) {
|
|
13654
|
-
const inside = git(root, ["rev-parse", "--is-inside-work-tree"]);
|
|
13655
|
-
if (inside === null || inside.trim() !== "true") return {
|
|
13656
|
-
repository: false,
|
|
13657
|
-
shallow: false,
|
|
13658
|
-
entries: null,
|
|
13659
|
-
unreadable: null
|
|
13660
|
-
};
|
|
13661
|
-
const shallow = (git(root, ["rev-parse", "--is-shallow-repository"]) ?? "").trim() === "true";
|
|
13662
|
-
const born = git(root, [
|
|
13663
|
-
"rev-parse",
|
|
13664
|
-
"--verify",
|
|
13665
|
-
"--quiet",
|
|
13666
|
-
"HEAD"
|
|
13667
|
-
]) !== null;
|
|
13668
|
-
const entries = shallow ? null : born ? historicEntries(root) : [];
|
|
13669
|
-
return {
|
|
13670
|
-
repository: true,
|
|
13671
|
-
shallow,
|
|
13672
|
-
entries,
|
|
13673
|
-
unreadable: entries !== null ? null : shallow ? "shallow" : "unreadable"
|
|
13674
|
-
};
|
|
13675
|
-
}
|
|
13676
|
-
/**
|
|
13677
|
-
* Every id history has ever recorded, each with the text it carried the FIRST
|
|
13678
|
-
* time it was written. A version that parses contributes each entry's digest,
|
|
13679
|
-
* so an entry EDITED in place is caught, not only one deleted; a version that
|
|
13680
|
-
* no longer parses still contributes its ids, read permissively — the point
|
|
13681
|
-
* there is that an id once written never disappears.
|
|
13682
|
-
*
|
|
13683
|
-
* FIRST, not every: keying this by `id\tdigest` kept one baseline entry per
|
|
13684
|
-
* version an id ever had, so a tamper that was COMMITTED and then UNDONE left
|
|
13685
|
-
* two digests for one id, the restored entry matched only one of them, and
|
|
13686
|
-
* `ksor-ledger-amended` fired for good. The record became permanently
|
|
13687
|
-
* unbuildable — by a tamper that had already been put right — and the only
|
|
13688
|
-
* escape was rewriting git history, which is not a remedy a refusal may
|
|
13689
|
-
* demand (found in review, 2026-08-25).
|
|
13690
|
-
*
|
|
13691
|
-
* Taking the OLDEST is what makes the guarantee both enforceable and
|
|
13692
|
-
* escapable. It still refuses a committed tamper (the baseline is what the
|
|
13693
|
-
* entry said when it was written, so committing the edit does not launder
|
|
13694
|
-
* it), and the remedy it names — put the entry back — now actually clears
|
|
13695
|
-
* it. Taking the NEWEST would have done the opposite on both counts.
|
|
13696
|
-
*/
|
|
13697
|
-
function historicEntries(root) {
|
|
13698
|
-
const atRoot = `${(git(root, ["rev-parse", "--show-prefix"]) ?? "").trim()}${LEDGER}`;
|
|
13699
|
-
const commits = git(root, [
|
|
13700
|
-
"log",
|
|
13701
|
-
"--full-history",
|
|
13702
|
-
"--topo-order",
|
|
13703
|
-
"--format=%H",
|
|
13704
|
-
"--",
|
|
13705
|
-
LEDGER
|
|
13706
|
-
]);
|
|
13707
|
-
if (commits === null) return null;
|
|
13708
|
-
const seen = /* @__PURE__ */ new Map();
|
|
13709
|
-
for (const sha of commits.split("\n").filter((s) => s !== "")) {
|
|
13710
|
-
const text = git(root, ["show", `${sha}:${atRoot}`]);
|
|
13711
|
-
if (text === null) {
|
|
13712
|
-
const listed = git(root, [
|
|
13713
|
-
"ls-tree",
|
|
13714
|
-
"--full-tree",
|
|
13715
|
-
"--name-only",
|
|
13716
|
-
sha,
|
|
13717
|
-
"--",
|
|
13718
|
-
atRoot
|
|
13719
|
-
]);
|
|
13720
|
-
if (listed !== null && listed.trim() === "") continue;
|
|
13721
|
-
return null;
|
|
13722
|
-
}
|
|
13723
|
-
const where = sha.slice(0, 7);
|
|
13724
|
-
const parsed = parseLedger(text, LEDGER);
|
|
13725
|
-
if (parsed.ok) {
|
|
13726
|
-
for (const entry of parsed.ledger.entries) seen.set(entry.id, {
|
|
13727
|
-
id: entry.id,
|
|
13728
|
-
digest: entryDigest(entry),
|
|
13729
|
-
entry,
|
|
13730
|
-
where
|
|
13731
|
-
});
|
|
13732
|
-
continue;
|
|
13733
|
-
}
|
|
13734
|
-
for (const m of text.matchAll(/^\s*(?:-\s+)?id:\s*["']?([^\s"']+)/gm)) {
|
|
13735
|
-
const id = m[1] ?? "";
|
|
13736
|
-
if (!seen.has(id)) seen.set(id, {
|
|
13737
|
-
id,
|
|
13738
|
-
digest: null,
|
|
13739
|
-
where
|
|
13740
|
-
});
|
|
13741
|
-
}
|
|
13742
|
-
}
|
|
13743
|
-
return [...seen.values()].sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
|
|
13744
|
-
}
|
|
13745
13751
|
/** The inputs a projection reads; nothing else moves `source_commit` (the lock itself included). */
|
|
13746
13752
|
const INPUTS = [
|
|
13747
13753
|
"knowledge",
|
|
@@ -146,11 +146,12 @@ never an email address.
|
|
|
146
146
|
MAP from each actor to its natural name — `"human:bashiraziz": Bashir Aziz`.
|
|
147
147
|
Keyed by the actor exactly as the record stores it, quoted because it
|
|
148
148
|
contains a colon. Nothing else — the site looks the actor up at render time,
|
|
149
|
-
so pages read "Owner · Bashir Aziz" instead of "Owner · human:bashiraziz".
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
149
|
+
so pages read "Owner · Bashir Aziz" instead of "Owner · human:bashiraziz". This
|
|
150
|
+
is the skill that writes actors into the policy, so it is the one that asks
|
|
151
|
+
the owner for a natural name for each — the owner is the only source of a
|
|
152
|
+
display name, never a convention-based guess. An actor that arrives later
|
|
153
|
+
(an owner named in a document, an approver added by hand) gets its entry
|
|
154
|
+
when the owner adds one; the site prints the identifier until then.
|
|
154
155
|
- **Offer to start replacing the starter documents — they are already
|
|
155
156
|
published.** All five ship `status: stable`, approved by
|
|
156
157
|
`ksor-starter/KSOR-STAMP-VERSION`, so the site and `llms.txt` carry them from
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
# name has to keep rendering on those acts.
|
|
27
27
|
#
|
|
28
28
|
# Optional. An actor with no entry renders exactly as stored, as it did before
|
|
29
|
-
# this file existed. The intake
|
|
30
|
-
#
|
|
29
|
+
# this file existed. The intake interview offers to add one; the owner can
|
|
30
|
+
# also edit this file by hand — it is theirs.
|
|
31
31
|
version: "0.1"
|
|
32
32
|
people: {}
|