@cassiomc1/forgeloop 1.14.0 → 2.0.0-rc.4
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/CONTRIBUTING.md +11 -7
- package/DOCS_INDEX.md +2 -1
- 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 +8 -4
- 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/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/GUIDE_ROUTER.md +6 -0
- package/LICENSE +133 -21
- package/LOOP_SYSTEM_DESIGN.md +10 -10
- package/README.md +30 -40
- package/THIRD_PARTY_NOTICES.md +3 -4
- package/completions/_forgeloop +11 -3
- package/completions/forgeloop.bash +19 -3
- package/completions/forgeloop.fish +61 -1
- package/docs/AGENT_PROTOCOL_SUMMARY.md +50 -40
- package/docs/ARTIFACT_REFERENCE.md +50 -37
- package/docs/CLI_REFERENCE.md +147 -3
- package/docs/DOCUMENTATION_GUIDE.md +6 -4
- package/docs/GETTING_STARTED.md +3 -3
- package/docs/PACKAGE_CONTENTS.md +14 -13
- package/docs/RELEASE_CHECKLIST.md +110 -10
- package/docs/SELF_HOSTED_TESTS.md +121 -0
- package/docs/TROUBLESHOOTING.md +33 -0
- package/docs/documentation-manifest.json +25 -12
- package/package.json +15 -10
- package/schemas/task-bundle.schema.json +7 -2
- package/scripts/generate-agent-protocol-summary.mjs +2 -2
- package/scripts/run-mcp-clean-tests.mjs +30 -0
- package/src/adapters/agent-browser/provider.js +14 -11
- package/src/adapters/emulated-services/provider.js +11 -4
- package/src/adapters/temporary-paths.js +18 -0
- package/src/cli.js +146 -210
- 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 +24 -8
- package/src/commands/complete.js +19 -3
- package/src/commands/contract-create.js +3 -1
- package/src/commands/doctor.js +36 -13
- package/src/commands/gate-record.js +20 -31
- package/src/commands/gate-revalidate.js +11 -13
- 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 +9 -1
- 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/semantic-plan.js +26 -2
- 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 +1 -1
- package/src/commands/task-list.js +8 -43
- package/src/commands/task-migrate.js +3 -3
- package/src/commands/task-recover.js +10 -2
- package/src/commands/task-scope.js +18 -2
- package/src/commands/task-show.js +16 -2
- package/src/commands/validate-protocol.js +29 -14
- 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 +59 -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.js +6 -1
- package/src/core/bundles.js +160 -66
- package/src/core/checkpoint-revalidation.js +12 -10
- package/src/core/cli-command-definitions.js +109 -7
- package/src/core/code-manifest.js +9 -3
- package/src/core/command-executors.js +182 -126
- package/src/core/command-input.js +21 -1
- package/src/core/completion-artifacts.js +85 -36
- package/src/core/completion-ownership.js +19 -8
- package/src/core/completion-recovery-rebind.js +11 -1
- package/src/core/completion.js +60 -9
- package/src/core/conformance.js +2 -1
- 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 +42 -41
- package/src/core/contract-revision.js +8 -9
- package/src/core/decision/artifact.js +2 -1
- package/src/core/decision/events.js +9 -6
- package/src/core/decision/resolver.js +19 -11
- package/src/core/decision/service.js +63 -38
- package/src/core/decision/task-bindings.js +6 -1
- 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/events.js +316 -97
- package/src/core/execution-prerequisites.js +22 -13
- 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 +6 -5
- 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 +10 -0
- package/src/core/integration-resources.js +41 -34
- package/src/core/ledger-event-collection.js +189 -0
- package/src/core/ledger-relations.js +23 -0
- package/src/core/native-storage.js +12 -0
- package/src/core/next-action-continuity.js +31 -9
- package/src/core/next-action-phases.js +1 -1
- package/src/core/next-action-review-phase.js +2 -2
- package/src/core/next-action-verification-phase.js +2 -1
- package/src/core/next-action.js +21 -2
- package/src/core/phase.js +138 -93
- package/src/core/policy-engine.js +12 -13
- package/src/core/preflight-consistency.js +72 -59
- package/src/core/preflight-loaders.js +19 -12
- 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 +3 -0
- package/src/core/protocol-migration.js +7 -6
- package/src/core/reconcile-closure.js +162 -24
- package/src/core/recovery-history.js +66 -47
- package/src/core/reflection.js +72 -77
- package/src/core/responsibility.js +25 -13
- package/src/core/route-artifact.js +13 -3
- package/src/core/runtime-context.js +5 -0
- package/src/core/schema-validation.js +8 -3
- 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/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 +52 -18
- package/src/core/task-command.js +21 -1
- package/src/core/task-conflict-inspection.js +112 -107
- 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-snapshot.js +51 -8
- package/src/core/task-storage-migration.js +18 -0
- package/src/core/templates.js +20 -8
- package/src/core/test-intelligence/prune.js +5 -1
- package/src/core/trace.js +154 -99
- package/src/core/trajectory-evaluation.js +15 -3
- package/src/core/trajectory-metrics.js +47 -32
- package/src/core/transaction.js +16 -288
- package/src/core/verification-scope.js +20 -12
- package/src/core/work-state.js +100 -59
- package/src/repository-index/binary-manager.js +15 -7
- 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-execution-provenance.js +26 -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 +667 -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
|
@@ -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,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
|
+
}
|
|
@@ -1,15 +1,31 @@
|
|
|
1
1
|
import { ARTIFACT_PATHS } from "./artifacts.js";
|
|
2
2
|
import { reconcileContinuity } from "./continuity-reconciliation.js";
|
|
3
|
-
import { NEXT_ACTIONS, result } from "./next-action-model.js";
|
|
3
|
+
import { directCommandSpec, NEXT_ACTIONS, result } from "./next-action-model.js";
|
|
4
|
+
import { taskArtifactPath } from "./task-paths.js";
|
|
4
5
|
|
|
5
|
-
const
|
|
6
|
+
const SINGLETON_REQUIRED_ARTIFACTS = Object.freeze([ARTIFACT_PATHS.state, ARTIFACT_PATHS.continuity]);
|
|
6
7
|
|
|
7
|
-
function reason(code, message, artifacts =
|
|
8
|
+
function reason(code, message, artifacts = SINGLETON_REQUIRED_ARTIFACTS) {
|
|
8
9
|
return { code, message, artifacts };
|
|
9
10
|
}
|
|
10
11
|
|
|
12
|
+
function continuityArtifacts(taskId) {
|
|
13
|
+
if (!taskId) {
|
|
14
|
+
return {
|
|
15
|
+
continuity: ARTIFACT_PATHS.continuity,
|
|
16
|
+
required: SINGLETON_REQUIRED_ARTIFACTS,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
continuity: taskArtifactPath(taskId, "continuity"),
|
|
21
|
+
required: [taskArtifactPath(taskId, "state"), taskArtifactPath(taskId, "continuity")],
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
11
25
|
export function nextActionForContinuity({ context, continuity } = {}) {
|
|
12
26
|
if (!continuity || ["ABSENT", "NOT_APPLICABLE"].includes(continuity.classification)) return null;
|
|
27
|
+
const taskId = context?.taskId ?? null;
|
|
28
|
+
const artifacts = continuityArtifacts(taskId);
|
|
13
29
|
|
|
14
30
|
if (continuity.classification === "FRESH") {
|
|
15
31
|
const remaining = continuity.continuity?.remainingWork ?? [];
|
|
@@ -20,22 +36,27 @@ export function nextActionForContinuity({ context, continuity } = {}) {
|
|
|
20
36
|
reasons: [reason(
|
|
21
37
|
"CONTINUITY_REMAINING_WORK",
|
|
22
38
|
`Execution continuity records ${remaining.length} remaining implementation item${remaining.length === 1 ? "" : "s"}.`,
|
|
23
|
-
[
|
|
39
|
+
[artifacts.continuity],
|
|
24
40
|
)],
|
|
25
|
-
requiredArtifacts:
|
|
41
|
+
requiredArtifacts: artifacts.required,
|
|
26
42
|
});
|
|
27
43
|
}
|
|
28
44
|
|
|
29
45
|
if (continuity.classification === "RECONCILIATION_REQUIRED") {
|
|
46
|
+
const command = taskId
|
|
47
|
+
? `forgeloop reconcile-continuity --task ${taskId}`
|
|
48
|
+
: "forgeloop reconcile-continuity";
|
|
30
49
|
return result({
|
|
31
50
|
...context,
|
|
32
51
|
nextAction: NEXT_ACTIONS.RESOLVE_BLOCKER,
|
|
33
|
-
commands: [
|
|
52
|
+
commands: [command],
|
|
53
|
+
...(taskId ? { commandSpecs: [directCommandSpec("reconcile-continuity", taskId)] } : {}),
|
|
34
54
|
reasons: [reason(
|
|
35
55
|
"E_CONTINUITY_RECONCILIATION_REQUIRED",
|
|
36
56
|
"Execution continuity no longer matches canonical state or the current checkout; reconcile it before advancing verification.",
|
|
57
|
+
artifacts.required,
|
|
37
58
|
)],
|
|
38
|
-
requiredArtifacts:
|
|
59
|
+
requiredArtifacts: artifacts.required,
|
|
39
60
|
});
|
|
40
61
|
}
|
|
41
62
|
|
|
@@ -49,8 +70,9 @@ export function nextActionForContinuity({ context, continuity } = {}) {
|
|
|
49
70
|
reasons: codes.map((code, index) => reason(
|
|
50
71
|
code,
|
|
51
72
|
continuity.reasons?.[index] ?? `Execution continuity is ${continuity.classification.toLowerCase()}.`,
|
|
73
|
+
artifacts.required,
|
|
52
74
|
)),
|
|
53
|
-
requiredArtifacts:
|
|
75
|
+
requiredArtifacts: artifacts.required,
|
|
54
76
|
});
|
|
55
77
|
}
|
|
56
78
|
|
|
@@ -60,6 +82,6 @@ export function nextActionForContinuity({ context, continuity } = {}) {
|
|
|
60
82
|
export async function evaluateContinuityNextAction({ target, packageRoot, context } = {}) {
|
|
61
83
|
return nextActionForContinuity({
|
|
62
84
|
context,
|
|
63
|
-
continuity: await reconcileContinuity({ target, packageRoot }),
|
|
85
|
+
continuity: await reconcileContinuity({ target, packageRoot, taskId: context?.taskId ?? null }),
|
|
64
86
|
});
|
|
65
87
|
}
|
|
@@ -311,7 +311,7 @@ export async function resolveNextActionPhase({
|
|
|
311
311
|
const preflightArtifacts = [...requiredArtifacts, preflightRel];
|
|
312
312
|
const persistedPreflightErrors = phaseNeedsChronology
|
|
313
313
|
? []
|
|
314
|
-
: validatePersistedPreflight(preflightArtifact.value?.value, preflight);
|
|
314
|
+
: validatePersistedPreflight(preflightArtifact.value?.value, preflight, preflightArtifact.error);
|
|
315
315
|
|
|
316
316
|
if (["ROUTED", "DESIGNING", "PLANNED"].includes(state.phase) && missingGates.length > 0) {
|
|
317
317
|
const missingGatePaths = missingGates.map((gate) => taskGatePath(state.taskId, gate));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readJsonArtifact } from "./artifacts.js";
|
|
2
|
-
import { evaluateCompletion } from "./completion.js";
|
|
2
|
+
import { evaluateCompletion, receiptReadFailure } from "./completion.js";
|
|
3
3
|
import { validateReceipt } from "./receipt.js";
|
|
4
4
|
import { completionRelationshipErrors } from "./completion-relationships.js";
|
|
5
5
|
import { evaluateRequiredEvidence, classifyRequirement, terminalRequirementsForContract } from "./evidence-readiness.js";
|
|
@@ -82,7 +82,7 @@ export async function resolveReviewingPhase({ state, context, requiredArtifacts,
|
|
|
82
82
|
return decision(
|
|
83
83
|
context,
|
|
84
84
|
NEXT_ACTIONS.RESOLVE_BLOCKER,
|
|
85
|
-
|
|
85
|
+
receiptReadFailure(receipt.error, receiptRel),
|
|
86
86
|
[...requiredArtifacts, receiptRel],
|
|
87
87
|
);
|
|
88
88
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { receiptReadFailure } from "./completion.js";
|
|
1
2
|
import { readJsonArtifact } from "./artifacts.js";
|
|
2
3
|
import { taskArtifactPath, taskStructuralQualityDirectory } from "./task-paths.js";
|
|
3
4
|
import { validateReceipt } from "./receipt.js";
|
|
@@ -100,7 +101,7 @@ export async function resolveVerifyingPhase({ target, packageRoot, explicitTaskI
|
|
|
100
101
|
return decision(
|
|
101
102
|
context,
|
|
102
103
|
NEXT_ACTIONS.RESOLVE_BLOCKER,
|
|
103
|
-
|
|
104
|
+
receiptReadFailure(receipt.error, receiptRel),
|
|
104
105
|
[...requiredArtifacts, receiptRel],
|
|
105
106
|
);
|
|
106
107
|
}
|
package/src/core/next-action.js
CHANGED
|
@@ -15,6 +15,9 @@ import { resolveNextActionPhase } from "./next-action-phases.js";
|
|
|
15
15
|
import { criterionForDecision } from "./settlement-model.js";
|
|
16
16
|
import { validateApprovalForAction } from "./approvals.js";
|
|
17
17
|
import { evaluateActionCapability } from "./capability-policy.js";
|
|
18
|
+
import { resolveTaskContext, TASK_SELECTION_MODES } from "./task-context.js";
|
|
19
|
+
import { getOperationalStore } from "../storage/operational-context.js";
|
|
20
|
+
import { withProjectReadSnapshot } from "../storage/project-read-snapshot.js";
|
|
18
21
|
|
|
19
22
|
export { NEXT_ACTIONS } from "./next-action-model.js";
|
|
20
23
|
|
|
@@ -355,9 +358,25 @@ async function computeNextAction(targetOrOptions = {}, packageRootOption) {
|
|
|
355
358
|
}
|
|
356
359
|
|
|
357
360
|
export async function getNextAction(targetOrOptions = {}, packageRootOption) {
|
|
358
|
-
const
|
|
361
|
+
const target = typeof targetOrOptions === "string" ? targetOrOptions : targetOrOptions?.target;
|
|
362
|
+
const read = () => getSelectedNextAction(targetOrOptions, packageRootOption);
|
|
363
|
+
return target ? withProjectReadSnapshot(target, read) : read();
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
async function getSelectedNextAction(targetOrOptions, packageRootOption) {
|
|
367
|
+
let normalized = typeof targetOrOptions === "string"
|
|
368
|
+
? { target: targetOrOptions, packageRoot: packageRootOption }
|
|
369
|
+
: { ...targetOrOptions };
|
|
370
|
+
if (getOperationalStore(normalized.target)) {
|
|
371
|
+
const context = await resolveTaskContext(normalized.target, {
|
|
372
|
+
taskId: normalized.taskId,
|
|
373
|
+
packageRoot: normalized.packageRoot,
|
|
374
|
+
selectionMode: TASK_SELECTION_MODES.READ,
|
|
375
|
+
});
|
|
376
|
+
if (context) normalized = { ...normalized, taskId: context.taskId };
|
|
377
|
+
}
|
|
378
|
+
const res = await computeNextAction(normalized);
|
|
359
379
|
if (res && res.reasons && res.reasons.some((r) => r.code === "E_CONTRACT_UNRESOLVED_DECISION" || r.code === "E_UNRESOLVED_DECISION")) {
|
|
360
|
-
const normalized = typeof targetOrOptions === "string" ? { target: targetOrOptions, packageRoot: packageRootOption } : targetOrOptions;
|
|
361
380
|
const { target, packageRoot, taskId } = normalized ?? {};
|
|
362
381
|
try {
|
|
363
382
|
const explicitTaskId = taskId ?? null;
|