@cleocode/core 2026.6.11 → 2026.6.13
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/dist/conduit/local-transport.d.ts +12 -0
- package/dist/conduit/local-transport.d.ts.map +1 -1
- package/dist/conduit/local-transport.js +53 -23
- package/dist/conduit/local-transport.js.map +1 -1
- package/dist/crypto/credentials.d.ts +37 -0
- package/dist/crypto/credentials.d.ts.map +1 -1
- package/dist/crypto/credentials.js +110 -0
- package/dist/crypto/credentials.js.map +1 -1
- package/dist/dispatch/contracts/derive-output-contract.d.ts +86 -0
- package/dist/dispatch/contracts/derive-output-contract.d.ts.map +1 -0
- package/dist/dispatch/contracts/derive-output-contract.js +347 -0
- package/dist/dispatch/contracts/derive-output-contract.js.map +1 -0
- package/dist/dispatch/contracts/ensures-schema.d.ts +77 -0
- package/dist/dispatch/contracts/ensures-schema.d.ts.map +1 -0
- package/dist/dispatch/contracts/ensures-schema.js +91 -0
- package/dist/dispatch/contracts/ensures-schema.js.map +1 -0
- package/dist/dispatch/contracts/output-contracts.d.ts +27 -5
- package/dist/dispatch/contracts/output-contracts.d.ts.map +1 -1
- package/dist/dispatch/contracts/output-contracts.js +29 -6
- package/dist/dispatch/contracts/output-contracts.js.map +1 -1
- package/dist/docs/export-document.js +2309 -1262
- package/dist/docs/export-document.js.map +3 -3
- package/dist/go/driver.d.ts +132 -7
- package/dist/go/driver.d.ts.map +1 -1
- package/dist/go/driver.js +135 -10
- package/dist/go/driver.js.map +1 -1
- package/dist/go/index.d.ts +1 -1
- package/dist/go/index.d.ts.map +1 -1
- package/dist/go/index.js +1 -1
- package/dist/go/index.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +13 -10
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +11 -11
- package/dist/internal.js.map +1 -1
- package/dist/lifecycle/engine-ops.d.ts.map +1 -1
- package/dist/lifecycle/engine-ops.js +7 -4
- package/dist/lifecycle/engine-ops.js.map +1 -1
- package/dist/lifecycle/ivtr-loop.d.ts +108 -183
- package/dist/lifecycle/ivtr-loop.d.ts.map +1 -1
- package/dist/lifecycle/ivtr-loop.js +207 -522
- package/dist/lifecycle/ivtr-loop.js.map +1 -1
- package/dist/llm/auxiliary-fallback.js +1 -1
- package/dist/llm/auxiliary-fallback.js.map +1 -1
- package/dist/llm/cli-ops.d.ts +14 -1
- package/dist/llm/cli-ops.d.ts.map +1 -1
- package/dist/llm/cli-ops.js +41 -12
- package/dist/llm/cli-ops.js.map +1 -1
- package/dist/llm/concrete-session.d.ts.map +1 -1
- package/dist/llm/concrete-session.js +4 -0
- package/dist/llm/concrete-session.js.map +1 -1
- package/dist/llm/credentials.d.ts +35 -0
- package/dist/llm/credentials.d.ts.map +1 -1
- package/dist/llm/credentials.js +49 -0
- package/dist/llm/credentials.js.map +1 -1
- package/dist/llm/index.d.ts +4 -0
- package/dist/llm/index.d.ts.map +1 -1
- package/dist/llm/index.js +4 -0
- package/dist/llm/index.js.map +1 -1
- package/dist/llm/pi/gondolin-loader.d.ts +241 -0
- package/dist/llm/pi/gondolin-loader.d.ts.map +1 -0
- package/dist/llm/pi/gondolin-loader.js +195 -0
- package/dist/llm/pi/gondolin-loader.js.map +1 -0
- package/dist/llm/pi/index.d.ts +28 -0
- package/dist/llm/pi/index.d.ts.map +1 -0
- package/dist/llm/pi/index.js +27 -0
- package/dist/llm/pi/index.js.map +1 -0
- package/dist/llm/pi/pi-agent-adapter.d.ts +135 -0
- package/dist/llm/pi/pi-agent-adapter.d.ts.map +1 -0
- package/dist/llm/pi/pi-agent-adapter.js +329 -0
- package/dist/llm/pi/pi-agent-adapter.js.map +1 -0
- package/dist/llm/pi/pi-errors.d.ts +161 -0
- package/dist/llm/pi/pi-errors.d.ts.map +1 -0
- package/dist/llm/pi/pi-errors.js +296 -0
- package/dist/llm/pi/pi-errors.js.map +1 -0
- package/dist/llm/pi/pi-execution-env.d.ts +286 -0
- package/dist/llm/pi/pi-execution-env.d.ts.map +1 -0
- package/dist/llm/pi/pi-execution-env.js +406 -0
- package/dist/llm/pi/pi-execution-env.js.map +1 -0
- package/dist/llm/pi/pi-gondolin-env.d.ts +227 -0
- package/dist/llm/pi/pi-gondolin-env.d.ts.map +1 -0
- package/dist/llm/pi/pi-gondolin-env.js +541 -0
- package/dist/llm/pi/pi-gondolin-env.js.map +1 -0
- package/dist/llm/pi/pi-session-storage.d.ts +154 -0
- package/dist/llm/pi/pi-session-storage.d.ts.map +1 -0
- package/dist/llm/pi/pi-session-storage.js +314 -0
- package/dist/llm/pi/pi-session-storage.js.map +1 -0
- package/dist/llm/pi/pi-stream-fn.d.ts +124 -0
- package/dist/llm/pi/pi-stream-fn.d.ts.map +1 -0
- package/dist/llm/pi/pi-stream-fn.js +504 -0
- package/dist/llm/pi/pi-stream-fn.js.map +1 -0
- package/dist/llm/pi/pi-tool-bridge.d.ts +99 -0
- package/dist/llm/pi/pi-tool-bridge.d.ts.map +1 -0
- package/dist/llm/pi/pi-tool-bridge.js +117 -0
- package/dist/llm/pi/pi-tool-bridge.js.map +1 -0
- package/dist/llm/pi/pi-types.d.ts +56 -0
- package/dist/llm/pi/pi-types.d.ts.map +1 -0
- package/dist/llm/pi/pi-types.js +16 -0
- package/dist/llm/pi/pi-types.js.map +1 -0
- package/dist/llm/pi/resolve-execution-env.d.ts +194 -0
- package/dist/llm/pi/resolve-execution-env.d.ts.map +1 -0
- package/dist/llm/pi/resolve-execution-env.js +132 -0
- package/dist/llm/pi/resolve-execution-env.js.map +1 -0
- package/dist/llm/plugin-facade.js +2253 -1151
- package/dist/llm/plugin-facade.js.map +3 -3
- package/dist/llm/role-executor.d.ts.map +1 -1
- package/dist/llm/role-executor.js +8 -5
- package/dist/llm/role-executor.js.map +1 -1
- package/dist/llm/role-resolver.d.ts +46 -14
- package/dist/llm/role-resolver.d.ts.map +1 -1
- package/dist/llm/role-resolver.js +178 -20
- package/dist/llm/role-resolver.js.map +1 -1
- package/dist/llm/sealed-credential.d.ts +125 -0
- package/dist/llm/sealed-credential.d.ts.map +1 -0
- package/dist/llm/sealed-credential.js +133 -0
- package/dist/llm/sealed-credential.js.map +1 -0
- package/dist/llm/session-factory.d.ts.map +1 -1
- package/dist/llm/session-factory.js +6 -2
- package/dist/llm/session-factory.js.map +1 -1
- package/dist/llm/system-key.d.ts +67 -0
- package/dist/llm/system-key.d.ts.map +1 -0
- package/dist/llm/system-key.js +87 -0
- package/dist/llm/system-key.js.map +1 -0
- package/dist/llm/system-of-use-registry.d.ts +119 -0
- package/dist/llm/system-of-use-registry.d.ts.map +1 -0
- package/dist/llm/system-of-use-registry.js +200 -0
- package/dist/llm/system-of-use-registry.js.map +1 -0
- package/dist/llm/system-resolver.d.ts +32 -10
- package/dist/llm/system-resolver.d.ts.map +1 -1
- package/dist/llm/system-resolver.js +70 -18
- package/dist/llm/system-resolver.js.map +1 -1
- package/dist/memory/brain-writer-thread.d.ts.map +1 -1
- package/dist/memory/brain-writer-thread.js +116 -11
- package/dist/memory/brain-writer-thread.js.map +1 -1
- package/dist/memory/claude-mem-migration.d.ts.map +1 -1
- package/dist/memory/claude-mem-migration.js +21 -0
- package/dist/memory/claude-mem-migration.js.map +1 -1
- package/dist/memory/graph-memory-bridge.d.ts.map +1 -1
- package/dist/memory/graph-memory-bridge.js +32 -25
- package/dist/memory/graph-memory-bridge.js.map +1 -1
- package/dist/memory/llm-backend-resolver.js +23 -5
- package/dist/memory/llm-backend-resolver.js.map +1 -1
- package/dist/nexus/migrations/M-split-graph.d.ts.map +1 -1
- package/dist/nexus/migrations/M-split-graph.js +60 -53
- package/dist/nexus/migrations/M-split-graph.js.map +1 -1
- package/dist/orchestrate/pivot.d.ts.map +1 -1
- package/dist/orchestrate/pivot.js +20 -2
- package/dist/orchestrate/pivot.js.map +1 -1
- package/dist/release/engine-ops.js +2 -2
- package/dist/release/engine-ops.js.map +1 -1
- package/dist/release/plan.d.ts +4 -6
- package/dist/release/plan.d.ts.map +1 -1
- package/dist/release/plan.js +10 -23
- package/dist/release/plan.js.map +1 -1
- package/dist/release/reconcile.d.ts +0 -2
- package/dist/release/reconcile.d.ts.map +1 -1
- package/dist/release/reconcile.js +43 -50
- package/dist/release/reconcile.js.map +1 -1
- package/dist/release/release-manifest.d.ts.map +1 -1
- package/dist/release/release-manifest.js +4 -1
- package/dist/release/release-manifest.js.map +1 -1
- package/dist/release/verify-provenance.js +20 -20
- package/dist/release/verify-provenance.js.map +1 -1
- package/dist/routing/capability-matrix.d.ts.map +1 -1
- package/dist/routing/capability-matrix.js +0 -57
- package/dist/routing/capability-matrix.js.map +1 -1
- package/dist/selfimprove/budget.d.ts +206 -0
- package/dist/selfimprove/budget.d.ts.map +1 -0
- package/dist/selfimprove/budget.js +203 -0
- package/dist/selfimprove/budget.js.map +1 -0
- package/dist/selfimprove/dhq-adapter.d.ts +105 -0
- package/dist/selfimprove/dhq-adapter.d.ts.map +1 -0
- package/dist/selfimprove/dhq-adapter.js +95 -0
- package/dist/selfimprove/dhq-adapter.js.map +1 -0
- package/dist/selfimprove/draft-pr.d.ts +129 -0
- package/dist/selfimprove/draft-pr.d.ts.map +1 -0
- package/dist/selfimprove/draft-pr.js +158 -0
- package/dist/selfimprove/draft-pr.js.map +1 -0
- package/dist/selfimprove/envelope-diff.d.ts +162 -0
- package/dist/selfimprove/envelope-diff.d.ts.map +1 -0
- package/dist/selfimprove/envelope-diff.js +321 -0
- package/dist/selfimprove/envelope-diff.js.map +1 -0
- package/dist/selfimprove/replay.d.ts +121 -0
- package/dist/selfimprove/replay.d.ts.map +1 -0
- package/dist/selfimprove/replay.js +109 -0
- package/dist/selfimprove/replay.js.map +1 -0
- package/dist/selfimprove/run-loop.d.ts +148 -0
- package/dist/selfimprove/run-loop.d.ts.map +1 -0
- package/dist/selfimprove/run-loop.js +240 -0
- package/dist/selfimprove/run-loop.js.map +1 -0
- package/dist/selfimprove/scenario.d.ts +145 -0
- package/dist/selfimprove/scenario.d.ts.map +1 -0
- package/dist/selfimprove/scenario.js +243 -0
- package/dist/selfimprove/scenario.js.map +1 -0
- package/dist/sentient/daemon-entry.js +5 -0
- package/dist/sentient/daemon-entry.js.map +1 -1
- package/dist/sentient/daemon.d.ts.map +1 -1
- package/dist/sentient/daemon.js +19 -0
- package/dist/sentient/daemon.js.map +1 -1
- package/dist/sentient/hygiene-scan.d.ts.map +1 -1
- package/dist/sentient/hygiene-scan.js +14 -6
- package/dist/sentient/hygiene-scan.js.map +1 -1
- package/dist/sessions/briefing.d.ts.map +1 -1
- package/dist/sessions/briefing.js +13 -9
- package/dist/sessions/briefing.js.map +1 -1
- package/dist/sessions/connection-session-handle.d.ts +161 -0
- package/dist/sessions/connection-session-handle.d.ts.map +1 -0
- package/dist/sessions/connection-session-handle.js +168 -0
- package/dist/sessions/connection-session-handle.js.map +1 -0
- package/dist/sessions/handoff.d.ts.map +1 -1
- package/dist/sessions/handoff.js +9 -0
- package/dist/sessions/handoff.js.map +1 -1
- package/dist/sessions/index.d.ts +4 -1
- package/dist/sessions/index.d.ts.map +1 -1
- package/dist/sessions/index.js +31 -1
- package/dist/sessions/index.js.map +1 -1
- package/dist/sessions/session-id.d.ts +34 -0
- package/dist/sessions/session-id.d.ts.map +1 -1
- package/dist/sessions/session-id.js +37 -0
- package/dist/sessions/session-id.js.map +1 -1
- package/dist/sessions/session-manifest-mirror.d.ts +115 -0
- package/dist/sessions/session-manifest-mirror.d.ts.map +1 -0
- package/dist/sessions/session-manifest-mirror.js +250 -0
- package/dist/sessions/session-manifest-mirror.js.map +1 -0
- package/dist/sessions/session-switch.d.ts.map +1 -1
- package/dist/sessions/session-switch.js +5 -2
- package/dist/sessions/session-switch.js.map +1 -1
- package/dist/store/converters.d.ts.map +1 -1
- package/dist/store/converters.js +2 -0
- package/dist/store/converters.js.map +1 -1
- package/dist/store/db-helpers.d.ts.map +1 -1
- package/dist/store/db-helpers.js +2 -0
- package/dist/store/db-helpers.js.map +1 -1
- package/dist/store/dual-scope-db.d.ts.map +1 -1
- package/dist/store/dual-scope-db.js +87 -47
- package/dist/store/dual-scope-db.js.map +1 -1
- package/dist/store/pi-session-store.d.ts +151 -0
- package/dist/store/pi-session-store.d.ts.map +1 -0
- package/dist/store/pi-session-store.js +166 -0
- package/dist/store/pi-session-store.js.map +1 -0
- package/dist/store/safety-data-accessor.d.ts +1 -0
- package/dist/store/safety-data-accessor.d.ts.map +1 -1
- package/dist/store/safety-data-accessor.js +5 -0
- package/dist/store/safety-data-accessor.js.map +1 -1
- package/dist/store/schema/cleo-global/accounts.d.ts +357 -0
- package/dist/store/schema/cleo-global/accounts.d.ts.map +1 -0
- package/dist/store/schema/cleo-global/accounts.js +136 -0
- package/dist/store/schema/cleo-global/accounts.js.map +1 -0
- package/dist/store/schema/cleo-global/index.d.ts +2 -0
- package/dist/store/schema/cleo-global/index.d.ts.map +1 -1
- package/dist/store/schema/cleo-global/index.js +2 -0
- package/dist/store/schema/cleo-global/index.js.map +1 -1
- package/dist/store/schema/cleo-global/session-manifest.d.ts +217 -0
- package/dist/store/schema/cleo-global/session-manifest.d.ts.map +1 -0
- package/dist/store/schema/cleo-global/session-manifest.js +99 -0
- package/dist/store/schema/cleo-global/session-manifest.js.map +1 -0
- package/dist/store/schema/cleo-project/tasks-core.d.ts +16 -0
- package/dist/store/schema/cleo-project/tasks-core.d.ts.map +1 -1
- package/dist/store/schema/cleo-project/tasks-core.js +14 -0
- package/dist/store/schema/cleo-project/tasks-core.js.map +1 -1
- package/dist/store/schema/tasks.d.ts +16 -0
- package/dist/store/schema/tasks.d.ts.map +1 -1
- package/dist/store/schema/tasks.js +10 -0
- package/dist/store/schema/tasks.js.map +1 -1
- package/dist/store/selfimprove-dhq-schema.d.ts +284 -0
- package/dist/store/selfimprove-dhq-schema.d.ts.map +1 -0
- package/dist/store/selfimprove-dhq-schema.js +128 -0
- package/dist/store/selfimprove-dhq-schema.js.map +1 -0
- package/dist/store/selfimprove-dhq-store.d.ts +175 -0
- package/dist/store/selfimprove-dhq-store.d.ts.map +1 -0
- package/dist/store/selfimprove-dhq-store.js +182 -0
- package/dist/store/selfimprove-dhq-store.js.map +1 -0
- package/dist/store/session-store.d.ts +52 -13
- package/dist/store/session-store.d.ts.map +1 -1
- package/dist/store/session-store.js +71 -13
- package/dist/store/session-store.js.map +1 -1
- package/dist/store/sqlite-data-accessor.d.ts.map +1 -1
- package/dist/store/sqlite-data-accessor.js +7 -0
- package/dist/store/sqlite-data-accessor.js.map +1 -1
- package/dist/store/tasks-schema.d.ts +4 -0
- package/dist/store/tasks-schema.d.ts.map +1 -1
- package/dist/store/tasks-schema.js +14 -0
- package/dist/store/tasks-schema.js.map +1 -1
- package/dist/store/umbrella-data-accessor.d.ts +1 -0
- package/dist/store/umbrella-data-accessor.d.ts.map +1 -1
- package/dist/store/umbrella-data-accessor.js +5 -0
- package/dist/store/umbrella-data-accessor.js.map +1 -1
- package/dist/store/validation-schemas.d.ts +94 -62
- package/dist/store/validation-schemas.d.ts.map +1 -1
- package/dist/store/writer-lease-schema.d.ts +392 -0
- package/dist/store/writer-lease-schema.d.ts.map +1 -0
- package/dist/store/writer-lease-schema.js +142 -0
- package/dist/store/writer-lease-schema.js.map +1 -0
- package/dist/store/writer-lease.d.ts +368 -0
- package/dist/store/writer-lease.d.ts.map +1 -0
- package/dist/store/writer-lease.js +1002 -0
- package/dist/store/writer-lease.js.map +1 -0
- package/dist/task-tools/describe-schema.d.ts +4 -2
- package/dist/task-tools/describe-schema.d.ts.map +1 -1
- package/dist/task-tools/describe-schema.js +9 -3
- package/dist/task-tools/describe-schema.js.map +1 -1
- package/dist/tasks/backfill-child-projections.d.ts.map +1 -1
- package/dist/tasks/backfill-child-projections.js +14 -9
- package/dist/tasks/backfill-child-projections.js.map +1 -1
- package/dist/tasks/complete.d.ts.map +1 -1
- package/dist/tasks/complete.js +7 -10
- package/dist/tasks/complete.js.map +1 -1
- package/dist/tasks/duplicate-detector.d.ts.map +1 -1
- package/dist/tasks/duplicate-detector.js +14 -7
- package/dist/tasks/duplicate-detector.js.map +1 -1
- package/dist/telemetry/index.d.ts.map +1 -1
- package/dist/telemetry/index.js +10 -4
- package/dist/telemetry/index.js.map +1 -1
- package/dist/tools/agent-registry.d.ts +250 -0
- package/dist/tools/agent-registry.d.ts.map +1 -0
- package/dist/tools/agent-registry.js +292 -0
- package/dist/tools/agent-registry.js.map +1 -0
- package/dist/tools/agent-tool-families.d.ts +107 -0
- package/dist/tools/agent-tool-families.d.ts.map +1 -0
- package/dist/tools/agent-tool-families.js +527 -0
- package/dist/tools/agent-tool-families.js.map +1 -0
- package/dist/tools/browser-driver.d.ts +183 -0
- package/dist/tools/browser-driver.d.ts.map +1 -0
- package/dist/tools/browser-driver.js +242 -0
- package/dist/tools/browser-driver.js.map +1 -0
- package/dist/tools/builtin-agent-tools.d.ts +36 -0
- package/dist/tools/builtin-agent-tools.d.ts.map +1 -0
- package/dist/tools/builtin-agent-tools.js +150 -0
- package/dist/tools/builtin-agent-tools.js.map +1 -0
- package/dist/tools/dispatch.d.ts +370 -0
- package/dist/tools/dispatch.d.ts.map +1 -0
- package/dist/tools/dispatch.js +505 -0
- package/dist/tools/dispatch.js.map +1 -0
- package/dist/tools/env-scrub.d.ts +93 -0
- package/dist/tools/env-scrub.d.ts.map +1 -0
- package/dist/tools/env-scrub.js +176 -0
- package/dist/tools/env-scrub.js.map +1 -0
- package/dist/tools/fs.d.ts +30 -0
- package/dist/tools/fs.d.ts.map +1 -1
- package/dist/tools/fs.js +55 -2
- package/dist/tools/fs.js.map +1 -1
- package/dist/tools/guard.d.ts +15 -0
- package/dist/tools/guard.d.ts.map +1 -1
- package/dist/tools/guard.js +49 -12
- package/dist/tools/guard.js.map +1 -1
- package/dist/tools/index.d.ts +10 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +37 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/pty.d.ts +45 -0
- package/dist/tools/pty.d.ts.map +1 -0
- package/dist/tools/pty.js +166 -0
- package/dist/tools/pty.js.map +1 -0
- package/dist/tools/schema-gen.d.ts +57 -0
- package/dist/tools/schema-gen.d.ts.map +1 -0
- package/dist/tools/schema-gen.js +52 -0
- package/dist/tools/schema-gen.js.map +1 -0
- package/dist/tools/shell.d.ts +12 -0
- package/dist/tools/shell.d.ts.map +1 -1
- package/dist/tools/shell.js +14 -1
- package/dist/tools/shell.js.map +1 -1
- package/dist/tools/web-agent-tools.d.ts +72 -0
- package/dist/tools/web-agent-tools.d.ts.map +1 -0
- package/dist/tools/web-agent-tools.js +393 -0
- package/dist/tools/web-agent-tools.js.map +1 -0
- package/dist/tools/web-search-backends.d.ts +156 -0
- package/dist/tools/web-search-backends.d.ts.map +1 -0
- package/dist/tools/web-search-backends.js +290 -0
- package/dist/tools/web-search-backends.js.map +1 -0
- package/dist/validation/ops.d.ts +1 -15
- package/dist/validation/ops.d.ts.map +1 -1
- package/dist/validation/ops.js +0 -20
- package/dist/validation/ops.js.map +1 -1
- package/migrations/drizzle-cleo-global/20260607000000_t11891-writer-leases/migration.sql +55 -0
- package/migrations/drizzle-cleo-global/20260607010000_t11639-session-manifest/migration.sql +43 -0
- package/migrations/drizzle-cleo-global/20260608000000_t11899-pi-session-tree/migration.sql +52 -0
- package/migrations/drizzle-cleo-global/20260608010000_t11709-accounts-credential-pool/migration.sql +72 -0
- package/migrations/drizzle-cleo-global/20260608020000_t11889-selfimprove-dhq/migration.sql +64 -0
- package/migrations/drizzle-cleo-project/20260606000000_t11884-restore-prefixed-task-triggers/migration.sql +272 -0
- package/migrations/drizzle-cleo-project/20260606000000_t11884-restore-prefixed-task-triggers/revert.sql +29 -0
- package/migrations/drizzle-cleo-project/20260606000100_t11883-tasks-releases-version-unique/migration.sql +21 -0
- package/migrations/drizzle-cleo-project/20260606000100_t11883-tasks-releases-version-unique/revert.sql +4 -0
- package/migrations/drizzle-cleo-project/20260607000000_t11891-writer-leases/migration.sql +55 -0
- package/migrations/drizzle-cleo-project/20260607010000_t11639-session-parent/migration.sql +22 -0
- package/migrations/drizzle-cleo-project/20260608000000_t11899-pi-session-tree/migration.sql +52 -0
- package/migrations/drizzle-cleo-project/20260608020000_t11889-selfimprove-dhq/migration.sql +64 -0
- package/package.json +15 -13
- package/dist/lifecycle/chain-composition.d.ts +0 -30
- package/dist/lifecycle/chain-composition.d.ts.map +0 -1
- package/dist/lifecycle/chain-composition.js +0 -152
- package/dist/lifecycle/chain-composition.js.map +0 -1
- package/dist/lifecycle/chain-store.d.ts +0 -70
- package/dist/lifecycle/chain-store.d.ts.map +0 -1
- package/dist/lifecycle/chain-store.js +0 -246
- package/dist/lifecycle/chain-store.js.map +0 -1
- package/dist/lifecycle/default-chain.d.ts +0 -39
- package/dist/lifecycle/default-chain.d.ts.map +0 -1
- package/dist/lifecycle/default-chain.js +0 -176
- package/dist/lifecycle/default-chain.js.map +0 -1
- package/dist/lifecycle/tessera-engine.d.ts +0 -48
- package/dist/lifecycle/tessera-engine.d.ts.map +0 -1
- package/dist/lifecycle/tessera-engine.js +0 -249
- package/dist/lifecycle/tessera-engine.js.map +0 -1
- package/dist/release/provenance-fk.d.ts +0 -74
- package/dist/release/provenance-fk.d.ts.map +0 -1
- package/dist/release/provenance-fk.js +0 -122
- package/dist/release/provenance-fk.js.map +0 -1
- package/dist/validation/chain-validation.d.ts +0 -43
- package/dist/validation/chain-validation.d.ts.map +0 -1
- package/dist/validation/chain-validation.js +0 -146
- package/dist/validation/chain-validation.js.map +0 -1
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Envelope normalization + structural diff vs a golden (T11889-B).
|
|
3
|
+
*
|
|
4
|
+
* The self-improvement loop replays a scenario (see {@link "./replay.js"}) and
|
|
5
|
+
* diffs each captured envelope against the golden expected envelope. This module:
|
|
6
|
+
*
|
|
7
|
+
* 1. {@link normalizeEnvelope} — strips the VOLATILE `meta` fields so only
|
|
8
|
+
* deterministic structure is compared. Two classes are stripped:
|
|
9
|
+
* timing/trace fields (`timestamp`, `requestId`, `duration_ms` /
|
|
10
|
+
* `durationMs`) AND the per-run session-lineage UUIDs (`sessionId`,
|
|
11
|
+
* `originSessionId`, `executionSessionId`). The latter are non-deterministic:
|
|
12
|
+
* the live `Dispatcher` defaults `executionSessionId`/`originSessionId` to a
|
|
13
|
+
* fresh `randomUUID()` per request
|
|
14
|
+
* (`ensureRequestSessionLineage`), then stamps all three onto `response.meta`
|
|
15
|
+
* — so a real envelope carries UUIDs the hand-authored golden cannot know.
|
|
16
|
+
* Stripping them prevents a permanent phantom DHQ that self-fires on every
|
|
17
|
+
* clean run. (The runtime field is `meta` with snake_case `duration_ms`; the
|
|
18
|
+
* spec wording uses `_meta`/`durationMs`, so both spellings and both
|
|
19
|
+
* container keys are stripped defensively.)
|
|
20
|
+
* 2. {@link diffEnvelopes} — structurally compares the normalized envelope set
|
|
21
|
+
* against the golden, producing `{ regressions: DiffEntry[] }`. Zero
|
|
22
|
+
* regressions on a golden match; N on injected divergence. The `meta`
|
|
23
|
+
* container is compared as a SUBSET (only golden-declared meta keys are
|
|
24
|
+
* asserted) so deterministic-but-golden-absent infra keys
|
|
25
|
+
* (`specVersion`, `schemaVersion`, `transport`, `mvi`, `contextVersion`,
|
|
26
|
+
* `strict`, `x-cleo-transport`, …) stamped by the runtime are NOT phantom
|
|
27
|
+
* regressions. The semantic payload (`data`/`error`) is still compared by
|
|
28
|
+
* full key-union — a missing or extra payload key IS a regression.
|
|
29
|
+
* 3. {@link computeQuestionHash} — sha256 of the normalized regression
|
|
30
|
+
* signature (op coordinates + diff path set) so the SAME regression maps to
|
|
31
|
+
* the SAME open DHQ row (the idempotency partial-UNIQUE index in T11889-A).
|
|
32
|
+
*
|
|
33
|
+
* `extractFieldFromResult` from `@cleocode/lafs` is reused for targeted-field
|
|
34
|
+
* asserts where a full structural compare would be too brittle.
|
|
35
|
+
*
|
|
36
|
+
* This module is PURE — no DB, no native handle, no `cleo` mutation.
|
|
37
|
+
* Import-time side-effect-free.
|
|
38
|
+
*
|
|
39
|
+
* @module @cleocode/core/selfimprove/envelope-diff
|
|
40
|
+
* @epic T11889
|
|
41
|
+
* @task T11912
|
|
42
|
+
*/
|
|
43
|
+
import type { ReplayEnvelope } from './replay.js';
|
|
44
|
+
import type { GoldenEntry, ScenarioOp } from './scenario.js';
|
|
45
|
+
/**
|
|
46
|
+
* A normalized envelope: the replayed envelope with volatile `meta` fields removed.
|
|
47
|
+
*
|
|
48
|
+
* Structurally identical to {@link ReplayEnvelope} except every volatile
|
|
49
|
+
* meta field is absent. Stored as a plain JSON-serializable record so it can be
|
|
50
|
+
* compared deeply and hashed deterministically.
|
|
51
|
+
*/
|
|
52
|
+
export type NormalizedEnvelope = Record<string, unknown>;
|
|
53
|
+
/**
|
|
54
|
+
* A single structural difference between a normalized envelope and its golden.
|
|
55
|
+
*/
|
|
56
|
+
export interface DiffEntry {
|
|
57
|
+
/** Zero-based index of the op in the scenario whose envelope diverged. */
|
|
58
|
+
opIndex: number;
|
|
59
|
+
/** The op coordinate (`domain.operation`) for the diverging op. */
|
|
60
|
+
opCoord: string;
|
|
61
|
+
/** JSON-pointer-ish path to the diverging value (e.g. `data/tasks/0/id`). */
|
|
62
|
+
path: string;
|
|
63
|
+
/** The value found in the replayed (actual) normalized envelope. */
|
|
64
|
+
actual: unknown;
|
|
65
|
+
/** The value found in the golden (expected) envelope. */
|
|
66
|
+
expected: unknown;
|
|
67
|
+
}
|
|
68
|
+
/** The result of diffing a replayed envelope set against a golden. */
|
|
69
|
+
export interface EnvelopeDiffResult {
|
|
70
|
+
/** All structural regressions; empty ⇒ the replay matched the golden. */
|
|
71
|
+
regressions: DiffEntry[];
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Strip the volatile `meta`/`_meta` fields from an envelope.
|
|
75
|
+
*
|
|
76
|
+
* Returns a NEW object; the input is not mutated. The volatile timing/trace fields
|
|
77
|
+
* AND the per-run session-lineage UUIDs (`sessionId`, `originSessionId`,
|
|
78
|
+
* `executionSessionId`) are removed — see {@link VOLATILE_META_FIELDS}. The stable
|
|
79
|
+
* meta remnant (`gateway`, `domain`, `operation`, `source`, …) is preserved so
|
|
80
|
+
* structural identity (which operation produced the envelope) still compares.
|
|
81
|
+
*
|
|
82
|
+
* Note: deterministic-but-golden-absent infra meta keys (`specVersion`,
|
|
83
|
+
* `transport`, …) are NOT stripped here — they are tolerated by the SUBSET compare
|
|
84
|
+
* in {@link diffEnvelopes} instead, so the strip set stays exactly the volatile
|
|
85
|
+
* fields and nothing semantic.
|
|
86
|
+
*
|
|
87
|
+
* @param envelope - The replayed envelope to normalize.
|
|
88
|
+
* @returns The normalized envelope with volatile meta fields removed.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* const norm = normalizeEnvelope(envelope);
|
|
93
|
+
* // norm.meta has no timestamp / requestId / duration_ms / *SessionId
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export declare function normalizeEnvelope(envelope: ReplayEnvelope): NormalizedEnvelope;
|
|
97
|
+
/**
|
|
98
|
+
* Diff a set of replayed envelopes against the golden envelope set.
|
|
99
|
+
*
|
|
100
|
+
* Normalizes each replayed envelope (volatile meta stripped) and structurally
|
|
101
|
+
* compares it against the positionally-aligned golden entry. The op coordinate
|
|
102
|
+
* for each `DiffEntry` is taken from `ops[opIndex]`. Callers MUST pass aligned
|
|
103
|
+
* arrays (`ops.length === replayed.length === golden.length`); the function
|
|
104
|
+
* diffs up to the shortest length and reports an extra regression for any length
|
|
105
|
+
* mismatch.
|
|
106
|
+
*
|
|
107
|
+
* The `meta` container is compared as a SUBSET (only golden-declared meta keys are
|
|
108
|
+
* asserted) so deterministic-but-golden-absent infra keys the runtime stamps
|
|
109
|
+
* (`specVersion`, `transport`, …) are not phantom regressions; the semantic
|
|
110
|
+
* payload (`data`/`error`) keeps a full key-union compare where an extra or
|
|
111
|
+
* missing key IS a regression. Together with the volatile-lineage strip in
|
|
112
|
+
* {@link normalizeEnvelope}, a real live envelope that matches the golden body
|
|
113
|
+
* yields ZERO regressions.
|
|
114
|
+
*
|
|
115
|
+
* @param ops - The scenario ops (for op-coordinate labelling).
|
|
116
|
+
* @param replayed - The captured envelopes, one per op (replay order).
|
|
117
|
+
* @param golden - The golden expected entries, positionally aligned with `ops`.
|
|
118
|
+
* @returns `{ regressions }` — empty when the replay matches the golden.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```ts
|
|
122
|
+
* const { regressions } = diffEnvelopes(scenario.ops, replayed, golden.envelopes);
|
|
123
|
+
* if (regressions.length === 0) { /* happy path — no DHQ, no PR *\/ }
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
export declare function diffEnvelopes(ops: ScenarioOp[], replayed: ReplayEnvelope[], golden: GoldenEntry[]): EnvelopeDiffResult;
|
|
127
|
+
/**
|
|
128
|
+
* Extract a targeted field from a normalized envelope's `data` payload.
|
|
129
|
+
*
|
|
130
|
+
* Reuses the LAFS `--field` extractor (`extractFieldFromResult`) for cases where
|
|
131
|
+
* a full structural diff is too brittle and only a specific field's value matters
|
|
132
|
+
* (e.g. assert `data.tasks[0].id` without comparing the whole envelope).
|
|
133
|
+
*
|
|
134
|
+
* @param normalized - A normalized envelope (from {@link normalizeEnvelope}).
|
|
135
|
+
* @param field - The field name to extract from the envelope's `data` payload.
|
|
136
|
+
* @returns The extracted value, or `undefined` when absent.
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```ts
|
|
140
|
+
* const id = extractTargetedField(normalizeEnvelope(env), 'id');
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
export declare function extractTargetedField(normalized: NormalizedEnvelope, field: string): unknown;
|
|
144
|
+
/**
|
|
145
|
+
* Compute the sha256 `question_hash` of a diff result's normalized signature.
|
|
146
|
+
*
|
|
147
|
+
* The hash is over the {@link regressionSignature} (op coordinates + diff path
|
|
148
|
+
* set), so it is stable across runs of the SAME regression and feeds the
|
|
149
|
+
* idempotency partial-UNIQUE index (`ux_selfimprove_dhq_open`, T11889-A): one
|
|
150
|
+
* open DHQ row per `question_hash`. An empty regression set hashes the empty
|
|
151
|
+
* signature deterministically (callers should not persist on the happy path).
|
|
152
|
+
*
|
|
153
|
+
* @param result - The diff result whose regressions are hashed.
|
|
154
|
+
* @returns The lowercase hex sha256 of the regression signature.
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* ```ts
|
|
158
|
+
* const hash = computeQuestionHash(diffEnvelopes(ops, replayed, golden));
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
export declare function computeQuestionHash(result: EnvelopeDiffResult): string;
|
|
162
|
+
//# sourceMappingURL=envelope-diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope-diff.d.ts","sourceRoot":"","sources":["../../src/selfimprove/envelope-diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAmD7D;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEzD;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,MAAM,EAAE,OAAO,CAAC;IAChB,yDAAyD;IACzD,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,sEAAsE;AACtE,MAAM,WAAW,kBAAkB;IACjC,yEAAyE;IACzE,WAAW,EAAE,SAAS,EAAE,CAAC;CAC1B;AAeD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,cAAc,GAAG,kBAAkB,CAY9E;AAkED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,UAAU,EAAE,EACjB,QAAQ,EAAE,cAAc,EAAE,EAC1B,MAAM,EAAE,WAAW,EAAE,GACpB,kBAAkB,CAqCpB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAO3F;AAqBD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAGtE"}
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Envelope normalization + structural diff vs a golden (T11889-B).
|
|
3
|
+
*
|
|
4
|
+
* The self-improvement loop replays a scenario (see {@link "./replay.js"}) and
|
|
5
|
+
* diffs each captured envelope against the golden expected envelope. This module:
|
|
6
|
+
*
|
|
7
|
+
* 1. {@link normalizeEnvelope} — strips the VOLATILE `meta` fields so only
|
|
8
|
+
* deterministic structure is compared. Two classes are stripped:
|
|
9
|
+
* timing/trace fields (`timestamp`, `requestId`, `duration_ms` /
|
|
10
|
+
* `durationMs`) AND the per-run session-lineage UUIDs (`sessionId`,
|
|
11
|
+
* `originSessionId`, `executionSessionId`). The latter are non-deterministic:
|
|
12
|
+
* the live `Dispatcher` defaults `executionSessionId`/`originSessionId` to a
|
|
13
|
+
* fresh `randomUUID()` per request
|
|
14
|
+
* (`ensureRequestSessionLineage`), then stamps all three onto `response.meta`
|
|
15
|
+
* — so a real envelope carries UUIDs the hand-authored golden cannot know.
|
|
16
|
+
* Stripping them prevents a permanent phantom DHQ that self-fires on every
|
|
17
|
+
* clean run. (The runtime field is `meta` with snake_case `duration_ms`; the
|
|
18
|
+
* spec wording uses `_meta`/`durationMs`, so both spellings and both
|
|
19
|
+
* container keys are stripped defensively.)
|
|
20
|
+
* 2. {@link diffEnvelopes} — structurally compares the normalized envelope set
|
|
21
|
+
* against the golden, producing `{ regressions: DiffEntry[] }`. Zero
|
|
22
|
+
* regressions on a golden match; N on injected divergence. The `meta`
|
|
23
|
+
* container is compared as a SUBSET (only golden-declared meta keys are
|
|
24
|
+
* asserted) so deterministic-but-golden-absent infra keys
|
|
25
|
+
* (`specVersion`, `schemaVersion`, `transport`, `mvi`, `contextVersion`,
|
|
26
|
+
* `strict`, `x-cleo-transport`, …) stamped by the runtime are NOT phantom
|
|
27
|
+
* regressions. The semantic payload (`data`/`error`) is still compared by
|
|
28
|
+
* full key-union — a missing or extra payload key IS a regression.
|
|
29
|
+
* 3. {@link computeQuestionHash} — sha256 of the normalized regression
|
|
30
|
+
* signature (op coordinates + diff path set) so the SAME regression maps to
|
|
31
|
+
* the SAME open DHQ row (the idempotency partial-UNIQUE index in T11889-A).
|
|
32
|
+
*
|
|
33
|
+
* `extractFieldFromResult` from `@cleocode/lafs` is reused for targeted-field
|
|
34
|
+
* asserts where a full structural compare would be too brittle.
|
|
35
|
+
*
|
|
36
|
+
* This module is PURE — no DB, no native handle, no `cleo` mutation.
|
|
37
|
+
* Import-time side-effect-free.
|
|
38
|
+
*
|
|
39
|
+
* @module @cleocode/core/selfimprove/envelope-diff
|
|
40
|
+
* @epic T11889
|
|
41
|
+
* @task T11912
|
|
42
|
+
*/
|
|
43
|
+
import { createHash } from 'node:crypto';
|
|
44
|
+
import { extractFieldFromResult } from '@cleocode/lafs';
|
|
45
|
+
/**
|
|
46
|
+
* Volatile envelope-meta field names stripped before diffing.
|
|
47
|
+
*
|
|
48
|
+
* Two classes, both non-deterministic per run:
|
|
49
|
+
*
|
|
50
|
+
* - Timing / trace: `timestamp`, `requestId`, `duration_ms` (the runtime
|
|
51
|
+
* canonical, snake_case) and `durationMs` (the spec wording — stripped so a
|
|
52
|
+
* golden authored either way normalizes identically).
|
|
53
|
+
* - Session lineage: `sessionId`, `originSessionId`, `executionSessionId`. The
|
|
54
|
+
* live `Dispatcher` stamps these onto `response.meta`
|
|
55
|
+
* after defaulting `executionSessionId`/`originSessionId` to a fresh
|
|
56
|
+
* `randomUUID()` per request (`ensureRequestSessionLineage`). They are
|
|
57
|
+
* per-run UUIDs the hand-authored golden cannot encode; leaving them in would
|
|
58
|
+
* make every clean replay emit a phantom regression at
|
|
59
|
+
* `meta/executionSessionId` and `meta/originSessionId`, and because the
|
|
60
|
+
* regression signature hashes only `opCoord@path` (constant), the resulting
|
|
61
|
+
* `question_hash` would be STABLE — a permanent self-firing DHQ. Stripping
|
|
62
|
+
* them keeps an identical-but-for-lineage envelope a non-regression.
|
|
63
|
+
*/
|
|
64
|
+
const VOLATILE_META_FIELDS = [
|
|
65
|
+
'timestamp',
|
|
66
|
+
'requestId',
|
|
67
|
+
'duration_ms',
|
|
68
|
+
'durationMs',
|
|
69
|
+
'sessionId',
|
|
70
|
+
'originSessionId',
|
|
71
|
+
'executionSessionId',
|
|
72
|
+
];
|
|
73
|
+
/**
|
|
74
|
+
* Meta container keys whose volatile fields are stripped, and whose remaining
|
|
75
|
+
* keys are compared as a SUBSET (see {@link diffEnvelopes}).
|
|
76
|
+
*
|
|
77
|
+
* Runtime envelopes use `meta`; `_meta` is stripped too for defensive parity with
|
|
78
|
+
* the gateway envelope shape.
|
|
79
|
+
*/
|
|
80
|
+
const META_CONTAINER_KEYS = ['meta', '_meta'];
|
|
81
|
+
/**
|
|
82
|
+
* Top-level envelope keys whose value is a meta container.
|
|
83
|
+
*
|
|
84
|
+
* The structural diff treats these containers as a SUBSET compare (golden-declared
|
|
85
|
+
* keys only) so deterministic-but-golden-absent infra keys the runtime stamps
|
|
86
|
+
* (`specVersion`, `schemaVersion`, `transport`, `mvi`, `contextVersion`, `strict`,
|
|
87
|
+
* `x-cleo-transport`, …) are not phantom regressions. Everything else (`data`,
|
|
88
|
+
* `error`, …) keeps a full key-union compare.
|
|
89
|
+
*/
|
|
90
|
+
const SUBSET_COMPARE_KEYS = new Set(META_CONTAINER_KEYS);
|
|
91
|
+
/**
|
|
92
|
+
* Deep-clone a JSON-serializable value via structured round-trip.
|
|
93
|
+
*
|
|
94
|
+
* Replay envelopes are JSON-shaped (they round-trip through transports), so a
|
|
95
|
+
* JSON clone is safe and avoids mutating the caller's object during normalization.
|
|
96
|
+
*
|
|
97
|
+
* @param value - The value to clone.
|
|
98
|
+
* @returns A deep copy.
|
|
99
|
+
*/
|
|
100
|
+
function jsonClone(value) {
|
|
101
|
+
return JSON.parse(JSON.stringify(value));
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Strip the volatile `meta`/`_meta` fields from an envelope.
|
|
105
|
+
*
|
|
106
|
+
* Returns a NEW object; the input is not mutated. The volatile timing/trace fields
|
|
107
|
+
* AND the per-run session-lineage UUIDs (`sessionId`, `originSessionId`,
|
|
108
|
+
* `executionSessionId`) are removed — see {@link VOLATILE_META_FIELDS}. The stable
|
|
109
|
+
* meta remnant (`gateway`, `domain`, `operation`, `source`, …) is preserved so
|
|
110
|
+
* structural identity (which operation produced the envelope) still compares.
|
|
111
|
+
*
|
|
112
|
+
* Note: deterministic-but-golden-absent infra meta keys (`specVersion`,
|
|
113
|
+
* `transport`, …) are NOT stripped here — they are tolerated by the SUBSET compare
|
|
114
|
+
* in {@link diffEnvelopes} instead, so the strip set stays exactly the volatile
|
|
115
|
+
* fields and nothing semantic.
|
|
116
|
+
*
|
|
117
|
+
* @param envelope - The replayed envelope to normalize.
|
|
118
|
+
* @returns The normalized envelope with volatile meta fields removed.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```ts
|
|
122
|
+
* const norm = normalizeEnvelope(envelope);
|
|
123
|
+
* // norm.meta has no timestamp / requestId / duration_ms / *SessionId
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
export function normalizeEnvelope(envelope) {
|
|
127
|
+
const cloned = jsonClone(envelope);
|
|
128
|
+
for (const containerKey of META_CONTAINER_KEYS) {
|
|
129
|
+
const container = cloned[containerKey];
|
|
130
|
+
if (container !== null && typeof container === 'object' && !Array.isArray(container)) {
|
|
131
|
+
const meta = container;
|
|
132
|
+
for (const field of VOLATILE_META_FIELDS) {
|
|
133
|
+
delete meta[field];
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return cloned;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Recursively collect structural differences between two JSON values.
|
|
141
|
+
*
|
|
142
|
+
* Walks both trees in parallel, recording a `{ path, actual, expected }` for each
|
|
143
|
+
* leaf-level divergence. Object key sets and array lengths are compared; the path
|
|
144
|
+
* uses `/`-delimited segments.
|
|
145
|
+
*
|
|
146
|
+
* Key-set semantics depend on the container:
|
|
147
|
+
* - **Subset** (`subset === true`): only the EXPECTED (golden) object's keys are
|
|
148
|
+
* compared. Extra keys present in `actual` but absent from the golden are
|
|
149
|
+
* ignored. Applied to the `meta` container (see {@link SUBSET_COMPARE_KEYS}) so
|
|
150
|
+
* deterministic infra meta keys the runtime stamps but the golden omits are not
|
|
151
|
+
* phantom regressions.
|
|
152
|
+
* - **Full union** (`subset === false`, the default): keys from BOTH objects are
|
|
153
|
+
* compared, so an extra OR missing key is a regression. Applied to the semantic
|
|
154
|
+
* payload (`data`/`error`).
|
|
155
|
+
*
|
|
156
|
+
* A child whose top-level key is in {@link SUBSET_COMPARE_KEYS} (i.e. `meta`)
|
|
157
|
+
* switches its subtree into subset mode.
|
|
158
|
+
*
|
|
159
|
+
* @param actual - The actual (normalized replay) value.
|
|
160
|
+
* @param expected - The expected (golden) value.
|
|
161
|
+
* @param path - Accumulated path prefix.
|
|
162
|
+
* @param out - Mutable accumulator of `{ path, actual, expected }` tuples.
|
|
163
|
+
* @param subset - When `true`, compare only the golden-declared keys at this node.
|
|
164
|
+
*/
|
|
165
|
+
function collectStructuralDiffs(actual, expected, path, out, subset = false) {
|
|
166
|
+
if (actual === expected)
|
|
167
|
+
return;
|
|
168
|
+
const bothObjects = actual !== null &&
|
|
169
|
+
expected !== null &&
|
|
170
|
+
typeof actual === 'object' &&
|
|
171
|
+
typeof expected === 'object' &&
|
|
172
|
+
Array.isArray(actual) === Array.isArray(expected);
|
|
173
|
+
if (!bothObjects) {
|
|
174
|
+
out.push({ path, actual, expected });
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const actualRec = actual;
|
|
178
|
+
const expectedRec = expected;
|
|
179
|
+
// Subset mode (meta container): compare ONLY the golden's keys, so extra
|
|
180
|
+
// deterministic runtime meta keys are not regressions. Full mode: union both
|
|
181
|
+
// key sets, so an extra OR missing payload key IS a regression.
|
|
182
|
+
const keys = subset
|
|
183
|
+
? new Set(Object.keys(expectedRec))
|
|
184
|
+
: new Set([...Object.keys(actualRec), ...Object.keys(expectedRec)]);
|
|
185
|
+
for (const key of keys) {
|
|
186
|
+
const childPath = path === '' ? key : `${path}/${key}`;
|
|
187
|
+
// A `meta`/`_meta` container's subtree is compared as a subset; never widen
|
|
188
|
+
// back to full-union once inside a subset container.
|
|
189
|
+
const childSubset = subset || SUBSET_COMPARE_KEYS.has(key);
|
|
190
|
+
collectStructuralDiffs(actualRec[key], expectedRec[key], childPath, out, childSubset);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Diff a set of replayed envelopes against the golden envelope set.
|
|
195
|
+
*
|
|
196
|
+
* Normalizes each replayed envelope (volatile meta stripped) and structurally
|
|
197
|
+
* compares it against the positionally-aligned golden entry. The op coordinate
|
|
198
|
+
* for each `DiffEntry` is taken from `ops[opIndex]`. Callers MUST pass aligned
|
|
199
|
+
* arrays (`ops.length === replayed.length === golden.length`); the function
|
|
200
|
+
* diffs up to the shortest length and reports an extra regression for any length
|
|
201
|
+
* mismatch.
|
|
202
|
+
*
|
|
203
|
+
* The `meta` container is compared as a SUBSET (only golden-declared meta keys are
|
|
204
|
+
* asserted) so deterministic-but-golden-absent infra keys the runtime stamps
|
|
205
|
+
* (`specVersion`, `transport`, …) are not phantom regressions; the semantic
|
|
206
|
+
* payload (`data`/`error`) keeps a full key-union compare where an extra or
|
|
207
|
+
* missing key IS a regression. Together with the volatile-lineage strip in
|
|
208
|
+
* {@link normalizeEnvelope}, a real live envelope that matches the golden body
|
|
209
|
+
* yields ZERO regressions.
|
|
210
|
+
*
|
|
211
|
+
* @param ops - The scenario ops (for op-coordinate labelling).
|
|
212
|
+
* @param replayed - The captured envelopes, one per op (replay order).
|
|
213
|
+
* @param golden - The golden expected entries, positionally aligned with `ops`.
|
|
214
|
+
* @returns `{ regressions }` — empty when the replay matches the golden.
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* ```ts
|
|
218
|
+
* const { regressions } = diffEnvelopes(scenario.ops, replayed, golden.envelopes);
|
|
219
|
+
* if (regressions.length === 0) { /* happy path — no DHQ, no PR *\/ }
|
|
220
|
+
* ```
|
|
221
|
+
*/
|
|
222
|
+
export function diffEnvelopes(ops, replayed, golden) {
|
|
223
|
+
const regressions = [];
|
|
224
|
+
const n = Math.min(ops.length, replayed.length, golden.length);
|
|
225
|
+
for (let i = 0; i < n; i++) {
|
|
226
|
+
const op = ops[i];
|
|
227
|
+
const replayEnvelope = replayed[i];
|
|
228
|
+
const goldenEntry = golden[i];
|
|
229
|
+
if (op === undefined || replayEnvelope === undefined || goldenEntry === undefined)
|
|
230
|
+
continue;
|
|
231
|
+
const opCoord = `${op.domain}.${op.operation}`;
|
|
232
|
+
const normalized = normalizeEnvelope(replayEnvelope);
|
|
233
|
+
const leafDiffs = [];
|
|
234
|
+
collectStructuralDiffs(normalized, goldenEntry, '', leafDiffs);
|
|
235
|
+
for (const d of leafDiffs) {
|
|
236
|
+
regressions.push({
|
|
237
|
+
opIndex: i,
|
|
238
|
+
opCoord,
|
|
239
|
+
path: d.path,
|
|
240
|
+
actual: d.actual,
|
|
241
|
+
expected: d.expected,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (replayed.length !== golden.length) {
|
|
246
|
+
regressions.push({
|
|
247
|
+
opIndex: -1,
|
|
248
|
+
opCoord: '<count>',
|
|
249
|
+
path: 'envelopes/length',
|
|
250
|
+
actual: replayed.length,
|
|
251
|
+
expected: golden.length,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
return { regressions };
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Extract a targeted field from a normalized envelope's `data` payload.
|
|
258
|
+
*
|
|
259
|
+
* Reuses the LAFS `--field` extractor (`extractFieldFromResult`) for cases where
|
|
260
|
+
* a full structural diff is too brittle and only a specific field's value matters
|
|
261
|
+
* (e.g. assert `data.tasks[0].id` without comparing the whole envelope).
|
|
262
|
+
*
|
|
263
|
+
* @param normalized - A normalized envelope (from {@link normalizeEnvelope}).
|
|
264
|
+
* @param field - The field name to extract from the envelope's `data` payload.
|
|
265
|
+
* @returns The extracted value, or `undefined` when absent.
|
|
266
|
+
*
|
|
267
|
+
* @example
|
|
268
|
+
* ```ts
|
|
269
|
+
* const id = extractTargetedField(normalizeEnvelope(env), 'id');
|
|
270
|
+
* ```
|
|
271
|
+
*/
|
|
272
|
+
export function extractTargetedField(normalized, field) {
|
|
273
|
+
const data = normalized.data;
|
|
274
|
+
if (data === undefined || data === null)
|
|
275
|
+
return undefined;
|
|
276
|
+
// The LAFS extractor operates on a result value (object | array | null); the
|
|
277
|
+
// dispatch envelope's `data` is the equivalent payload.
|
|
278
|
+
if (typeof data !== 'object')
|
|
279
|
+
return undefined;
|
|
280
|
+
return extractFieldFromResult(data, field);
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Build the deterministic regression signature for a diff result.
|
|
284
|
+
*
|
|
285
|
+
* The signature is the SORTED set of `{ opCoord, path }` pairs from the
|
|
286
|
+
* regressions — NOT the values. Two runs that diverge at the same op coordinates
|
|
287
|
+
* on the same paths produce the same signature (and thus the same
|
|
288
|
+
* {@link computeQuestionHash}), so a repeated regression maps to ONE open DHQ row
|
|
289
|
+
* rather than spamming duplicates. Actual/expected values are intentionally
|
|
290
|
+
* excluded so transient value noise does not fork the hash.
|
|
291
|
+
*
|
|
292
|
+
* @param regressions - The diff regressions.
|
|
293
|
+
* @returns A stable, sorted signature string.
|
|
294
|
+
*/
|
|
295
|
+
function regressionSignature(regressions) {
|
|
296
|
+
const pairs = regressions.map((r) => `${r.opCoord}@${r.path}`);
|
|
297
|
+
pairs.sort();
|
|
298
|
+
return pairs.join('\n');
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Compute the sha256 `question_hash` of a diff result's normalized signature.
|
|
302
|
+
*
|
|
303
|
+
* The hash is over the {@link regressionSignature} (op coordinates + diff path
|
|
304
|
+
* set), so it is stable across runs of the SAME regression and feeds the
|
|
305
|
+
* idempotency partial-UNIQUE index (`ux_selfimprove_dhq_open`, T11889-A): one
|
|
306
|
+
* open DHQ row per `question_hash`. An empty regression set hashes the empty
|
|
307
|
+
* signature deterministically (callers should not persist on the happy path).
|
|
308
|
+
*
|
|
309
|
+
* @param result - The diff result whose regressions are hashed.
|
|
310
|
+
* @returns The lowercase hex sha256 of the regression signature.
|
|
311
|
+
*
|
|
312
|
+
* @example
|
|
313
|
+
* ```ts
|
|
314
|
+
* const hash = computeQuestionHash(diffEnvelopes(ops, replayed, golden));
|
|
315
|
+
* ```
|
|
316
|
+
*/
|
|
317
|
+
export function computeQuestionHash(result) {
|
|
318
|
+
const signature = regressionSignature(result.regressions);
|
|
319
|
+
return createHash('sha256').update(signature, 'utf-8').digest('hex');
|
|
320
|
+
}
|
|
321
|
+
//# sourceMappingURL=envelope-diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope-diff.js","sourceRoot":"","sources":["../../src/selfimprove/envelope-diff.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Self-improvement scenario replay via an injected dispatch port (T11889-B).
|
|
3
|
+
*
|
|
4
|
+
* `replayScenario` replays a scenario's ordered ops through an injected
|
|
5
|
+
* {@link ReplayDispatch} port — it captures ONE LAFS envelope per op. CORE owns
|
|
6
|
+
* the PORT TYPE only; the real adapter (a thin closure over the cleo-resident
|
|
7
|
+
* `Dispatcher`) is supplied by `packages/cleo` at the call site (dependency
|
|
8
|
+
* inversion — `core` MUST NOT import the cleo dispatcher, and `dispatchFromCore`
|
|
9
|
+
* does not exist; see the P5 self-improvement spec §B.0.1).
|
|
10
|
+
*
|
|
11
|
+
* This module is PURE — no DB, no native handle, no `cleo` mutation. Tests inject
|
|
12
|
+
* a mocked `ReplayDispatch`. Import-time side-effect-free: the logger is resolved
|
|
13
|
+
* lazily on first use.
|
|
14
|
+
*
|
|
15
|
+
* Read-only guarantee: in the in-process fallback (no VM isolation) a `mutate` op
|
|
16
|
+
* could touch a live handle, so {@link replayScenario} HARD-REJECTS any
|
|
17
|
+
* `gateway:'mutate'` op when `allowMutate` is not explicitly set, throwing
|
|
18
|
+
* {@link MutateInFallbackError} (code `E_SELFIMPROVE_MUTATE_IN_FALLBACK`). The
|
|
19
|
+
* canned dogfood scenario is `query`-only, so the default replay never mutates.
|
|
20
|
+
*
|
|
21
|
+
* @module @cleocode/core/selfimprove/replay
|
|
22
|
+
* @epic T11889
|
|
23
|
+
* @task T11912
|
|
24
|
+
*/
|
|
25
|
+
import type { DispatchResponse } from '@cleocode/contracts/gateway';
|
|
26
|
+
import type { Scenario, ScenarioOp } from './scenario.js';
|
|
27
|
+
/**
|
|
28
|
+
* The captured envelope shape per replayed op.
|
|
29
|
+
*
|
|
30
|
+
* This is the canonical {@link DispatchResponse} the cleo-side `Dispatcher`
|
|
31
|
+
* returns (a `meta` block + `success` + optional `data`/`error`/`page`/`partial`).
|
|
32
|
+
* The diff layer (see {@link "./envelope-diff.js"}) normalizes this by stripping
|
|
33
|
+
* the volatile `meta` fields before comparing against the golden.
|
|
34
|
+
*/
|
|
35
|
+
export type ReplayEnvelope = DispatchResponse;
|
|
36
|
+
/**
|
|
37
|
+
* Narrow dispatch port the replay engine calls — CORE owns this TYPE, NOT the impl.
|
|
38
|
+
*
|
|
39
|
+
* The cleo dispatch handler supplies the concrete adapter by closing over its
|
|
40
|
+
* already-instantiated `Dispatcher` (`dispatcher.dispatch({ gateway, domain,
|
|
41
|
+
* operation, params, source, requestId })`, where `source` is a valid
|
|
42
|
+
* `GatewaySource` — e.g. `'rpc'`) and returning the resulting envelope. Injecting
|
|
43
|
+
* the port keeps the engine + diff + budget logic
|
|
44
|
+
* in `core` while the dispatcher binding lives in `cleo` (CORE-first, no
|
|
45
|
+
* package-boundary inversion).
|
|
46
|
+
*/
|
|
47
|
+
/**
|
|
48
|
+
* The dispatch coordinate handed to a {@link ReplayDispatch} port for one op.
|
|
49
|
+
*/
|
|
50
|
+
export interface ReplayDispatchOp {
|
|
51
|
+
/** CQRS gateway. */
|
|
52
|
+
gateway: ScenarioOp['gateway'];
|
|
53
|
+
/** Registered domain handler key (plural, e.g. `'tasks'`). */
|
|
54
|
+
domain: string;
|
|
55
|
+
/** Operation name within the domain. */
|
|
56
|
+
operation: string;
|
|
57
|
+
/** Optional operation parameters. */
|
|
58
|
+
params?: Record<string, unknown>;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Dispatch a single op and return its captured envelope.
|
|
62
|
+
*
|
|
63
|
+
* @param op - The dispatch coordinate (gateway, domain, operation, params).
|
|
64
|
+
* @returns The captured {@link ReplayEnvelope}.
|
|
65
|
+
*/
|
|
66
|
+
export type ReplayDispatch = (op: ReplayDispatchOp) => Promise<ReplayEnvelope>;
|
|
67
|
+
/** Options controlling a replay run. */
|
|
68
|
+
export interface ReplayOptions {
|
|
69
|
+
/**
|
|
70
|
+
* When `true`, permit `gateway:'mutate'` ops (VM-isolated execution path).
|
|
71
|
+
*
|
|
72
|
+
* Defaults to `false`: in the in-process fallback there is no VM boundary, so a
|
|
73
|
+
* mutate op is HARD-REJECTED with {@link MutateInFallbackError}. The canned
|
|
74
|
+
* dogfood scenario is `query`-only and never sets this.
|
|
75
|
+
*
|
|
76
|
+
* @defaultValue false
|
|
77
|
+
*/
|
|
78
|
+
allowMutate?: boolean;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Thrown when a `gateway:'mutate'` op is replayed without `allowMutate`.
|
|
82
|
+
*
|
|
83
|
+
* In the in-process fallback the replay runs in the host process, which DOES hold
|
|
84
|
+
* live-DB handles; a mutate op there could corrupt a live `tasks.db`/`brain.db`
|
|
85
|
+
* (the T5158 vector). The hard guard ensures no mutate path can fire without an
|
|
86
|
+
* explicit VM-isolation opt-in.
|
|
87
|
+
*/
|
|
88
|
+
export declare class MutateInFallbackError extends Error {
|
|
89
|
+
/** Stable machine-readable error code. */
|
|
90
|
+
readonly code: "E_SELFIMPROVE_MUTATE_IN_FALLBACK";
|
|
91
|
+
/** The op coordinate (`domain.operation`) that was rejected. */
|
|
92
|
+
readonly opCoord: string;
|
|
93
|
+
/**
|
|
94
|
+
* @param op - The rejected mutate op.
|
|
95
|
+
*/
|
|
96
|
+
constructor(op: ScenarioOp);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Replay a scenario's ordered ops through the injected dispatch port.
|
|
100
|
+
*
|
|
101
|
+
* Captures ONE envelope per op, in op order. Read-only by default: every
|
|
102
|
+
* `gateway:'mutate'` op is HARD-REJECTED with {@link MutateInFallbackError}
|
|
103
|
+
* unless `options.allowMutate` is set (the VM-isolation path).
|
|
104
|
+
*
|
|
105
|
+
* PURE — no DB, no mutation. The `dispatch` port is the only external dependency;
|
|
106
|
+
* tests inject a mock.
|
|
107
|
+
*
|
|
108
|
+
* @param scenario - The validated scenario whose ops are replayed.
|
|
109
|
+
* @param dispatch - The injected dispatch port (cleo supplies the real adapter).
|
|
110
|
+
* @param options - Replay options; see {@link ReplayOptions}.
|
|
111
|
+
* @returns The captured envelopes, one per op, in scenario order.
|
|
112
|
+
* @throws {@link MutateInFallbackError} On a `mutate` op without `allowMutate`.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```ts
|
|
116
|
+
* const envelopes = await replayScenario(scenario, dispatch);
|
|
117
|
+
* // envelopes.length === scenario.ops.length
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
export declare function replayScenario(scenario: Scenario, dispatch: ReplayDispatch, options?: ReplayOptions): Promise<ReplayEnvelope[]>;
|
|
121
|
+
//# sourceMappingURL=replay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../../src/selfimprove/replay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAEpE,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE1D;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG,gBAAgB,CAAC;AAE9C;;;;;;;;;;GAUG;AACH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,oBAAoB;IACpB,OAAO,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC;IAC/B,8DAA8D;IAC9D,MAAM,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,EAAE,EAAE,gBAAgB,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;AAE/E,wCAAwC;AACxC,MAAM,WAAW,aAAa;IAC5B;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,0CAA0C;IAC1C,SAAgB,IAAI,EAAG,kCAAkC,CAAU;IAEnE,gEAAgE;IAChE,SAAgB,OAAO,EAAE,MAAM,CAAC;IAEhC;;OAEG;gBACS,EAAE,EAAE,UAAU;CAS3B;AAuBD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,cAAc,EACxB,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,cAAc,EAAE,CAAC,CAwB3B"}
|