@cyd-prc/dsh-audit-chain 0.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 +27 -0
- package/README.md +93 -0
- package/README.zh-CN.md +81 -0
- package/docs/CHAIN-GRADING-CONTRACT.md +97 -0
- package/index.js +18 -0
- package/lib/chain.js +642 -0
- package/package.json +45 -0
- package/test/core.test.mjs +478 -0
- package/tools/verify-chain.mjs +46 -0
- package/tools/verify-release.mjs +554 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Wang Miaosheng (ORCID: 0009-0003-2767-2421)
|
|
4
|
+
|
|
5
|
+
This package is the DeepSeek Harness binding of `entropy-sdk`
|
|
6
|
+
(https://github.com/CYD-PRC/entropy-sdk), the embeddable distillation of the
|
|
7
|
+
EntropyRuntime paper (arXiv:2607.00334). `lib/core.js` is a JavaScript port of
|
|
8
|
+
that SDK's published core abstractions; the remaining modules bind those
|
|
9
|
+
abstractions to the DeepSeek Harness plugin APIs.
|
|
10
|
+
|
|
11
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
12
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
13
|
+
in the Software without restriction, including without limitation the rights
|
|
14
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
16
|
+
furnished to do so, subject to the following conditions:
|
|
17
|
+
|
|
18
|
+
The above copyright notice and this permission notice shall be included in all
|
|
19
|
+
copies or substantial portions of the Software.
|
|
20
|
+
|
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# dsh-audit-chain — one chain, one implementation
|
|
2
|
+
|
|
3
|
+
The tamper-evident JSONL audit chain shared by the dsh guard plugins
|
|
4
|
+
(`dsh-entropy-guard`, `dsh-shape-guard`, `dsh-threat-gate`). It exists because
|
|
5
|
+
the chain used to live in **two copies** (`entropy-guard`'s `AuditLog` and
|
|
6
|
+
`shape-guard`'s vendored-out `lib/ledger.js`), and copies drift: one grading
|
|
7
|
+
defect (S3) shipped in two published packages, and a lock that one copy had
|
|
8
|
+
(`wx` + fresh tail) took a measured fork incident to reach the other.
|
|
9
|
+
|
|
10
|
+
This package is the end of that drift: **one writer, one grader, one contract.**
|
|
11
|
+
|
|
12
|
+
## What it is
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
import { ChainLog, verifyChain } from '@cyd-prc/dsh-audit-chain';
|
|
16
|
+
|
|
17
|
+
const chain = new ChainLog('/path/to/session.jsonl'); // or null for in-memory
|
|
18
|
+
chain.record('gate_decision', { admitted: true }); // locked, fresh tail
|
|
19
|
+
chain.seal('acknowledged'); // human acknowledgement
|
|
20
|
+
const reading = chain.verify(); // the contract, graded
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
- **Writer** — every append takes an exclusive lock (`<chain>.lock`: atomic `wx`
|
|
24
|
+
create, stale-broken past a timeout, fail-closed when held too long), re-reads
|
|
25
|
+
the on-disk tail *inside* the lock, and terminates a crash-torn tail line
|
|
26
|
+
before writing. Two plugins sharing one chain cannot fork it.
|
|
27
|
+
- **Grader** — `verify()` implements the shared chain-grading contract, eight
|
|
28
|
+
clauses: content re-hash always, fork-aware links (dangling = rewrite,
|
|
29
|
+
resolvable = branch), forks counted without early exit, seals bounding
|
|
30
|
+
ordering findings (by `seq` for chained axes, by file position for unchained),
|
|
31
|
+
tamper never sealable, corrupt lines reported but never graded on their own.
|
|
32
|
+
- **Byte-compatible** with both historical writers: chains written by
|
|
33
|
+
`entropy-guard ≤ 0.3.3` or `shape-guard ≤ 0.1.6` verify unchanged, and chains
|
|
34
|
+
written by this package verify under both. The hash-payload equivalence is
|
|
35
|
+
pinned by a test, not by prose.
|
|
36
|
+
|
|
37
|
+
## The contract
|
|
38
|
+
|
|
39
|
+
[`docs/CHAIN-GRADING-CONTRACT.md`](docs/CHAIN-GRADING-CONTRACT.md) ships a
|
|
40
|
+
byte-exact mirror of the grading contract (md5 `500f62b603140477317ed03bec167553`,
|
|
41
|
+
v4). The authoritative copy belongs to the test side; if two copies ever
|
|
42
|
+
disagree, the fingerprint is how you find out, and the test side's reading wins.
|
|
43
|
+
|
|
44
|
+
## Tools
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
node tools/verify-chain.mjs <chain.jsonl> [--json] # read-only by construction; exit 0 = verified
|
|
48
|
+
node tools/verify-release.mjs --pack --run-tests # pre-publish self-proof
|
|
49
|
+
node tools/verify-release.mjs --spec @cyd-prc/dsh-audit-chain@<v> --run-tests --wait 120
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`verify-chain` has no report mode on purpose: the report path is what made the
|
|
53
|
+
old tool write into the chain it audited (entropy-guard defect 16). This one
|
|
54
|
+
reads and leaves.
|
|
55
|
+
|
|
56
|
+
## API surface
|
|
57
|
+
|
|
58
|
+
| export | what it is |
|
|
59
|
+
|---|---|
|
|
60
|
+
| `ChainLog` | the chain: `record`, `seal`, `verify`, `entries`, `corruptLines`, `failures`/`lastError` |
|
|
61
|
+
| `verifyChain(path)` | the functional twin of `new ChainLog(path).verify()`, for pure readers |
|
|
62
|
+
| `encodeEntry` / `auditReplacer` / `hashEntry` | the byte format, public so writers and graders can never drift on it |
|
|
63
|
+
| `chainStem` / `resolveChainDir` | how the guards find the shared file |
|
|
64
|
+
| `LOCK_TIMEOUT_MS` / `LOCK_BACKOFF_MS` | the lock's tuning constants |
|
|
65
|
+
|
|
66
|
+
## Migration notes for the three plugins
|
|
67
|
+
|
|
68
|
+
- **entropy-guard**: `AuditLog` becomes a subclass adding its own readers
|
|
69
|
+
(`replayState`, `gearHistogram`, `gateAcceptanceRate`). One wording change to
|
|
70
|
+
expect: the interleaved reason says "two generations wrote this chain" here
|
|
71
|
+
(this package does not presume plugins).
|
|
72
|
+
- **shape-guard**: `ShapeLedger` becomes an alias of `ChainLog`; `lib/ledger.js`
|
|
73
|
+
turns into a re-export adapter so importers never move.
|
|
74
|
+
- **threat-gate**: the vendored copy is deleted; `lib/VENDORED.md` retires in
|
|
75
|
+
favour of a real dependency.
|
|
76
|
+
|
|
77
|
+
## Tests
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
node --test test/core.test.mjs # 32 tests, no dependencies
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The suite is the union of the anchors that pinned both historical
|
|
84
|
+
implementations (entropy-guard defects 14/15/16/19/20, shape-guard I7–I13 /
|
|
85
|
+
S1–S4), plus the byte-compatibility pin.
|
|
86
|
+
|
|
87
|
+
## Provenance
|
|
88
|
+
|
|
89
|
+
Written against the published implementations (`@cyd-prc/dsh-entropy-guard`
|
|
90
|
+
0.3.3, `@cyd-prc/dsh-shape-guard` 0.1.6) and the frozen real-world fixtures the
|
|
91
|
+
contract names. Cross-verified both ways: this package reads the fixtures with
|
|
92
|
+
the contract-conformant readings, and chains it writes grade `verified` under
|
|
93
|
+
both historical implementations. MIT © Wang Miaosheng (ORCID: 0009-0003-2767-2421).
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# dsh-audit-chain —— 一条链,一份实现
|
|
2
|
+
|
|
3
|
+
供 dsh 守卫插件(`dsh-entropy-guard`、`dsh-shape-guard`、`dsh-threat-gate`)共用的
|
|
4
|
+
防篡改 JSONL 审计链。它存在的原因:这条链过去活在**两份副本**里(entropy-guard 的
|
|
5
|
+
`AuditLog` 与 shape-guard 外抄出去的 `lib/ledger.js`),而副本会漂移——一个分级缺陷
|
|
6
|
+
(S3)曾搭车进两个已发布包;一份副本有的锁(`wx` + 新鲜链尾),要付出一次实测分叉事故
|
|
7
|
+
才传到另一份。
|
|
8
|
+
|
|
9
|
+
这个包终结漂移:**一个写入者、一个分级器、一份契约。**
|
|
10
|
+
|
|
11
|
+
## 是什么
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
import { ChainLog, verifyChain } from '@cyd-prc/dsh-audit-chain';
|
|
15
|
+
|
|
16
|
+
const chain = new ChainLog('/path/to/session.jsonl'); // 或 null(内存账本)
|
|
17
|
+
chain.record('gate_decision', { admitted: true }); // 带锁、新鲜链尾
|
|
18
|
+
chain.seal('acknowledged'); // 人类确认
|
|
19
|
+
const reading = chain.verify(); // 按契约分级
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
- **写入者**——每次追加取独占锁(`<chain>.lock`:`wx` 原子创建、超时破旧锁、
|
|
23
|
+
持锁过久则 fail-closed),在**锁内**重读磁盘链尾,并先终止崩溃撕断的破行再写入。
|
|
24
|
+
两个插件共享一条链,不可能再写出分叉。
|
|
25
|
+
- **分级器**——`verify()` 实现共享链分级契约八条:内容哈希恒重算;分叉感知链接
|
|
26
|
+
(悬空 = 改写,可解析 = 分支);分叉计数永不提前停;封存界定顺序类发现(链化轴按
|
|
27
|
+
`seq`、无链化轴按文件位置);篡改永不封存;不可解析行恒上报但不单独定级。
|
|
28
|
+
- **字节兼容**两代历史写入者:`entropy-guard ≤ 0.3.3` 或 `shape-guard ≤ 0.1.6` 写的链
|
|
29
|
+
照常通过校验,本包写的链在两边的旧实现下也照常通过。哈希载荷的等价性由测试钉住,
|
|
30
|
+
不靠散文。
|
|
31
|
+
|
|
32
|
+
## 契约
|
|
33
|
+
|
|
34
|
+
[`docs/CHAIN-GRADING-CONTRACT.md`](docs/CHAIN-GRADING-CONTRACT.md) 随包带一份逐字节镜像
|
|
35
|
+
(md5 `500f62b603140477317ed03bec167553`,v4)。权威件归测试侧;两份副本若哪天不一致,
|
|
36
|
+
指纹就是发现的方式,且以测试侧的读数为准。
|
|
37
|
+
|
|
38
|
+
## 工具
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
node tools/verify-chain.mjs <chain.jsonl> [--json] # 构造上只读;exit 0 = verified
|
|
42
|
+
node tools/verify-release.mjs --pack --run-tests # 发布前自证
|
|
43
|
+
node tools/verify-release.mjs --spec @cyd-prc/dsh-audit-chain@<v> --run-tests --wait 120
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`verify-chain` 刻意没有报告模式:当年的报告路径正是让旧工具往它审的链里写字的原因
|
|
47
|
+
(entropy-guard 缺陷 16)。这个工具只读,读完就走。
|
|
48
|
+
|
|
49
|
+
## API 面
|
|
50
|
+
|
|
51
|
+
| 导出 | 是什么 |
|
|
52
|
+
|---|---|
|
|
53
|
+
| `ChainLog` | 链本体:`record`、`seal`、`verify`、`entries`、`corruptLines`、`failures`/`lastError` |
|
|
54
|
+
| `verifyChain(path)` | `new ChainLog(path).verify()` 的函数孪生,给纯读者 |
|
|
55
|
+
| `encodeEntry` / `auditReplacer` / `hashEntry` | 字节格式本身公开,写入者与分级器再无漂移空间 |
|
|
56
|
+
| `chainStem` / `resolveChainDir` | 守卫们定位共享文件的方式 |
|
|
57
|
+
| `LOCK_TIMEOUT_MS` / `LOCK_BACKOFF_MS` | 锁的调参常量 |
|
|
58
|
+
|
|
59
|
+
## 三个插件的迁移注记
|
|
60
|
+
|
|
61
|
+
- **entropy-guard**:`AuditLog` 变为子类,只加自己的读数(`replayState`、
|
|
62
|
+
`gearHistogram`、`gateAcceptanceRate`)。一处措辞预期内变化:交错原因的文案在这里是
|
|
63
|
+
「two generations wrote this chain」(本包不预设插件)。
|
|
64
|
+
- **shape-guard**:`ShapeLedger` 成为 `ChainLog` 的别名;`lib/ledger.js` 变成
|
|
65
|
+
re-export 适配层,引用方一行不动。
|
|
66
|
+
- **threat-gate**:删除 vendored 副本;`lib/VENDORED.md` 退役,换成真依赖。
|
|
67
|
+
|
|
68
|
+
## 测试
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
node --test test/core.test.mjs # 32 项,无依赖
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
套件是两份历史实现的锚的并集(entropy-guard 缺陷 14/15/16/19/20、shape-guard
|
|
75
|
+
I7–I13 / S1–S4),外加字节兼容针。
|
|
76
|
+
|
|
77
|
+
## 溯源
|
|
78
|
+
|
|
79
|
+
对照已发布实现写作(`@cyd-prc/dsh-entropy-guard` 0.3.3、`@cyd-prc/dsh-shape-guard`
|
|
80
|
+
0.1.6),并用契约点名的冻结真实 fixture 双向交叉验证:本包以契约合规读数读 fixture,
|
|
81
|
+
本包写的链在两份历史实现下都判 `verified`。MIT © Wang Miaosheng(ORCID: 0009-0003-2767-2421)。
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Chain grading contract — shared by entropy-guard and shape-guard
|
|
2
|
+
|
|
3
|
+
Why this file exists: the two guards write **one** chain, so they must read it the
|
|
4
|
+
same way. An external review built a fixture of acknowledged forks and found the two
|
|
5
|
+
verifiers disagreeing — and, more usefully, disagreeing on *different axes*:
|
|
6
|
+
|
|
7
|
+
| axis | entropy-guard 0.3.1 | shape-guard 0.1.4 |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| **fork** (a duplicate `seq`: two writers branched from one tail) | ✗ stops at the first fork — counted **1 of 8**, and then graded a chain with **2 live forks** as `verified` | ✓ counts all 8, reports `liveForks`, and the seal clears them (`2 → 0`) |
|
|
10
|
+
| **interleaved** (unchained entries among chained ones — what an in-place upgrade looks like) | ✓ the seal clears `liveInterleaved` | ✗ grades `discontinuity` from the **lifetime** count (7) while reporting `liveDiscontinuities: 0` |
|
|
11
|
+
| **rewrite** (a value changed after it was written) | ✓ `tampered`, never sealed | ✓ `tampered`, never sealed |
|
|
12
|
+
| **writes to the chain it audits** | ✗ appends `init`+`restore` on every run (+2/run, measured) | ✓ read-only |
|
|
13
|
+
|
|
14
|
+
## The contract
|
|
15
|
+
|
|
16
|
+
1. **Both axes carry a lifetime count and a live count.** `forks`/`liveForks` and
|
|
17
|
+
`interleaved`/`liveInterleaved` (or `discontinuities`/`liveDiscontinuities`).
|
|
18
|
+
Two names for one axis is how this disagreement started: pick one vocabulary and
|
|
19
|
+
use it in every reading, the CLI line, and the report.
|
|
20
|
+
2. **The grade comes from live findings only**, ordered
|
|
21
|
+
`tampered` > `forked` > `discontinuity` > `verified`.
|
|
22
|
+
3. **A `chain_seal` bounds both axes.** Findings before the last seal are
|
|
23
|
+
acknowledged history: reported, never dropped, never graded.
|
|
24
|
+
4. **A tamper is never sealed** — on either side of the seal, by either guard.
|
|
25
|
+
5. **The `reason` string names the live finding**, never a lifetime count.
|
|
26
|
+
6. **Hash checks always run.** Only the *link/ordering* expectation may be relaxed
|
|
27
|
+
after a fork, and then only per branch: a fork-aware check restarts the expected
|
|
28
|
+
`prev` at each branch instead of abandoning the remainder. (Relaxing the rest is
|
|
29
|
+
what let a **deleted entry** pass as `verified` on the entropy-guard side.)
|
|
30
|
+
7. **A verifier never writes to the chain it audits.** The instrument must not be a
|
|
31
|
+
participant.
|
|
32
|
+
8. **An unparsable line is reported, never graded by itself.** A crash mid-append leaves
|
|
33
|
+
a torn tail: that is an availability accident, not an attack. The hostile variant it
|
|
34
|
+
could represent — an entry scrubbed out of the middle — is *already* `tampered` under
|
|
35
|
+
clause 6, because the following entry's `prev` resolves to nothing. So `corrupt` counts
|
|
36
|
+
travel in every reading and the `reason` names them, but they never raise the grade
|
|
37
|
+
above `discontinuity` on their own.
|
|
38
|
+
A **writer** owes the other half of this: terminate a torn tail before appending.
|
|
39
|
+
Without that the next entry fuses into the half-line, the line count does not move, and
|
|
40
|
+
the write is silently lost (defect 19, measured both ways: the old writer left
|
|
41
|
+
`2 lines → 2`, the new one `2 → 3` with the torn line preserved and counted).
|
|
42
|
+
|
|
43
|
+
Clauses 6–8 are the defects this review found on the **entropy-guard** side
|
|
44
|
+
(M1: the verifier appended `init`+`restore` to the chain it audits, +2 entries per run;
|
|
45
|
+
M2: it stopped at the first fork, which undercounted 8 forks as 1 and let a **deleted
|
|
46
|
+
entry** pass as `verified`; defect 19: a writer fusing into a torn tail). They are
|
|
47
|
+
**closed at `0.3.2@82765b3`**, measured — see the table. Clauses 1–5 are the
|
|
48
|
+
**shape-guard** side, and clause 8 gives shape-guard one open item (**S4**).
|
|
49
|
+
|
|
50
|
+
## Conformance — measured, not asserted
|
|
51
|
+
|
|
52
|
+
This table records only what a **named source** measured. *Reported* means the builder
|
|
53
|
+
side measured it and the test side has not re-run it yet: a closed row is not a
|
|
54
|
+
signature, and this file changes when a re-run changes it.
|
|
55
|
+
|
|
56
|
+
| package | clauses 1–5 (grading) | clauses 6–8 (instrument) | source |
|
|
57
|
+
|---|---|---|---|
|
|
58
|
+
| entropy-guard 0.3.1 | ✗ fork axis: 8 forks counted as 1, a live-forked chain graded `verified` | ✗ M1, M2 open | test side, measured |
|
|
59
|
+
| shape-guard 0.1.4 | ✗ S3: the interleaved axis is graded from the lifetime count | ✓ | test side, measured |
|
|
60
|
+
| shape-guard 0.1.5 | ✓ S3 **closed** (control `forked` with `liveInterleaved: 0`, one seal ⇒ `verified` with `reason: ""`, pre-seal rewrite still `tampered`) · ✗ S4 open: a torn tail is graded `tampered` from the `corrupt` count alone | ✓ | **test side, measured** (the builder's I10/I11 agree) |
|
|
61
|
+
| threat-gate 0.1.1 | ✗ V1: the vendored 0.1.4 ledger carried S3 into a second published package | ✓ | test side, measured |
|
|
62
|
+
| threat-gate 0.1.3 | ✓ V1 **closed** on the same sealed fixture; T1 **closed** (`vetoOnCritical` leaves read-only tools a way out); 13/13 | ✓ | **test side, measured** |
|
|
63
|
+
| entropy-guard 0.3.2 @`82765b3` | ✓ **closed** — `forked · 8 forks (live 2)`; sealed ⇒ `verified`; **delete-after-fork ⇒ `tampered`** (the case 0.3.1 missed); clause 8 conformant (`corrupt` reported, not graded) | ✓ **closed** — read-only (two runs, hash unchanged); a foreign `--spec` refused with exit 1; the lock A/B: new writer **0** duplicate `seq` where the old one produced **30**; torn-tail fix measured both ways | **test side, measured** |
|
|
64
|
+
| entropy-guard 0.3.3 @`e5a37bd` | ✓ unchanged from 0.3.2, plus clause 8's *letter*: the `reason` names the corrupt count (`1 unparsable line(s) (reported, not graded)`) | ✓ **closed** — defect 20: a CRLF checkout can no longer fake a DIFF (**17 phantom DIFFs → 0**, measured both ways), the tree HEAD is named in the output, and the HEAD anchor holds inside the artifact (in-package suite exit 0 on a non-git tree) | **test side, measured** |
|
|
65
|
+
| shape-guard 0.1.6 *(patch-reconstructed)* | ✓ **S4 closed** — the S4 pin (`s4-corrupt-not-hostile.finding.test.mjs`) flips green; S3's contract test and S1's record stay green, and the 20-case judgement suite holds, so the grading fix did not regress the earlier rulings | ✓ | **test side, measured** |
|
|
66
|
+
| threat-gate 0.1.4 *(patch-reconstructed)* | ✓ V1 closed at the source: `lib/ledger.js` is **byte-identical to shape-guard 0.1.6's** (`3A5476636C4B593E`), and the sealed fixture now grades `verified` | ✓ | **test side, measured** |
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
Standing rule, learned twice in this review: a status table that is not re-measured rots.
|
|
71
|
+
The two closed rows above moved from *reported* to *measured* only because the test side
|
|
72
|
+
re-ran its own tests against the published tarballs — not because the builder said so, and
|
|
73
|
+
not because the labels changed. `entropy-guard 0.3.1` is now the **only** verifier in the
|
|
74
|
+
fleet that reads the frozen fixture wrong (`VERIFIED · 1 fork` against the true
|
|
75
|
+
`FORKED · 8 forks, 2 live`), which is what its 0.3.2 owes clauses 6–7.
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
## Fixtures and tests that pin it
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
fixtures/live-mixed-generation.jsonl 727 entries: 194 pre-chaining, 8 duplicate
|
|
82
|
+
seq (2 after the last seal), 7 interleaved,
|
|
83
|
+
3 seals. Safe to ship — the ledger records
|
|
84
|
+
span digests and offsets, never payloads.
|
|
85
|
+
fixtures/contract-sealed-fork.jsonl the same chain plus one acknowledgement seal:
|
|
86
|
+
the input that separates "fork" from
|
|
87
|
+
"interleaved" as the top live finding.
|
|
88
|
+
chain-grading.contract.test.mjs control / claim / adversarial, in that order,
|
|
89
|
+
so the claim cannot pass vacuously.
|
|
90
|
+
chain-semantics.finding.test.mjs S1's red→green record: fails on 0.1.3 with
|
|
91
|
+
its raw reading, passes on 0.1.4.
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The fixtures are the shared input; the two test files are the recomputable definition of
|
|
95
|
+
what a grade means. They live beside the fixtures rather than inside any package, which is
|
|
96
|
+
why they are the test side's to own.
|
|
97
|
+
|
package/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-audit-chain — the one tamper-evident JSONL chain every guard shares.
|
|
3
|
+
* The public surface is `lib/chain.js`; see the README for the contract.
|
|
4
|
+
*
|
|
5
|
+
* @module dsh-audit-chain
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
ChainLog,
|
|
10
|
+
verifyChain,
|
|
11
|
+
encodeEntry,
|
|
12
|
+
auditReplacer,
|
|
13
|
+
hashEntry,
|
|
14
|
+
chainStem,
|
|
15
|
+
resolveChainDir,
|
|
16
|
+
LOCK_TIMEOUT_MS,
|
|
17
|
+
LOCK_BACKOFF_MS,
|
|
18
|
+
} from './lib/chain.js';
|