simfile 0.0.1
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/README.md +143 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +348 -0
- package/dist/coverage/index.d.ts +2 -0
- package/dist/coverage/index.d.ts.map +1 -0
- package/dist/coverage/index.js +1 -0
- package/dist/coverage/matrix.d.ts +21 -0
- package/dist/coverage/matrix.d.ts.map +1 -0
- package/dist/coverage/matrix.js +173 -0
- package/dist/coverage/render.d.ts +3 -0
- package/dist/coverage/render.d.ts.map +1 -0
- package/dist/coverage/render.js +26 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/kernel/duration.d.ts +9 -0
- package/dist/kernel/duration.d.ts.map +1 -0
- package/dist/kernel/duration.js +44 -0
- package/dist/kernel/index.d.ts +4 -0
- package/dist/kernel/index.d.ts.map +1 -0
- package/dist/kernel/index.js +3 -0
- package/dist/kernel/range.d.ts +6 -0
- package/dist/kernel/range.d.ts.map +1 -0
- package/dist/kernel/range.js +16 -0
- package/dist/kernel/stochastic.d.ts +10 -0
- package/dist/kernel/stochastic.d.ts.map +1 -0
- package/dist/kernel/stochastic.js +25 -0
- package/dist/ledger/index.d.ts +4 -0
- package/dist/ledger/index.d.ts.map +1 -0
- package/dist/ledger/index.js +3 -0
- package/dist/ledger/markers.d.ts +46 -0
- package/dist/ledger/markers.d.ts.map +1 -0
- package/dist/ledger/markers.js +108 -0
- package/dist/ledger/stable.d.ts +65 -0
- package/dist/ledger/stable.d.ts.map +1 -0
- package/dist/ledger/stable.js +78 -0
- package/dist/ledger/validation.d.ts +16 -0
- package/dist/ledger/validation.d.ts.map +1 -0
- package/dist/ledger/validation.js +127 -0
- package/dist/moltnet/index.d.ts +3 -0
- package/dist/moltnet/index.d.ts.map +1 -0
- package/dist/moltnet/index.js +2 -0
- package/dist/moltnet/transcript-export.d.ts +34 -0
- package/dist/moltnet/transcript-export.d.ts.map +1 -0
- package/dist/moltnet/transcript-export.js +68 -0
- package/dist/moltnet/world-participant.d.ts +77 -0
- package/dist/moltnet/world-participant.d.ts.map +1 -0
- package/dist/moltnet/world-participant.js +221 -0
- package/dist/observe/artifacts.d.ts +16 -0
- package/dist/observe/artifacts.d.ts.map +1 -0
- package/dist/observe/artifacts.js +31 -0
- package/dist/observe/causalStreams.d.ts +19 -0
- package/dist/observe/causalStreams.d.ts.map +1 -0
- package/dist/observe/causalStreams.js +38 -0
- package/dist/observe/compute.d.ts +17 -0
- package/dist/observe/compute.d.ts.map +1 -0
- package/dist/observe/compute.js +97 -0
- package/dist/observe/index.d.ts +11 -0
- package/dist/observe/index.d.ts.map +1 -0
- package/dist/observe/index.js +10 -0
- package/dist/observe/manifest.d.ts +79 -0
- package/dist/observe/manifest.d.ts.map +1 -0
- package/dist/observe/manifest.js +87 -0
- package/dist/observe/memoryBanks.d.ts +38 -0
- package/dist/observe/memoryBanks.d.ts.map +1 -0
- package/dist/observe/memoryBanks.js +86 -0
- package/dist/observe/observe.d.ts +32 -0
- package/dist/observe/observe.d.ts.map +1 -0
- package/dist/observe/observe.js +73 -0
- package/dist/observe/report.d.ts +165 -0
- package/dist/observe/report.d.ts.map +1 -0
- package/dist/observe/report.js +138 -0
- package/dist/observe/seedSpread.d.ts +49 -0
- package/dist/observe/seedSpread.d.ts.map +1 -0
- package/dist/observe/seedSpread.js +262 -0
- package/dist/observe/seedSpreadArtifacts.d.ts +49 -0
- package/dist/observe/seedSpreadArtifacts.d.ts.map +1 -0
- package/dist/observe/seedSpreadArtifacts.js +118 -0
- package/dist/observe/spreadMatcher.d.ts +45 -0
- package/dist/observe/spreadMatcher.d.ts.map +1 -0
- package/dist/observe/spreadMatcher.js +124 -0
- package/dist/report/index.d.ts +4 -0
- package/dist/report/index.d.ts.map +1 -0
- package/dist/report/index.js +3 -0
- package/dist/report/probeArtifact.d.ts +26 -0
- package/dist/report/probeArtifact.d.ts.map +1 -0
- package/dist/report/probeArtifact.js +119 -0
- package/dist/report/probes.d.ts +52 -0
- package/dist/report/probes.d.ts.map +1 -0
- package/dist/report/probes.js +164 -0
- package/dist/report/score.d.ts +27 -0
- package/dist/report/score.d.ts.map +1 -0
- package/dist/report/score.js +14 -0
- package/dist/report/transcripts.d.ts +12 -0
- package/dist/report/transcripts.d.ts.map +1 -0
- package/dist/report/transcripts.js +17 -0
- package/dist/runtime/causal-fixture.d.ts +26 -0
- package/dist/runtime/causal-fixture.d.ts.map +1 -0
- package/dist/runtime/causal-fixture.js +36 -0
- package/dist/runtime/clock.d.ts +25 -0
- package/dist/runtime/clock.d.ts.map +1 -0
- package/dist/runtime/clock.js +63 -0
- package/dist/runtime/condition.d.ts +55 -0
- package/dist/runtime/condition.d.ts.map +1 -0
- package/dist/runtime/condition.js +122 -0
- package/dist/runtime/emit-causal-fixture.d.ts +2 -0
- package/dist/runtime/emit-causal-fixture.d.ts.map +1 -0
- package/dist/runtime/emit-causal-fixture.js +45 -0
- package/dist/runtime/expression.d.ts +11 -0
- package/dist/runtime/expression.d.ts.map +1 -0
- package/dist/runtime/expression.js +305 -0
- package/dist/runtime/numeric.d.ts +7 -0
- package/dist/runtime/numeric.d.ts.map +1 -0
- package/dist/runtime/numeric.js +11 -0
- package/dist/runtime/rule-actions.d.ts +5 -0
- package/dist/runtime/rule-actions.d.ts.map +1 -0
- package/dist/runtime/rule-actions.js +82 -0
- package/dist/runtime/run-record.d.ts +73 -0
- package/dist/runtime/run-record.d.ts.map +1 -0
- package/dist/runtime/run-record.js +179 -0
- package/dist/runtime/step-tick.d.ts +43 -0
- package/dist/runtime/step-tick.d.ts.map +1 -0
- package/dist/runtime/step-tick.js +177 -0
- package/dist/runtime/trace-compile.d.ts +66 -0
- package/dist/runtime/trace-compile.d.ts.map +1 -0
- package/dist/runtime/trace-compile.js +157 -0
- package/dist/runtime/trace-export.d.ts +5 -0
- package/dist/runtime/trace-export.d.ts.map +1 -0
- package/dist/runtime/trace-export.js +4 -0
- package/dist/runtime/trace-run.d.ts +15 -0
- package/dist/runtime/trace-run.d.ts.map +1 -0
- package/dist/runtime/trace-run.js +92 -0
- package/dist/runtime/trace.d.ts +10 -0
- package/dist/runtime/trace.d.ts.map +1 -0
- package/dist/runtime/trace.js +9 -0
- package/dist/runtime/types.d.ts +61 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +1 -0
- package/dist/runtime/viewer-trace.d.ts +64 -0
- package/dist/runtime/viewer-trace.d.ts.map +1 -0
- package/dist/runtime/viewer-trace.js +164 -0
- package/dist/runtime/world-act.d.ts +55 -0
- package/dist/runtime/world-act.d.ts.map +1 -0
- package/dist/runtime/world-act.js +156 -0
- package/dist/schema/binding.d.ts +23 -0
- package/dist/schema/binding.d.ts.map +1 -0
- package/dist/schema/binding.js +249 -0
- package/dist/schema/index.d.ts +5 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +4 -0
- package/dist/schema/model.d.ts +244 -0
- package/dist/schema/model.d.ts.map +1 -0
- package/dist/schema/model.js +222 -0
- package/dist/schema/parse.d.ts +10 -0
- package/dist/schema/parse.d.ts.map +1 -0
- package/dist/schema/parse.js +15 -0
- package/dist/schema/semantic.d.ts +3 -0
- package/dist/schema/semantic.d.ts.map +1 -0
- package/dist/schema/semantic.js +135 -0
- package/dist/sims/composeRunManifest.d.ts +54 -0
- package/dist/sims/composeRunManifest.d.ts.map +1 -0
- package/dist/sims/composeRunManifest.js +40 -0
- package/dist/sims/composedJungianSimDriver.d.ts +50 -0
- package/dist/sims/composedJungianSimDriver.d.ts.map +1 -0
- package/dist/sims/composedJungianSimDriver.js +199 -0
- package/dist/sims/composedOfficeSimDriver.d.ts +53 -0
- package/dist/sims/composedOfficeSimDriver.d.ts.map +1 -0
- package/dist/sims/composedOfficeSimDriver.js +162 -0
- package/dist/sims/exchangeWait.d.ts +56 -0
- package/dist/sims/exchangeWait.d.ts.map +1 -0
- package/dist/sims/exchangeWait.js +66 -0
- package/dist/sims/index.d.ts +14 -0
- package/dist/sims/index.d.ts.map +1 -0
- package/dist/sims/index.js +13 -0
- package/dist/sims/moltnetRoomClient.d.ts +47 -0
- package/dist/sims/moltnetRoomClient.d.ts.map +1 -0
- package/dist/sims/moltnetRoomClient.js +41 -0
- package/dist/sims/poll.d.ts +19 -0
- package/dist/sims/poll.d.ts.map +1 -0
- package/dist/sims/poll.js +23 -0
- package/dist/sims/spawnfileCli.d.ts +49 -0
- package/dist/sims/spawnfileCli.d.ts.map +1 -0
- package/dist/sims/spawnfileCli.js +90 -0
- package/dist/sims/spawnfileReceipts.d.ts +76 -0
- package/dist/sims/spawnfileReceipts.d.ts.map +1 -0
- package/dist/sims/spawnfileReceipts.js +107 -0
- package/dist/sims/worldDrivenOfficeSimDriver.d.ts +59 -0
- package/dist/sims/worldDrivenOfficeSimDriver.d.ts.map +1 -0
- package/dist/sims/worldDrivenOfficeSimDriver.js +182 -0
- package/dist/sims/worldLedgerWriter.d.ts +32 -0
- package/dist/sims/worldLedgerWriter.d.ts.map +1 -0
- package/dist/sims/worldLedgerWriter.js +39 -0
- package/dist/sims/worldSeedLint.d.ts +42 -0
- package/dist/sims/worldSeedLint.d.ts.map +1 -0
- package/dist/sims/worldSeedLint.js +73 -0
- package/dist/sims/worldTickIngest.d.ts +27 -0
- package/dist/sims/worldTickIngest.d.ts.map +1 -0
- package/dist/sims/worldTickIngest.js +35 -0
- package/dist/sims/worldTickLoop.d.ts +64 -0
- package/dist/sims/worldTickLoop.d.ts.map +1 -0
- package/dist/sims/worldTickLoop.js +122 -0
- package/dist/view/engineProvenance.d.ts +46 -0
- package/dist/view/engineProvenance.d.ts.map +1 -0
- package/dist/view/engineProvenance.js +76 -0
- package/dist/view/index.d.ts +14 -0
- package/dist/view/index.d.ts.map +1 -0
- package/dist/view/index.js +107 -0
- package/dist/view/membranes.d.ts +14 -0
- package/dist/view/membranes.d.ts.map +1 -0
- package/dist/view/membranes.js +127 -0
- package/dist/view/runDetect.d.ts +2 -0
- package/dist/view/runDetect.d.ts.map +1 -0
- package/dist/view/runDetect.js +47 -0
- package/dist/view/runRawArtifacts.d.ts +48 -0
- package/dist/view/runRawArtifacts.d.ts.map +1 -0
- package/dist/view/runRawArtifacts.js +143 -0
- package/dist/view/runTimeline.d.ts +24 -0
- package/dist/view/runTimeline.d.ts.map +1 -0
- package/dist/view/runTimeline.js +204 -0
- package/dist/view/runTimelineRecords.d.ts +42 -0
- package/dist/view/runTimelineRecords.d.ts.map +1 -0
- package/dist/view/runTimelineRecords.js +244 -0
- package/dist/view/runTimelineRefs.d.ts +27 -0
- package/dist/view/runTimelineRefs.d.ts.map +1 -0
- package/dist/view/runTimelineRefs.js +31 -0
- package/dist/view/runTimelineTypes.d.ts +99 -0
- package/dist/view/runTimelineTypes.d.ts.map +1 -0
- package/dist/view/runTimelineTypes.js +1 -0
- package/dist/view/runViewModel.d.ts +21 -0
- package/dist/view/runViewModel.d.ts.map +1 -0
- package/dist/view/runViewModel.js +66 -0
- package/dist/view/runViewModelCompute.d.ts +24 -0
- package/dist/view/runViewModelCompute.d.ts.map +1 -0
- package/dist/view/runViewModelCompute.js +157 -0
- package/dist/view/runViewModelTypes.d.ts +177 -0
- package/dist/view/runViewModelTypes.d.ts.map +1 -0
- package/dist/view/runViewModelTypes.js +1 -0
- package/dist/view/runWorldTrace.d.ts +97 -0
- package/dist/view/runWorldTrace.d.ts.map +1 -0
- package/dist/view/runWorldTrace.js +88 -0
- package/dist/view/server.d.ts +12 -0
- package/dist/view/server.d.ts.map +1 -0
- package/dist/view/server.js +306 -0
- package/package.json +65 -0
- package/web/dist/assets/index-CJHLjfsG.js +49 -0
- package/web/dist/assets/index-DJOsPsU8.css +1 -0
- package/web/dist/index.html +13 -0
- package/web/dist/models/AnimatedMushnub.glb +0 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
const sha256Hex = (buffer) => createHash("sha256").update(buffer).digest("hex");
|
|
5
|
+
/**
|
|
6
|
+
* Verifies every manifest-declared artifact's sha256 against the file on
|
|
7
|
+
* disk. A mismatch (or a missing file) is reported as a failed check, never
|
|
8
|
+
* silently repaired or stitched over — the caller decides what to do with a
|
|
9
|
+
* failed integrity check (contracts.md: "missing links are reported, not
|
|
10
|
+
* synthesized" applies just as much to artifact bytes as to causal edges).
|
|
11
|
+
*/
|
|
12
|
+
export const verifyManifestArtifacts = async (runDir, artifacts) => {
|
|
13
|
+
const checks = [];
|
|
14
|
+
for (const artifact of artifacts) {
|
|
15
|
+
const absolutePath = path.resolve(runDir, artifact.path);
|
|
16
|
+
try {
|
|
17
|
+
const buffer = await readFile(absolutePath);
|
|
18
|
+
const actualSha256 = sha256Hex(buffer);
|
|
19
|
+
checks.push({
|
|
20
|
+
actualSha256,
|
|
21
|
+
expectedSha256: artifact.sha256,
|
|
22
|
+
ok: actualSha256 === artifact.sha256,
|
|
23
|
+
path: artifact.path
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
checks.push({ actualSha256: null, expectedSha256: artifact.sha256, ok: false, path: artifact.path });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return checks;
|
|
31
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type CausalEvent, type CausalJsonlParseError } from "@noopolis/stele";
|
|
2
|
+
export interface CausalStreamSource {
|
|
3
|
+
/** The authority directory name directly under `raw/` (e.g. "moltnet", "daimon", "mneme"). */
|
|
4
|
+
authority: string;
|
|
5
|
+
errors: CausalJsonlParseError[];
|
|
6
|
+
events: CausalEvent[];
|
|
7
|
+
/** Path relative to the run directory. */
|
|
8
|
+
relativePath: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Reads and parses every `causal.jsonl` file under `<runDir>/raw/**`,
|
|
12
|
+
* tagging each stream by the authority directory it lives under
|
|
13
|
+
* (`raw/<authority>/...causal.jsonl`). Never reads any other file kind here
|
|
14
|
+
* — that keeps this module a single-purpose causal-stream collector; other
|
|
15
|
+
* per-authority artifacts (transcripts, bank event logs) are read by their
|
|
16
|
+
* own modules.
|
|
17
|
+
*/
|
|
18
|
+
export declare const collectCausalStreams: (runDir: string) => Promise<CausalStreamSource[]>;
|
|
19
|
+
//# sourceMappingURL=causalStreams.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"causalStreams.d.ts","sourceRoot":"","sources":["../../src/observe/causalStreams.ts"],"names":[],"mappings":"AAGA,OAAO,EAAoB,KAAK,WAAW,EAAE,KAAK,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAEjG,MAAM,WAAW,kBAAkB;IACjC,8FAA8F;IAC9F,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,qBAAqB,EAAE,CAAC;IAChC,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,0CAA0C;IAC1C,YAAY,EAAE,MAAM,CAAC;CACtB;AAgBD;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAAU,QAAQ,MAAM,KAAG,OAAO,CAAC,kBAAkB,EAAE,CAavF,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { parseCausalJsonl } from "@noopolis/stele";
|
|
4
|
+
const walkFiles = async (root) => {
|
|
5
|
+
const entries = await readdir(root, { withFileTypes: true }).catch(() => []);
|
|
6
|
+
const files = [];
|
|
7
|
+
for (const entry of entries) {
|
|
8
|
+
const entryPath = path.join(root, entry.name);
|
|
9
|
+
if (entry.isDirectory()) {
|
|
10
|
+
files.push(...(await walkFiles(entryPath)));
|
|
11
|
+
}
|
|
12
|
+
else if (entry.isFile()) {
|
|
13
|
+
files.push(entryPath);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return files;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Reads and parses every `causal.jsonl` file under `<runDir>/raw/**`,
|
|
20
|
+
* tagging each stream by the authority directory it lives under
|
|
21
|
+
* (`raw/<authority>/...causal.jsonl`). Never reads any other file kind here
|
|
22
|
+
* — that keeps this module a single-purpose causal-stream collector; other
|
|
23
|
+
* per-authority artifacts (transcripts, bank event logs) are read by their
|
|
24
|
+
* own modules.
|
|
25
|
+
*/
|
|
26
|
+
export const collectCausalStreams = async (runDir) => {
|
|
27
|
+
const rawDir = path.join(runDir, "raw");
|
|
28
|
+
const files = (await walkFiles(rawDir)).filter((file) => file.endsWith("causal.jsonl")).sort();
|
|
29
|
+
const sources = [];
|
|
30
|
+
for (const file of files) {
|
|
31
|
+
const relativePath = path.relative(runDir, file);
|
|
32
|
+
const authority = relativePath.split(path.sep)[1] ?? "unknown";
|
|
33
|
+
const text = await readFile(file, "utf8");
|
|
34
|
+
const { errors, events } = parseCausalJsonl(text);
|
|
35
|
+
sources.push({ authority, errors, events, relativePath });
|
|
36
|
+
}
|
|
37
|
+
return sources;
|
|
38
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { CausalEvent, ReconcileResult } from "@noopolis/stele";
|
|
2
|
+
import type { MemoryBankCounts } from "./memoryBanks.js";
|
|
3
|
+
import type { SimfileRunManifest } from "./manifest.js";
|
|
4
|
+
import { type SimfileObserveReport } from "./report.js";
|
|
5
|
+
import type { SeedSpreadComputeResult } from "./seedSpread.js";
|
|
6
|
+
export interface BuildObserveReportInput {
|
|
7
|
+
allEvents: readonly CausalEvent[];
|
|
8
|
+
manifest: SimfileRunManifest;
|
|
9
|
+
memoryBanks: readonly MemoryBankCounts[];
|
|
10
|
+
reconciled: ReconcileResult;
|
|
11
|
+
/** Memetics increment (b): present only when `manifest.seed_declaration`
|
|
12
|
+
* exists. `excluded` hits (instrument/operator actors) fold into
|
|
13
|
+
* `failures`, never into `seed_spread`. */
|
|
14
|
+
seedSpread?: SeedSpreadComputeResult;
|
|
15
|
+
}
|
|
16
|
+
export declare const buildObserveReport: (input: BuildObserveReportInput) => SimfileObserveReport;
|
|
17
|
+
//# sourceMappingURL=compute.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compute.d.ts","sourceRoot":"","sources":["../../src/observe/compute.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAuB,MAAM,iBAAiB,CAAC;AAEzF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAkD,KAAK,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxG,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAiG/D,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,SAAS,WAAW,EAAE,CAAC;IAClC,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,WAAW,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACzC,UAAU,EAAE,eAAe,CAAC;IAC5B;;+CAE2C;IAC3C,UAAU,CAAC,EAAE,uBAAuB,CAAC;CACtC;AAED,eAAO,MAAM,kBAAkB,GAAI,OAAO,uBAAuB,KAAG,oBAmBlE,CAAC"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { OBSERVE_REPORT_VERSION } from "./report.js";
|
|
2
|
+
const FAILURE_TYPES = new Set(["turn.failed", "wake.failed"]);
|
|
3
|
+
const AGENT_PRINCIPAL_PATTERN = /^agent:(.+)$/u;
|
|
4
|
+
const agentIdFromStreamId = (streamId) => streamId.replace(/^agent:/u, "");
|
|
5
|
+
/**
|
|
6
|
+
* Orders an agent's `turn.output.completed` events by the moltnet message
|
|
7
|
+
* seq that triggered the underlying turn (never `recorded_at`): each
|
|
8
|
+
* `turn.input.submitted` carries `payload.input_message_ids`, the message
|
|
9
|
+
* event ids that caused it; resolving those back to moltnet's own
|
|
10
|
+
* per-stream `emitter.seq` gives a causal, non-wall-clock ordering.
|
|
11
|
+
*/
|
|
12
|
+
const triggeringMoltnetSeq = (inputEvent, byEventId) => {
|
|
13
|
+
const messageIds = inputEvent?.payload.input_message_ids;
|
|
14
|
+
if (!Array.isArray(messageIds))
|
|
15
|
+
return undefined;
|
|
16
|
+
let minSeq;
|
|
17
|
+
for (const messageId of messageIds) {
|
|
18
|
+
if (typeof messageId !== "string")
|
|
19
|
+
continue;
|
|
20
|
+
const message = byEventId.get(messageId);
|
|
21
|
+
if (!message || message.emitter.system !== "moltnet")
|
|
22
|
+
continue;
|
|
23
|
+
minSeq = minSeq === undefined ? message.emitter.seq : Math.min(minSeq, message.emitter.seq);
|
|
24
|
+
}
|
|
25
|
+
return minSeq;
|
|
26
|
+
};
|
|
27
|
+
const computeParticipants = (events) => {
|
|
28
|
+
const participants = new Set();
|
|
29
|
+
for (const event of events) {
|
|
30
|
+
const match = AGENT_PRINCIPAL_PATTERN.exec(event.principal_id);
|
|
31
|
+
if (match?.[1])
|
|
32
|
+
participants.add(match[1]);
|
|
33
|
+
}
|
|
34
|
+
return [...participants].sort();
|
|
35
|
+
};
|
|
36
|
+
const computeAgentTurns = (events) => {
|
|
37
|
+
const byEventId = new Map(events.map((event) => [event.event_id, event]));
|
|
38
|
+
const turnOutputs = events.filter((event) => event.emitter.system === "daimon" && event.type === "turn.output.completed");
|
|
39
|
+
const ordered = turnOutputs
|
|
40
|
+
.map((turnOutput) => {
|
|
41
|
+
const inputEventId = turnOutput.cause_event_ids.find((causeId) => {
|
|
42
|
+
const cause = byEventId.get(causeId);
|
|
43
|
+
return cause?.emitter.system === "daimon" && cause.type === "turn.input.submitted";
|
|
44
|
+
});
|
|
45
|
+
const inputEvent = inputEventId ? byEventId.get(inputEventId) : undefined;
|
|
46
|
+
return {
|
|
47
|
+
agentId: agentIdFromStreamId(turnOutput.emitter.stream_id),
|
|
48
|
+
eventId: turnOutput.event_id,
|
|
49
|
+
seq: triggeringMoltnetSeq(inputEvent, byEventId)
|
|
50
|
+
};
|
|
51
|
+
})
|
|
52
|
+
.sort((left, right) => {
|
|
53
|
+
const leftSeq = left.seq ?? Number.POSITIVE_INFINITY;
|
|
54
|
+
const rightSeq = right.seq ?? Number.POSITIVE_INFINITY;
|
|
55
|
+
return leftSeq - rightSeq || left.eventId.localeCompare(right.eventId);
|
|
56
|
+
});
|
|
57
|
+
return { count: ordered.length, sequence: ordered.map((entry) => entry.agentId) };
|
|
58
|
+
};
|
|
59
|
+
const computeChains = (reconciled) => {
|
|
60
|
+
let complete = 0;
|
|
61
|
+
const incomplete = [];
|
|
62
|
+
for (const [eventId, record] of reconciled.byEventId) {
|
|
63
|
+
if (record.state === "complete") {
|
|
64
|
+
complete += 1;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
incomplete.push({ event_id: eventId, flag: record.state });
|
|
68
|
+
}
|
|
69
|
+
incomplete.sort((left, right) => left.event_id.localeCompare(right.event_id));
|
|
70
|
+
return { complete, incomplete };
|
|
71
|
+
};
|
|
72
|
+
const computeFailures = (events) => events
|
|
73
|
+
.filter((event) => FAILURE_TYPES.has(event.type))
|
|
74
|
+
.map((event) => ({
|
|
75
|
+
event_id: event.event_id,
|
|
76
|
+
reason: typeof event.payload.reason === "string" ? event.payload.reason : event.type
|
|
77
|
+
}));
|
|
78
|
+
export const buildObserveReport = (input) => ({
|
|
79
|
+
version: OBSERVE_REPORT_VERSION,
|
|
80
|
+
run_id: input.manifest.run_id,
|
|
81
|
+
contract_versions: input.manifest.contract_versions,
|
|
82
|
+
participants: computeParticipants(input.allEvents),
|
|
83
|
+
agent_turns: computeAgentTurns(input.allEvents),
|
|
84
|
+
chains: computeChains(input.reconciled),
|
|
85
|
+
memory: input.memoryBanks.map((bank) => ({
|
|
86
|
+
bank: bank.bank,
|
|
87
|
+
events: bank.events,
|
|
88
|
+
recalls: bank.recalls,
|
|
89
|
+
memory_write_source: bank.memory_write_source,
|
|
90
|
+
...(bank.writes_by_agent ? { writes_by_agent: bank.writes_by_agent } : {})
|
|
91
|
+
})),
|
|
92
|
+
failures: [
|
|
93
|
+
...computeFailures(input.allEvents),
|
|
94
|
+
...(input.seedSpread?.excluded.map((excluded) => ({ event_id: excluded.event_id, reason: excluded.reason })) ?? [])
|
|
95
|
+
],
|
|
96
|
+
...(input.seedSpread ? { seed_spread: input.seedSpread.entries, spread_summary: input.seedSpread.summary } : {})
|
|
97
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from "./artifacts.js";
|
|
2
|
+
export * from "./causalStreams.js";
|
|
3
|
+
export * from "./compute.js";
|
|
4
|
+
export * from "./manifest.js";
|
|
5
|
+
export * from "./memoryBanks.js";
|
|
6
|
+
export * from "./observe.js";
|
|
7
|
+
export * from "./report.js";
|
|
8
|
+
export * from "./seedSpread.js";
|
|
9
|
+
export * from "./seedSpreadArtifacts.js";
|
|
10
|
+
export * from "./spreadMatcher.js";
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/observe/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from "./artifacts.js";
|
|
2
|
+
export * from "./causalStreams.js";
|
|
3
|
+
export * from "./compute.js";
|
|
4
|
+
export * from "./manifest.js";
|
|
5
|
+
export * from "./memoryBanks.js";
|
|
6
|
+
export * from "./observe.js";
|
|
7
|
+
export * from "./report.js";
|
|
8
|
+
export * from "./seedSpread.js";
|
|
9
|
+
export * from "./seedSpreadArtifacts.js";
|
|
10
|
+
export * from "./spreadMatcher.js";
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* `simfile.run-manifest.v1` — the composite run manifest simfile writes for
|
|
4
|
+
* a run's directory (Decision 21 / contracts.md's `simfile.run-manifest.v1`
|
|
5
|
+
* row). `seed_declaration` and `expected_wakes` are DEFINED-BUT-OPTIONAL:
|
|
6
|
+
* office-sim runs omit both (no seeded secret, no compiled wake schedule to
|
|
7
|
+
* diff against yet), so a manifest without them is still fully conformant.
|
|
8
|
+
* A future memetics phase (Phase G) populates both without a v2 bump.
|
|
9
|
+
*/
|
|
10
|
+
export declare const RUN_MANIFEST_VERSION: "simfile.run-manifest.v1";
|
|
11
|
+
declare const artifactEntrySchema: z.ZodObject<{
|
|
12
|
+
path: z.ZodString;
|
|
13
|
+
sha256: z.ZodString;
|
|
14
|
+
}, z.core.$strict>;
|
|
15
|
+
export type RunManifestArtifactEntry = z.infer<typeof artifactEntrySchema>;
|
|
16
|
+
/**
|
|
17
|
+
* The observer's ground truth for a seeded memetics secret (contracts.md
|
|
18
|
+
* "measurement-critical contracts" section). `matcher_policy` is kept as a
|
|
19
|
+
* documented free-form string rather than a tight enum: the named policies
|
|
20
|
+
* (`exact` / `edit-distance:<k>` / `embedding` / `judge`) may carry pinned
|
|
21
|
+
* experiment parameters. `spreadMatcher.ts` validates and dispatches this
|
|
22
|
+
* field; model-backed policies fail loudly in builds without those models.
|
|
23
|
+
*/
|
|
24
|
+
declare const seedDeclarationSchema: z.ZodObject<{
|
|
25
|
+
content_hash: z.ZodString;
|
|
26
|
+
token_set: z.ZodArray<z.ZodString>;
|
|
27
|
+
matcher_policy: z.ZodString;
|
|
28
|
+
seed_agent: z.ZodString;
|
|
29
|
+
seed_epoch: z.ZodString;
|
|
30
|
+
entry_channel: z.ZodLiteral<"doc-seeded">;
|
|
31
|
+
}, z.core.$strict>;
|
|
32
|
+
export type SeedDeclaration = z.infer<typeof seedDeclarationSchema>;
|
|
33
|
+
/**
|
|
34
|
+
* One compiled schedule fire simfile expects to observe within the run's
|
|
35
|
+
* sim-time window (the denominator oracle for the 100%-reply-or-recover
|
|
36
|
+
* bar, contracts.md). Kept minimal and generic: the compiled-schedule ->
|
|
37
|
+
* wake-diff lowering is Phase 7 scope (Decision 21's phasing), so this only
|
|
38
|
+
* carries what `simfile observe`'s wake-diff will need to match against —
|
|
39
|
+
* which agent, which wake, and when.
|
|
40
|
+
*/
|
|
41
|
+
declare const expectedWakeSchema: z.ZodObject<{
|
|
42
|
+
agent_id: z.ZodString;
|
|
43
|
+
wake_id: z.ZodString;
|
|
44
|
+
sim_time: z.ZodOptional<z.ZodNumber>;
|
|
45
|
+
}, z.core.$strict>;
|
|
46
|
+
export type ExpectedWake = z.infer<typeof expectedWakeSchema>;
|
|
47
|
+
export declare const runManifestSchema: z.ZodObject<{
|
|
48
|
+
version: z.ZodLiteral<"simfile.run-manifest.v1">;
|
|
49
|
+
run_id: z.ZodString;
|
|
50
|
+
created_at: z.ZodString;
|
|
51
|
+
contract_versions: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
52
|
+
spawnfile: z.ZodOptional<z.ZodObject<{
|
|
53
|
+
up_receipt_ref: z.ZodOptional<z.ZodString>;
|
|
54
|
+
fingerprint: z.ZodOptional<z.ZodString>;
|
|
55
|
+
}, z.core.$strict>>;
|
|
56
|
+
artifacts: z.ZodArray<z.ZodObject<{
|
|
57
|
+
path: z.ZodString;
|
|
58
|
+
sha256: z.ZodString;
|
|
59
|
+
}, z.core.$strict>>;
|
|
60
|
+
engine: z.ZodOptional<z.ZodString>;
|
|
61
|
+
world: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
62
|
+
seed_declaration: z.ZodOptional<z.ZodObject<{
|
|
63
|
+
content_hash: z.ZodString;
|
|
64
|
+
token_set: z.ZodArray<z.ZodString>;
|
|
65
|
+
matcher_policy: z.ZodString;
|
|
66
|
+
seed_agent: z.ZodString;
|
|
67
|
+
seed_epoch: z.ZodString;
|
|
68
|
+
entry_channel: z.ZodLiteral<"doc-seeded">;
|
|
69
|
+
}, z.core.$strict>>;
|
|
70
|
+
expected_wakes: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
71
|
+
agent_id: z.ZodString;
|
|
72
|
+
wake_id: z.ZodString;
|
|
73
|
+
sim_time: z.ZodOptional<z.ZodNumber>;
|
|
74
|
+
}, z.core.$strict>>>;
|
|
75
|
+
}, z.core.$strict>;
|
|
76
|
+
export type SimfileRunManifest = z.infer<typeof runManifestSchema>;
|
|
77
|
+
export declare const parseRunManifest: (raw: unknown) => SimfileRunManifest;
|
|
78
|
+
export {};
|
|
79
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/observe/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,EAAG,yBAAkC,CAAC;AAEvE,QAAA,MAAM,mBAAmB;;;kBAKd,CAAC;AAEZ,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAS3E;;;;;;;GAOG;AACH,QAAA,MAAM,qBAAqB;;;;;;;kBAShB,CAAC;AAEZ,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE;;;;;;;GAOG;AACH,QAAA,MAAM,kBAAkB;;;;kBAMb,CAAC;AAEZ,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAsB1B,CAAC;AAEL,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAEnE,eAAO,MAAM,gBAAgB,GAAI,KAAK,OAAO,KAAG,kBAU/C,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* `simfile.run-manifest.v1` — the composite run manifest simfile writes for
|
|
4
|
+
* a run's directory (Decision 21 / contracts.md's `simfile.run-manifest.v1`
|
|
5
|
+
* row). `seed_declaration` and `expected_wakes` are DEFINED-BUT-OPTIONAL:
|
|
6
|
+
* office-sim runs omit both (no seeded secret, no compiled wake schedule to
|
|
7
|
+
* diff against yet), so a manifest without them is still fully conformant.
|
|
8
|
+
* A future memetics phase (Phase G) populates both without a v2 bump.
|
|
9
|
+
*/
|
|
10
|
+
export const RUN_MANIFEST_VERSION = "simfile.run-manifest.v1";
|
|
11
|
+
const artifactEntrySchema = z
|
|
12
|
+
.object({
|
|
13
|
+
path: z.string().min(1),
|
|
14
|
+
sha256: z.string().regex(/^[0-9a-f]{64}$/u, "sha256 must be a 64-character lowercase hex digest")
|
|
15
|
+
})
|
|
16
|
+
.strict();
|
|
17
|
+
const spawnfileRefSchema = z
|
|
18
|
+
.object({
|
|
19
|
+
up_receipt_ref: z.string().min(1).optional(),
|
|
20
|
+
fingerprint: z.string().min(1).optional()
|
|
21
|
+
})
|
|
22
|
+
.strict();
|
|
23
|
+
/**
|
|
24
|
+
* The observer's ground truth for a seeded memetics secret (contracts.md
|
|
25
|
+
* "measurement-critical contracts" section). `matcher_policy` is kept as a
|
|
26
|
+
* documented free-form string rather than a tight enum: the named policies
|
|
27
|
+
* (`exact` / `edit-distance:<k>` / `embedding` / `judge`) may carry pinned
|
|
28
|
+
* experiment parameters. `spreadMatcher.ts` validates and dispatches this
|
|
29
|
+
* field; model-backed policies fail loudly in builds without those models.
|
|
30
|
+
*/
|
|
31
|
+
const seedDeclarationSchema = z
|
|
32
|
+
.object({
|
|
33
|
+
content_hash: z.string().min(1),
|
|
34
|
+
token_set: z.array(z.string().min(1)),
|
|
35
|
+
matcher_policy: z.string().min(1),
|
|
36
|
+
seed_agent: z.string().min(1),
|
|
37
|
+
seed_epoch: z.string().min(1),
|
|
38
|
+
entry_channel: z.literal("doc-seeded")
|
|
39
|
+
})
|
|
40
|
+
.strict();
|
|
41
|
+
/**
|
|
42
|
+
* One compiled schedule fire simfile expects to observe within the run's
|
|
43
|
+
* sim-time window (the denominator oracle for the 100%-reply-or-recover
|
|
44
|
+
* bar, contracts.md). Kept minimal and generic: the compiled-schedule ->
|
|
45
|
+
* wake-diff lowering is Phase 7 scope (Decision 21's phasing), so this only
|
|
46
|
+
* carries what `simfile observe`'s wake-diff will need to match against —
|
|
47
|
+
* which agent, which wake, and when.
|
|
48
|
+
*/
|
|
49
|
+
const expectedWakeSchema = z
|
|
50
|
+
.object({
|
|
51
|
+
agent_id: z.string().min(1),
|
|
52
|
+
wake_id: z.string().min(1),
|
|
53
|
+
sim_time: z.number().optional()
|
|
54
|
+
})
|
|
55
|
+
.strict();
|
|
56
|
+
export const runManifestSchema = z
|
|
57
|
+
.object({
|
|
58
|
+
version: z.literal(RUN_MANIFEST_VERSION),
|
|
59
|
+
run_id: z.string().min(1),
|
|
60
|
+
created_at: z.string().min(1),
|
|
61
|
+
contract_versions: z.record(z.string(), z.string()),
|
|
62
|
+
spawnfile: spawnfileRefSchema.optional(),
|
|
63
|
+
artifacts: z.array(artifactEntrySchema),
|
|
64
|
+
engine: z.string().min(1).optional(),
|
|
65
|
+
world: z.record(z.string(), z.unknown()).optional(),
|
|
66
|
+
seed_declaration: seedDeclarationSchema.optional(),
|
|
67
|
+
expected_wakes: z.array(expectedWakeSchema).optional()
|
|
68
|
+
})
|
|
69
|
+
.strict()
|
|
70
|
+
.superRefine((value, context) => {
|
|
71
|
+
if (Number.isNaN(Date.parse(value.created_at))) {
|
|
72
|
+
context.addIssue({
|
|
73
|
+
code: z.ZodIssueCode.custom,
|
|
74
|
+
message: "created_at must be a valid ISO 8601 timestamp",
|
|
75
|
+
path: ["created_at"]
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
export const parseRunManifest = (raw) => {
|
|
80
|
+
const result = runManifestSchema.safeParse(raw);
|
|
81
|
+
if (!result.success) {
|
|
82
|
+
throw new Error(`invalid ${RUN_MANIFEST_VERSION} manifest: ${result.error.issues
|
|
83
|
+
.map((issue) => `${issue.path.join(".") || "<root>"}: ${issue.message}`)
|
|
84
|
+
.join("; ")}`);
|
|
85
|
+
}
|
|
86
|
+
return result.data;
|
|
87
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { CausalEvent } from "@noopolis/stele";
|
|
2
|
+
import type { MemoryWriteSource } from "./report.js";
|
|
3
|
+
export interface MemoryBankCounts {
|
|
4
|
+
bank: string;
|
|
5
|
+
events: number;
|
|
6
|
+
recalls: number;
|
|
7
|
+
memory_write_source: MemoryWriteSource;
|
|
8
|
+
/** Per-agent write counts, derived from `memory.written`'s `principal_id`. Only set on the ledger path. */
|
|
9
|
+
writes_by_agent?: Record<string, number>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Derives each mneme bank's memory-write count, per-agent write signal, and
|
|
13
|
+
* recall count.
|
|
14
|
+
*
|
|
15
|
+
* Ledger-first (Slice B Piece 4b): mneme stamps a `memory.written` causal
|
|
16
|
+
* event (`noopolis.causal-event.v1`, same `memory/causal.jsonl` stream as
|
|
17
|
+
* `memory.recalled`) on every durable memory register, with
|
|
18
|
+
* `cause_event_ids` chaining it to the wake/turn that produced it. When a
|
|
19
|
+
* bank's reconciled causal stream (`causalEventsByBank`) contains at least
|
|
20
|
+
* one `memory.written` event, that count is authoritative
|
|
21
|
+
* (`memory_write_source: "ledger"`), and `writes_by_agent` is derived from
|
|
22
|
+
* each event's `principal_id`.
|
|
23
|
+
*
|
|
24
|
+
* Fallback (pre-4b runs, e.g. the office-sim golden fixture captured before
|
|
25
|
+
* mneme shipped the write-side event): if a bank's causal stream has ZERO
|
|
26
|
+
* `memory.written` events, this falls back to the interim signal — mneme's
|
|
27
|
+
* own `raw/mneme/<bank>/events.jsonl` bank event log (line count as the
|
|
28
|
+
* write proxy) — marking `memory_write_source: "events-fallback"` so a
|
|
29
|
+
* stale run is visibly on the fallback, never silently. If neither
|
|
30
|
+
* `events.jsonl` nor any `memory.written` event exists, `events` is 0.
|
|
31
|
+
*
|
|
32
|
+
* `recalls` is unaffected by which write source wins: it always prefers
|
|
33
|
+
* `events.jsonl`'s own `memory.recalled` lines when the file exists, falling
|
|
34
|
+
* back to the bank's `memory.recalled` causal events otherwise — the same
|
|
35
|
+
* behavior this function had before Piece 4b.
|
|
36
|
+
*/
|
|
37
|
+
export declare const collectMemoryBankCounts: (runDir: string, causalEventsByBank: ReadonlyMap<string, CausalEvent[]>) => Promise<MemoryBankCounts[]>;
|
|
38
|
+
//# sourceMappingURL=memoryBanks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memoryBanks.d.ts","sourceRoot":"","sources":["../../src/observe/memoryBanks.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,mBAAmB,EAAE,iBAAiB,CAAC;IACvC,2GAA2G;IAC3G,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AA6BD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,uBAAuB,GAClC,QAAQ,MAAM,EACd,oBAAoB,WAAW,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,KACrD,OAAO,CAAC,gBAAgB,EAAE,CAwC5B,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
const AGENT_PRINCIPAL_PATTERN = /^agent:(.+)$/u;
|
|
4
|
+
const countJsonlLines = (content) => content
|
|
5
|
+
.split(/\r?\n/u)
|
|
6
|
+
.map((line) => line.trim())
|
|
7
|
+
.filter((line) => line.length > 0);
|
|
8
|
+
const countRecallsFromEventsJsonl = (lines) => lines.filter((line) => {
|
|
9
|
+
try {
|
|
10
|
+
return JSON.parse(line).type === "memory.recalled";
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
}).length;
|
|
16
|
+
const countByAgent = (events) => {
|
|
17
|
+
const counts = {};
|
|
18
|
+
for (const event of events) {
|
|
19
|
+
const agentId = AGENT_PRINCIPAL_PATTERN.exec(event.principal_id)?.[1];
|
|
20
|
+
if (!agentId)
|
|
21
|
+
continue;
|
|
22
|
+
counts[agentId] = (counts[agentId] ?? 0) + 1;
|
|
23
|
+
}
|
|
24
|
+
return counts;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Derives each mneme bank's memory-write count, per-agent write signal, and
|
|
28
|
+
* recall count.
|
|
29
|
+
*
|
|
30
|
+
* Ledger-first (Slice B Piece 4b): mneme stamps a `memory.written` causal
|
|
31
|
+
* event (`noopolis.causal-event.v1`, same `memory/causal.jsonl` stream as
|
|
32
|
+
* `memory.recalled`) on every durable memory register, with
|
|
33
|
+
* `cause_event_ids` chaining it to the wake/turn that produced it. When a
|
|
34
|
+
* bank's reconciled causal stream (`causalEventsByBank`) contains at least
|
|
35
|
+
* one `memory.written` event, that count is authoritative
|
|
36
|
+
* (`memory_write_source: "ledger"`), and `writes_by_agent` is derived from
|
|
37
|
+
* each event's `principal_id`.
|
|
38
|
+
*
|
|
39
|
+
* Fallback (pre-4b runs, e.g. the office-sim golden fixture captured before
|
|
40
|
+
* mneme shipped the write-side event): if a bank's causal stream has ZERO
|
|
41
|
+
* `memory.written` events, this falls back to the interim signal — mneme's
|
|
42
|
+
* own `raw/mneme/<bank>/events.jsonl` bank event log (line count as the
|
|
43
|
+
* write proxy) — marking `memory_write_source: "events-fallback"` so a
|
|
44
|
+
* stale run is visibly on the fallback, never silently. If neither
|
|
45
|
+
* `events.jsonl` nor any `memory.written` event exists, `events` is 0.
|
|
46
|
+
*
|
|
47
|
+
* `recalls` is unaffected by which write source wins: it always prefers
|
|
48
|
+
* `events.jsonl`'s own `memory.recalled` lines when the file exists, falling
|
|
49
|
+
* back to the bank's `memory.recalled` causal events otherwise — the same
|
|
50
|
+
* behavior this function had before Piece 4b.
|
|
51
|
+
*/
|
|
52
|
+
export const collectMemoryBankCounts = async (runDir, causalEventsByBank) => {
|
|
53
|
+
const mnemeDir = path.join(runDir, "raw", "mneme");
|
|
54
|
+
const bankDirs = await readdir(mnemeDir, { withFileTypes: true }).catch(() => []);
|
|
55
|
+
const results = [];
|
|
56
|
+
for (const entry of bankDirs) {
|
|
57
|
+
if (!entry.isDirectory())
|
|
58
|
+
continue;
|
|
59
|
+
const bank = entry.name;
|
|
60
|
+
const bankCausalEvents = causalEventsByBank.get(bank) ?? [];
|
|
61
|
+
const eventsPath = path.join(mnemeDir, bank, "events.jsonl");
|
|
62
|
+
const eventsText = await readFile(eventsPath, "utf8").catch(() => null);
|
|
63
|
+
const eventsJsonlLines = eventsText !== null ? countJsonlLines(eventsText) : null;
|
|
64
|
+
const recalls = eventsJsonlLines !== null
|
|
65
|
+
? countRecallsFromEventsJsonl(eventsJsonlLines)
|
|
66
|
+
: bankCausalEvents.filter((event) => event.type === "memory.recalled").length;
|
|
67
|
+
const ledgerWrites = bankCausalEvents.filter((event) => event.type === "memory.written");
|
|
68
|
+
if (ledgerWrites.length > 0) {
|
|
69
|
+
results.push({
|
|
70
|
+
bank,
|
|
71
|
+
events: ledgerWrites.length,
|
|
72
|
+
recalls,
|
|
73
|
+
memory_write_source: "ledger",
|
|
74
|
+
writes_by_agent: countByAgent(ledgerWrites)
|
|
75
|
+
});
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
results.push({
|
|
79
|
+
bank,
|
|
80
|
+
events: eventsJsonlLines !== null ? eventsJsonlLines.length : 0,
|
|
81
|
+
recalls,
|
|
82
|
+
memory_write_source: "events-fallback"
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return results.sort((left, right) => left.bank.localeCompare(right.bank));
|
|
86
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ArtifactIntegrityCheck } from "./artifacts.js";
|
|
2
|
+
import type { CausalStreamSource } from "./causalStreams.js";
|
|
3
|
+
import type { SimfileRunManifest } from "./manifest.js";
|
|
4
|
+
import type { SimfileObserveReport } from "./report.js";
|
|
5
|
+
import { type SeedSpreadSelfCheck } from "./seedSpread.js";
|
|
6
|
+
export interface ObserveResult {
|
|
7
|
+
artifactIntegrity: ArtifactIntegrityCheck[];
|
|
8
|
+
causalParseErrors: {
|
|
9
|
+
relativePath: string;
|
|
10
|
+
line: number;
|
|
11
|
+
message: string;
|
|
12
|
+
}[];
|
|
13
|
+
manifest: SimfileRunManifest;
|
|
14
|
+
report: SimfileObserveReport;
|
|
15
|
+
streams: CausalStreamSource[];
|
|
16
|
+
/** Memetics increment (b): present only when `manifest.seed_declaration`
|
|
17
|
+
* exists — the live-`marker.seen` self-check, diagnostic only (never fed
|
|
18
|
+
* into `report.seed_spread`, see `seedSpread.ts`'s own doc comment). */
|
|
19
|
+
spreadSelfCheck?: SeedSpreadSelfCheck;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Reads a sealed run directory (`manifest.json` + `raw/**\/causal.jsonl` +
|
|
23
|
+
* per-bank `raw/mneme/<bank>/events.jsonl`), reconciles the causal streams
|
|
24
|
+
* with `@noopolis/stele` (no stitching, ever — an incomplete chain is
|
|
25
|
+
* flagged, not synthesized), and emits the `simfile.observe.v1` report.
|
|
26
|
+
* Pure file-reading + reconciliation: no Docker, no compile, no runtime
|
|
27
|
+
* auth (this package's charter, `ecosystem/simfile/AGENTS.md`).
|
|
28
|
+
*/
|
|
29
|
+
export declare const runObserve: (runDir: string) => Promise<ObserveResult>;
|
|
30
|
+
/** Writes `observe/report.json` under the run directory; returns its path. */
|
|
31
|
+
export declare const writeObserveReport: (runDir: string, report: SimfileObserveReport) => Promise<string>;
|
|
32
|
+
//# sourceMappingURL=observe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../../src/observe/observe.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAE7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAI7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAA0D,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAOnH,MAAM,WAAW,aAAa;IAC5B,iBAAiB,EAAE,sBAAsB,EAAE,CAAC;IAC5C,iBAAiB,EAAE;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC7E,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,MAAM,EAAE,oBAAoB,CAAC;IAC7B,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B;;4EAEwE;IACxE,eAAe,CAAC,EAAE,mBAAmB,CAAC;CACvC;AAaD;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,GAAU,QAAQ,MAAM,KAAG,OAAO,CAAC,aAAa,CAmDtE,CAAC;AAEF,8EAA8E;AAC9E,eAAO,MAAM,kBAAkB,GAAU,QAAQ,MAAM,EAAE,QAAQ,oBAAoB,KAAG,OAAO,CAAC,MAAM,CAMrG,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { reconcileEvents } from "@noopolis/stele";
|
|
4
|
+
import { verifyManifestArtifacts } from "./artifacts.js";
|
|
5
|
+
import { collectCausalStreams } from "./causalStreams.js";
|
|
6
|
+
import { buildObserveReport } from "./compute.js";
|
|
7
|
+
import { collectMemoryBankCounts } from "./memoryBanks.js";
|
|
8
|
+
import { parseRunManifest } from "./manifest.js";
|
|
9
|
+
import { computeSeedSpread, diffSeedSpreadAgainstLiveMarkerSeen } from "./seedSpread.js";
|
|
10
|
+
import { readSpreadTranscriptMessages, readTickByIngestedMessageId, readSpreadMnemeEventsByBank } from "./seedSpreadArtifacts.js";
|
|
11
|
+
const loadRunManifest = async (runDir) => {
|
|
12
|
+
const raw = JSON.parse(await readFile(path.join(runDir, "manifest.json"), "utf8"));
|
|
13
|
+
return parseRunManifest(raw);
|
|
14
|
+
};
|
|
15
|
+
const bankFromRelativePath = (relativePath) => {
|
|
16
|
+
// raw/mneme/<bank>/causal.jsonl
|
|
17
|
+
const segments = relativePath.split(path.sep);
|
|
18
|
+
return segments[0] === "raw" && segments[1] === "mneme" ? segments[2] : undefined;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Reads a sealed run directory (`manifest.json` + `raw/**\/causal.jsonl` +
|
|
22
|
+
* per-bank `raw/mneme/<bank>/events.jsonl`), reconciles the causal streams
|
|
23
|
+
* with `@noopolis/stele` (no stitching, ever — an incomplete chain is
|
|
24
|
+
* flagged, not synthesized), and emits the `simfile.observe.v1` report.
|
|
25
|
+
* Pure file-reading + reconciliation: no Docker, no compile, no runtime
|
|
26
|
+
* auth (this package's charter, `ecosystem/simfile/AGENTS.md`).
|
|
27
|
+
*/
|
|
28
|
+
export const runObserve = async (runDir) => {
|
|
29
|
+
const manifest = await loadRunManifest(runDir);
|
|
30
|
+
const artifactIntegrity = await verifyManifestArtifacts(runDir, manifest.artifacts);
|
|
31
|
+
const streams = await collectCausalStreams(runDir);
|
|
32
|
+
const causalParseErrors = streams.flatMap((stream) => stream.errors.map((error) => ({ relativePath: stream.relativePath, ...error })));
|
|
33
|
+
const allEvents = streams.flatMap((stream) => stream.events);
|
|
34
|
+
const reconciled = reconcileEvents(allEvents);
|
|
35
|
+
const eventsByBank = new Map();
|
|
36
|
+
for (const stream of streams) {
|
|
37
|
+
const bank = bankFromRelativePath(stream.relativePath);
|
|
38
|
+
if (!bank)
|
|
39
|
+
continue;
|
|
40
|
+
eventsByBank.set(bank, [...(eventsByBank.get(bank) ?? []), ...stream.events]);
|
|
41
|
+
}
|
|
42
|
+
const memoryBanks = await collectMemoryBankCounts(runDir, eventsByBank);
|
|
43
|
+
let seedSpread;
|
|
44
|
+
let spreadSelfCheck;
|
|
45
|
+
if (manifest.seed_declaration) {
|
|
46
|
+
const [transcriptMessages, mnemeEventsByBank, tickByMoltnetMessageId] = await Promise.all([
|
|
47
|
+
readSpreadTranscriptMessages(runDir),
|
|
48
|
+
readSpreadMnemeEventsByBank(runDir),
|
|
49
|
+
readTickByIngestedMessageId(runDir)
|
|
50
|
+
]);
|
|
51
|
+
const causalEventsById = new Map(allEvents.map((event) => [event.event_id, event]));
|
|
52
|
+
seedSpread = computeSeedSpread({
|
|
53
|
+
seedDeclaration: manifest.seed_declaration,
|
|
54
|
+
causalEventsById,
|
|
55
|
+
transcriptMessages,
|
|
56
|
+
causalEventsByBank: eventsByBank,
|
|
57
|
+
mnemeEventsByBank,
|
|
58
|
+
tickByMoltnetMessageId
|
|
59
|
+
});
|
|
60
|
+
const worldEvents = streams.filter((stream) => stream.authority === "world").flatMap((stream) => stream.events);
|
|
61
|
+
spreadSelfCheck = diffSeedSpreadAgainstLiveMarkerSeen(worldEvents, transcriptMessages, manifest.seed_declaration.token_set, manifest.seed_declaration.matcher_policy);
|
|
62
|
+
}
|
|
63
|
+
const report = buildObserveReport({ allEvents, manifest, memoryBanks, reconciled, seedSpread });
|
|
64
|
+
return { artifactIntegrity, causalParseErrors, manifest, report, streams, spreadSelfCheck };
|
|
65
|
+
};
|
|
66
|
+
/** Writes `observe/report.json` under the run directory; returns its path. */
|
|
67
|
+
export const writeObserveReport = async (runDir, report) => {
|
|
68
|
+
const observeDir = path.join(runDir, "observe");
|
|
69
|
+
await mkdir(observeDir, { recursive: true });
|
|
70
|
+
const reportPath = path.join(observeDir, "report.json");
|
|
71
|
+
await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`, "utf8");
|
|
72
|
+
return reportPath;
|
|
73
|
+
};
|