@akagilnc/pi-workflow-roles 0.1.3412 → 0.1.3439

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.
Files changed (67) hide show
  1. package/dist/archivist-record-entry.js +21 -12
  2. package/dist/archivist-record-topology.js +20 -0
  3. package/dist/auditor-dossier-tool.js +67 -76
  4. package/dist/canonical-json.js +66 -69
  5. package/dist/compliance-transport.js +99 -86
  6. package/dist/countersign-contracts.js +23 -25
  7. package/dist/doctor-contracts.js +169 -145
  8. package/dist/engine-detour-tool.js +83 -87
  9. package/dist/engine-detour.js +148 -183
  10. package/dist/evidence-child-executor.js +10 -1
  11. package/dist/exact-utf8.js +11 -10
  12. package/dist/git-object-id.js +10 -5
  13. package/dist/gleaner-left-contracts.js +33 -35
  14. package/dist/grok/production-host.js +229 -118
  15. package/dist/inspector-contracts.js +28 -31
  16. package/dist/institutional-resolution.js +101 -104
  17. package/dist/ledger-session-read.js +241 -0
  18. package/dist/merger-contracts.js +66 -56
  19. package/dist/notary-contracts.js +91 -100
  20. package/dist/open-tool-schema.js +32 -31
  21. package/dist/package-contracts/collector-output.js +56 -43
  22. package/dist/package-contracts/fixer-output.js +52 -50
  23. package/dist/package-contracts/fixer-packet.js +67 -64
  24. package/dist/package-contracts/gatekeeper-output.js +48 -56
  25. package/dist/package-contracts/judge-output.js +23 -20
  26. package/dist/package-contracts/navigator-output.js +35 -40
  27. package/dist/package-contracts/reviewer-output.js +94 -110
  28. package/dist/package-contracts/terminating-infrastructure.js +62 -90
  29. package/dist/package-contracts/worker-output.js +30 -11
  30. package/dist/package-resources/engine-material.js +58 -94
  31. package/dist/public-cli/config.js +420 -484
  32. package/dist/public-cli/main.js +1219 -524
  33. package/dist/public-cli/registry.js +107 -114
  34. package/dist/receipt-delivery-policy.js +74 -76
  35. package/dist/session-opening-materials.js +44 -47
  36. package/dist/sha256.js +5 -3
  37. package/dist/sitian-appender.js +204 -210
  38. package/dist/sitian-contracts.js +15 -19
  39. package/dist/sitian-facade.js +5 -10
  40. package/dist/sitian-reader.js +37 -46
  41. package/dist/stream-idle-guard.js +63 -71
  42. package/dist/ticket-seat-memory.js +244 -0
  43. package/package.json +1 -1
  44. package/scripts/build-package.mjs +41 -0
  45. package/souls/audit-law.md +4 -0
  46. package/souls/countersign.md +1 -1
  47. package/souls/gleaner-left.md +1 -1
  48. package/souls/inspector.md +1 -1
  49. package/souls/notary.md +1 -1
  50. package/souls/reviewer.md +1 -1
  51. package/src/analyst-gate-cycles-read.ts +152 -83
  52. package/src/analyst-ledger.ts +170 -43
  53. package/src/archivist-record-entry.ts +32 -11
  54. package/src/archivist-record-topology.ts +39 -0
  55. package/src/evidence-child-executor.ts +14 -1
  56. package/src/grok/production-host.ts +44 -9
  57. package/src/host-contracts.ts +18 -0
  58. package/src/host-transition-prior-native.ts +8 -1
  59. package/src/ledger-session-read.ts +56 -0
  60. package/src/pi/durable-principal.ts +6 -0
  61. package/src/public-cli/inspector-run.ts +21 -10
  62. package/src/public-cli/invocation.ts +4 -20
  63. package/src/public-cli/notary-run.ts +21 -4
  64. package/src/public-cli/post-admission.ts +333 -42
  65. package/src/public-cli/settlement.ts +266 -81
  66. package/src/session-opening-materials.ts +4 -2
  67. package/src/ticket-seat-memory.ts +454 -0
@@ -1,237 +1,231 @@
1
- /**
2
- * Sitian Appender kernel (ADR 0065).
3
- * Computes destination automatically from ledger topology without destination parameters.
4
- * Owns volume open, torn-tail recovery, entry-level idempotency, and commit boundary.
5
- */
6
1
  import { createHash, randomUUID } from "node:crypto";
7
- import { appendFileSync, existsSync, readFileSync, unlinkSync, writeFileSync, } from "node:fs";
2
+ import {
3
+ appendFileSync,
4
+ existsSync,
5
+ readFileSync,
6
+ unlinkSync,
7
+ writeFileSync
8
+ } from "node:fs";
8
9
  import { basename, dirname, join, resolve } from "node:path";
9
10
  import { resolveBookKeyFromGit } from "./activation-ledger-git.js";
10
- import { activationBookDirectory, ensureRealDirectoryTree, errorText, physicallyContainedIn, resolveActivationLedgerHome, resolveActivationLedgerHomeForPath, } from "./activation-ledger-topology.js";
11
- import { SitianInfrastructureError, } from "./sitian-contracts.js";
11
+ import {
12
+ activationBookDirectory,
13
+ ensureRealDirectoryTree,
14
+ errorText,
15
+ physicallyContainedIn,
16
+ resolveActivationLedgerHome,
17
+ resolveActivationLedgerHomeForPath
18
+ } from "./activation-ledger-topology.js";
19
+ import {
20
+ SitianInfrastructureError
21
+ } from "./sitian-contracts.js";
12
22
  function isRecord(value) {
13
- return typeof value === "object" && value !== null && !Array.isArray(value);
23
+ return typeof value === "object" && value !== null && !Array.isArray(value);
14
24
  }
15
25
  function errorCodeOf(error) {
16
- return error.code;
26
+ return error.code;
17
27
  }
18
28
  function identityClaimPath(recordFile, identity) {
19
- const digest = createHash("sha256").update(identity, "utf8").digest("hex");
20
- return `${recordFile}.id-${digest}`;
29
+ const digest = createHash("sha256").update(identity, "utf8").digest("hex");
30
+ return `${recordFile}.id-${digest}`;
21
31
  }
22
- /**
23
- * Exclusive create at `path` exactly once across processes.
24
- * Reuses the package's existing `wx` / O_EXCL zero-content occupancy primitive
25
- * (same shape as activation-ledger-session / archivist-record-entry).
26
- */
27
32
  function createExclusiveFile(path, contents) {
28
- writeFileSync(path, contents, { encoding: "utf8", flag: "wx" });
33
+ writeFileSync(path, contents, { encoding: "utf8", flag: "wx" });
29
34
  }
30
35
  function sealTornTail(recordFile) {
31
- if (!existsSync(recordFile))
32
- return;
33
- const buffer = readFileSync(recordFile);
34
- if (buffer.length > 0 && buffer[buffer.length - 1] !== 0x0a) {
35
- appendFileSync(recordFile, "\n", "utf8");
36
- }
36
+ if (!existsSync(recordFile)) return;
37
+ const buffer = readFileSync(recordFile);
38
+ if (buffer.length > 0 && buffer[buffer.length - 1] !== 10) {
39
+ appendFileSync(recordFile, "\n", "utf8");
40
+ }
37
41
  }
38
42
  function findIdentityPointer(recordFile, identity, kind, level) {
39
- if (!existsSync(recordFile))
40
- return undefined;
41
- const text = readFileSync(recordFile, "utf8");
42
- for (const line of text.split("\n")) {
43
- const trimmed = line.trim();
44
- if (!trimmed)
45
- continue;
46
- try {
47
- const parsed = JSON.parse(trimmed);
48
- if (isRecord(parsed) && parsed.identity === identity) {
49
- return { identity, recordFile, kind, level };
50
- }
51
- }
52
- catch {
53
- // Malformed lines (including substate b preserved bad lines) are ignored during self-check
54
- }
55
- }
56
- return undefined;
43
+ if (!existsSync(recordFile)) return void 0;
44
+ const text = readFileSync(recordFile, "utf8");
45
+ for (const line of text.split("\n")) {
46
+ const trimmed = line.trim();
47
+ if (!trimmed) continue;
48
+ try {
49
+ const parsed = JSON.parse(trimmed);
50
+ if (isRecord(parsed) && parsed.identity === identity) {
51
+ return { identity, recordFile, kind, level };
52
+ }
53
+ } catch {
54
+ }
55
+ }
56
+ return void 0;
57
57
  }
58
58
  function unlinkAbsentOk(path) {
59
- try {
60
- unlinkSync(path);
61
- return undefined;
62
- }
63
- catch (error) {
64
- if (errorCodeOf(error) === "ENOENT")
65
- return undefined;
66
- return error instanceof Error ? error : new Error(errorText(error));
67
- }
59
+ try {
60
+ unlinkSync(path);
61
+ return void 0;
62
+ } catch (error) {
63
+ if (errorCodeOf(error) === "ENOENT") return void 0;
64
+ return error instanceof Error ? error : new Error(errorText(error));
65
+ }
68
66
  }
69
- /**
70
- * Same-identity uniqueness under normal concurrent writers.
71
- *
72
- * Exclusive per-identity claim (`wx`) makes check+append atomic for one
73
- * identity. The winner appends under the claim and always releases it on both
74
- * normal and throwing exits. A loser that already sees the published row
75
- * returns that pointer; a loser that hits claim EEXIST without a published row
76
- * fails as SitianInfrastructureError (knownCause session). Crash residue can
77
- * leave that one identity blocked — identity-scoped, never a volume lock. No
78
- * wait loop, write-ahead recovery, PID reclaim, or compare-and-unlink.
79
- */
80
67
  function appendWithIdentityClaim(recordFile, record, row) {
68
+ sealTornTail(recordFile);
69
+ const claimPath = identityClaimPath(recordFile, record.identity);
70
+ const existing = findIdentityPointer(
71
+ recordFile,
72
+ record.identity,
73
+ record.kind,
74
+ record.level
75
+ );
76
+ if (existing !== void 0) {
77
+ unlinkAbsentOk(claimPath);
78
+ return existing;
79
+ }
80
+ try {
81
+ createExclusiveFile(claimPath, "");
82
+ } catch (error) {
83
+ if (errorCodeOf(error) !== "EEXIST") throw error;
81
84
  sealTornTail(recordFile);
82
- const claimPath = identityClaimPath(recordFile, record.identity);
83
- const existing = findIdentityPointer(recordFile, record.identity, record.kind, record.level);
84
- if (existing !== undefined) {
85
- // Best-effort: drop leftover claim after a prior crash-after-append.
86
- unlinkAbsentOk(claimPath);
87
- return existing;
88
- }
89
- try {
90
- createExclusiveFile(claimPath, "");
91
- }
92
- catch (error) {
93
- if (errorCodeOf(error) !== "EEXIST")
94
- throw error;
95
- sealTornTail(recordFile);
96
- const published = findIdentityPointer(recordFile, record.identity, record.kind, record.level);
97
- if (published !== undefined) {
98
- unlinkAbsentOk(claimPath);
99
- return published;
100
- }
101
- throw new SitianInfrastructureError(`Sitian identity claim at ${claimPath} already exists for identity ${record.identity}`, { cause: error });
102
- }
103
- let primaryFailure;
104
- let result;
105
- let cleanupFailure;
106
- try {
107
- sealTornTail(recordFile);
108
- const raced = findIdentityPointer(recordFile, record.identity, record.kind, record.level);
109
- if (raced !== undefined) {
110
- result = raced;
111
- }
112
- else {
113
- appendFileSync(recordFile, row, "utf8");
114
- result = {
115
- identity: record.identity,
116
- recordFile,
117
- kind: record.kind,
118
- level: record.level,
119
- };
120
- }
121
- }
122
- catch (error) {
123
- primaryFailure = error;
124
- }
125
- finally {
126
- cleanupFailure = unlinkAbsentOk(claimPath);
127
- }
128
- if (primaryFailure !== undefined) {
129
- if (primaryFailure instanceof SitianInfrastructureError)
130
- throw primaryFailure;
131
- throw new SitianInfrastructureError(`Sitian appender persistence failure: ${errorText(primaryFailure)}`, { cause: primaryFailure });
132
- }
133
- if (cleanupFailure !== undefined) {
134
- throw new SitianInfrastructureError(`Sitian identity claim at ${claimPath} could not be released after append for identity ${record.identity}: ${errorText(cleanupFailure)}`, { cause: cleanupFailure });
135
- }
136
- return result;
85
+ const published = findIdentityPointer(
86
+ recordFile,
87
+ record.identity,
88
+ record.kind,
89
+ record.level
90
+ );
91
+ if (published !== void 0) {
92
+ unlinkAbsentOk(claimPath);
93
+ return published;
94
+ }
95
+ throw new SitianInfrastructureError(
96
+ `Sitian identity claim at ${claimPath} already exists for identity ${record.identity}`,
97
+ { cause: error }
98
+ );
99
+ }
100
+ let primaryFailure;
101
+ let result;
102
+ let cleanupFailure;
103
+ try {
104
+ sealTornTail(recordFile);
105
+ const raced = findIdentityPointer(
106
+ recordFile,
107
+ record.identity,
108
+ record.kind,
109
+ record.level
110
+ );
111
+ if (raced !== void 0) {
112
+ result = raced;
113
+ } else {
114
+ appendFileSync(recordFile, row, "utf8");
115
+ result = {
116
+ identity: record.identity,
117
+ recordFile,
118
+ kind: record.kind,
119
+ level: record.level
120
+ };
121
+ }
122
+ } catch (error) {
123
+ primaryFailure = error;
124
+ } finally {
125
+ cleanupFailure = unlinkAbsentOk(claimPath);
126
+ }
127
+ if (primaryFailure !== void 0) {
128
+ if (primaryFailure instanceof SitianInfrastructureError) throw primaryFailure;
129
+ throw new SitianInfrastructureError(
130
+ `Sitian appender persistence failure: ${errorText(primaryFailure)}`,
131
+ { cause: primaryFailure }
132
+ );
133
+ }
134
+ if (cleanupFailure !== void 0) {
135
+ throw new SitianInfrastructureError(
136
+ `Sitian identity claim at ${claimPath} could not be released after append for identity ${record.identity}: ${errorText(cleanupFailure)}`,
137
+ { cause: cleanupFailure }
138
+ );
139
+ }
140
+ return result;
137
141
  }
138
- /** Authorized S4 submission ledger kinds that share a common run submission volume. */
139
- export const S4_SUBMISSION_LEDGER_KINDS = new Set([
140
- "candidate",
141
- "roundContext",
142
- "outcome",
143
- "sealed",
144
- "post-seal-anomaly"
142
+ const S4_SUBMISSION_LEDGER_KINDS = /* @__PURE__ */ new Set([
143
+ "candidate",
144
+ "roundContext",
145
+ "outcome",
146
+ "sealed",
147
+ "post-seal-anomaly"
145
148
  ]);
146
- /** Compute the volume partition key for directory placement. */
147
- export function resolveSitianVolumeCategory(kind) {
148
- if (S4_SUBMISSION_LEDGER_KINDS.has(kind)) {
149
- return "submission-ledger";
150
- }
151
- return kind;
149
+ function resolveSitianVolumeCategory(kind) {
150
+ if (S4_SUBMISSION_LEDGER_KINDS.has(kind)) {
151
+ return "submission-ledger";
152
+ }
153
+ return kind;
152
154
  }
153
155
  function safeBookKey(cwd) {
154
- try {
155
- return resolveBookKeyFromGit(cwd);
156
- }
157
- catch {
158
- return basename(resolve(cwd)) || "default";
159
- }
156
+ try {
157
+ return resolveBookKeyFromGit(cwd);
158
+ } catch {
159
+ return basename(resolve(cwd)) || "default";
160
+ }
160
161
  }
161
- /** Pure topology owner shared by ambient writes and explicit-home submission reads. */
162
- export function resolveSitianRecordPathInLedger(input, ledgerHome) {
163
- const cwd = input.cwd ?? process.cwd();
164
- const category = resolveSitianVolumeCategory(input.kind);
165
- let sessionDir;
166
- if (input.sessionParent !== undefined && input.sessionParent.length > 0 && physicallyContainedIn(ledgerHome, input.sessionParent)) {
167
- sessionDir = join(dirname(input.sessionParent), category);
168
- }
169
- else {
170
- const bookKey = safeBookKey(cwd);
171
- const bookDir = activationBookDirectory(ledgerHome, bookKey);
172
- if (input.subject !== undefined) {
173
- let subjectStr;
174
- if (typeof input.subject === "string") {
175
- subjectStr = input.subject;
176
- }
177
- else if (typeof input.subject.runId === "string" && input.subject.runId.length > 0) {
178
- subjectStr = input.subject.runId;
179
- }
180
- else {
181
- subjectStr = JSON.stringify(input.subject);
182
- }
183
- const digest = createHash("sha256").update(subjectStr).digest("hex").slice(0, 32);
184
- sessionDir = join(bookDir, category, digest);
185
- }
186
- else {
187
- sessionDir = join(bookDir, category);
188
- }
189
- }
190
- const recordFile = join(sessionDir, "records.jsonl");
191
- return { sessionDir, recordFile, ledgerHome };
162
+ function resolveSitianRecordPathInLedger(input, ledgerHome) {
163
+ const cwd = input.cwd ?? process.cwd();
164
+ const category = resolveSitianVolumeCategory(input.kind);
165
+ let sessionDir;
166
+ if (input.sessionParent !== void 0 && input.sessionParent.length > 0 && physicallyContainedIn(ledgerHome, input.sessionParent)) {
167
+ sessionDir = join(dirname(input.sessionParent), category);
168
+ } else {
169
+ const bookKey = safeBookKey(cwd);
170
+ const bookDir = activationBookDirectory(ledgerHome, bookKey);
171
+ if (input.subject !== void 0) {
172
+ let subjectStr;
173
+ if (typeof input.subject === "string") {
174
+ subjectStr = input.subject;
175
+ } else if (typeof input.subject.runId === "string" && input.subject.runId.length > 0) {
176
+ subjectStr = input.subject.runId;
177
+ } else {
178
+ subjectStr = JSON.stringify(input.subject);
179
+ }
180
+ const digest = createHash("sha256").update(subjectStr).digest("hex").slice(0, 32);
181
+ sessionDir = join(bookDir, category, digest);
182
+ } else {
183
+ sessionDir = join(bookDir, category);
184
+ }
185
+ }
186
+ const recordFile = join(sessionDir, "records.jsonl");
187
+ return { sessionDir, recordFile, ledgerHome };
192
188
  }
193
- /** Compute a write destination from ambient ledger topology (ADR 0065). */
194
- export function resolveSitianRecordPath(input) {
195
- const ledgerHome = input.home !== undefined && input.home.length > 0
196
- ? resolveActivationLedgerHome(input.home)
197
- : resolveActivationLedgerHomeForPath(input.sessionParent);
198
- return resolveSitianRecordPathInLedger(input, ledgerHome);
189
+ function resolveSitianRecordPath(input) {
190
+ const ledgerHome = input.home !== void 0 && input.home.length > 0 ? resolveActivationLedgerHome(input.home) : resolveActivationLedgerHomeForPath(input.sessionParent);
191
+ return resolveSitianRecordPathInLedger(input, ledgerHome);
199
192
  }
200
- /**
201
- * Appends a canonical record to its self-computed volume under the Sitian contract.
202
- * - Idempotency: checks volume by deterministic canonical identity; returns existing pointer on hit.
203
- * - Torn-tail recovery: checks file tail; un-terminated trailing bytes are sealed with a newline and re-parsed.
204
- * Substate a (valid JSON): committed on recovery, returns existing pointer.
205
- * Substate b (malformed): preserved as bad line, check misses, appends new row.
206
- * - Commit point: full JSON string ending with newline.
207
- */
208
- export function appendSitianRecord(input) {
209
- try {
210
- const { sessionDir, recordFile, ledgerHome } = resolveSitianRecordPath(input);
211
- ensureRealDirectoryTree(ledgerHome, sessionDir);
212
- const identity = input.identity ?? randomUUID();
213
- const timestamp = input.timestamp ?? new Date().toISOString();
214
- const host = input.host ?? "pi";
215
- const record = {
216
- level: input.level,
217
- kind: input.kind,
218
- identity,
219
- ...(input.subject === undefined ? {} : { subject: input.subject }),
220
- ...(input.sessionParent === undefined ? {} : { sessionParent: input.sessionParent }),
221
- ...(input.priorEventId === undefined ? {} : { priorEventId: input.priorEventId }),
222
- timestamp,
223
- host,
224
- ...(input.source === undefined ? {} : { source: input.source }),
225
- ...(input.payload === undefined ? {} : { payload: input.payload }),
226
- ...(input.raw === undefined ? {} : { raw: input.raw }),
227
- ...(input.usage === undefined ? {} : { usage: input.usage }),
228
- };
229
- const row = `${JSON.stringify(record)}\n`;
230
- return appendWithIdentityClaim(recordFile, record, row);
231
- }
232
- catch (error) {
233
- if (error instanceof SitianInfrastructureError)
234
- throw error;
235
- throw new SitianInfrastructureError(`Sitian appender persistence failure: ${errorText(error)}`, { cause: error });
236
- }
193
+ function appendSitianRecord(input) {
194
+ try {
195
+ const { sessionDir, recordFile, ledgerHome } = resolveSitianRecordPath(input);
196
+ ensureRealDirectoryTree(ledgerHome, sessionDir);
197
+ const identity = input.identity ?? randomUUID();
198
+ const timestamp = input.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
199
+ const host = input.host ?? "pi";
200
+ const record = {
201
+ level: input.level,
202
+ kind: input.kind,
203
+ identity,
204
+ ...input.subject === void 0 ? {} : { subject: input.subject },
205
+ ...input.sessionParent === void 0 ? {} : { sessionParent: input.sessionParent },
206
+ ...input.priorEventId === void 0 ? {} : { priorEventId: input.priorEventId },
207
+ timestamp,
208
+ host,
209
+ ...input.source === void 0 ? {} : { source: input.source },
210
+ ...input.payload === void 0 ? {} : { payload: input.payload },
211
+ ...input.raw === void 0 ? {} : { raw: input.raw },
212
+ ...input.usage === void 0 ? {} : { usage: input.usage }
213
+ };
214
+ const row = `${JSON.stringify(record)}
215
+ `;
216
+ return appendWithIdentityClaim(recordFile, record, row);
217
+ } catch (error) {
218
+ if (error instanceof SitianInfrastructureError) throw error;
219
+ throw new SitianInfrastructureError(
220
+ `Sitian appender persistence failure: ${errorText(error)}`,
221
+ { cause: error }
222
+ );
223
+ }
237
224
  }
225
+ export {
226
+ S4_SUBMISSION_LEDGER_KINDS,
227
+ appendSitianRecord,
228
+ resolveSitianRecordPath,
229
+ resolveSitianRecordPathInLedger,
230
+ resolveSitianVolumeCategory
231
+ };
@@ -1,21 +1,17 @@
1
- /**
2
- * Sitian (司天台) canonical contracts, Layout schema, and pointer definitions.
3
- * ADR 0065 single record entry + ADR 0068 Taishi analysis.
4
- */
5
- /** Lift direct-cause fs errno onto a wrap error (no chain walk). */
6
- export function attachDirectErrnoCode(error, cause) {
7
- if (cause === null || typeof cause !== "object" || !("code" in cause))
8
- return;
9
- const code = cause.code;
10
- if (typeof code === "string")
11
- error.code = code;
1
+ function attachDirectErrnoCode(error, cause) {
2
+ if (cause === null || typeof cause !== "object" || !("code" in cause)) return;
3
+ const code = cause.code;
4
+ if (typeof code === "string") error.code = code;
12
5
  }
13
- /** Typed infrastructure error for real ledger persistence / IO failures. */
14
- export class SitianInfrastructureError extends Error {
15
- knownCause = "session";
16
- constructor(message, options) {
17
- super(message, options);
18
- this.name = "SitianInfrastructureError";
19
- attachDirectErrnoCode(this, options?.cause);
20
- }
6
+ class SitianInfrastructureError extends Error {
7
+ knownCause = "session";
8
+ constructor(message, options) {
9
+ super(message, options);
10
+ this.name = "SitianInfrastructureError";
11
+ attachDirectErrnoCode(this, options?.cause);
12
+ }
21
13
  }
14
+ export {
15
+ SitianInfrastructureError,
16
+ attachDirectErrnoCode
17
+ };
@@ -1,15 +1,10 @@
1
- /**
2
- * Sitian Facade (司天门面) — Sole entrypoint for record reporting across all producers.
3
- * ADR 0065 single record entry, #520 r8.
4
- */
5
1
  import { appendSitianRecord } from "./sitian-appender.js";
6
2
  export * from "./sitian-contracts.js";
7
3
  export * from "./sitian-appender.js";
8
4
  export * from "./sitian-reader.js";
9
- /**
10
- * Sole write API for Sitian canonical records.
11
- * Returns typed RecordPointer with durable record identity and readable file location.
12
- */
13
- export function sitianReport(input) {
14
- return appendSitianRecord(input);
5
+ function sitianReport(input) {
6
+ return appendSitianRecord(input);
15
7
  }
8
+ export {
9
+ sitianReport
10
+ };
@@ -1,52 +1,43 @@
1
- /**
2
- * Sitian Reader kernel (ADR 0068 / #520 r8).
3
- * Sole authoritative read path for canonical Sitian records.
4
- * Traversal contract:
5
- * - Malformed lines are exposed as typed malformed diagnostics and traversal continues.
6
- * - Zero whitewashing, zero deduplication.
7
- * - Canonical rows after malformed lines are always reachable.
8
- */
9
1
  import { existsSync } from "node:fs";
10
2
  import { readFile } from "node:fs/promises";
11
3
  function isRecord(value) {
12
- return typeof value === "object" && value !== null && !Array.isArray(value);
4
+ return typeof value === "object" && value !== null && !Array.isArray(value);
13
5
  }
14
- /** Read a Sitian record volume with full traversal and non-destructive diagnostics. */
15
- export async function readSitianRecords(recordFile) {
16
- if (!existsSync(recordFile)) {
17
- return { records: [], diagnostics: [] };
6
+ async function readSitianRecords(recordFile) {
7
+ if (!existsSync(recordFile)) {
8
+ return { records: [], diagnostics: [] };
9
+ }
10
+ const text = await readFile(recordFile, "utf8");
11
+ const lines = text.split("\n");
12
+ const records = [];
13
+ const diagnostics = [];
14
+ for (let index = 0; index < lines.length; index += 1) {
15
+ const line = lines[index];
16
+ if (!line.trim()) continue;
17
+ try {
18
+ const parsed = JSON.parse(line);
19
+ if (isRecord(parsed)) {
20
+ records.push(parsed);
21
+ } else {
22
+ const typeDesc = parsed === null ? "null" : Array.isArray(parsed) ? "array" : typeof parsed;
23
+ diagnostics.push({
24
+ kind: "malformed",
25
+ line: index + 1,
26
+ raw: line,
27
+ error: `expected JSON object, got ${typeDesc}`
28
+ });
29
+ }
30
+ } catch (error) {
31
+ diagnostics.push({
32
+ kind: "malformed",
33
+ line: index + 1,
34
+ raw: line,
35
+ error: error instanceof Error ? error.message : String(error)
36
+ });
18
37
  }
19
- const text = await readFile(recordFile, "utf8");
20
- const lines = text.split("\n");
21
- const records = [];
22
- const diagnostics = [];
23
- for (let index = 0; index < lines.length; index += 1) {
24
- const line = lines[index];
25
- if (!line.trim())
26
- continue;
27
- try {
28
- const parsed = JSON.parse(line);
29
- if (isRecord(parsed)) {
30
- records.push(parsed);
31
- }
32
- else {
33
- const typeDesc = parsed === null ? "null" : Array.isArray(parsed) ? "array" : typeof parsed;
34
- diagnostics.push({
35
- kind: "malformed",
36
- line: index + 1,
37
- raw: line,
38
- error: `expected JSON object, got ${typeDesc}`,
39
- });
40
- }
41
- }
42
- catch (error) {
43
- diagnostics.push({
44
- kind: "malformed",
45
- line: index + 1,
46
- raw: line,
47
- error: error instanceof Error ? error.message : String(error),
48
- });
49
- }
50
- }
51
- return { records, diagnostics };
38
+ }
39
+ return { records, diagnostics };
52
40
  }
41
+ export {
42
+ readSitianRecords
43
+ };