@cassiomc1/forgeloop 1.13.0 → 2.0.0-rc.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/AGENT_COMPATIBILITY.md +8 -0
- package/CONTRIBUTING.md +11 -7
- package/DOCS_INDEX.md +37 -4
- package/ENG/c-development-eng.md +2 -2
- package/ENG/cpp-development-eng.md +2 -2
- package/ENG/dotnet-aspnetcore-development-eng.md +7 -1
- package/ENG/flutter-development-eng.md +4 -2
- package/ENG/go-development-eng.md +2 -2
- package/ENG/java-development-eng.md +3 -3
- package/ENG/nodejs-backend-development-eng.md +10 -6
- package/ENG/php-development-eng.md +3 -3
- package/ENG/python-development-eng.md +205 -0
- package/ENG/rust-development-eng.md +42 -1
- package/ENG/sec-code-eng.md +7 -7
- package/ENG/sql-development-eng.md +4 -4
- package/ENG/swift-development-eng.md +5 -4
- package/ENG/test-code-eng.md +1 -1
- package/ENG/typescript-development-eng.md +4 -4
- package/EXECUTION_STATE.md +12 -0
- package/GUIDE_ROUTER.md +6 -0
- package/LICENSE +133 -21
- package/LOOP_ENGINEERING.md +28 -2
- package/LOOP_SYSTEM_DESIGN.md +10 -10
- package/ORCHESTRATOR_INTEGRATION.md +9 -5
- package/PROTOCOL_INTEGRATION.md +55 -2
- package/README.md +63 -59
- package/TERMINOLOGY.md +2 -0
- package/THIRD_PARTY_NOTICES.md +3 -4
- package/THREAT_MODEL.md +140 -1
- package/completions/_forgeloop +29 -3
- package/completions/forgeloop.bash +55 -3
- package/completions/forgeloop.fish +183 -1
- package/docs/ADVISORY_CONTEXT.md +25 -0
- package/docs/AGENT_BROWSER_ADAPTER.md +81 -0
- package/docs/AGENT_BROWSER_VERIFICATION.md +6 -0
- package/docs/AGENT_PROTOCOL_SUMMARY.md +74 -39
- package/docs/AGENT_SKILL.md +66 -0
- package/docs/ARTIFACT_REFERENCE.md +171 -35
- package/docs/AUDIT_UX.md +46 -0
- package/docs/BROWSER_VERIFICATION.md +136 -0
- package/docs/CLI_REFERENCE.md +512 -8
- package/docs/CODE_ATTESTATION.md +2 -2
- package/docs/DOCUMENTATION_GUIDE.md +34 -11
- package/docs/GETTING_STARTED.md +3 -3
- package/docs/JEV_BENCHMARKS.md +31 -0
- package/docs/MODEL_ROUTING.md +37 -0
- package/docs/OPENSRC_ADAPTER.md +241 -0
- package/docs/PACKAGE_CONTENTS.md +46 -18
- package/docs/PROVIDERS.md +126 -0
- package/docs/PROVIDER_ARCHITECTURE.md +199 -0
- package/docs/RECIPES.md +9 -0
- package/docs/RELEASE_CHECKLIST.md +116 -12
- package/docs/SECURITY_REVIEW.md +71 -0
- package/docs/SELF_HOSTED_TESTS.md +121 -0
- package/docs/SEMANTIC_DECISION_PLANE.md +71 -0
- package/docs/TEST_INTELLIGENCE.md +29 -0
- package/docs/TEST_PRUNING.md +14 -0
- package/docs/TROUBLESHOOTING.md +198 -1
- package/docs/UNIVERSAL_INTEGRATION.md +31 -0
- package/docs/assets/diagrams/forgeloop-code-attestation-flow.html +2 -2
- package/docs/assets/diagrams/forgeloop-code-attestation-flow.receipt.json +5 -5
- package/docs/assets/diagrams/forgeloop-code-attestation-flow.svg +1 -1
- package/docs/assets/diagrams/forgeloop-engineering-flow.html +39 -26
- package/docs/assets/diagrams/forgeloop-engineering-flow.receipt.json +6 -6
- package/docs/assets/diagrams/forgeloop-engineering-flow.svg +26 -26
- package/docs/assets/diagrams/forgeloop-verification-trust-flow.html +2 -1
- package/docs/assets/diagrams/forgeloop-verification-trust-flow.receipt.json +5 -5
- package/docs/assets/diagrams/forgeloop-verification-trust-flow.svg +1 -1
- package/docs/diagrams/README.md +13 -9
- package/docs/diagrams/forgeloop-code-attestation-flow.workflow.json +1 -1
- package/docs/diagrams/forgeloop-engineering-flow.workflow.json +24 -19
- package/docs/diagrams/forgeloop-verification-trust-flow.workflow.json +1 -0
- package/docs/diagrams/reviews/forgeloop-code-attestation-flow.review.json +4 -4
- package/docs/diagrams/reviews/forgeloop-engineering-flow.review.json +4 -4
- package/docs/diagrams/reviews/forgeloop-verification-trust-flow.review.json +4 -4
- package/docs/documentation-manifest.json +774 -16
- package/docs/protocol-requirements.json +24 -0
- package/package.json +43 -11
- package/schemas/config.schema.json +14 -0
- package/schemas/context-plan.schema.json +18 -0
- package/schemas/semantic-decision.schema.json +46 -0
- package/schemas/task-bundle.schema.json +7 -2
- package/schemas/test-utility.schema.json +44 -0
- package/scripts/CI_VALIDATORS.md +6 -6
- package/scripts/benchmark-jev.mjs +5 -0
- package/scripts/benchmark-test-intelligence.mjs +4 -0
- package/scripts/generate-agent-protocol-summary.mjs +6 -3
- package/scripts/generate-forgeloop-skill.mjs +133 -0
- package/scripts/jev-smoke.mjs +19 -0
- package/scripts/run-mcp-clean-tests.mjs +30 -0
- package/skills/forgeloop/README.md +9 -0
- package/skills/forgeloop/SKILL.md +77 -0
- package/skills/forgeloop/references/lifecycle.md +9 -0
- package/skills/forgeloop/references/recovery.md +7 -0
- package/skills/forgeloop/references/verification.md +7 -0
- package/src/adapters/agent-browser/assertions.js +47 -0
- package/src/adapters/agent-browser/commands.js +54 -0
- package/src/adapters/agent-browser/index.js +3 -0
- package/src/adapters/agent-browser/locator.js +40 -0
- package/src/adapters/agent-browser/process.js +215 -0
- package/src/adapters/agent-browser/provider.js +316 -0
- package/src/adapters/emulated-services/constants.js +24 -0
- package/src/adapters/emulated-services/index.js +7 -0
- package/src/adapters/emulated-services/process.js +162 -0
- package/src/adapters/emulated-services/provider.js +289 -0
- package/src/adapters/opensrc/normalize.js +90 -0
- package/src/adapters/opensrc/process.js +248 -0
- package/src/adapters/opensrc/provider.js +338 -0
- package/src/adapters/opensrc/search.js +264 -0
- package/src/adapters/temporary-paths.js +18 -0
- package/src/adapters/typesafe/client.js +28 -0
- package/src/adapters/typesafe/engine.js +63 -0
- package/src/adapters/typesafe/normalize.js +41 -0
- package/src/cli.js +218 -174
- package/src/commands/action-show.js +5 -2
- package/src/commands/advance.js +5 -1
- package/src/commands/baseline.js +13 -11
- package/src/commands/checkpoint-revalidate.js +192 -0
- package/src/commands/complete.js +19 -3
- package/src/commands/context-plan.js +38 -0
- package/src/commands/contract-create.js +266 -0
- package/src/commands/contract-revise.js +236 -0
- package/src/commands/decision-show.js +14 -0
- package/src/commands/decision-status.js +22 -0
- package/src/commands/discover.js +41 -0
- package/src/commands/doctor.js +51 -13
- package/src/commands/gate-record.js +194 -0
- package/src/commands/gate-revalidate.js +135 -0
- package/src/commands/handoff-list.js +6 -1
- package/src/commands/handoff-show.js +6 -1
- package/src/commands/migrate-protocol.js +2 -2
- package/src/commands/model-route.js +40 -0
- package/src/commands/next.js +7 -1
- package/src/commands/policy-diff.js +25 -4
- package/src/commands/progress.js +17 -11
- package/src/commands/record-diagnosis.js +3 -0
- package/src/commands/route.js +146 -18
- package/src/commands/semantic-plan.js +41 -0
- package/src/commands/status.js +6 -1
- package/src/commands/storage-backup.js +15 -0
- package/src/commands/storage-migrate.js +5 -0
- package/src/commands/storage-migration-resume.js +5 -0
- package/src/commands/storage-migration-status.js +44 -0
- package/src/commands/storage-restore-resume.js +7 -0
- package/src/commands/storage-restore.js +8 -0
- package/src/commands/task-abandon.js +224 -0
- package/src/commands/task-list.js +8 -43
- package/src/commands/task-migrate-contract-bootstrap-repair.js +288 -0
- package/src/commands/task-migrate.js +3 -3
- package/src/commands/task-recover.js +10 -2
- package/src/commands/task-repair-contract-bootstrap.js +263 -0
- package/src/commands/task-scope.js +18 -2
- package/src/commands/task-show.js +16 -2
- package/src/commands/test-inventory.js +5 -0
- package/src/commands/test-prune-plan.js +5 -0
- package/src/commands/test-prune-probe.js +5 -0
- package/src/commands/test-utility.js +5 -0
- package/src/commands/validate-protocol.js +39 -15
- package/src/commands/validate-receipt.js +8 -1
- package/src/config/guides.json +4 -0
- package/src/core/action-ledger-projection.js +10 -3
- package/src/core/actions.js +38 -75
- package/src/core/activation.js +11 -3
- package/src/core/approvals.js +17 -51
- package/src/core/artifact-registry.js +83 -2
- package/src/core/artifacts.js +81 -27
- package/src/core/attachment-paths.js +45 -0
- package/src/core/attestation-coverage.js +6 -1
- package/src/core/attestation-verifier.js +21 -2
- package/src/core/attestation.js +17 -6
- package/src/core/audit-ux.js +514 -0
- package/src/core/audit.js +6 -1
- package/src/core/browser-verification/constants.js +149 -0
- package/src/core/browser-verification/normalize.js +254 -0
- package/src/core/browser-verification/provider.js +519 -0
- package/src/core/browser-verification/service.js +115 -0
- package/src/core/bundles.js +160 -66
- package/src/core/checkpoint-revalidation.js +321 -0
- package/src/core/cli-command-definitions.js +350 -7
- package/src/core/code-manifest.js +9 -3
- package/src/core/command-executors.js +274 -108
- package/src/core/command-input.js +136 -44
- package/src/core/completion-artifacts.js +85 -34
- package/src/core/completion-ownership.js +19 -8
- package/src/core/completion-recovery-rebind.js +11 -1
- package/src/core/completion.js +64 -15
- package/src/core/config.js +3 -0
- package/src/core/conformance.js +2 -1
- package/src/core/context-compiler/budget.js +9 -0
- package/src/core/context-compiler/candidates.js +39 -0
- package/src/core/context-compiler/compiler.js +63 -0
- package/src/core/context-compiler/fingerprint.js +11 -0
- package/src/core/context-compiler/policy.js +13 -0
- package/src/core/context-compiler/result.js +23 -0
- package/src/core/continuity-lint.js +13 -2
- package/src/core/continuity-reconciliation.js +16 -3
- package/src/core/continuity.js +16 -8
- package/src/core/contract-bootstrap-recovery.js +656 -0
- package/src/core/contract-revision.js +209 -0
- package/src/core/decision/artifact.js +70 -0
- package/src/core/decision/benchmarks.js +103 -0
- package/src/core/decision/cache.js +27 -0
- package/src/core/decision/constants.js +58 -0
- package/src/core/decision/cutover.js +34 -0
- package/src/core/decision/engine.js +22 -0
- package/src/core/decision/errors.js +68 -0
- package/src/core/decision/events.js +104 -0
- package/src/core/decision/freshness.js +19 -0
- package/src/core/decision/normalizers/index.js +115 -0
- package/src/core/decision/policy.js +18 -0
- package/src/core/decision/projection.js +16 -0
- package/src/core/decision/question-registry.js +201 -0
- package/src/core/decision/request.js +26 -0
- package/src/core/decision/resolver.js +138 -0
- package/src/core/decision/result.js +58 -0
- package/src/core/decision/service.js +181 -0
- package/src/core/decision/state-builder.js +65 -0
- package/src/core/decision/task-bindings.js +35 -0
- package/src/core/decision/test-provider.js +32 -0
- package/src/core/decision/thresholds.js +15 -0
- package/src/core/diagnosis-model.js +11 -0
- package/src/core/diagnosis.js +10 -1
- package/src/core/diagnostic-projection.js +29 -12
- package/src/core/diagnostic-record.js +28 -3
- package/src/core/efficiency.js +6 -1
- package/src/core/error-codes.js +278 -0
- package/src/core/events.js +535 -147
- package/src/core/evidence-readiness.js +9 -0
- package/src/core/execution-prerequisites.js +36 -13
- package/src/core/execution-profile.js +63 -38
- package/src/core/execution.js +26 -40
- package/src/core/filesystem.js +11 -0
- package/src/core/gate-artifact.js +105 -19
- package/src/core/gate-provenance.js +125 -0
- package/src/core/handoff.js +26 -14
- package/src/core/history.js +39 -35
- package/src/core/hypothesis-projection.js +32 -0
- package/src/core/information-gain-projection.js +104 -100
- package/src/core/inspect.js +12 -3
- package/src/core/integration-invocation-policy.js +37 -4
- package/src/core/integration-resources.js +119 -87
- package/src/core/ledger-event-collection.js +189 -0
- package/src/core/ledger-relations.js +23 -0
- package/src/core/model-router/constants.js +10 -0
- package/src/core/model-router/policy.js +103 -0
- package/src/core/model-router/router.js +37 -0
- package/src/core/native-storage.js +12 -0
- package/src/core/next-action-continuity.js +31 -9
- package/src/core/next-action-model.js +58 -0
- package/src/core/next-action-phases.js +131 -43
- package/src/core/next-action-refresh.js +43 -9
- package/src/core/next-action-review-phase.js +9 -4
- package/src/core/next-action-verification-phase.js +2 -1
- package/src/core/next-action.js +56 -9
- package/src/core/phase.js +266 -103
- package/src/core/policy-engine.js +12 -13
- package/src/core/preflight-consistency.js +89 -62
- package/src/core/preflight-loaders.js +48 -9
- package/src/core/preflight-model.js +6 -1
- package/src/core/preflight.js +29 -12
- package/src/core/progress.js +21 -10
- package/src/core/protocol-info.js +68 -0
- package/src/core/protocol-migration.js +7 -6
- package/src/core/protocol.js +20 -0
- package/src/core/reconcile-closure.js +281 -67
- package/src/core/recovery-history.js +67 -47
- package/src/core/reflection.js +72 -77
- package/src/core/responsibility.js +25 -13
- package/src/core/resumability.js +154 -44
- package/src/core/route-artifact.js +28 -4
- package/src/core/router.js +67 -1
- package/src/core/runtime-context.js +123 -61
- package/src/core/schema-validation.js +11 -3
- package/src/core/security-review/constants.js +64 -0
- package/src/core/security-review/normalize.js +245 -0
- package/src/core/security-review/provider.js +204 -0
- package/src/core/security-review/service.js +134 -0
- package/src/core/semantic-planning/constants.js +19 -0
- package/src/core/semantic-planning/projection.js +94 -0
- package/src/core/semantic-planning/service.js +15 -0
- package/src/core/settlement.js +12 -1
- package/src/core/signing/bundle-file.js +53 -0
- package/src/core/signing/bundle-reference.js +15 -0
- package/src/core/signing/sigstore.js +60 -33
- package/src/core/signing/statement-file.js +27 -0
- package/src/core/sources.js +37 -0
- package/src/core/storage-runtime-registry.js +41 -0
- package/src/core/structural-quality/artifacts.js +20 -14
- package/src/core/structural-quality/service.js +81 -56
- package/src/core/target-layout.js +1 -1
- package/src/core/task-claim-state.js +249 -15
- package/src/core/task-command.js +21 -1
- package/src/core/task-conflict-inspection.js +133 -102
- package/src/core/task-descriptor.js +29 -22
- package/src/core/task-discovery.js +288 -90
- package/src/core/task-lock.js +66 -306
- package/src/core/task-migration-validation.js +5 -5
- package/src/core/task-migration.js +17 -287
- package/src/core/task-paths.js +13 -0
- package/src/core/task-recovery.js +1 -0
- package/src/core/task-snapshot.js +51 -8
- package/src/core/task-storage-migration.js +18 -0
- package/src/core/templates.js +23 -8
- package/src/core/test-intelligence/benchmarks.js +68 -0
- package/src/core/test-intelligence/inventory.js +73 -0
- package/src/core/test-intelligence/prune.js +94 -0
- package/src/core/test-intelligence/semantic-state.js +15 -0
- package/src/core/test-intelligence/service.js +40 -0
- package/src/core/test-intelligence/utility.js +50 -0
- package/src/core/trace.js +164 -105
- package/src/core/trajectory-evaluation.js +15 -3
- package/src/core/trajectory-metrics.js +47 -32
- package/src/core/transaction.js +16 -287
- package/src/core/verification-scope.js +20 -12
- package/src/core/work-state.js +100 -59
- package/src/integration.d.ts +492 -0
- package/src/integration.js +54 -0
- package/src/providers/README.md +47 -0
- package/src/providers/capabilities.js +46 -0
- package/src/providers/errors.js +15 -0
- package/src/providers/index.js +29 -0
- package/src/providers/json-snapshot.js +105 -0
- package/src/providers/registry.js +152 -0
- package/src/repository-index/binary-manager.js +7 -5
- package/src/storage/artifact-bytes.js +22 -0
- package/src/storage/attachment-binding.js +11 -0
- package/src/storage/attachment-files.js +82 -0
- package/src/storage/attachment-references.js +36 -0
- package/src/storage/backup.js +53 -0
- package/src/storage/capabilities.js +31 -0
- package/src/storage/connection-owner.js +119 -0
- package/src/storage/connection.js +376 -0
- package/src/storage/existing-project-scope.js +45 -0
- package/src/storage/export-destination.js +44 -0
- package/src/storage/exporter.js +284 -0
- package/src/storage/file-durability.js +46 -0
- package/src/storage/importer.js +461 -0
- package/src/storage/index.js +74 -0
- package/src/storage/leases.js +63 -0
- package/src/storage/ledger-event-snapshot.js +150 -0
- package/src/storage/ledger-relations.js +220 -0
- package/src/storage/legacy-maintenance-boundary.js +18 -0
- package/src/storage/legacy-signature.js +115 -0
- package/src/storage/maintenance-handoff.js +129 -0
- package/src/storage/maintenance-owner.js +42 -0
- package/src/storage/maintenance.js +310 -0
- package/src/storage/metadata-json.js +35 -0
- package/src/storage/migration-activate.js +59 -0
- package/src/storage/migration-archive.js +57 -0
- package/src/storage/migration-attachment-root.js +61 -0
- package/src/storage/migration-candidate.js +398 -0
- package/src/storage/migration-publication.js +143 -0
- package/src/storage/migration-rollback-admission.js +54 -0
- package/src/storage/migration-rollback-preparation.js +132 -0
- package/src/storage/migration-rollback-publication.js +183 -0
- package/src/storage/migration-rollback-release.js +66 -0
- package/src/storage/migration-rollback-source-stage.js +103 -0
- package/src/storage/migration-rollback.js +43 -0
- package/src/storage/migration-source-partition.js +56 -0
- package/src/storage/migration-source.js +255 -0
- package/src/storage/migration-terminal.js +39 -0
- package/src/storage/migration-validation.js +75 -0
- package/src/storage/migration.js +43 -0
- package/src/storage/operational-attachments.js +49 -0
- package/src/storage/operational-context.js +50 -0
- package/src/storage/project-backup.js +98 -0
- package/src/storage/project-bootstrap.js +24 -0
- package/src/storage/project-boundary.js +79 -0
- package/src/storage/project-read-snapshot.js +18 -0
- package/src/storage/project-replacement.js +137 -0
- package/src/storage/project-restore.js +203 -0
- package/src/storage/record-definitions.js +45 -0
- package/src/storage/repository.js +507 -0
- package/src/storage/restore-journal.js +62 -0
- package/src/storage/restore-layout.js +30 -0
- package/src/storage/restore-preparation.js +84 -0
- package/src/storage/restore-replacement-archive.js +162 -0
- package/src/storage/restore-replacement-owner.js +31 -0
- package/src/storage/restore-replacement-preparation.js +128 -0
- package/src/storage/restore-replacement.js +142 -0
- package/src/storage/restore-terminal.js +32 -0
- package/src/storage/runtime.js +31 -0
- package/src/storage/schema.js +214 -0
- package/src/storage/singleton-import.js +84 -0
- package/src/storage/snapshot-continuity.js +16 -0
- package/src/storage/snapshot.js +36 -0
- package/src/storage/storage-marker.js +79 -0
- package/src/storage/task-guards.js +107 -0
- package/src/storage/topology.js +42 -0
- package/src/storage/transaction.js +179 -0
- package/src/storage/unit-of-work.js +663 -0
- package/src/storage/windows-process-incarnation.js +206 -0
- package/.forgeloop/forgeloop.gitignore +0 -4
- package/LICENSE-DOCS.md +0 -13
- package/src/core/transaction-maintenance.js +0 -70
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import { withProjectStorage } from "../storage/project-boundary.js";
|
|
3
|
+
import { withProjectReadSnapshot } from "../storage/project-read-snapshot.js";
|
|
2
4
|
import { runProtocolInfo } from "../commands/protocol-info.js";
|
|
3
5
|
import { readContract } from "./contract.js";
|
|
4
|
-
import {
|
|
6
|
+
import { discoverTaskSummaries } from "./task-discovery.js";
|
|
5
7
|
import { resolveTaskClaimState } from "./task-claim-state.js";
|
|
6
8
|
import { runStatus } from "../commands/status.js";
|
|
7
9
|
import { runContinuity } from "../commands/continuity.js";
|
|
@@ -10,17 +12,23 @@ import { listApprovals } from "./approvals.js";
|
|
|
10
12
|
import { buildTrajectoryMetrics } from "./trajectory-metrics.js";
|
|
11
13
|
import { loadCapabilityPolicy } from "./capability-policy.js";
|
|
12
14
|
import { readdir } from "node:fs/promises";
|
|
13
|
-
import {
|
|
15
|
+
import { getOperationalStore, listOperationalArtifactNames } from "../storage/operational-context.js";
|
|
16
|
+
import { readJsonArtifact, parseCapturedJsonArtifact } from "./artifacts.js";
|
|
14
17
|
import { taskDirectory } from "./task-paths.js";
|
|
15
18
|
import { resolveWorkspaceBindingStatus } from "./workspace-binding.js";
|
|
16
|
-
import {
|
|
17
|
-
import { readHandoffAcceptanceLedger, resolveHandoffAcceptance } from "./handoff-acceptance.js";
|
|
19
|
+
import { runHandoffList } from "../commands/handoff-list.js";
|
|
18
20
|
import { resolveResponsibilityStatus } from "./responsibility.js";
|
|
19
21
|
import { readVerificationScope } from "./verification-scope.js";
|
|
20
22
|
import { resolveAttestationStatus } from "./attestation.js";
|
|
21
23
|
import { buildExecutionProfileContext } from "./execution-profile-context.js";
|
|
22
24
|
import { projectStructuralQualityStatus } from "./structural-quality/service.js";
|
|
23
25
|
import { getRepositoryIndexStatus } from "../repository-index/status.js";
|
|
26
|
+
import { buildAuditUxView } from "./audit-ux.js";
|
|
27
|
+
import { runContextPlan } from "../commands/context-plan.js";
|
|
28
|
+
import { runModelRoute } from "../commands/model-route.js";
|
|
29
|
+
import { readPersistedRoute } from "./route-artifact.js";
|
|
30
|
+
import { readWorkState } from "./work-state.js";
|
|
31
|
+
import { readTestUtility } from "./test-intelligence/service.js";
|
|
24
32
|
|
|
25
33
|
/**
|
|
26
34
|
* Canonical integration resource allowlist.
|
|
@@ -86,11 +94,18 @@ export const INTEGRATION_RESOURCE_DEFINITIONS = Object.freeze({
|
|
|
86
94
|
"task/approvals": Object.freeze({ scope: "TASK", description: "Durable approval artifacts for one task." }),
|
|
87
95
|
"task/metrics": Object.freeze({ scope: "TASK", description: "Read-only trajectory metrics for one task." }),
|
|
88
96
|
"task/context": Object.freeze({ scope: "TASK", description: "Read-only profile-aware task context with bounded presentation policy." }),
|
|
97
|
+
"task/audit-view": Object.freeze({ scope: "TASK", description: "Bounded read-only Audit UX projection composed from canonical task resolvers." }),
|
|
89
98
|
"task/evaluations": Object.freeze({ scope: "TASK", description: "Persisted trajectory evaluations for one task." }),
|
|
99
|
+
"task/decisions": Object.freeze({ scope: "TASK", description: "Persisted, fingerprint-bound semantic decisions without lifecycle or evidence authority." }),
|
|
100
|
+
"task/context-plan": Object.freeze({ scope: "TASK", description: "Bounded non-authoritative semantic context-plan projection." }),
|
|
101
|
+
"task/model-route": Object.freeze({ scope: "TASK", description: "Deterministic model-routing floor with advisory semantic escalation." }),
|
|
102
|
+
"task/test-utility": Object.freeze({ scope: "TASK", description: "Non-evidence test inventory and utility analysis; never deletion authority." }),
|
|
90
103
|
"project/capability-policy": Object.freeze({ scope: "PROJECT", description: "Project capability policy, never host authority." }),
|
|
91
104
|
"repository/index-status": Object.freeze({ scope: "PROJECT", description: "Provider-neutral repository-index health and owned-server status." }),
|
|
92
105
|
});
|
|
93
106
|
|
|
107
|
+
const TASK_RESOURCE_URIS = new Set(Object.keys(INTEGRATION_RESOURCE_DEFINITIONS).filter((uri) => uri.startsWith("task/")));
|
|
108
|
+
|
|
94
109
|
function ownershipProjection(projection) {
|
|
95
110
|
return {
|
|
96
111
|
taskId: projection.taskId,
|
|
@@ -105,6 +120,12 @@ function ownershipProjection(projection) {
|
|
|
105
120
|
};
|
|
106
121
|
}
|
|
107
122
|
|
|
123
|
+
async function resourceArtifactNames(projectPath, taskId, kind, directory) {
|
|
124
|
+
const names = listOperationalArtifactNames(projectPath, taskId, kind);
|
|
125
|
+
if (names !== null) return names;
|
|
126
|
+
try { return await readdir(directory); } catch { return []; }
|
|
127
|
+
}
|
|
128
|
+
|
|
108
129
|
async function readForgeLoopIntegrationResourceCore(uri, {
|
|
109
130
|
projectPath = ".",
|
|
110
131
|
packageRoot = undefined,
|
|
@@ -120,67 +141,15 @@ async function readForgeLoopIntegrationResourceCore(uri, {
|
|
|
120
141
|
throw error;
|
|
121
142
|
}
|
|
122
143
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
count: tasks.length,
|
|
133
|
-
tasks: tasks.map((task) => ({
|
|
134
|
-
taskId: task.taskId,
|
|
135
|
-
healthy: task.healthy !== false,
|
|
136
|
-
phase: task.phase ?? null,
|
|
137
|
-
mutationAllowed: task.mutationAllowed !== false,
|
|
138
|
-
})),
|
|
139
|
-
},
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
case "task/status":
|
|
143
|
-
case "task/ownership":
|
|
144
|
-
case "task/contract":
|
|
145
|
-
case "task/continuity": {
|
|
146
|
-
if (typeof taskId !== "string" || !taskId) {
|
|
147
|
-
const error = new Error(`Resource ${uri} requires a taskId`);
|
|
148
|
-
error.code = "E_TASK_REQUIRED";
|
|
149
|
-
throw error;
|
|
150
|
-
}
|
|
151
|
-
break;
|
|
152
|
-
}
|
|
153
|
-
case "task/workspace-binding":
|
|
154
|
-
case "task/handoffs":
|
|
155
|
-
case "task/responsibility":
|
|
156
|
-
case "task/verification-scope":
|
|
157
|
-
case "task/attestation": {
|
|
158
|
-
if (typeof taskId !== "string" || !taskId) {
|
|
159
|
-
const error = new Error(`Resource ${uri} requires a taskId`);
|
|
160
|
-
error.code = "E_TASK_REQUIRED";
|
|
161
|
-
throw error;
|
|
162
|
-
}
|
|
163
|
-
break;
|
|
164
|
-
}
|
|
165
|
-
case "task/structural-quality": {
|
|
166
|
-
if (typeof taskId !== "string" || !taskId) {
|
|
167
|
-
const error = new Error(`Resource ${uri} requires a taskId`);
|
|
168
|
-
error.code = "E_TASK_REQUIRED";
|
|
169
|
-
throw error;
|
|
170
|
-
}
|
|
171
|
-
break;
|
|
172
|
-
}
|
|
173
|
-
case "task/actions":
|
|
174
|
-
case "task/action":
|
|
175
|
-
case "task/approvals":
|
|
176
|
-
case "task/metrics":
|
|
177
|
-
case "task/context":
|
|
178
|
-
case "task/evaluations": {
|
|
179
|
-
if (typeof taskId !== "string" || !taskId) {
|
|
180
|
-
const error = new Error(`Resource ${uri} requires a taskId`); error.code = "E_TASK_REQUIRED"; throw error;
|
|
181
|
-
}
|
|
182
|
-
break;
|
|
183
|
-
}
|
|
144
|
+
if (uri === "protocol/info") return { uri, data: await runProtocolInfo({ packageVersion }) };
|
|
145
|
+
if (uri === "project/tasks") {
|
|
146
|
+
const tasks = await discoverTaskSummaries(projectPath, packageRoot);
|
|
147
|
+
return { uri, data: { count: tasks.length, tasks } };
|
|
148
|
+
}
|
|
149
|
+
if (TASK_RESOURCE_URIS.has(uri) && (typeof taskId !== "string" || !taskId)) {
|
|
150
|
+
const error = new Error(`Resource ${uri} requires a taskId`);
|
|
151
|
+
error.code = "E_TASK_REQUIRED";
|
|
152
|
+
throw error;
|
|
184
153
|
}
|
|
185
154
|
|
|
186
155
|
if (uri === "task/ownership") {
|
|
@@ -198,27 +167,7 @@ async function readForgeLoopIntegrationResourceCore(uri, {
|
|
|
198
167
|
return { uri, taskId, data: await resolveWorkspaceBindingStatus(projectPath, { packageRoot, taskId }) };
|
|
199
168
|
}
|
|
200
169
|
if (uri === "task/handoffs") {
|
|
201
|
-
|
|
202
|
-
const ledger = await readHandoffAcceptanceLedger(projectPath, packageRoot, { taskId });
|
|
203
|
-
const projectedHandoffs = handoffs.map((handoff) => {
|
|
204
|
-
const resolved = resolveHandoffAcceptance({
|
|
205
|
-
events: ledger.events,
|
|
206
|
-
handoff,
|
|
207
|
-
ledgerValid: ledger.valid,
|
|
208
|
-
ledgerErrors: ledger.errors,
|
|
209
|
-
});
|
|
210
|
-
return {
|
|
211
|
-
...handoff,
|
|
212
|
-
acceptance: {
|
|
213
|
-
status: resolved.status,
|
|
214
|
-
consumerId: resolved.consumerId ?? null,
|
|
215
|
-
harness: resolved.harness ?? null,
|
|
216
|
-
acceptedAt: resolved.acceptedAt ?? null,
|
|
217
|
-
...(resolved.reasonCodes ? { reasonCodes: [...resolved.reasonCodes] } : {}),
|
|
218
|
-
},
|
|
219
|
-
};
|
|
220
|
-
});
|
|
221
|
-
return { uri, taskId, data: { taskId, count: projectedHandoffs.length, handoffs: projectedHandoffs } };
|
|
170
|
+
return { uri, taskId, data: await runHandoffList({ target: projectPath, packageRoot, taskId }) };
|
|
222
171
|
}
|
|
223
172
|
if (uri === "task/responsibility") {
|
|
224
173
|
return { uri, taskId, data: await resolveResponsibilityStatus(projectPath, { packageRoot, taskId }) };
|
|
@@ -263,13 +212,57 @@ async function readForgeLoopIntegrationResourceCore(uri, {
|
|
|
263
212
|
}
|
|
264
213
|
if (uri === "task/evaluations") {
|
|
265
214
|
const dir = path.join(projectPath, taskDirectory(taskId), "evaluations");
|
|
266
|
-
|
|
215
|
+
const names = await resourceArtifactNames(projectPath, taskId, "evaluations", dir);
|
|
267
216
|
const evaluations = [];
|
|
268
217
|
for (const name of names.filter((entry) => /^eval-[A-Za-z0-9_-]+\.json$/.test(entry)).sort()) {
|
|
269
218
|
evaluations.push((await readJsonArtifact(projectPath, `${taskDirectory(taskId)}/evaluations/${name}`, "trajectory-evaluation", packageRoot)).value);
|
|
270
219
|
}
|
|
271
220
|
return { uri, taskId, data: { evaluations } };
|
|
272
221
|
}
|
|
222
|
+
if (uri === "task/decisions") {
|
|
223
|
+
const store = getOperationalStore(projectPath);
|
|
224
|
+
if (store) {
|
|
225
|
+
const decisions = await readCapturedDecisions(store, taskId, packageRoot);
|
|
226
|
+
return { uri, taskId, data: { taskId, decisions } };
|
|
227
|
+
}
|
|
228
|
+
const dir = path.join(projectPath, taskDirectory(taskId), "decisions");
|
|
229
|
+
const names = await resourceArtifactNames(projectPath, taskId, "decisions", dir);
|
|
230
|
+
const decisions = [];
|
|
231
|
+
for (const name of names.filter((entry) => /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}\.json$/.test(entry)).sort()) {
|
|
232
|
+
decisions.push((await readJsonArtifact(projectPath, `${taskDirectory(taskId)}/decisions/${name}`, "semantic-decision", packageRoot)).value);
|
|
233
|
+
}
|
|
234
|
+
return { uri, taskId, data: { taskId, decisions } };
|
|
235
|
+
}
|
|
236
|
+
if (uri === "task/context-plan") {
|
|
237
|
+
return { uri, taskId, data: await runContextPlan({ target: projectPath, packageRoot, taskId, profile: runtimeContext?.contextProfile ?? "balanced", readOnly: true }) };
|
|
238
|
+
}
|
|
239
|
+
if (uri === "task/model-route") {
|
|
240
|
+
const state = await readWorkState(projectPath, { packageRoot, taskId });
|
|
241
|
+
const route = await readPersistedRoute(projectPath, packageRoot, { taskId });
|
|
242
|
+
return {
|
|
243
|
+
uri,
|
|
244
|
+
taskId,
|
|
245
|
+
data: await runModelRoute({
|
|
246
|
+
target: projectPath,
|
|
247
|
+
packageRoot,
|
|
248
|
+
taskId,
|
|
249
|
+
workType: route.value.input?.workType,
|
|
250
|
+
surfaces: route.value.input?.surfaces,
|
|
251
|
+
risks: route.value.input?.risks,
|
|
252
|
+
platforms: route.value.input?.platforms,
|
|
253
|
+
behaviorChange: route.value.input?.behaviorChange,
|
|
254
|
+
executableChange: route.value.input?.executableChange,
|
|
255
|
+
generationRequired: route.value.input?.generationRequired,
|
|
256
|
+
architectureChange: route.value.input?.architectureChange,
|
|
257
|
+
ambiguity: route.value.input?.ambiguity,
|
|
258
|
+
contract: { phase: state.phase },
|
|
259
|
+
}),
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
if (uri === "task/test-utility") {
|
|
263
|
+
const artifact = await readTestUtility({ target: projectPath, packageRoot, taskId });
|
|
264
|
+
return { uri, taskId, data: artifact.value };
|
|
265
|
+
}
|
|
273
266
|
if (uri === "project/capability-policy") {
|
|
274
267
|
return { uri, data: await loadCapabilityPolicy(projectPath, packageRoot) };
|
|
275
268
|
}
|
|
@@ -292,6 +285,35 @@ async function readForgeLoopIntegrationResourceCore(uri, {
|
|
|
292
285
|
}
|
|
293
286
|
|
|
294
287
|
export async function readForgeLoopIntegrationResource(uri, options = {}) {
|
|
288
|
+
const target = options.projectPath ?? ".";
|
|
289
|
+
const read = () => readSelectedIntegrationResource(uri, options);
|
|
290
|
+
// Decisions capture their finite catalog and bytes synchronously; other
|
|
291
|
+
// task projections retain the complete committed project snapshot.
|
|
292
|
+
return withProjectStorage(target, () => TASK_RESOURCE_URIS.has(uri) && uri !== "task/decisions"
|
|
293
|
+
? withProjectReadSnapshot(target, read) : read(), { readOnly: true, runtimeContext: options.runtimeContext });
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async function readSelectedIntegrationResource(uri, options) {
|
|
297
|
+
if (uri === "task/audit-view") {
|
|
298
|
+
if (typeof options.taskId !== "string" || !options.taskId) {
|
|
299
|
+
const error = new Error("Resource task/audit-view requires a taskId"); error.code = "E_TASK_REQUIRED"; throw error;
|
|
300
|
+
}
|
|
301
|
+
return {
|
|
302
|
+
uri,
|
|
303
|
+
taskId: options.taskId,
|
|
304
|
+
data: await buildAuditUxView({
|
|
305
|
+
target: options.projectPath ?? ".",
|
|
306
|
+
packageRoot: options.packageRoot,
|
|
307
|
+
taskId: options.taskId,
|
|
308
|
+
limit: options.limit,
|
|
309
|
+
beforeSequence: options.beforeSequence,
|
|
310
|
+
afterSequence: options.afterSequence,
|
|
311
|
+
categories: options.categories,
|
|
312
|
+
authorityContext: options.runtimeContext?.authorityContext,
|
|
313
|
+
runtimeContext: options.runtimeContext,
|
|
314
|
+
}),
|
|
315
|
+
};
|
|
316
|
+
}
|
|
295
317
|
if (uri === "repository/index-status") {
|
|
296
318
|
return {
|
|
297
319
|
uri,
|
|
@@ -303,3 +325,13 @@ export async function readForgeLoopIntegrationResource(uri, options = {}) {
|
|
|
303
325
|
}
|
|
304
326
|
return readForgeLoopIntegrationResourceCore(uri, options);
|
|
305
327
|
}
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
async function readCapturedDecisions(store, taskId, packageRoot) {
|
|
331
|
+
const decisions = [];
|
|
332
|
+
for (const entry of store.captureDecisionTexts(taskId)) {
|
|
333
|
+
if (entry.error) throw entry.error;
|
|
334
|
+
decisions.push((await parseCapturedJsonArtifact(entry.text, entry.relativePath, "semantic-decision", packageRoot)).value);
|
|
335
|
+
}
|
|
336
|
+
return decisions;
|
|
337
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Explicit immutable-source event sequence. This is not an Array or a Proxy.
|
|
3
|
+
* Readers decode on demand; historical views share only source position identity.
|
|
4
|
+
* The source owner must hold one immutable snapshot for the sequence's lifetime.
|
|
5
|
+
* Array-returning filter/map operations deliberately materialize selected proofs;
|
|
6
|
+
* they do not establish bounded memory for arbitrarily large relation state.
|
|
7
|
+
*/
|
|
8
|
+
const collections = new WeakSet();
|
|
9
|
+
const viewToken = Symbol("ledger-source-view");
|
|
10
|
+
|
|
11
|
+
function sourceError(message) {
|
|
12
|
+
return Object.assign(new Error(message), { code: "E_LEDGER_SOURCE_INVALID" });
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function integer(value) {
|
|
16
|
+
const number = Number(value);
|
|
17
|
+
return Number.isNaN(number) ? 0 : Math.trunc(number);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function bound(value, length) {
|
|
21
|
+
const index = integer(value);
|
|
22
|
+
return index < 0 ? Math.max(length + index, 0) : Math.min(index, length);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class LedgerEventCollection {
|
|
26
|
+
#source;
|
|
27
|
+
#start;
|
|
28
|
+
#end;
|
|
29
|
+
|
|
30
|
+
constructor({ length, readAt, iterateRange = null, iterateTypes = null }, view = null, token = null) {
|
|
31
|
+
if (view) {
|
|
32
|
+
if (token !== viewToken) throw sourceError("Ledger views must come from their source collection");
|
|
33
|
+
this.#source = view.source;
|
|
34
|
+
this.#start = view.start;
|
|
35
|
+
this.#end = view.end;
|
|
36
|
+
} else {
|
|
37
|
+
if (!Number.isSafeInteger(length) || length < 0 || typeof readAt !== "function"
|
|
38
|
+
|| (iterateRange !== null && typeof iterateRange !== "function")
|
|
39
|
+
|| (iterateTypes !== null && typeof iterateTypes !== "function")) {
|
|
40
|
+
throw sourceError("Ledger source requires a finite length and synchronous readers");
|
|
41
|
+
}
|
|
42
|
+
this.#source = { length, readAt, iterateRange, iterateTypes, positions: new WeakMap() };
|
|
43
|
+
this.#start = 0;
|
|
44
|
+
this.#end = length;
|
|
45
|
+
}
|
|
46
|
+
collections.add(this);
|
|
47
|
+
Object.freeze(this);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
get length() { return this.#end - this.#start; }
|
|
51
|
+
|
|
52
|
+
#observe(event, index) {
|
|
53
|
+
if (!event || typeof event !== "object" || Array.isArray(event)) {
|
|
54
|
+
throw sourceError("Ledger source returned a non-object event");
|
|
55
|
+
}
|
|
56
|
+
const known = this.#source.positions.get(event);
|
|
57
|
+
if (known !== undefined && known !== index) {
|
|
58
|
+
throw sourceError("Ledger source reused one event object at distinct positions");
|
|
59
|
+
}
|
|
60
|
+
this.#source.positions.set(event, index);
|
|
61
|
+
return event;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
at(index) {
|
|
65
|
+
const position = integer(index);
|
|
66
|
+
const local = position < 0 ? this.length + position : position;
|
|
67
|
+
if (local < 0 || local >= this.length) return undefined;
|
|
68
|
+
const absolute = this.#start + local;
|
|
69
|
+
return this.#observe(this.#source.readAt(absolute), absolute);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
*values() {
|
|
73
|
+
if (!this.#source.iterateRange) {
|
|
74
|
+
for (let index = 0; index < this.length; index += 1) yield this.at(index);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
let index = this.#start;
|
|
78
|
+
for (const event of this.#source.iterateRange(this.#start, this.#end)) {
|
|
79
|
+
if (index >= this.#end) throw sourceError("Ledger source exceeded its declared range");
|
|
80
|
+
yield this.#observe(event, index);
|
|
81
|
+
index += 1;
|
|
82
|
+
}
|
|
83
|
+
if (index !== this.#end) throw sourceError("Ledger source truncated its declared range");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
[Symbol.iterator]() { return this.values(); }
|
|
87
|
+
|
|
88
|
+
*entries() {
|
|
89
|
+
let index = 0;
|
|
90
|
+
for (const event of this) { yield [index, event]; index += 1; }
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
*entriesOfTypes(types) {
|
|
94
|
+
const selected = new Set(types);
|
|
95
|
+
if (!this.#source.iterateTypes) {
|
|
96
|
+
for (const [index, event] of this.entries()) if (selected.has(event.event)) yield [index, event];
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
let previous = this.#start - 1;
|
|
100
|
+
for (const { index, event } of this.#source.iterateTypes(this.#start, this.#end, [...selected])) {
|
|
101
|
+
if (!Number.isSafeInteger(index) || index <= previous || index < this.#start || index >= this.#end || !selected.has(event?.event)) {
|
|
102
|
+
throw sourceError("Ledger typed source returned an invalid position or event type");
|
|
103
|
+
}
|
|
104
|
+
previous = index;
|
|
105
|
+
yield [index - this.#start, this.#observe(event, index)];
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
slice(start = 0, end = this.length) {
|
|
110
|
+
const first = bound(start, this.length);
|
|
111
|
+
const last = Math.max(first, bound(end, this.length));
|
|
112
|
+
return new LedgerEventCollection({}, { source: this.#source, start: this.#start + first, end: this.#start + last }, viewToken);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
indexOf(event) {
|
|
116
|
+
const absolute = event && typeof event === "object" ? this.#source.positions.get(event) : undefined;
|
|
117
|
+
return absolute === undefined || absolute < this.#start || absolute >= this.#end ? -1 : absolute - this.#start;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
findIndex(predicate) {
|
|
121
|
+
for (const [index, event] of this.entries()) if (predicate(event, index, this)) return index;
|
|
122
|
+
return -1;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
find(predicate) {
|
|
126
|
+
for (const [index, event] of this.entries()) if (predicate(event, index, this)) return event;
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
findLast(predicate) {
|
|
131
|
+
for (let index = this.length - 1; index >= 0; index -= 1) {
|
|
132
|
+
const event = this.at(index);
|
|
133
|
+
if (predicate(event, index, this)) return event;
|
|
134
|
+
}
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
some(predicate) { return this.findIndex(predicate) !== -1; }
|
|
139
|
+
every(predicate) { return this.findIndex((event, index) => !predicate(event, index, this)) === -1; }
|
|
140
|
+
|
|
141
|
+
filter(predicate) {
|
|
142
|
+
const selected = [];
|
|
143
|
+
for (const [index, event] of this.entries()) if (predicate(event, index, this)) selected.push(event);
|
|
144
|
+
return selected;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
map(project) {
|
|
148
|
+
const values = [];
|
|
149
|
+
for (const [index, event] of this.entries()) values.push(project(event, index, this));
|
|
150
|
+
return values;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function isLedgerEventCollection(events) {
|
|
155
|
+
return Array.isArray(events) || collections.has(events);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function ledgerEventAt(events, index) {
|
|
159
|
+
return Array.isArray(events) ? events[index] : (Number.isSafeInteger(index) && index >= 0 ? events.at(index) : undefined);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** Preserve strict Array identity; decoded collections prove private source position. */
|
|
163
|
+
export function ledgerEventAtIs(events, index, event) {
|
|
164
|
+
if (Array.isArray(events)) return events[index] === event;
|
|
165
|
+
return Number.isSafeInteger(index) && index >= 0 && index < events.length && events.indexOf(event) === index;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** Typed selection preserves canonical source positions without retaining selected payload arrays. */
|
|
169
|
+
export function* ledgerEntriesOfTypes(events, types) {
|
|
170
|
+
if (!Array.isArray(events)) { yield* events.entriesOfTypes(types); return; }
|
|
171
|
+
const selected = new Set(types);
|
|
172
|
+
for (const [index, event] of events.entries()) if (selected.has(event.event)) yield [index, event];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export function* ledgerEventsOfTypes(events, types) {
|
|
176
|
+
for (const [, event] of ledgerEntriesOfTypes(events, types)) yield event;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function ledgerTypeSummary(events, type) {
|
|
180
|
+
let count = 0;
|
|
181
|
+
let first;
|
|
182
|
+
let latest;
|
|
183
|
+
for (const event of ledgerEventsOfTypes(events, [type])) {
|
|
184
|
+
if (!count) first = event;
|
|
185
|
+
latest = event;
|
|
186
|
+
count += 1;
|
|
187
|
+
}
|
|
188
|
+
return { count, first, latest };
|
|
189
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
|
|
3
|
+
const owners = new AsyncLocalStorage();
|
|
4
|
+
|
|
5
|
+
/** Storage supplies an owned scratch backing; pure/array callers retain native collections. */
|
|
6
|
+
export function withLedgerRelationOwner(owner, callback) { return owners.run(owner, callback); }
|
|
7
|
+
export function ledgerRelationMap() { return owners.getStore()?.map() ?? new Map(); }
|
|
8
|
+
export function ledgerRelationSet() { return owners.getStore()?.set() ?? new Set(); }
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
/** Primitive grouped membership; storage may index groups without nested resident Sets. */
|
|
12
|
+
export function ledgerGroupedSet() {
|
|
13
|
+
const owner = owners.getStore();
|
|
14
|
+
if (owner?.groupedSet) return owner.groupedSet();
|
|
15
|
+
const groups = new Map();
|
|
16
|
+
return {
|
|
17
|
+
add(group, value) {
|
|
18
|
+
if (!groups.has(group)) groups.set(group, new Set());
|
|
19
|
+
groups.get(group).add(value);
|
|
20
|
+
},
|
|
21
|
+
*values(group) { yield* groups.get(group) ?? []; },
|
|
22
|
+
};
|
|
23
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { DECISION_AUTHORITY, DECISION_EVIDENCE_AUTHORITY, PINNED_JEV_MODEL } from "../decision/constants.js";
|
|
2
|
+
|
|
3
|
+
export const MODEL_ROUTE_TIERS = Object.freeze(["NONE", "FAST", "STANDARD", "PRIMARY"]);
|
|
4
|
+
export const MODEL_ROUTE_POLICY_VERSION = 1;
|
|
5
|
+
export const MODEL_ROUTE_PROJECTION_AUTHORITY = DECISION_AUTHORITY;
|
|
6
|
+
export const MODEL_ROUTE_PROJECTION_EVIDENCE_AUTHORITY = DECISION_EVIDENCE_AUTHORITY;
|
|
7
|
+
export const MODEL_ROUTE_JEV_MODEL = PINNED_JEV_MODEL;
|
|
8
|
+
|
|
9
|
+
export const MODEL_ROUTE_RANK = Object.freeze({ NONE: 0, FAST: 1, STANDARD: 2, PRIMARY: 3 });
|
|
10
|
+
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { MODEL_ROUTE_RANK, MODEL_ROUTE_TIERS } from "./constants.js";
|
|
2
|
+
|
|
3
|
+
const GENERATION_WORK_TYPES = new Set([
|
|
4
|
+
"code", "bug", "refactor", "backend", "api", "infrastructure", "security-review", "release",
|
|
5
|
+
]);
|
|
6
|
+
const PRIMARY_WORK_TYPES = new Set(["infrastructure", "security-review", "release"]);
|
|
7
|
+
const PRIMARY_RISKS = new Set(["secrets", "personal-data", "publication", "critical-path", "destructive", "irreversible", "migration", "credentials", "payment"]);
|
|
8
|
+
const PRIMARY_SURFACES = new Set(["auth", "critical-path", "database"]);
|
|
9
|
+
|
|
10
|
+
function text(value) {
|
|
11
|
+
return typeof value === "string" ? value.toLowerCase() : "";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function array(value) {
|
|
15
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function contractText(contract) {
|
|
19
|
+
if (!contract || typeof contract !== "object" || Array.isArray(contract)) return "";
|
|
20
|
+
const values = [contract.objective, contract.summary, ...(contract.deliverables ?? []), ...(contract.successCriteria ?? []), ...(contract.risks ?? []), ...(contract.constraints ?? [])];
|
|
21
|
+
return values.map((value) => value && typeof value === "object" ? value.text : value).filter((value) => typeof value === "string").join(" ").toLowerCase();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function normalizedInput(input = {}) {
|
|
25
|
+
return {
|
|
26
|
+
workType: text(input.workType),
|
|
27
|
+
surfaces: array(input.surfaces).map(text),
|
|
28
|
+
risks: array(input.risks).map(text),
|
|
29
|
+
platforms: array(input.platforms).map(text),
|
|
30
|
+
behaviorChange: input.behaviorChange === true,
|
|
31
|
+
executableChange: input.executableChange === true,
|
|
32
|
+
generationRequired: input.generationRequired === true,
|
|
33
|
+
architectureChange: input.architectureChange === true,
|
|
34
|
+
ambiguity: input.ambiguity === true,
|
|
35
|
+
contract: input.contract,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function deterministicFloor(input) {
|
|
40
|
+
const normalized = normalizedInput(input);
|
|
41
|
+
const reasons = [];
|
|
42
|
+
const combined = `${contractText(normalized.contract)} ${normalized.workType} ${normalized.surfaces.join(" ")} ${normalized.risks.join(" ")}`;
|
|
43
|
+
const generationRequired = normalized.generationRequired
|
|
44
|
+
|| normalized.behaviorChange
|
|
45
|
+
|| normalized.executableChange
|
|
46
|
+
|| GENERATION_WORK_TYPES.has(normalized.workType)
|
|
47
|
+
|| /\b(implement|fix|refactor|change|build|generate|write|modify|code)\b/.test(combined);
|
|
48
|
+
const primary = normalized.architectureChange
|
|
49
|
+
|| normalized.ambiguity
|
|
50
|
+
|| PRIMARY_WORK_TYPES.has(normalized.workType)
|
|
51
|
+
|| normalized.risks.some((risk) => PRIMARY_RISKS.has(risk))
|
|
52
|
+
|| normalized.surfaces.some((surface) => PRIMARY_SURFACES.has(surface))
|
|
53
|
+
|| /\b(architecture|architectural|security boundary|migration|ambiguous|unknown requirements)\b/.test(combined);
|
|
54
|
+
|
|
55
|
+
if (!generationRequired) {
|
|
56
|
+
reasons.push("NO_GENERATION_REQUIRED");
|
|
57
|
+
return { floor: "NONE", reasons };
|
|
58
|
+
}
|
|
59
|
+
reasons.push("GENERATION_REQUIRED");
|
|
60
|
+
if (primary) {
|
|
61
|
+
reasons.push("PRIMARY_COMPLEXITY_OR_RISK");
|
|
62
|
+
return { floor: "PRIMARY", reasons };
|
|
63
|
+
}
|
|
64
|
+
reasons.push("STANDARD_GENERATION_FLOOR");
|
|
65
|
+
return { floor: "STANDARD", reasons };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function normalizeRecommendation(recommendation) {
|
|
69
|
+
if (recommendation === null || recommendation === undefined) return null;
|
|
70
|
+
if (typeof recommendation === "string") {
|
|
71
|
+
return MODEL_ROUTE_TIERS.includes(recommendation) ? { tier: recommendation, confidence: null, requiresEscalation: false } : null;
|
|
72
|
+
}
|
|
73
|
+
if (!recommendation || typeof recommendation !== "object" || Array.isArray(recommendation)) return null;
|
|
74
|
+
const tier = typeof recommendation.tier === "string" && MODEL_ROUTE_TIERS.includes(recommendation.tier) ? recommendation.tier : null;
|
|
75
|
+
if (!tier) return null;
|
|
76
|
+
return {
|
|
77
|
+
tier,
|
|
78
|
+
confidence: typeof recommendation.confidence === "number" && Number.isFinite(recommendation.confidence) ? recommendation.confidence : null,
|
|
79
|
+
requiresEscalation: recommendation.requiresEscalation === true,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function resolveModelRoute({ input = {}, semanticRecommendation = null } = {}) {
|
|
84
|
+
const deterministic = deterministicFloor(input);
|
|
85
|
+
const recommendation = normalizeRecommendation(semanticRecommendation);
|
|
86
|
+
let resolved = deterministic.floor;
|
|
87
|
+
const reasons = [...deterministic.reasons];
|
|
88
|
+
if (recommendation?.requiresEscalation) {
|
|
89
|
+
if (MODEL_ROUTE_RANK[resolved] < MODEL_ROUTE_RANK.PRIMARY) resolved = "PRIMARY";
|
|
90
|
+
reasons.push("JEV_LOW_CONFIDENCE_ESCALATION");
|
|
91
|
+
} else if (recommendation && MODEL_ROUTE_RANK[recommendation.tier] > MODEL_ROUTE_RANK[resolved]) {
|
|
92
|
+
resolved = recommendation.tier;
|
|
93
|
+
reasons.push("JEV_ESCALATION_ONLY");
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
floor: deterministic.floor,
|
|
97
|
+
resolved,
|
|
98
|
+
reasons: [...new Set(reasons)],
|
|
99
|
+
semanticRecommendation: recommendation,
|
|
100
|
+
generationRequired: deterministic.floor !== "NONE",
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MODEL_ROUTE_JEV_MODEL,
|
|
3
|
+
MODEL_ROUTE_POLICY_VERSION,
|
|
4
|
+
MODEL_ROUTE_PROJECTION_AUTHORITY,
|
|
5
|
+
MODEL_ROUTE_PROJECTION_EVIDENCE_AUTHORITY,
|
|
6
|
+
MODEL_ROUTE_RANK,
|
|
7
|
+
MODEL_ROUTE_TIERS,
|
|
8
|
+
} from "./constants.js";
|
|
9
|
+
import { resolveModelRoute } from "./policy.js";
|
|
10
|
+
|
|
11
|
+
export function projectModelRoute({ input = {}, semanticRecommendation = null } = {}) {
|
|
12
|
+
const route = resolveModelRoute({ input, semanticRecommendation });
|
|
13
|
+
if (!MODEL_ROUTE_TIERS.includes(route.floor) || !MODEL_ROUTE_TIERS.includes(route.resolved)
|
|
14
|
+
|| MODEL_ROUTE_RANK[route.resolved] < MODEL_ROUTE_RANK[route.floor]) {
|
|
15
|
+
const error = new Error("Model route violates its deterministic safety floor.");
|
|
16
|
+
error.code = "E_MODEL_ROUTE_SAFETY_FLOOR_INVALID";
|
|
17
|
+
throw error;
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
schemaVersion: 1,
|
|
21
|
+
policyVersion: MODEL_ROUTE_POLICY_VERSION,
|
|
22
|
+
engine: "typesafe-jev",
|
|
23
|
+
model: MODEL_ROUTE_JEV_MODEL,
|
|
24
|
+
floor: route.floor,
|
|
25
|
+
resolved: route.resolved,
|
|
26
|
+
reasons: route.reasons,
|
|
27
|
+
generationRequired: route.generationRequired,
|
|
28
|
+
semanticRecommendation: route.semanticRecommendation,
|
|
29
|
+
authority: MODEL_ROUTE_PROJECTION_AUTHORITY,
|
|
30
|
+
evidenceAuthority: MODEL_ROUTE_PROJECTION_EVIDENCE_AUTHORITY,
|
|
31
|
+
lifecycleAuthority: false,
|
|
32
|
+
completionAuthority: false,
|
|
33
|
+
ownershipAuthority: false,
|
|
34
|
+
installationAuthority: false,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { needsExistingProjectScope, withExistingProjectScope } from "../storage/existing-project-scope.js";
|
|
2
|
+
import { getOperationalStore } from "../storage/operational-context.js";
|
|
3
|
+
|
|
4
|
+
export async function withNativeReadScope(target, callback) {
|
|
5
|
+
return (await needsExistingProjectScope(target)) ? withExistingProjectScope(target, callback, { readOnly: true }) : callback();
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function requireNativeStore(target, errorFactory, refusalMessage) {
|
|
9
|
+
const store = getOperationalStore(target);
|
|
10
|
+
if (!store) throw errorFactory("E_STORAGE_MIGRATION_REQUIRED", refusalMessage);
|
|
11
|
+
return store;
|
|
12
|
+
}
|