@quolu/lattice 0.1.0 → 0.12.2
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 +87 -4
- package/bin/lattice-bridge.mjs +87 -0
- package/bin/lattice-dashboard.mjs +70 -0
- package/bin/lattice-mcp.mjs +9 -9
- package/bin/lattice.mjs +61 -8
- package/docs/bridge-setup.md +87 -0
- package/docs/schemas/lattice.plan_create_input.v1.schema.json +56 -0
- package/docs/schemas/lattice.plan_create_input.v2.schema.json +72 -0
- package/docs/schemas/lattice.plan_create_input.v3.schema.json +81 -0
- package/package.json +19 -7
- package/sensor/dist/bin/command-supervision.d.ts +1 -1
- package/sensor/dist/bin/command-supervision.js +4 -4
- package/sensor/dist/bin/command-supervision.js.map +1 -1
- package/sensor/dist/bin/fatal-handler.js +2 -2
- package/sensor/dist/bin/fatal-handler.js.map +1 -1
- package/sensor/dist/bin/{codegraph.js → lattice-sensor.js} +207 -328
- package/sensor/dist/bin/node-version-check.d.ts +7 -5
- package/sensor/dist/bin/node-version-check.d.ts.map +1 -1
- package/sensor/dist/bin/node-version-check.js +19 -14
- package/sensor/dist/bin/node-version-check.js.map +1 -1
- package/sensor/dist/context/index.d.ts +1 -1
- package/sensor/dist/context/index.js +6 -6
- package/sensor/dist/context/index.js.map +1 -1
- package/sensor/dist/db/index.d.ts +5 -5
- package/sensor/dist/db/index.d.ts.map +1 -1
- package/sensor/dist/db/index.js +7 -7
- package/sensor/dist/db/index.js.map +1 -1
- package/sensor/dist/db/migrations.js +1 -1
- package/sensor/dist/db/migrations.js.map +1 -1
- package/sensor/dist/db/queries.d.ts +1 -1
- package/sensor/dist/db/queries.js +5 -5
- package/sensor/dist/db/queries.js.map +1 -1
- package/sensor/dist/db/schema.sql +2 -2
- package/sensor/dist/db/sqlite-adapter.d.ts +2 -2
- package/sensor/dist/db/sqlite-adapter.js +3 -3
- package/sensor/dist/db/sqlite-adapter.js.map +1 -1
- package/sensor/dist/db/wal-valve.d.ts +1 -1
- package/sensor/dist/db/wal-valve.d.ts.map +1 -1
- package/sensor/dist/db/wal-valve.js +2 -2
- package/sensor/dist/db/wal-valve.js.map +1 -1
- package/sensor/dist/directory.d.ts +27 -63
- package/sensor/dist/directory.d.ts.map +1 -1
- package/sensor/dist/directory.js +78 -134
- package/sensor/dist/directory.js.map +1 -1
- package/sensor/dist/errors.d.ts +15 -15
- package/sensor/dist/errors.d.ts.map +1 -1
- package/sensor/dist/errors.js +21 -21
- package/sensor/dist/errors.js.map +1 -1
- package/sensor/dist/extraction/dynamic-import.d.ts +1 -1
- package/sensor/dist/extraction/dynamic-import.js +1 -1
- package/sensor/dist/extraction/extraction-version.d.ts +1 -1
- package/sensor/dist/extraction/extraction-version.js +1 -1
- package/sensor/dist/extraction/generated-detection.d.ts +1 -1
- package/sensor/dist/extraction/generated-detection.js +1 -1
- package/sensor/dist/extraction/grammars.d.ts +3 -3
- package/sensor/dist/extraction/grammars.js +5 -5
- package/sensor/dist/extraction/grammars.js.map +1 -1
- package/sensor/dist/extraction/index.d.ts +6 -6
- package/sensor/dist/extraction/index.js +50 -50
- package/sensor/dist/extraction/index.js.map +1 -1
- package/sensor/dist/extraction/kernel/decode.d.ts +1 -1
- package/sensor/dist/extraction/kernel/decode.js +1 -1
- package/sensor/dist/extraction/kernel/index.d.ts +3 -3
- package/sensor/dist/extraction/kernel/index.js +6 -6
- package/sensor/dist/extraction/kernel/index.js.map +1 -1
- package/sensor/dist/extraction/kernel/layout.d.ts +1 -1
- package/sensor/dist/extraction/kernel/layout.js +1 -1
- package/sensor/dist/extraction/kernel/loader.d.ts +6 -6
- package/sensor/dist/extraction/kernel/loader.js +13 -13
- package/sensor/dist/extraction/kernel/loader.js.map +1 -1
- package/sensor/dist/extraction/languages/cfquery.d.ts +1 -1
- package/sensor/dist/extraction/languages/cfquery.js +1 -1
- package/sensor/dist/extraction/languages/lua.d.ts +11 -0
- package/sensor/dist/extraction/languages/lua.d.ts.map +1 -1
- package/sensor/dist/extraction/languages/lua.js +1 -0
- package/sensor/dist/extraction/languages/lua.js.map +1 -1
- package/sensor/dist/extraction/parse-pool.d.ts +5 -5
- package/sensor/dist/extraction/parse-pool.d.ts.map +1 -1
- package/sensor/dist/extraction/parse-pool.js +4 -4
- package/sensor/dist/extraction/parse-worker.js +1 -1
- package/sensor/dist/extraction/parse-worker.js.map +1 -1
- package/sensor/dist/extraction/store-writer.d.ts +1 -1
- package/sensor/dist/extraction/store-writer.js +1 -1
- package/sensor/dist/extraction/svelte-extractor.d.ts +1 -1
- package/sensor/dist/extraction/svelte-extractor.js +1 -1
- package/sensor/dist/extraction/tree-sitter-helpers.js +1 -1
- package/sensor/dist/extraction/tree-sitter.d.ts +2 -2
- package/sensor/dist/extraction/tree-sitter.d.ts.map +1 -1
- package/sensor/dist/extraction/tree-sitter.js +71 -4
- package/sensor/dist/extraction/tree-sitter.js.map +1 -1
- package/sensor/dist/extraction/wasm-runtime-flags.d.ts +2 -2
- package/sensor/dist/extraction/wasm-runtime-flags.d.ts.map +1 -1
- package/sensor/dist/extraction/wasm-runtime-flags.js +5 -5
- package/sensor/dist/extraction/wasm-runtime-flags.js.map +1 -1
- package/sensor/dist/index.d.ts +36 -36
- package/sensor/dist/index.d.ts.map +1 -1
- package/sensor/dist/index.js +71 -71
- package/sensor/dist/index.js.map +1 -1
- package/sensor/dist/mcp/daemon-manager.js +1 -1
- package/sensor/dist/mcp/daemon-paths.d.ts +3 -3
- package/sensor/dist/mcp/daemon-paths.js +7 -7
- package/sensor/dist/mcp/daemon-paths.js.map +1 -1
- package/sensor/dist/mcp/daemon-registry.d.ts +2 -2
- package/sensor/dist/mcp/daemon-registry.js +5 -5
- package/sensor/dist/mcp/daemon.d.ts +7 -7
- package/sensor/dist/mcp/daemon.d.ts.map +1 -1
- package/sensor/dist/mcp/daemon.js +21 -21
- package/sensor/dist/mcp/daemon.js.map +1 -1
- package/sensor/dist/mcp/dynamic-boundaries.js +1 -1
- package/sensor/dist/mcp/engine.d.ts +9 -9
- package/sensor/dist/mcp/engine.d.ts.map +1 -1
- package/sensor/dist/mcp/engine.js +44 -44
- package/sensor/dist/mcp/engine.js.map +1 -1
- package/sensor/dist/mcp/index.d.ts +14 -14
- package/sensor/dist/mcp/index.d.ts.map +1 -1
- package/sensor/dist/mcp/index.js +41 -41
- package/sensor/dist/mcp/index.js.map +1 -1
- package/sensor/dist/mcp/liveness-watchdog.js +7 -7
- package/sensor/dist/mcp/liveness-watchdog.js.map +1 -1
- package/sensor/dist/mcp/ppid-watchdog.d.ts +3 -3
- package/sensor/dist/mcp/ppid-watchdog.js +2 -2
- package/sensor/dist/mcp/proxy.d.ts.map +1 -1
- package/sensor/dist/mcp/proxy.js +37 -37
- package/sensor/dist/mcp/proxy.js.map +1 -1
- package/sensor/dist/mcp/query-pool.d.ts +3 -3
- package/sensor/dist/mcp/query-pool.js +7 -7
- package/sensor/dist/mcp/query-pool.js.map +1 -1
- package/sensor/dist/mcp/query-worker.d.ts +2 -2
- package/sensor/dist/mcp/query-worker.js +7 -7
- package/sensor/dist/mcp/query-worker.js.map +1 -1
- package/sensor/dist/mcp/server-instructions.d.ts +10 -12
- package/sensor/dist/mcp/server-instructions.d.ts.map +1 -1
- package/sensor/dist/mcp/server-instructions.js +39 -37
- package/sensor/dist/mcp/server-instructions.js.map +1 -1
- package/sensor/dist/mcp/session.d.ts +2 -2
- package/sensor/dist/mcp/session.js +18 -18
- package/sensor/dist/mcp/session.js.map +1 -1
- package/sensor/dist/mcp/startup-handshake.d.ts +3 -3
- package/sensor/dist/mcp/startup-handshake.d.ts.map +1 -1
- package/sensor/dist/mcp/startup-handshake.js +3 -3
- package/sensor/dist/mcp/startup-handshake.js.map +1 -1
- package/sensor/dist/mcp/tools.d.ts +53 -53
- package/sensor/dist/mcp/tools.d.ts.map +1 -1
- package/sensor/dist/mcp/tools.js +180 -216
- package/sensor/dist/mcp/tools.js.map +1 -1
- package/sensor/dist/mcp/transport.d.ts +1 -1
- package/sensor/dist/mcp/transport.js +6 -6
- package/sensor/dist/mcp/transport.js.map +1 -1
- package/sensor/dist/mcp/version.d.ts +2 -2
- package/sensor/dist/mcp/version.d.ts.map +1 -1
- package/sensor/dist/mcp/version.js +3 -3
- package/sensor/dist/mcp/version.js.map +1 -1
- package/sensor/dist/project-config.d.ts +6 -6
- package/sensor/dist/project-config.d.ts.map +1 -1
- package/sensor/dist/project-config.js +10 -10
- package/sensor/dist/project-config.js.map +1 -1
- package/sensor/dist/resolution/callback-synthesizer.js +4 -4
- package/sensor/dist/resolution/callback-synthesizer.js.map +1 -1
- package/sensor/dist/resolution/frameworks/drupal.d.ts +3 -3
- package/sensor/dist/resolution/frameworks/drupal.js +3 -3
- package/sensor/dist/resolution/frameworks/fabric.js +1 -1
- package/sensor/dist/resolution/frameworks/fabric.js.map +1 -1
- package/sensor/dist/resolution/frameworks/java.js +1 -1
- package/sensor/dist/resolution/frameworks/java.js.map +1 -1
- package/sensor/dist/resolution/frameworks/svelte.js +1 -1
- package/sensor/dist/resolution/frameworks/svelte.js.map +1 -1
- package/sensor/dist/resolution/goframe-synthesizer.d.ts +1 -1
- package/sensor/dist/resolution/goframe-synthesizer.js +1 -1
- package/sensor/dist/resolution/index.d.ts +1 -1
- package/sensor/dist/resolution/index.js +9 -9
- package/sensor/dist/resolution/index.js.map +1 -1
- package/sensor/dist/resolution/name-matcher.js +2 -2
- package/sensor/dist/resolution/name-matcher.js.map +1 -1
- package/sensor/dist/resolution/resolver-pool.d.ts +2 -2
- package/sensor/dist/resolution/resolver-pool.js +4 -4
- package/sensor/dist/resolution/resolver-pool.js.map +1 -1
- package/sensor/dist/resolution/resolver-worker.js +2 -2
- package/sensor/dist/resolution/resolver-worker.js.map +1 -1
- package/sensor/dist/resolution/workspace-packages.js +1 -1
- package/sensor/dist/resolution/workspace-packages.js.map +1 -1
- package/sensor/dist/search/identifier-segments.d.ts +1 -1
- package/sensor/dist/search/identifier-segments.js +1 -1
- package/sensor/dist/search/query-utils.d.ts +1 -0
- package/sensor/dist/search/query-utils.d.ts.map +1 -1
- package/sensor/dist/search/query-utils.js +10 -3
- package/sensor/dist/search/query-utils.js.map +1 -1
- package/sensor/dist/sync/git-hooks.d.ts +9 -9
- package/sensor/dist/sync/git-hooks.d.ts.map +1 -1
- package/sensor/dist/sync/git-hooks.js +15 -15
- package/sensor/dist/sync/git-hooks.js.map +1 -1
- package/sensor/dist/sync/watch-policy.d.ts +2 -2
- package/sensor/dist/sync/watch-policy.js +5 -5
- package/sensor/dist/sync/watch-policy.js.map +1 -1
- package/sensor/dist/sync/watcher.d.ts +2 -2
- package/sensor/dist/sync/watcher.d.ts.map +1 -1
- package/sensor/dist/sync/watcher.js +16 -16
- package/sensor/dist/sync/watcher.js.map +1 -1
- package/sensor/dist/sync/worktree.d.ts +5 -5
- package/sensor/dist/sync/worktree.d.ts.map +1 -1
- package/sensor/dist/sync/worktree.js +9 -9
- package/sensor/dist/sync/worktree.js.map +1 -1
- package/sensor/dist/telemetry/index.d.ts +8 -8
- package/sensor/dist/telemetry/index.d.ts.map +1 -1
- package/sensor/dist/telemetry/index.js +16 -16
- package/sensor/dist/telemetry/index.js.map +1 -1
- package/sensor/dist/types.d.ts +2 -2
- package/sensor/dist/types.js +1 -1
- package/sensor/dist/ui/color.d.ts +2 -2
- package/sensor/dist/ui/color.js +2 -2
- package/sensor/dist/ui/glyphs.d.ts +3 -3
- package/sensor/dist/ui/glyphs.js +7 -7
- package/sensor/dist/ui/glyphs.js.map +1 -1
- package/sensor/dist/utils.d.ts +4 -4
- package/sensor/dist/utils.js +8 -8
- package/sensor/dist/utils.js.map +1 -1
- package/sensor/package.json +8 -13
- package/src/artifact-contracts.mjs +2 -2
- package/src/boundary-compiler.mjs +28 -28
- package/src/boundary-observation-compiler-v2.mjs +10 -10
- package/src/bounded-seam.mjs +144 -0
- package/src/bridge-cli.mjs +227 -0
- package/src/bridge-config.mjs +346 -0
- package/src/bridge-daemon.mjs +328 -0
- package/src/bridge-launch-agent.mjs +311 -0
- package/src/bridge-server.mjs +309 -0
- package/src/cli-help.mjs +163 -0
- package/src/control-compiler.mjs +30 -30
- package/src/dag-chain.mjs +261 -0
- package/src/factory-diagnostics.mjs +8 -7
- package/src/hash-chain.mjs +76 -0
- package/src/node-version-guard.mjs +5 -4
- package/src/project-cli.mjs +392 -0
- package/src/project-identity.mjs +71 -0
- package/src/rc1-evidence-bundle.mjs +16 -16
- package/src/rc1-v4-campaign.mjs +15 -14
- package/src/rc1-v5-artifact-set.mjs +2 -2
- package/src/rc1-v5-campaign.mjs +15 -14
- package/src/rc1-v6-artifact-set.mjs +18 -18
- package/src/rc1-v6-campaign.mjs +16 -16
- package/src/rc1-v6-causal-binding.mjs +16 -14
- package/src/rc1-v6-measurement.mjs +20 -38
- package/src/rc2-artifact-set.mjs +45 -40
- package/src/rc2-campaign.mjs +48 -66
- package/src/rc2-delivery-policy-front-end.mjs +30 -30
- package/src/rc2-rc1-transfer-front-end.mjs +5 -5
- package/src/rc3-actual-dogfood.mjs +6 -6
- package/src/rc3-dogfood-scaffold.mjs +12 -7
- package/src/rc3-scripted-campaign.mjs +75 -21
- package/src/rc4-stage1-dogfood.mjs +24 -7
- package/src/runtime-cli.mjs +2424 -45
- package/src/runtime-contracts.mjs +7 -7
- package/src/runtime-control-store.mjs +547 -0
- package/src/runtime-controller-protocol.mjs +517 -0
- package/src/runtime-direct-os-observer.mjs +284 -0
- package/src/runtime-engine.mjs +2 -2
- package/src/runtime-errors.mjs +1 -1
- package/src/runtime-event-store.mjs +15 -43
- package/src/runtime-front-end.mjs +26 -26
- package/src/runtime-gate-store.mjs +477 -0
- package/src/runtime-hold-recompile.mjs +214 -23
- package/src/runtime-lifecycle-lock.mjs +290 -0
- package/src/runtime-managed-supervisor.mjs +1276 -0
- package/src/runtime-multi-epoch-store.mjs +761 -0
- package/src/runtime-projection.mjs +62 -0
- package/src/seam-transform.mjs +38 -38
- package/src/{codegraph-adapter.mjs → sensor-adapter.mjs} +7 -7
- package/src/sensor-cli.mjs +107 -0
- package/src/sensor-runtime.mjs +48 -0
- package/src/timestamp-contract.mjs +8 -0
- package/src/todo-chain.mjs +178 -0
- package/src/todo-cli.mjs +1032 -0
- package/src/todo-contracts.mjs +501 -0
- package/src/todo-dashboard-registry.mjs +318 -0
- package/src/todo-gantt-html.mjs +416 -0
- package/src/todo-gantt-layout.mjs +603 -0
- package/src/todo-gantt-live.mjs +269 -0
- package/src/todo-gantt-presentation.mjs +217 -0
- package/src/todo-gantt-svg.mjs +249 -0
- package/src/todo-markdown-renderer.mjs +260 -0
- package/src/todo-migration.mjs +260 -0
- package/src/todo-narrative-anchor.mjs +130 -0
- package/src/todo-revision.mjs +425 -0
- package/src/todo-status.mjs +340 -0
- package/src/todo-store.mjs +3451 -0
- package/src/treatment-compiler.mjs +28 -28
- package/src/treatment-runner.mjs +42 -44
- package/sensor/dist/bin/codegraph.d.ts +0 -26
- package/sensor/dist/bin/codegraph.d.ts.map +0 -1
- package/sensor/dist/bin/codegraph.js.map +0 -1
- package/sensor/dist/bin/uninstall.d.ts +0 -14
- package/sensor/dist/bin/uninstall.d.ts.map +0 -1
- package/sensor/dist/bin/uninstall.js +0 -36
- package/sensor/dist/bin/uninstall.js.map +0 -1
- package/sensor/dist/installer/beta-signup.d.ts +0 -54
- package/sensor/dist/installer/beta-signup.d.ts.map +0 -1
- package/sensor/dist/installer/beta-signup.js +0 -178
- package/sensor/dist/installer/beta-signup.js.map +0 -1
- package/sensor/dist/installer/config-writer.d.ts +0 -28
- package/sensor/dist/installer/config-writer.d.ts.map +0 -1
- package/sensor/dist/installer/config-writer.js +0 -91
- package/sensor/dist/installer/config-writer.js.map +0 -1
- package/sensor/dist/installer/index.d.ts +0 -142
- package/sensor/dist/installer/index.d.ts.map +0 -1
- package/sensor/dist/installer/index.js +0 -622
- package/sensor/dist/installer/index.js.map +0 -1
- package/sensor/dist/installer/instructions-template.d.ts +0 -41
- package/sensor/dist/installer/instructions-template.d.ts.map +0 -1
- package/sensor/dist/installer/instructions-template.js +0 -53
- package/sensor/dist/installer/instructions-template.js.map +0 -1
- package/sensor/dist/installer/targets/antigravity.d.ts +0 -57
- package/sensor/dist/installer/targets/antigravity.d.ts.map +0 -1
- package/sensor/dist/installer/targets/antigravity.js +0 -308
- package/sensor/dist/installer/targets/antigravity.js.map +0 -1
- package/sensor/dist/installer/targets/claude.d.ts +0 -62
- package/sensor/dist/installer/targets/claude.d.ts.map +0 -1
- package/sensor/dist/installer/targets/claude.js +0 -454
- package/sensor/dist/installer/targets/claude.js.map +0 -1
- package/sensor/dist/installer/targets/codex.d.ts +0 -18
- package/sensor/dist/installer/targets/codex.d.ts.map +0 -1
- package/sensor/dist/installer/targets/codex.js +0 -185
- package/sensor/dist/installer/targets/codex.js.map +0 -1
- package/sensor/dist/installer/targets/cursor.d.ts +0 -35
- package/sensor/dist/installer/targets/cursor.d.ts.map +0 -1
- package/sensor/dist/installer/targets/cursor.js +0 -254
- package/sensor/dist/installer/targets/cursor.js.map +0 -1
- package/sensor/dist/installer/targets/gemini.d.ts +0 -26
- package/sensor/dist/installer/targets/gemini.d.ts.map +0 -1
- package/sensor/dist/installer/targets/gemini.js +0 -165
- package/sensor/dist/installer/targets/gemini.js.map +0 -1
- package/sensor/dist/installer/targets/hermes.d.ts +0 -18
- package/sensor/dist/installer/targets/hermes.d.ts.map +0 -1
- package/sensor/dist/installer/targets/hermes.js +0 -359
- package/sensor/dist/installer/targets/hermes.js.map +0 -1
- package/sensor/dist/installer/targets/kiro.d.ts +0 -27
- package/sensor/dist/installer/targets/kiro.d.ts.map +0 -1
- package/sensor/dist/installer/targets/kiro.js +0 -178
- package/sensor/dist/installer/targets/kiro.js.map +0 -1
- package/sensor/dist/installer/targets/opencode.d.ts +0 -38
- package/sensor/dist/installer/targets/opencode.d.ts.map +0 -1
- package/sensor/dist/installer/targets/opencode.js +0 -288
- package/sensor/dist/installer/targets/opencode.js.map +0 -1
- package/sensor/dist/installer/targets/registry.d.ts +0 -35
- package/sensor/dist/installer/targets/registry.d.ts.map +0 -1
- package/sensor/dist/installer/targets/registry.js +0 -91
- package/sensor/dist/installer/targets/registry.js.map +0 -1
- package/sensor/dist/installer/targets/shared.d.ts +0 -101
- package/sensor/dist/installer/targets/shared.d.ts.map +0 -1
- package/sensor/dist/installer/targets/shared.js +0 -264
- package/sensor/dist/installer/targets/shared.js.map +0 -1
- package/sensor/dist/installer/targets/toml.d.ts +0 -52
- package/sensor/dist/installer/targets/toml.d.ts.map +0 -1
- package/sensor/dist/installer/targets/toml.js +0 -147
- package/sensor/dist/installer/targets/toml.js.map +0 -1
- package/sensor/dist/installer/targets/types.d.ts +0 -108
- package/sensor/dist/installer/targets/types.d.ts.map +0 -1
- package/sensor/dist/installer/targets/types.js +0 -16
- package/sensor/dist/installer/targets/types.js.map +0 -1
- package/sensor/dist/upgrade/index.d.ts +0 -171
- package/sensor/dist/upgrade/index.d.ts.map +0 -1
- package/sensor/dist/upgrade/index.js +0 -659
- package/sensor/dist/upgrade/index.js.map +0 -1
- package/sensor/dist/upgrade/remove-binary.d.ts +0 -87
- package/sensor/dist/upgrade/remove-binary.d.ts.map +0 -1
- package/sensor/dist/upgrade/remove-binary.js +0 -289
- package/sensor/dist/upgrade/remove-binary.js.map +0 -1
- package/sensor/dist/upgrade/update-check.d.ts +0 -92
- package/sensor/dist/upgrade/update-check.d.ts.map +0 -1
- package/sensor/dist/upgrade/update-check.js +0 -258
- package/sensor/dist/upgrade/update-check.js.map +0 -1
- package/src/bootstrap.mjs +0 -88
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { lstat, realpath } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { promisify } from 'node:util';
|
|
5
|
+
|
|
6
|
+
import { digestArtifact } from './artifact-contracts.mjs';
|
|
7
|
+
import { selfDigest } from './runtime-contracts.mjs';
|
|
8
|
+
import { validateProcessStartIdentity } from './runtime-controller-protocol.mjs';
|
|
9
|
+
import { captureWorktreeDiff } from './runtime-diff-observer.mjs';
|
|
10
|
+
|
|
11
|
+
const execFileAsync = promisify(execFile);
|
|
12
|
+
const GIT_SHA1 = /^[0-9a-f]{40}$/;
|
|
13
|
+
const SHA256 = /^[0-9a-f]{64}$/;
|
|
14
|
+
|
|
15
|
+
export class DirectOsObservationError extends Error {
|
|
16
|
+
constructor(detail) {
|
|
17
|
+
super(`HOLD_ACKS_INCOMPLETE: ${detail}`);
|
|
18
|
+
this.name = 'DirectOsObservationError';
|
|
19
|
+
this.code = 'HOLD_ACKS_INCOMPLETE';
|
|
20
|
+
this.detail = detail;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function fail(detail) {
|
|
25
|
+
throw new DirectOsObservationError(detail);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function positivePid(value) {
|
|
29
|
+
return Number.isSafeInteger(value) && value > 0;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function identityFor(pid, startedIdentity) {
|
|
33
|
+
const identity = {
|
|
34
|
+
schema: 'lattice.process_start_identity.v1',
|
|
35
|
+
platform: process.platform,
|
|
36
|
+
pid,
|
|
37
|
+
started_identity: startedIdentity,
|
|
38
|
+
identity_digest: '',
|
|
39
|
+
};
|
|
40
|
+
identity.identity_digest = selfDigest(identity, 'identity_digest');
|
|
41
|
+
return identity;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function validExpectedProcess(value) {
|
|
45
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
46
|
+
&& Object.keys(value).sort().join('\0') === ['pid', 'process_group_id', 'process_start_identity'].sort().join('\0')
|
|
47
|
+
&& positivePid(value.pid) && positivePid(value.process_group_id)
|
|
48
|
+
&& validateProcessStartIdentity(value.process_start_identity)
|
|
49
|
+
&& value.process_start_identity.pid === value.pid;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function validateResolvedBinding(value) {
|
|
53
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)
|
|
54
|
+
|| !positivePid(value.process_pid) || !positivePid(value.process_group_id)
|
|
55
|
+
|| !validateProcessStartIdentity(value.process_start_identity)
|
|
56
|
+
|| value.process_start_identity.pid !== value.process_pid
|
|
57
|
+
|| !Array.isArray(value.process_children)
|
|
58
|
+
|| !value.process_children.every(validExpectedProcess)
|
|
59
|
+
|| typeof value.worktree_path !== 'string' || !path.isAbsolute(value.worktree_path)
|
|
60
|
+
|| typeof value.base_sha !== 'string' || !GIT_SHA1.test(value.base_sha)) {
|
|
61
|
+
fail('observation binding不正');
|
|
62
|
+
}
|
|
63
|
+
const pids = [value.process_pid, ...value.process_children.map((child) => child.pid)];
|
|
64
|
+
if (new Set(pids).size !== pids.length) fail('observation bindingのPID重複');
|
|
65
|
+
if (value.process_children.some((child) => child.process_group_id !== value.process_group_id)) {
|
|
66
|
+
fail('observation binding内のprocess group不一致');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function runPsSnapshot() {
|
|
71
|
+
try {
|
|
72
|
+
const { stdout } = await execFileAsync('/bin/ps', [
|
|
73
|
+
'-axo', 'pid=,ppid=,pgid=,state=,lstart=',
|
|
74
|
+
], { encoding: 'utf8', maxBuffer: 8 * 1024 * 1024 });
|
|
75
|
+
return stdout;
|
|
76
|
+
} catch (error) {
|
|
77
|
+
fail(`ps観測失敗: ${error?.code ?? error?.message ?? 'unknown'}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function parsePsSnapshot(stdout) {
|
|
82
|
+
if (typeof stdout !== 'string') fail('ps観測結果が文字列でない');
|
|
83
|
+
const records = new Map();
|
|
84
|
+
for (const rawLine of stdout.split('\n')) {
|
|
85
|
+
const line = rawLine.trim();
|
|
86
|
+
if (line.length === 0) continue;
|
|
87
|
+
const match = line.match(/^(\d+)\s+(\d+)\s+(\d+)\s+(\S+)\s+(.+)$/);
|
|
88
|
+
if (!match) fail(`ps観測結果を解析できない: ${line}`);
|
|
89
|
+
const pid = Number(match[1]);
|
|
90
|
+
const record = {
|
|
91
|
+
pid,
|
|
92
|
+
parent_pid: Number(match[2]),
|
|
93
|
+
process_group_id: Number(match[3]),
|
|
94
|
+
raw_state: match[4],
|
|
95
|
+
started_identity: match[5].trim(),
|
|
96
|
+
};
|
|
97
|
+
if (!positivePid(record.pid) || !Number.isSafeInteger(record.parent_pid) || record.parent_pid < 0
|
|
98
|
+
|| !positivePid(record.process_group_id) || record.started_identity.length === 0
|
|
99
|
+
|| records.has(pid)) fail('ps観測結果のprocess record不正');
|
|
100
|
+
records.set(pid, record);
|
|
101
|
+
}
|
|
102
|
+
if (records.size === 0) fail('ps観測結果が空');
|
|
103
|
+
return records;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function takePsSnapshot(psSnapshot) {
|
|
107
|
+
try {
|
|
108
|
+
return parsePsSnapshot(await psSnapshot());
|
|
109
|
+
} catch (error) {
|
|
110
|
+
if (error instanceof DirectOsObservationError) throw error;
|
|
111
|
+
fail(`ps観測失敗: ${error?.code ?? error?.message ?? 'unknown'}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function descendantPids(records, rootPid) {
|
|
116
|
+
const found = new Set();
|
|
117
|
+
let changed = true;
|
|
118
|
+
while (changed) {
|
|
119
|
+
changed = false;
|
|
120
|
+
for (const record of records.values()) {
|
|
121
|
+
if (record.pid !== rootPid && !found.has(record.pid)
|
|
122
|
+
&& (record.parent_pid === rootPid || found.has(record.parent_pid))) {
|
|
123
|
+
found.add(record.pid);
|
|
124
|
+
changed = true;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return found;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function stateOf(record) {
|
|
132
|
+
if (record.raw_state.startsWith('T')) return 'stopped';
|
|
133
|
+
if (record.raw_state.startsWith('Z')) return 'zombie';
|
|
134
|
+
fail(`processがquiescedでない: ${record.pid} (${record.raw_state})`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function verifyProcess(expected, actual, label) {
|
|
138
|
+
if (!actual) fail(`${label} processが見つからない: ${expected.pid}`);
|
|
139
|
+
const observedIdentity = identityFor(actual.pid, actual.started_identity);
|
|
140
|
+
if (observedIdentity.identity_digest !== expected.process_start_identity.identity_digest) {
|
|
141
|
+
fail(`${label} PID再利用又はstart identity差替え: ${expected.pid}`);
|
|
142
|
+
}
|
|
143
|
+
if (actual.process_group_id !== expected.process_group_id) {
|
|
144
|
+
fail(`${label} process group不一致: ${expected.pid}`);
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
pid: actual.pid,
|
|
148
|
+
parent_pid: actual.parent_pid,
|
|
149
|
+
process_start_identity_digest: observedIdentity.identity_digest,
|
|
150
|
+
process_group_id: actual.process_group_id,
|
|
151
|
+
state: stateOf(actual),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function sameDirectoryIdentity(before, after) {
|
|
156
|
+
return before.dev === after.dev && before.ino === after.ino;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async function inspectWorktree(worktreePath, expectedRealpath = null) {
|
|
160
|
+
let info;
|
|
161
|
+
let observedRealpath;
|
|
162
|
+
try {
|
|
163
|
+
info = await lstat(worktreePath);
|
|
164
|
+
observedRealpath = await realpath(worktreePath);
|
|
165
|
+
} catch (error) {
|
|
166
|
+
fail(`worktree観測失敗: ${error?.code ?? error?.message ?? 'unknown'}`);
|
|
167
|
+
}
|
|
168
|
+
if (!info.isDirectory() || info.isSymbolicLink()) fail('worktreeがreal directoryでない');
|
|
169
|
+
if (observedRealpath !== worktreePath) fail('worktree pathがsymlink又は非canonical');
|
|
170
|
+
if (expectedRealpath !== null && observedRealpath !== expectedRealpath) fail('worktree realpath差替え');
|
|
171
|
+
return { info, observedRealpath };
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** durable bindingへ保存するためのprocess start identityをDirect OSから取得する。 */
|
|
175
|
+
export async function observeDirectOsProcessStartIdentity(pid, { psSnapshot = runPsSnapshot } = {}) {
|
|
176
|
+
if (!positivePid(pid) || typeof psSnapshot !== 'function') fail('process identity観測入力不正');
|
|
177
|
+
const records = await takePsSnapshot(psSnapshot);
|
|
178
|
+
const record = records.get(pid);
|
|
179
|
+
if (!record) fail(`processが見つからない: ${pid}`);
|
|
180
|
+
return identityFor(pid, record.started_identity);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* RuntimeManagedSupervisorのprocessObserverとして渡すDirect OS observer。
|
|
185
|
+
* resolverはjournal由来のimmutable bindingへprocess_pid、start identity、PGID、
|
|
186
|
+
* process_children、worktree_path、base_shaを補完する。
|
|
187
|
+
*/
|
|
188
|
+
export function createDirectOsProcessObserver({
|
|
189
|
+
resolveObservationBinding,
|
|
190
|
+
psSnapshot = runPsSnapshot,
|
|
191
|
+
captureCheckpoint = captureWorktreeDiff,
|
|
192
|
+
} = {}) {
|
|
193
|
+
if (typeof resolveObservationBinding !== 'function' || typeof psSnapshot !== 'function'
|
|
194
|
+
|| typeof captureCheckpoint !== 'function') fail('Direct OS observer dependency不足');
|
|
195
|
+
return async ({ kind, binding, ack }) => {
|
|
196
|
+
if (!['quiescence', 'rebind'].includes(kind)) fail('未知のDirect OS observation kind');
|
|
197
|
+
const resolved = await resolveObservationBinding({
|
|
198
|
+
binding: structuredClone(binding),
|
|
199
|
+
ack: structuredClone(ack),
|
|
200
|
+
});
|
|
201
|
+
validateResolvedBinding(resolved);
|
|
202
|
+
|
|
203
|
+
const records = await takePsSnapshot(psSnapshot);
|
|
204
|
+
const expectedRoot = {
|
|
205
|
+
pid: resolved.process_pid,
|
|
206
|
+
process_group_id: resolved.process_group_id,
|
|
207
|
+
process_start_identity: resolved.process_start_identity,
|
|
208
|
+
};
|
|
209
|
+
const root = verifyProcess(expectedRoot, records.get(resolved.process_pid), 'root');
|
|
210
|
+
const actualDescendants = descendantPids(records, resolved.process_pid);
|
|
211
|
+
const expectedDescendants = new Set(resolved.process_children.map((child) => child.pid));
|
|
212
|
+
for (const pid of expectedDescendants) {
|
|
213
|
+
if (!actualDescendants.has(pid)) fail(`保存済みchildが見つからない: ${pid}`);
|
|
214
|
+
}
|
|
215
|
+
for (const pid of actualDescendants) {
|
|
216
|
+
if (!expectedDescendants.has(pid)) fail(`未記録childを検出: ${pid}`);
|
|
217
|
+
}
|
|
218
|
+
const expectedGroup = new Set([resolved.process_pid, ...expectedDescendants]);
|
|
219
|
+
for (const record of records.values()) {
|
|
220
|
+
if (record.process_group_id === resolved.process_group_id && !expectedGroup.has(record.pid)) {
|
|
221
|
+
fail(`未記録process group memberを検出: ${record.pid}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
const children = resolved.process_children
|
|
225
|
+
.map((expected) => verifyProcess(expected, records.get(expected.pid), 'child'))
|
|
226
|
+
.sort((left, right) => left.pid - right.pid);
|
|
227
|
+
|
|
228
|
+
const before = await inspectWorktree(resolved.worktree_path, resolved.worktree_realpath ?? null);
|
|
229
|
+
let checkpoint;
|
|
230
|
+
try {
|
|
231
|
+
checkpoint = await captureCheckpoint({ worktreePath: before.observedRealpath, baseSha: resolved.base_sha });
|
|
232
|
+
} catch (error) {
|
|
233
|
+
if (error instanceof DirectOsObservationError) throw error;
|
|
234
|
+
fail(`checkpoint観測失敗: ${error?.message ?? 'unknown'}`);
|
|
235
|
+
}
|
|
236
|
+
if (checkpoint === null || typeof checkpoint !== 'object' || !SHA256.test(checkpoint.checkpoint_digest ?? '')) {
|
|
237
|
+
fail('checkpoint観測結果不正');
|
|
238
|
+
}
|
|
239
|
+
const after = await inspectWorktree(resolved.worktree_path, before.observedRealpath);
|
|
240
|
+
if (!sameDirectoryIdentity(before.info, after.info)) fail('checkpoint観測中にworktreeが差替えられた');
|
|
241
|
+
|
|
242
|
+
const processObservation = {
|
|
243
|
+
schema: 'lattice.direct_process_observation.v2',
|
|
244
|
+
root,
|
|
245
|
+
children,
|
|
246
|
+
process_group_id: resolved.process_group_id,
|
|
247
|
+
quiesced: true,
|
|
248
|
+
};
|
|
249
|
+
const worktreeFingerprint = {
|
|
250
|
+
schema: 'lattice.direct_worktree_fingerprint.v1',
|
|
251
|
+
worktree_id: binding?.worktree_id ?? ack?.worktree_id,
|
|
252
|
+
worktree_realpath: after.observedRealpath,
|
|
253
|
+
checkpoint_digest: checkpoint.checkpoint_digest,
|
|
254
|
+
};
|
|
255
|
+
return {
|
|
256
|
+
quiesced: true,
|
|
257
|
+
process_observation_digest: digestArtifact(processObservation),
|
|
258
|
+
worktree_fingerprint_digest: digestArtifact(worktreeFingerprint),
|
|
259
|
+
final_checkpoint_digest: checkpoint.checkpoint_digest,
|
|
260
|
+
observation: processObservation,
|
|
261
|
+
worktree_fingerprint: worktreeFingerprint,
|
|
262
|
+
checkpoint,
|
|
263
|
+
write_enabled: false,
|
|
264
|
+
};
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/** running=0の事実だけを表し、process停止証拠には昇格しないreceipt。 */
|
|
269
|
+
export function createEmptyRunningObservationReceipt({ runId, barrierId, frozenEventDigest }) {
|
|
270
|
+
if (typeof runId !== 'string' || runId.length === 0
|
|
271
|
+
|| typeof barrierId !== 'string' || barrierId.length === 0
|
|
272
|
+
|| !SHA256.test(frozenEventDigest ?? '')) fail('empty running receipt入力不正');
|
|
273
|
+
const receipt = {
|
|
274
|
+
schema: 'lattice.empty_running_observation_receipt.v1',
|
|
275
|
+
run_id: runId,
|
|
276
|
+
barrier_id: barrierId,
|
|
277
|
+
frozen_event_digest: frozenEventDigest,
|
|
278
|
+
running_count: 0,
|
|
279
|
+
establishes_process_quiescence: false,
|
|
280
|
+
receipt_digest: '',
|
|
281
|
+
};
|
|
282
|
+
receipt.receipt_digest = selfDigest(receipt, 'receipt_digest');
|
|
283
|
+
return receipt;
|
|
284
|
+
}
|
package/src/runtime-engine.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { digestArtifact } from './artifact-contracts.mjs';
|
|
2
2
|
import { digestRunEvent } from './runtime-event-store.mjs';
|
|
3
3
|
import { projectRuntimeState } from './runtime-projection.mjs';
|
|
4
|
+
import { isCanonicalUtcTimestamp } from './timestamp-contract.mjs';
|
|
4
5
|
import {
|
|
5
6
|
RUN_EVENT_KINDS,
|
|
6
7
|
computeContextContentDigest,
|
|
@@ -33,7 +34,6 @@ const ENGINE_ACTOR = 'lattice-runtime';
|
|
|
33
34
|
const FORBIDDEN_OPERATIONS = Object.freeze([
|
|
34
35
|
'commit', 'push', 'branch', 'merge', 'rebase', 'reset', 'stash',
|
|
35
36
|
]);
|
|
36
|
-
const TIMESTAMP = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
|
|
37
37
|
|
|
38
38
|
function fail(reason) {
|
|
39
39
|
throw new TypeError(`runtime engine契約違反: ${reason}`);
|
|
@@ -55,7 +55,7 @@ function exactRecord(value, keys) {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
function requireTimestamp(value) {
|
|
58
|
-
if (
|
|
58
|
+
if (!isCanonicalUtcTimestamp(value)) {
|
|
59
59
|
fail(`recordedAtがcanonical UTC timestampではない: ${String(value)}`);
|
|
60
60
|
}
|
|
61
61
|
return value;
|
package/src/runtime-errors.mjs
CHANGED
|
@@ -30,7 +30,7 @@ const LOCK_RETRY_MS = 100;
|
|
|
30
30
|
const LOCK_TIMEOUT_MS = 5_000;
|
|
31
31
|
|
|
32
32
|
const definitions = Object.freeze({
|
|
33
|
-
'LATTICE.
|
|
33
|
+
'LATTICE.SENSOR_EVIDENCE_FAILED': { component: 'sensor_adapter', severity: 'high', template: 'LatticeSensor evidence collection failed' },
|
|
34
34
|
'LATTICE.RUN_STORE_IO_FAILED': { component: 'run_store', severity: 'high', template: 'Lattice run store IO failed' },
|
|
35
35
|
'LATTICE.EVENT_CHAIN_INTEGRITY_FAILED': { component: 'event_store', severity: 'high', template: 'Lattice run event chain integrity check failed' },
|
|
36
36
|
'LATTICE.CLI_INTERNAL_FAILED': { component: 'cli', severity: 'high', template: 'Lattice CLI crashed outside the typed error contract' },
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { canonicalizeArtifact } from './artifact-contracts.mjs';
|
|
2
2
|
import {
|
|
3
3
|
RUN_EVENT_KINDS,
|
|
4
|
-
selfDigest,
|
|
5
4
|
validateRunEvent,
|
|
6
5
|
} from './runtime-contracts.mjs';
|
|
6
|
+
import { digestWithoutField, verifyLinearHashChain } from './hash-chain.mjs';
|
|
7
7
|
|
|
8
8
|
// RC3 event store契約(ADR 0044 Decision 3)。
|
|
9
9
|
// event storeはrun単位のappend-only canonical event列であり、`sequence`は0起点の
|
|
@@ -64,7 +64,7 @@ export function digestRunEvent(event) {
|
|
|
64
64
|
if (event === null || typeof event !== 'object' || Array.isArray(event)) {
|
|
65
65
|
throw new TypeError('run event契約違反: eventはplain objectでなければならない');
|
|
66
66
|
}
|
|
67
|
-
return
|
|
67
|
+
return digestWithoutField(event, 'event_digest', canonicalizeArtifact);
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
/**
|
|
@@ -134,7 +134,7 @@ export function verifyRunEventChain(options = {}) {
|
|
|
134
134
|
sequence: 0,
|
|
135
135
|
previous_digest: null,
|
|
136
136
|
};
|
|
137
|
-
probe.event_digest =
|
|
137
|
+
probe.event_digest = digestWithoutField(probe, 'event_digest', canonicalizeArtifact);
|
|
138
138
|
return validateRunEvent(probe);
|
|
139
139
|
});
|
|
140
140
|
checks.push(check('event_shape', shapeOk));
|
|
@@ -145,9 +145,12 @@ export function verifyRunEventChain(options = {}) {
|
|
|
145
145
|
const knownKindOk = shapeOk && events.every((event) => RUN_EVENT_KINDS.includes(event.kind));
|
|
146
146
|
checks.push(check('unknown_kind', knownKindOk));
|
|
147
147
|
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
const sharedFailures = shapeOk ? verifyLinearHashChain({
|
|
149
|
+
entries: events,
|
|
150
|
+
canonicalize: canonicalizeArtifact,
|
|
151
|
+
digestField: 'event_digest',
|
|
152
|
+
}) : new Set();
|
|
153
|
+
const eventDigestOk = shapeOk && !sharedFailures.has('event_digest_mismatch');
|
|
151
154
|
checks.push(check('event_digest_mismatch', eventDigestOk));
|
|
152
155
|
|
|
153
156
|
const redactionOk = shapeOk && events.every((event) => (
|
|
@@ -155,11 +158,7 @@ export function verifyRunEventChain(options = {}) {
|
|
|
155
158
|
));
|
|
156
159
|
checks.push(check('payload_redaction', redactionOk));
|
|
157
160
|
|
|
158
|
-
|
|
159
|
-
// 保存bytes自体が順序judgementと矛盾しないための条件。ADR 0044 Decision 3.4)。
|
|
160
|
-
const storageOrderOk = shapeOk && events.every((event, index) => (
|
|
161
|
-
index === 0 || events[index - 1].sequence < event.sequence
|
|
162
|
-
));
|
|
161
|
+
const storageOrderOk = shapeOk && !sharedFailures.has('storage_order');
|
|
163
162
|
checks.push(check('storage_order', storageOrderOk));
|
|
164
163
|
|
|
165
164
|
let duplicateOk = shapeOk;
|
|
@@ -168,38 +167,11 @@ export function verifyRunEventChain(options = {}) {
|
|
|
168
167
|
let genesisOk = shapeOk;
|
|
169
168
|
let chainOk = shapeOk;
|
|
170
169
|
if (shapeOk) {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
bySequence.set(event.sequence, { first: event, bytes: new Set([bytes]), count: 1 });
|
|
177
|
-
} else {
|
|
178
|
-
seen.count += 1;
|
|
179
|
-
seen.bytes.add(bytes);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
for (const entry of bySequence.values()) {
|
|
183
|
-
if (entry.count > 1 && entry.bytes.size === 1) duplicateOk = false;
|
|
184
|
-
if (entry.bytes.size > 1) forkOk = false;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
const sequences = [...bySequence.keys()].sort((left, right) => left - right);
|
|
188
|
-
gapOk = sequences[0] === 0
|
|
189
|
-
&& sequences.every((sequence, index) => sequence === index);
|
|
190
|
-
genesisOk = bySequence.get(0) !== undefined
|
|
191
|
-
&& bySequence.get(0).first.previous_digest === null
|
|
192
|
-
&& events.every((event) => (event.sequence === 0) === (event.previous_digest === null));
|
|
193
|
-
|
|
194
|
-
for (const [index, sequence] of sequences.entries()) {
|
|
195
|
-
if (index === 0) continue;
|
|
196
|
-
const previous = bySequence.get(sequences[index - 1]).first;
|
|
197
|
-
const current = bySequence.get(sequence).first;
|
|
198
|
-
if (current.previous_digest !== previous.event_digest) {
|
|
199
|
-
chainOk = false;
|
|
200
|
-
break;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
170
|
+
duplicateOk = !sharedFailures.has('duplicate_event');
|
|
171
|
+
forkOk = !sharedFailures.has('sequence_fork');
|
|
172
|
+
gapOk = !sharedFailures.has('sequence_gap');
|
|
173
|
+
genesisOk = !sharedFailures.has('genesis_binding');
|
|
174
|
+
chainOk = !sharedFailures.has('digest_chain_mismatch');
|
|
203
175
|
}
|
|
204
176
|
checks.push(check('duplicate_event', duplicateOk));
|
|
205
177
|
checks.push(check('sequence_fork', forkOk));
|
|
@@ -2,7 +2,7 @@ import { createHash } from 'node:crypto';
|
|
|
2
2
|
|
|
3
3
|
import { digestArtifact } from './artifact-contracts.mjs';
|
|
4
4
|
import { compileBoundaryObservationV2 } from './boundary-observation-compiler-v2.mjs';
|
|
5
|
-
import {
|
|
5
|
+
import { portableSensorOutcome } from './sensor-adapter.mjs';
|
|
6
6
|
import { compileSchedulabilityGraphV2 } from './schedulability-compiler-v2.mjs';
|
|
7
7
|
import { verifySchedulabilityPlanV2 } from './schedulability-verifier-v2.mjs';
|
|
8
8
|
import {
|
|
@@ -16,11 +16,11 @@ import {
|
|
|
16
16
|
/**
|
|
17
17
|
* RC3-D generic front-end(ADR 0044 Decision 2・8、plan RC3-D)。
|
|
18
18
|
*
|
|
19
|
-
* `lattice.run_request.v1`のmanual witnessとfresh
|
|
19
|
+
* `lattice.run_request.v1`のmanual witnessとfresh LatticeSensor観測evidenceから、
|
|
20
20
|
* fixture名・期待conflict・期待waveの分岐なしに`lattice.runtime_plan.v1`と
|
|
21
21
|
* TODOごとの`lattice.boundary_manifest.v2`をcompileする。
|
|
22
22
|
*
|
|
23
|
-
* adapter契約(witness.
|
|
23
|
+
* adapter契約(witness.sensor_provenance、RC3-Dで固定):
|
|
24
24
|
* { queries: [{ query_id, expect }] }
|
|
25
25
|
* expect = { kind: 'symbol', name, path } — query outcomeにnode.name/filePathの
|
|
26
26
|
* exact一致がちょうど1件あることを要求(fuzzy解決の誤読防止)
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
* NODE_LIMIT_EXCEEDED / BOUNDARY_UNKNOWN / SEARCH_BUDGET_EXHAUSTED /
|
|
33
33
|
* QUERY_DRIFT / AFFECTED_TEST_DRIFT
|
|
34
34
|
*
|
|
35
|
-
*
|
|
35
|
+
* LatticeSensor raw telemetryはevidence captureに留め、plan・manifest identityへは
|
|
36
36
|
* portable outcome projectionのcanonical digestだけを入れる(Decision 10.4)。
|
|
37
37
|
*/
|
|
38
38
|
|
|
@@ -124,10 +124,10 @@ function nonDispatchable(code, detail) {
|
|
|
124
124
|
return { outcome: 'non_dispatchable', code, detail };
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
/** query set(run_request.
|
|
127
|
+
/** query set(run_request.sensor_query_set)のexact shapeを検査する。 */
|
|
128
128
|
function normalizeQuerySet(querySet) {
|
|
129
|
-
if (!exactRecord(querySet, ['queries'])) fail('
|
|
130
|
-
if (!Array.isArray(querySet.queries)) fail('
|
|
129
|
+
if (!exactRecord(querySet, ['queries'])) fail('sensor_query_set shapeが不正');
|
|
130
|
+
if (!Array.isArray(querySet.queries)) fail('sensor_query_set.queriesがarrayではない');
|
|
131
131
|
const byId = new Map();
|
|
132
132
|
for (const query of querySet.queries) {
|
|
133
133
|
const keys = Object.hasOwn(query ?? {}, 'target')
|
|
@@ -150,7 +150,7 @@ function normalizeQuerySet(querySet) {
|
|
|
150
150
|
* evidence = { outcomes: [{ query_id, operation, status, raw }] }(query set順)
|
|
151
151
|
*/
|
|
152
152
|
function normalizeEvidence(evidence, queryById) {
|
|
153
|
-
if (!exactRecord(evidence, ['outcomes'])) fail('
|
|
153
|
+
if (!exactRecord(evidence, ['outcomes'])) fail('sensor evidence shapeが不正');
|
|
154
154
|
if (!Array.isArray(evidence.outcomes)) fail('evidence.outcomesがarrayではない');
|
|
155
155
|
if (evidence.outcomes.length !== queryById.size) {
|
|
156
156
|
fail(`evidence件数(${evidence.outcomes.length})がquery set件数(${queryById.size})と一致しない`);
|
|
@@ -168,7 +168,7 @@ function normalizeEvidence(evidence, queryById) {
|
|
|
168
168
|
if (typeof outcome.status !== 'string' || outcome.status.length === 0) {
|
|
169
169
|
fail('evidence outcome statusが不正');
|
|
170
170
|
}
|
|
171
|
-
const portable =
|
|
171
|
+
const portable = portableSensorOutcome(outcome.raw);
|
|
172
172
|
byQueryId.set(outcome.query_id, {
|
|
173
173
|
query_id: outcome.query_id,
|
|
174
174
|
operation: outcome.operation,
|
|
@@ -187,13 +187,13 @@ function normalizeEvidence(evidence, queryById) {
|
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
function normalizeProvenanceQueries(witness, todoId) {
|
|
190
|
-
const provenance = witness.
|
|
190
|
+
const provenance = witness.sensor_provenance;
|
|
191
191
|
if (!exactRecord(provenance, ['queries']) || !Array.isArray(provenance.queries)) {
|
|
192
|
-
fail(`witness ${todoId}.
|
|
192
|
+
fail(`witness ${todoId}.sensor_provenance shapeが不正`);
|
|
193
193
|
}
|
|
194
194
|
return provenance.queries.map((entry) => {
|
|
195
195
|
if (!exactRecord(entry, ['query_id', 'expect']) || !identifier(entry.query_id)) {
|
|
196
|
-
fail(`witness ${todoId}.
|
|
196
|
+
fail(`witness ${todoId}.sensor_provenance entry shapeが不正`);
|
|
197
197
|
}
|
|
198
198
|
const expect = entry.expect;
|
|
199
199
|
if (!plainRecord(expect) || !EXPECT_KINDS.has(expect.kind)) {
|
|
@@ -236,7 +236,7 @@ function rawPayload(raw) {
|
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
/**
|
|
239
|
-
* affected outcomeのpayloadを取り出す。
|
|
239
|
+
* affected outcomeのpayloadを取り出す。lattice-sensor-adapterのper-target形
|
|
240
240
|
* (`{targets: [{target, outcome, data}]}`)と直接data形の両方を受ける。
|
|
241
241
|
*/
|
|
242
242
|
function affectedPayload(raw, expectPath) {
|
|
@@ -262,7 +262,7 @@ function entryNode(entry) {
|
|
|
262
262
|
}
|
|
263
263
|
|
|
264
264
|
/**
|
|
265
|
-
* 束縛queryのoutcomeへexpectをexact照合し、
|
|
265
|
+
* 束縛queryのoutcomeへexpectをexact照合し、sensor statusを決める。
|
|
266
266
|
* fuzzy解決・空結果は依存なしへ丸めず、unknown系statusへ落とす(AGENTS.md)。
|
|
267
267
|
*/
|
|
268
268
|
function resolveBindingStatus(binding, outcome) {
|
|
@@ -331,7 +331,7 @@ function candidateProvenance(request) {
|
|
|
331
331
|
}
|
|
332
332
|
|
|
333
333
|
/**
|
|
334
|
-
* `
|
|
334
|
+
* `collectSensorEvidence`のraw収集結果を、query set順へexact整合した
|
|
335
335
|
* front-end evidence契約(`{outcomes: [{query_id, operation, status, raw}]}`)へ写す。
|
|
336
336
|
* 件数・id・operationの不一致はfail closed。
|
|
337
337
|
*/
|
|
@@ -369,15 +369,15 @@ export function evidenceFromCollectedOutcomes(options = {}) {
|
|
|
369
369
|
}
|
|
370
370
|
|
|
371
371
|
/**
|
|
372
|
-
* run_requestと
|
|
372
|
+
* run_requestとsensor evidenceからobservation set・graph・planを一括compileする。
|
|
373
373
|
* 成功時はdispatchable outcome、契約内の識別可能な不成立はtyped non-dispatchable、
|
|
374
374
|
* 入力shape違反はTypeErrorでfail closed。
|
|
375
375
|
*/
|
|
376
376
|
export function compileRuntimePlanV1(options = {}) {
|
|
377
|
-
if (!exactRecord(options, ['request', '
|
|
377
|
+
if (!exactRecord(options, ['request', 'sensorEvidence', 'planRef', 'planEpoch', 'predecessorRefs'])) {
|
|
378
378
|
fail('compileRuntimePlanV1 optionsがexact shapeでない');
|
|
379
379
|
}
|
|
380
|
-
const { request,
|
|
380
|
+
const { request, sensorEvidence, planRef, planEpoch, predecessorRefs } = options;
|
|
381
381
|
if (!validateRunRequest(request)) fail('run_request.v1がcontractを満たさない');
|
|
382
382
|
if (!identifier(planRef)) fail('planRefがidentifierではない');
|
|
383
383
|
if (!Number.isSafeInteger(planEpoch) || planEpoch < 0) fail('planEpochが不正');
|
|
@@ -385,8 +385,8 @@ export function compileRuntimePlanV1(options = {}) {
|
|
|
385
385
|
fail('predecessorRefsがstring arrayではない');
|
|
386
386
|
}
|
|
387
387
|
|
|
388
|
-
const queryById = normalizeQuerySet(request.
|
|
389
|
-
const outcomeByQueryId = normalizeEvidence(
|
|
388
|
+
const queryById = normalizeQuerySet(request.sensor_query_set);
|
|
389
|
+
const outcomeByQueryId = normalizeEvidence(sensorEvidence, queryById);
|
|
390
390
|
|
|
391
391
|
const todoIds = request.todos.map((todo) => todo.todo_id);
|
|
392
392
|
|
|
@@ -425,7 +425,7 @@ export function compileRuntimePlanV1(options = {}) {
|
|
|
425
425
|
const unknowns = [];
|
|
426
426
|
if (statusOutcome.status !== 'ready') {
|
|
427
427
|
for (const todoId of todoIds) {
|
|
428
|
-
unknowns.push({ todo_id: todoId, kind: `
|
|
428
|
+
unknowns.push({ todo_id: todoId, kind: `sensor_${statusOutcome.status}`, ref: statusQueries[0].id });
|
|
429
429
|
}
|
|
430
430
|
}
|
|
431
431
|
|
|
@@ -435,7 +435,7 @@ export function compileRuntimePlanV1(options = {}) {
|
|
|
435
435
|
for (const binding of bindingsByTodo.get(todoId)) {
|
|
436
436
|
const resolved = resolveBindingStatus(binding, outcomeByQueryId.get(binding.query_id));
|
|
437
437
|
if (resolved !== 'ready') {
|
|
438
|
-
unknowns.push({ todo_id: todoId, kind: `
|
|
438
|
+
unknowns.push({ todo_id: todoId, kind: `sensor_${resolved}`, ref: binding.query_id });
|
|
439
439
|
}
|
|
440
440
|
}
|
|
441
441
|
}
|
|
@@ -492,7 +492,7 @@ export function compileRuntimePlanV1(options = {}) {
|
|
|
492
492
|
}
|
|
493
493
|
}
|
|
494
494
|
if (covering.length === 0) {
|
|
495
|
-
unknowns.push({ todo_id: todoId, kind: '
|
|
495
|
+
unknowns.push({ todo_id: todoId, kind: 'sensor_unbound', ref: `${own.kind}:${own.target}` });
|
|
496
496
|
}
|
|
497
497
|
}
|
|
498
498
|
}
|
|
@@ -592,7 +592,7 @@ export function compileRuntimePlanV1(options = {}) {
|
|
|
592
592
|
todo_ids: [...group.todoIds].sort(compareText),
|
|
593
593
|
provenance: [
|
|
594
594
|
{
|
|
595
|
-
source: '
|
|
595
|
+
source: 'sensor',
|
|
596
596
|
evidence_ref: coveringQueryId,
|
|
597
597
|
evidence_digest: outcome.portable_digest,
|
|
598
598
|
status,
|
|
@@ -660,7 +660,7 @@ export function compileRuntimePlanV1(options = {}) {
|
|
|
660
660
|
source: {
|
|
661
661
|
snapshot_digest: digestArtifact({ base_sha: request.repo.base_sha }),
|
|
662
662
|
candidate_witness_digest: digestArtifact(request.manual_witness),
|
|
663
|
-
query_set_digest: digestArtifact(request.
|
|
663
|
+
query_set_digest: digestArtifact(request.sensor_query_set),
|
|
664
664
|
manual_evidence_digest: request.request_digest,
|
|
665
665
|
},
|
|
666
666
|
capacity: request.capacity.executors,
|
|
@@ -698,7 +698,7 @@ export function compileRuntimePlanV1(options = {}) {
|
|
|
698
698
|
for (const resource of resources) {
|
|
699
699
|
if (!resource.todo_ids.includes(todoId)) continue;
|
|
700
700
|
witnessProvenance[resource.resource_id] = resource.kind === 'symbol' || resource.kind === 'path'
|
|
701
|
-
? '
|
|
701
|
+
? 'sensor'
|
|
702
702
|
: 'manual_state_effect';
|
|
703
703
|
}
|
|
704
704
|
const manifest = {
|