@shivaedev/work-fleet 0.1.1 → 0.2.0
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/CHANGELOG.md +16 -0
- package/README.md +2 -2
- package/dist/admit.d.ts +54 -0
- package/dist/admit.d.ts.map +1 -1
- package/dist/engine/abandonStalled.d.ts +9807 -0
- package/dist/engine/abandonStalled.d.ts.map +1 -0
- package/dist/engine/abandonStalled.js +55 -0
- package/dist/engine/abandonStalled.js.map +1 -0
- package/dist/engine/applyResolution.d.ts +108 -0
- package/dist/engine/applyResolution.d.ts.map +1 -1
- package/dist/engine/applyResolution.js +3 -0
- package/dist/engine/applyResolution.js.map +1 -1
- package/dist/engine/approveBrief.d.ts +164 -2
- package/dist/engine/approveBrief.d.ts.map +1 -1
- package/dist/engine/approveBrief.js +7 -5
- package/dist/engine/approveBrief.js.map +1 -1
- package/dist/engine/authorizeResolution.d.ts +942 -24
- package/dist/engine/authorizeResolution.d.ts.map +1 -1
- package/dist/engine/boardBrief.d.ts +162 -0
- package/dist/engine/boardBrief.d.ts.map +1 -1
- package/dist/engine/capacityRetry.d.ts +2883 -75
- package/dist/engine/capacityRetry.d.ts.map +1 -1
- package/dist/engine/closeDecisions.d.ts +108 -0
- package/dist/engine/closeDecisions.d.ts.map +1 -1
- package/dist/engine/completeBoardWork.d.ts +108 -0
- package/dist/engine/completeBoardWork.d.ts.map +1 -1
- package/dist/engine/completeReport.d.ts +108 -0
- package/dist/engine/completeReport.d.ts.map +1 -1
- package/dist/engine/continueCommand.d.ts +54 -0
- package/dist/engine/continueCommand.d.ts.map +1 -1
- package/dist/engine/continueWorker.d.ts +108 -0
- package/dist/engine/continueWorker.d.ts.map +1 -1
- package/dist/engine/deliverPendingAnswers.d.ts +1104 -24
- package/dist/engine/deliverPendingAnswers.d.ts.map +1 -1
- package/dist/engine/dispatchCommand.d.ts +54 -0
- package/dist/engine/dispatchCommand.d.ts.map +1 -1
- package/dist/engine/ensureDecisionOwner.d.ts +108 -0
- package/dist/engine/ensureDecisionOwner.d.ts.map +1 -1
- package/dist/engine/ensurePublication.d.ts +108 -0
- package/dist/engine/ensurePublication.d.ts.map +1 -1
- package/dist/engine/inspectRenewal.d.ts +108 -0
- package/dist/engine/inspectRenewal.d.ts.map +1 -1
- package/dist/engine/launchInput.d.ts +54 -0
- package/dist/engine/launchInput.d.ts.map +1 -1
- package/dist/engine/launchReceipt.d.ts +54 -0
- package/dist/engine/launchReceipt.d.ts.map +1 -1
- package/dist/engine/makeAdopt.d.ts +108 -0
- package/dist/engine/makeAdopt.d.ts.map +1 -1
- package/dist/engine/makeAdvance.d.ts +54 -0
- package/dist/engine/makeAdvance.d.ts.map +1 -1
- package/dist/engine/makeDeliver.d.ts +108 -0
- package/dist/engine/makeDeliver.d.ts.map +1 -1
- package/dist/engine/makeHuman.d.ts +108 -0
- package/dist/engine/makeHuman.d.ts.map +1 -1
- package/dist/engine/makeLaunch.d.ts +108 -0
- package/dist/engine/makeLaunch.d.ts.map +1 -1
- package/dist/engine/makeObserve.d.ts +108 -0
- package/dist/engine/makeObserve.d.ts.map +1 -1
- package/dist/engine/makeReview.d.ts +108 -0
- package/dist/engine/makeReview.d.ts.map +1 -1
- package/dist/engine/makeState.d.ts +888 -24
- package/dist/engine/makeState.d.ts.map +1 -1
- package/dist/engine/makeValidate.d.ts +108 -0
- package/dist/engine/makeValidate.d.ts.map +1 -1
- package/dist/engine/mergeReadiness.d.ts +1212 -24
- package/dist/engine/mergeReadiness.d.ts.map +1 -1
- package/dist/engine/observeDeliveryFailure.d.ts +996 -24
- package/dist/engine/observeDeliveryFailure.d.ts.map +1 -1
- package/dist/engine/observeRenewal.d.ts +189 -0
- package/dist/engine/observeRenewal.d.ts.map +1 -1
- package/dist/engine/observedAttempt.d.ts.map +1 -1
- package/dist/engine/observedAttempt.js +3 -0
- package/dist/engine/observedAttempt.js.map +1 -1
- package/dist/engine/obtainReview.d.ts +54 -0
- package/dist/engine/obtainReview.d.ts.map +1 -1
- package/dist/engine/operationRecord.d.ts +726 -24
- package/dist/engine/operationRecord.d.ts.map +1 -1
- package/dist/engine/persistTerminalReceipts.d.ts +108 -0
- package/dist/engine/persistTerminalReceipts.d.ts.map +1 -1
- package/dist/engine/prepareCommand.d.ts +54 -0
- package/dist/engine/prepareCommand.d.ts.map +1 -1
- package/dist/engine/prepareCommand.js +19 -0
- package/dist/engine/prepareCommand.js.map +1 -1
- package/dist/engine/queueAnswerCommand.d.ts +54 -0
- package/dist/engine/queueAnswerCommand.d.ts.map +1 -1
- package/dist/engine/readOrContinueReview.d.ts +54 -0
- package/dist/engine/readOrContinueReview.d.ts.map +1 -1
- package/dist/engine/readRetry.d.ts +1995 -51
- package/dist/engine/readRetry.d.ts.map +1 -1
- package/dist/engine/reassignCommand.d.ts +54 -0
- package/dist/engine/reassignCommand.d.ts.map +1 -1
- package/dist/engine/reconcileAttempt.d.ts +81 -0
- package/dist/engine/reconcileAttempt.d.ts.map +1 -1
- package/dist/engine/reconcileCommand.d.ts +54 -0
- package/dist/engine/reconcileCommand.d.ts.map +1 -1
- package/dist/engine/recoverStall.d.ts +1023 -24
- package/dist/engine/recoverStall.d.ts.map +1 -1
- package/dist/engine/recoverStall.js +5 -1
- package/dist/engine/recoverStall.js.map +1 -1
- package/dist/engine/recoverUnobservable.d.ts +1023 -24
- package/dist/engine/recoverUnobservable.d.ts.map +1 -1
- package/dist/engine/refreshBrief.d.ts +1997 -53
- package/dist/engine/refreshBrief.d.ts.map +1 -1
- package/dist/engine/refreshReviewResult.d.ts +108 -0
- package/dist/engine/refreshReviewResult.d.ts.map +1 -1
- package/dist/engine/releaseClosedPreparation.d.ts +996 -24
- package/dist/engine/releaseClosedPreparation.d.ts.map +1 -1
- package/dist/engine/releaseExecution.d.ts +996 -24
- package/dist/engine/releaseExecution.d.ts.map +1 -1
- package/dist/engine/releaseFinishedWork.d.ts +54 -0
- package/dist/engine/releaseFinishedWork.d.ts.map +1 -1
- package/dist/engine/repository.d.ts +672 -24
- package/dist/engine/repository.d.ts.map +1 -1
- package/dist/engine/repository.js +1 -0
- package/dist/engine/repository.js.map +1 -1
- package/dist/engine/requestConflictRepair.d.ts +996 -24
- package/dist/engine/requestConflictRepair.d.ts.map +1 -1
- package/dist/engine/requestRework.d.ts +108 -0
- package/dist/engine/requestRework.d.ts.map +1 -1
- package/dist/engine/resolveCommand.d.ts +54 -0
- package/dist/engine/resolveCommand.d.ts.map +1 -1
- package/dist/engine/resolveExecution.d.ts +996 -24
- package/dist/engine/resolveExecution.d.ts.map +1 -1
- package/dist/engine/resolveExecution.js +3 -1
- package/dist/engine/resolveExecution.js.map +1 -1
- package/dist/engine/resumeAttempt.d.ts +1023 -24
- package/dist/engine/resumeAttempt.d.ts.map +1 -1
- package/dist/engine/retireUnacknowledged.d.ts +108 -0
- package/dist/engine/retireUnacknowledged.d.ts.map +1 -1
- package/dist/engine/retryTerminal.d.ts +942 -24
- package/dist/engine/retryTerminal.d.ts.map +1 -1
- package/dist/engine/scheduler.d.ts +108 -0
- package/dist/engine/scheduler.d.ts.map +1 -1
- package/dist/engine/sessionCleanup.d.ts +108 -0
- package/dist/engine/sessionCleanup.d.ts.map +1 -1
- package/dist/engine/sessionCleanup.js +3 -1
- package/dist/engine/sessionCleanup.js.map +1 -1
- package/dist/engine/sessionStatus.d.ts.map +1 -1
- package/dist/engine/sessionStatus.js +3 -0
- package/dist/engine/sessionStatus.js.map +1 -1
- package/dist/engine/settleMergedDelivery.d.ts +996 -24
- package/dist/engine/settleMergedDelivery.d.ts.map +1 -1
- package/dist/engine/steerBrief.d.ts +10340 -0
- package/dist/engine/steerBrief.d.ts.map +1 -0
- package/dist/engine/steerBrief.js +42 -0
- package/dist/engine/steerBrief.js.map +1 -0
- package/dist/engine/submissionFailure.d.ts +888 -24
- package/dist/engine/submissionFailure.d.ts.map +1 -1
- package/dist/engine/submitLaunch.d.ts +942 -24
- package/dist/engine/submitLaunch.d.ts.map +1 -1
- package/dist/engine/views.js +1 -0
- package/dist/engine/views.js.map +1 -1
- package/dist/engine/workerReport.d.ts +162 -0
- package/dist/engine/workerReport.d.ts.map +1 -1
- package/dist/fleet.d.ts +540 -0
- package/dist/fleet.d.ts.map +1 -1
- package/dist/host/admission.d.ts +108 -0
- package/dist/host/admission.d.ts.map +1 -1
- package/dist/host/admission.js +2 -1
- package/dist/host/admission.js.map +1 -1
- package/dist/host/answerWork.d.ts +54 -0
- package/dist/host/answerWork.d.ts.map +1 -1
- package/dist/host/commands.d.ts +108 -0
- package/dist/host/commands.d.ts.map +1 -1
- package/dist/host/daemon.d.ts +1465 -865
- package/dist/host/daemon.d.ts.map +1 -1
- package/dist/host/daemonClient.d.ts +691 -91
- package/dist/host/daemonClient.d.ts.map +1 -1
- package/dist/host/daemonContract.d.ts +984 -0
- package/dist/host/daemonContract.d.ts.map +1 -1
- package/dist/host/readWaitStates.d.ts.map +1 -1
- package/dist/host/readWaitStates.js +13 -4
- package/dist/host/readWaitStates.js.map +1 -1
- package/dist/host/reassignWork.d.ts +54 -0
- package/dist/host/reassignWork.d.ts.map +1 -1
- package/dist/host/recordPayloads.d.ts.map +1 -1
- package/dist/host/recordPayloads.js +8 -3
- package/dist/host/recordPayloads.js.map +1 -1
- package/dist/host/releaseWork.d.ts +108 -0
- package/dist/host/releaseWork.d.ts.map +1 -1
- package/dist/host/status.d.ts +30 -0
- package/dist/host/status.d.ts.map +1 -1
- package/dist/model.d.ts +144 -0
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +14 -1
- package/dist/model.js.map +1 -1
- package/dist/operations.d.ts +1224 -0
- package/dist/operations.d.ts.map +1 -1
- package/dist/packageInfo.d.ts +1 -1
- package/dist/packageInfo.js +1 -1
- package/dist/prompt/briefEdit.d.ts +2 -0
- package/dist/prompt/briefEdit.d.ts.map +1 -0
- package/dist/prompt/briefEdit.js +41 -0
- package/dist/prompt/briefEdit.js.map +1 -0
- package/dist/prompt/worker.d.ts.map +1 -1
- package/dist/prompt/worker.js +11 -2
- package/dist/prompt/worker.js.map +1 -1
- package/dist/qualifyDependencies.d.ts +54 -0
- package/dist/qualifyDependencies.d.ts.map +1 -1
- package/dist/scheduling/areas.d.ts +162 -0
- package/dist/scheduling/areas.d.ts.map +1 -1
- package/dist/storage/attemptV12.d.ts +108 -0
- package/dist/storage/attemptV12.d.ts.map +1 -0
- package/dist/storage/attemptV12.js +94 -0
- package/dist/storage/attemptV12.js.map +1 -0
- package/dist/storage/createCollections.d.ts +5 -0
- package/dist/storage/createCollections.d.ts.map +1 -0
- package/dist/storage/createCollections.js +21 -0
- package/dist/storage/createCollections.js.map +1 -0
- package/dist/storage/cycleV12.d.ts +287 -0
- package/dist/storage/cycleV12.d.ts.map +1 -0
- package/dist/storage/cycleV12.js +124 -0
- package/dist/storage/cycleV12.js.map +1 -0
- package/dist/storage/fleetMigrations.d.ts +0 -39
- package/dist/storage/fleetMigrations.d.ts.map +1 -1
- package/dist/storage/fleetMigrations.js +3 -9
- package/dist/storage/fleetMigrations.js.map +1 -1
- package/dist/storage/legacyColumns.d.ts +40 -0
- package/dist/storage/legacyColumns.d.ts.map +1 -0
- package/dist/storage/legacyColumns.js +12 -0
- package/dist/storage/legacyColumns.js.map +1 -0
- package/dist/storage/makeForeignReservations.d.ts +15 -0
- package/dist/storage/makeForeignReservations.d.ts.map +1 -0
- package/dist/storage/makeForeignReservations.js +34 -0
- package/dist/storage/makeForeignReservations.js.map +1 -0
- package/dist/storage/makePostgresFleetStore.d.ts +36 -16
- package/dist/storage/makePostgresFleetStore.d.ts.map +1 -1
- package/dist/storage/makePostgresFleetStore.js +24 -32
- package/dist/storage/makePostgresFleetStore.js.map +1 -1
- package/dist/storage/model.d.ts +53 -59
- package/dist/storage/model.d.ts.map +1 -1
- package/dist/storage/model.js +18 -60
- package/dist/storage/model.js.map +1 -1
- package/dist/storage/operationEntries.d.ts +6 -5
- package/dist/storage/operationEntries.d.ts.map +1 -1
- package/dist/storage/operationEntries.js +12 -15
- package/dist/storage/operationEntries.js.map +1 -1
- package/dist/storage/preparationV12.d.ts +44 -0
- package/dist/storage/preparationV12.d.ts.map +1 -0
- package/dist/storage/preparationV12.js +30 -0
- package/dist/storage/preparationV12.js.map +1 -0
- package/dist/storage/readRecords.d.ts +4 -0
- package/dist/storage/readRecords.d.ts.map +1 -0
- package/dist/storage/readRecords.js +10 -0
- package/dist/storage/readRecords.js.map +1 -0
- package/dist/storage/recordChildren.d.ts +11 -0
- package/dist/storage/recordChildren.d.ts.map +1 -0
- package/dist/storage/recordChildren.js +105 -0
- package/dist/storage/recordChildren.js.map +1 -0
- package/dist/storage/recordShape.d.ts +23 -0
- package/dist/storage/recordShape.d.ts.map +1 -0
- package/dist/storage/recordShape.js +112 -0
- package/dist/storage/recordShape.js.map +1 -0
- package/dist/storage/recordValue.d.ts +9 -6
- package/dist/storage/recordValue.d.ts.map +1 -1
- package/dist/storage/recordValue.js +42 -32
- package/dist/storage/recordValue.js.map +1 -1
- package/dist/storage/shapeV12.d.ts +794 -0
- package/dist/storage/shapeV12.d.ts.map +1 -0
- package/dist/storage/shapeV12.js +10 -0
- package/dist/storage/shapeV12.js.map +1 -0
- package/dist/storage/textRecordValue.d.ts +3 -0
- package/dist/storage/textRecordValue.d.ts.map +1 -0
- package/dist/storage/textRecordValue.js +13 -0
- package/dist/storage/textRecordValue.js.map +1 -0
- package/dist/storage/typedDecisionsV12.d.ts +103 -0
- package/dist/storage/typedDecisionsV12.d.ts.map +1 -0
- package/dist/storage/typedDecisionsV12.js +97 -0
- package/dist/storage/typedDecisionsV12.js.map +1 -0
- package/dist/storage/typedTables.d.ts +4 -0
- package/dist/storage/typedTables.d.ts.map +1 -0
- package/dist/storage/typedTables.js +39 -0
- package/dist/storage/typedTables.js.map +1 -0
- package/package.json +8 -8
- package/src/engine/abandonStalled.ts +63 -0
- package/src/engine/applyResolution.ts +3 -0
- package/src/engine/approveBrief.ts +34 -32
- package/src/engine/observedAttempt.ts +3 -0
- package/src/engine/prepareCommand.ts +21 -0
- package/src/engine/recoverStall.ts +6 -2
- package/src/engine/repository.ts +1 -0
- package/src/engine/resolveExecution.ts +3 -1
- package/src/engine/sessionCleanup.ts +3 -1
- package/src/engine/sessionStatus.ts +5 -0
- package/src/engine/steerBrief.ts +54 -0
- package/src/engine/views.ts +1 -0
- package/src/host/admission.ts +2 -1
- package/src/host/readWaitStates.ts +12 -11
- package/src/host/recordPayloads.ts +11 -3
- package/src/model.ts +20 -1
- package/src/packageInfo.ts +1 -1
- package/src/prompt/briefEdit.ts +44 -0
- package/src/prompt/worker.ts +11 -2
- package/src/storage/attemptV12.ts +95 -0
- package/src/storage/createCollections.ts +21 -0
- package/src/storage/cycleV12.ts +125 -0
- package/src/storage/fleetMigrations.ts +3 -10
- package/src/storage/legacyColumns.ts +12 -0
- package/src/storage/makeForeignReservations.ts +41 -0
- package/src/storage/makePostgresFleetStore.ts +30 -43
- package/src/storage/model.ts +19 -69
- package/src/storage/operationEntries.ts +12 -22
- package/src/storage/preparationV12.ts +31 -0
- package/src/storage/readRecords.ts +12 -0
- package/src/storage/recordChildren.ts +131 -0
- package/src/storage/recordShape.ts +137 -0
- package/src/storage/recordValue.ts +47 -34
- package/src/storage/shapeV12.ts +11 -0
- package/src/storage/textRecordValue.ts +16 -0
- package/src/storage/typedDecisionsV12.ts +100 -0
- package/src/storage/typedTables.ts +39 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Effect, Result } from "effect";
|
|
2
|
+
import { workRevision } from "#board/workRevision.ts";
|
|
3
|
+
import type { EngineState } from "#engine/makeState.ts";
|
|
4
|
+
import type { FleetRecord } from "#model.ts";
|
|
5
|
+
import { briefEditPrompt } from "#prompt/briefEdit.ts";
|
|
6
|
+
import type { Versioned } from "#storage/model.ts";
|
|
7
|
+
|
|
8
|
+
export function briefSteerIntent(previous: FleetRecord, record: FleetRecord, requestedAt: number): FleetRecord {
|
|
9
|
+
const revision = workRevision(record.boardRevision, record.boardContext);
|
|
10
|
+
const attempt = record.attempts.at(-1);
|
|
11
|
+
if (
|
|
12
|
+
revision === workRevision(previous.boardRevision, previous.boardContext)
|
|
13
|
+
|| record.stage !== "executing"
|
|
14
|
+
|| attempt?.receipt === undefined
|
|
15
|
+
|| attempt.role === "reviewer"
|
|
16
|
+
|| !["accepted", "running"].includes(attempt.status)
|
|
17
|
+
|| attempt.briefSteers?.some((entry) => entry.revision === revision)
|
|
18
|
+
) {
|
|
19
|
+
return record;
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
...record,
|
|
23
|
+
attempts: record.attempts.map((entry) =>
|
|
24
|
+
entry.operationId === attempt.operationId ? { ...entry, briefSteers: [...(entry.briefSteers ?? []), { requestedAt, revision }] } : entry,
|
|
25
|
+
),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const steerBrief = Effect.fn("Fleet.steerBrief")(function* (state: EngineState, stored: Versioned<FleetRecord>, previous: FleetRecord) {
|
|
30
|
+
const record = stored.value;
|
|
31
|
+
const revision = workRevision(record.boardRevision, record.boardContext);
|
|
32
|
+
const attempt = record.attempts.at(-1);
|
|
33
|
+
const intent = attempt?.briefSteers?.find((entry) => entry.revision === revision);
|
|
34
|
+
if (
|
|
35
|
+
attempt?.receipt === undefined
|
|
36
|
+
|| intent === undefined
|
|
37
|
+
|| previous.attempts.some((entry) => entry.operationId === attempt.operationId && entry.briefSteers?.some((saved) => saved.revision === revision))
|
|
38
|
+
) {
|
|
39
|
+
return stored;
|
|
40
|
+
}
|
|
41
|
+
const result = yield* state.sessions
|
|
42
|
+
.steer(attempt.receipt, briefEditPrompt(previous.boardContext, record.boardContext ?? record.prompt))
|
|
43
|
+
.pipe(Effect.result);
|
|
44
|
+
const evidence = Result.isFailure(result) ? { error: result.failure.message } : { steeredAt: state.policy.now() };
|
|
45
|
+
const current = yield* state.load(record.workId);
|
|
46
|
+
return yield* state.save(current, {
|
|
47
|
+
...current.value,
|
|
48
|
+
attempts: current.value.attempts.map((entry) =>
|
|
49
|
+
entry.operationId === attempt.operationId
|
|
50
|
+
? { ...entry, briefSteers: entry.briefSteers?.map((saved) => (saved.revision === revision ? { ...saved, ...evidence } : saved)) }
|
|
51
|
+
: entry,
|
|
52
|
+
),
|
|
53
|
+
});
|
|
54
|
+
});
|
package/src/engine/views.ts
CHANGED
|
@@ -33,6 +33,7 @@ function sessionView(attempt: Attempt) {
|
|
|
33
33
|
: [
|
|
34
34
|
{
|
|
35
35
|
...attempt.receipt,
|
|
36
|
+
briefSteers: attempt.briefSteers,
|
|
36
37
|
interruptedAt: attempt.stallRecovery?.interruptedAt,
|
|
37
38
|
interruptRequestedAt: attempt.stallRecovery?.interruptRequestedAt,
|
|
38
39
|
lastProgressAt: attempt.progress?.at,
|
package/src/host/admission.ts
CHANGED
|
@@ -57,7 +57,8 @@ function unlaunched(record: FleetRecord) {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
function stalePreparation(record: FleetRecord, work: BoardWork, main: MainSnapshot) {
|
|
60
|
-
|
|
60
|
+
const changed = briefChanged(record, work);
|
|
61
|
+
return record.stage === "prepared" && (unlaunched(record) || !changed) && (changed || record.preparation.baseRevision !== main.revision);
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
export type Approval = "board" | "explicit";
|
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
import * as Effect from "effect/Effect";
|
|
2
2
|
import * as Schema from "effect/Schema";
|
|
3
|
+
import { Model } from "effect/schema";
|
|
3
4
|
import { makeRepository } from "@shivaedev/effect-sql/repository.ts";
|
|
4
5
|
import { State } from "#host/waitOutcome.ts";
|
|
5
|
-
import {
|
|
6
|
+
import { columnSchema, schemaShape, shapeColumns } from "#storage/recordShape.ts";
|
|
7
|
+
import { recordValues } from "#storage/recordValue.ts";
|
|
6
8
|
|
|
7
9
|
export interface ReadOptions {
|
|
8
10
|
readonly namespace: string;
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
export const readWaitStates = Effect.fn("FleetReader.readWaitStates")(function* (options: ReadOptions, ids?: readonly string[]) {
|
|
14
|
+
const shape = schemaShape(State);
|
|
15
|
+
class SnapshotRow extends Model.Class<SnapshotRow>("FleetSnapshot")({
|
|
16
|
+
...Object.fromEntries(Object.entries(shapeColumns(shape)).map(([name, kind]) => [name, columnSchema(kind)])),
|
|
17
|
+
"work_id": Schema.String,
|
|
18
|
+
}) {}
|
|
12
19
|
const read = Effect.gen(function* () {
|
|
13
|
-
const repository = yield* makeRepository(
|
|
20
|
+
const repository = yield* makeRepository(SnapshotRow, {
|
|
14
21
|
idColumn: "work_id",
|
|
15
22
|
spanPrefix: "FleetReader",
|
|
16
23
|
tableName: `${options.namespace}_records`,
|
|
@@ -18,7 +25,6 @@ export const readWaitStates = Effect.fn("FleetReader.readWaitStates")(function*
|
|
|
18
25
|
const rows = yield* repository
|
|
19
26
|
.findMany({
|
|
20
27
|
orderBy: { direction: "asc", field: "work_id" },
|
|
21
|
-
select: ["work_id", "stage", "blocker", "attentionOwner", "checks", "decision", "outcome"],
|
|
22
28
|
})
|
|
23
29
|
.pipe(
|
|
24
30
|
Effect.catchTag("SqlError", (error) => {
|
|
@@ -26,14 +32,9 @@ export const readWaitStates = Effect.fn("FleetReader.readWaitStates")(function*
|
|
|
26
32
|
return typeof cause === "object" && cause !== null && "code" in cause && cause.code === "42P01" ? Effect.succeed([]) : Effect.fail(error);
|
|
27
33
|
}),
|
|
28
34
|
);
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
recordJson(row, recordColumns()).pipe(
|
|
33
|
-
Effect.flatMap(Schema.decodeUnknownEffect(Schema.fromJsonString(State))),
|
|
34
|
-
Effect.map((state) => ({ ...state, outcome: state.outcome ?? {} })),
|
|
35
|
-
),
|
|
36
|
-
);
|
|
35
|
+
const selected = rows.filter((row) => ids === undefined || ids.includes(row.work_id));
|
|
36
|
+
const states = yield* Schema.decodeUnknownEffect(Schema.Array(State))(yield* recordValues(selected, shape, options.namespace));
|
|
37
|
+
return states.map((state) => ({ ...state, outcome: state.outcome ?? {} }));
|
|
37
38
|
});
|
|
38
39
|
return yield* read;
|
|
39
40
|
});
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { SqlClient } from "effect/sql";
|
|
3
3
|
import { makeRepository } from "@shivaedev/effect-sql/repository.ts";
|
|
4
|
-
import {
|
|
4
|
+
import { recordModel } from "#storage/model.ts";
|
|
5
|
+
import { readRecords } from "#storage/readRecords.ts";
|
|
6
|
+
import { recordShape } from "#storage/recordShape.ts";
|
|
7
|
+
import { recordValues } from "#storage/recordValue.ts";
|
|
5
8
|
|
|
6
9
|
export const recordPayloads = Effect.fn("FleetHost.recordPayloads")(function* (namespace: string, workId?: string) {
|
|
7
10
|
const sql = yield* SqlClient.SqlClient;
|
|
@@ -11,6 +14,11 @@ export const recordPayloads = Effect.fn("FleetHost.recordPayloads")(function* (n
|
|
|
11
14
|
return [];
|
|
12
15
|
}
|
|
13
16
|
const repository = yield* makeRepository(recordModel(), { idColumn: "work_id", spanPrefix: "FleetReader", tableName: table });
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
return yield* readRecords(
|
|
18
|
+
namespace,
|
|
19
|
+
Effect.gen(function* () {
|
|
20
|
+
const rows = yield* repository.findMany({ orderBy: { direction: "asc", field: "work_id" }, where: { "work_id": workId } });
|
|
21
|
+
return (yield* recordValues(rows, recordShape(), namespace)).map((value) => JSON.stringify(value));
|
|
22
|
+
}),
|
|
23
|
+
);
|
|
16
24
|
});
|
package/src/model.ts
CHANGED
|
@@ -4,8 +4,26 @@ import { AttentionOwner } from "#attention.ts";
|
|
|
4
4
|
import { BoardReport } from "#board/schema.ts";
|
|
5
5
|
import { Checks, Decision, DecisionResponse, Delivery, Review, SupersededDecision, WorkResult } from "#policy.ts";
|
|
6
6
|
import { Preparation } from "#preparation/schema.ts";
|
|
7
|
-
import { LaunchSettings, SessionReceipt } from "#session/schema.ts";
|
|
7
|
+
import { LaunchSettings, SessionObservation, SessionReceipt } from "#session/schema.ts";
|
|
8
8
|
export const Attempt = Schema.Struct({
|
|
9
|
+
abandoned: Schema.optional(
|
|
10
|
+
Schema.Struct({
|
|
11
|
+
at: Schema.Number,
|
|
12
|
+
interruptError: Schema.optional(Schema.String),
|
|
13
|
+
observation: Schema.optional(SessionObservation),
|
|
14
|
+
observationError: Schema.optional(Schema.String),
|
|
15
|
+
}),
|
|
16
|
+
),
|
|
17
|
+
briefSteers: Schema.optional(
|
|
18
|
+
Schema.Array(
|
|
19
|
+
Schema.Struct({
|
|
20
|
+
error: Schema.optional(Schema.String),
|
|
21
|
+
requestedAt: Schema.Number,
|
|
22
|
+
revision: Schema.String,
|
|
23
|
+
steeredAt: Schema.optional(Schema.Number),
|
|
24
|
+
}),
|
|
25
|
+
),
|
|
26
|
+
),
|
|
9
27
|
checkFailures: Schema.optional(Schema.Array(Schema.String)),
|
|
10
28
|
missingSince: Schema.optional(Schema.Number),
|
|
11
29
|
observationRetries: Schema.optional(Schema.Number),
|
|
@@ -99,6 +117,7 @@ export const FleetView = Schema.Struct({
|
|
|
99
117
|
sessions: Schema.Array(
|
|
100
118
|
Schema.Struct({
|
|
101
119
|
...SessionReceipt.fields,
|
|
120
|
+
briefSteers: Attempt.fields.briefSteers,
|
|
102
121
|
interruptedAt: Schema.optional(Schema.Number),
|
|
103
122
|
interruptRequestedAt: Schema.optional(Schema.Number),
|
|
104
123
|
lastProgressAt: Schema.optional(Schema.Number),
|
package/src/packageInfo.ts
CHANGED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { board as boardApi } from "@shivaedev/work-board/integration/board.ts";
|
|
2
|
+
import { fleetDeliverable } from "#board/fleetField.ts";
|
|
3
|
+
|
|
4
|
+
export function briefEditPrompt(previous: string | undefined, current: string): string {
|
|
5
|
+
const before = boardApi.metadataParse(previous ?? "");
|
|
6
|
+
const after = boardApi.metadataParse(current);
|
|
7
|
+
const criteria = new Map((before.fields.criteria ?? []).map(({ id, text }) => [id, text]));
|
|
8
|
+
const next = new Map((after.fields.criteria ?? []).map(({ id, text }) => [id, text]));
|
|
9
|
+
const changes = [...new Set([...criteria.keys(), ...next.keys()])].flatMap((id) =>
|
|
10
|
+
criteria.get(id) === next.get(id) ? [] : [`Criterion ${id}: ${criteria.get(id) ?? "(added)"} -> ${next.get(id) ?? "(removed)"}`],
|
|
11
|
+
);
|
|
12
|
+
if (before.body !== after.body) {
|
|
13
|
+
changes.push(...bodyChanges(before.body, after.body));
|
|
14
|
+
}
|
|
15
|
+
for (const field of ["kind", "relationships"] as const) {
|
|
16
|
+
if (JSON.stringify(before.fields[field]) !== JSON.stringify(after.fields[field])) {
|
|
17
|
+
changes.push(`The ${field} changed.`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (fleetDeliverable(before) !== fleetDeliverable(after)) {
|
|
21
|
+
changes.push("The deliverable changed.");
|
|
22
|
+
}
|
|
23
|
+
return [
|
|
24
|
+
"Fleet approved an edited brief. Apply this correction to your running work.",
|
|
25
|
+
"What changed:",
|
|
26
|
+
...changes,
|
|
27
|
+
"Full new brief:",
|
|
28
|
+
current,
|
|
29
|
+
].join("\n\n");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function bodyChanges(before: string, after: string): readonly string[] {
|
|
33
|
+
const removed = before.split("\n");
|
|
34
|
+
const added = after.split("\n");
|
|
35
|
+
while (removed.length > 0 && added.length > 0 && removed[0] === added[0]) {
|
|
36
|
+
removed.shift();
|
|
37
|
+
added.shift();
|
|
38
|
+
}
|
|
39
|
+
while (removed.length > 0 && added.length > 0 && removed.at(-1) === added.at(-1)) {
|
|
40
|
+
removed.pop();
|
|
41
|
+
added.pop();
|
|
42
|
+
}
|
|
43
|
+
return [`Previous title/body excerpt:\n${removed.join("\n") || "(empty)"}`, `New title/body excerpt:\n${added.join("\n") || "(empty)"}`];
|
|
44
|
+
}
|
package/src/prompt/worker.ts
CHANGED
|
@@ -36,7 +36,8 @@ export function cloudStartup({ sharedEnvironment }: CloudStartup, access?: "read
|
|
|
36
36
|
return [
|
|
37
37
|
"Cloud startup:",
|
|
38
38
|
"- Your workspace may still be provisioning when this message arrives. If the cloud-environment runtime skill offers wait_for_environment, call it and wait calmly until the environment is ready; this usually takes about 90 seconds. Do not explore the snapshot or retry commands while waiting. Your instructions below stay valid.",
|
|
39
|
-
|
|
39
|
+
"- Default login shells activate the pinned Node, pnpm, Bun, gh and psql and every shared environment export through the profile hook, including the proxy, CA trust, caches and database settings.",
|
|
40
|
+
`- If \`node -v\` does not report the repository's \`.node-version\`, source ${sharedEnvironment} once in that command and say so in the final message.`,
|
|
40
41
|
...(access === "read-only"
|
|
41
42
|
? []
|
|
42
43
|
: [
|
|
@@ -47,13 +48,21 @@ export function cloudStartup({ sharedEnvironment }: CloudStartup, access?: "read
|
|
|
47
48
|
|
|
48
49
|
export function workerPrompt(input: WorkerPrompt) {
|
|
49
50
|
if (input.deliverable === "report") {
|
|
50
|
-
return [
|
|
51
|
+
return [
|
|
52
|
+
`Work Board task: ${input.workId}`,
|
|
53
|
+
"",
|
|
54
|
+
cloudStartup(input),
|
|
55
|
+
"- Before executing repository commands, run `./script/update` with escalation (require_escalated), since it installs dependencies.",
|
|
56
|
+
"",
|
|
57
|
+
reportPrompt(input.task.trim()),
|
|
58
|
+
].join("\n");
|
|
51
59
|
}
|
|
52
60
|
return [
|
|
53
61
|
`Work Board task: ${input.workId}`,
|
|
54
62
|
"",
|
|
55
63
|
cloudStartup(input),
|
|
56
64
|
`- Fetch origin/main and create ${input.branch} from that exact current revision, not from the environment snapshot. Use the supplied checkout and leave unrelated state alone.`,
|
|
65
|
+
"- Immediately after fetching origin/main and creating the branch, run `./script/update` with escalation (require_escalated), since it installs dependencies, before any other command or task work.",
|
|
57
66
|
"",
|
|
58
67
|
"Implement this approved Board task:",
|
|
59
68
|
"---",
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { Shape } from "#storage/recordShape.ts";
|
|
2
|
+
|
|
3
|
+
export const attemptV12 = {
|
|
4
|
+
fields: {
|
|
5
|
+
abandoned: {
|
|
6
|
+
fields: {
|
|
7
|
+
at: "number",
|
|
8
|
+
interruptError: "string",
|
|
9
|
+
observation: {
|
|
10
|
+
fields: {
|
|
11
|
+
capacity: "string",
|
|
12
|
+
error: "string",
|
|
13
|
+
execution: "string",
|
|
14
|
+
output: "string",
|
|
15
|
+
progress: { array: { fields: { id: "string", status: "string" } } },
|
|
16
|
+
provisioning: "string",
|
|
17
|
+
receipt: { fields: { sessionId: "string", turnId: "string" } },
|
|
18
|
+
turnMissing: "boolean",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
observationError: "string",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
briefSteers: {
|
|
25
|
+
array: {
|
|
26
|
+
fields: {
|
|
27
|
+
error: "string",
|
|
28
|
+
requestedAt: "number",
|
|
29
|
+
revision: "string",
|
|
30
|
+
steeredAt: "number",
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
checkFailures: { array: "string" },
|
|
35
|
+
missingSince: "number",
|
|
36
|
+
observationRetries: "number",
|
|
37
|
+
operationId: "string",
|
|
38
|
+
output: "string",
|
|
39
|
+
progress: {
|
|
40
|
+
fields: {
|
|
41
|
+
at: "number",
|
|
42
|
+
signature: "string",
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
prompt: "string",
|
|
46
|
+
providerFailures: "number",
|
|
47
|
+
readRetry: {
|
|
48
|
+
fields: {
|
|
49
|
+
error: "string",
|
|
50
|
+
failures: "number",
|
|
51
|
+
retryAt: "number",
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
receipt: {
|
|
55
|
+
fields: {
|
|
56
|
+
sessionId: "string",
|
|
57
|
+
turnId: "string",
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
reviewHead: "string",
|
|
61
|
+
reviewRevision: "string",
|
|
62
|
+
role: "string",
|
|
63
|
+
sessionCleanupComplete: "boolean",
|
|
64
|
+
sessionId: "string",
|
|
65
|
+
sessionUnusable: "boolean",
|
|
66
|
+
settings: {
|
|
67
|
+
fields: {
|
|
68
|
+
effort: "string",
|
|
69
|
+
model: "string",
|
|
70
|
+
serviceTier: "string",
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
stallRecovery: {
|
|
74
|
+
fields: {
|
|
75
|
+
count: "number",
|
|
76
|
+
interruptedAt: "number",
|
|
77
|
+
interruptRequestedAt: "number",
|
|
78
|
+
lastActionAt: "number",
|
|
79
|
+
steeredAt: "number",
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
status: "string",
|
|
83
|
+
submissionTimedOut: "boolean",
|
|
84
|
+
submissionUncertain: "boolean",
|
|
85
|
+
submittedAt: "number",
|
|
86
|
+
terminalReceipts: {
|
|
87
|
+
array: {
|
|
88
|
+
fields: {
|
|
89
|
+
sessionId: "string",
|
|
90
|
+
turnId: "string",
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
} as const satisfies Shape;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { SqlClient } from "effect/sql";
|
|
3
|
+
import { childTable, positions } from "#storage/recordChildren.ts";
|
|
4
|
+
import { collections, type Shape, shapeColumns, sqlTypes } from "#storage/recordShape.ts";
|
|
5
|
+
|
|
6
|
+
export const createCollections = Effect.fn("FleetStore.createCollections")(function* (namespace: string, shape: Shape) {
|
|
7
|
+
const sql = yield* SqlClient.SqlClient;
|
|
8
|
+
const table = `${namespace}_records`;
|
|
9
|
+
for (const collection of collections(shape)) {
|
|
10
|
+
const keys = positions(collection);
|
|
11
|
+
const fields = Object.entries(shapeColumns(collection.shape)).map(([name, kind]) => sql`${sql(name)} ${sql.literal(sqlTypes[kind])}`);
|
|
12
|
+
yield* sql`create table ${sql(childTable(namespace, collection.path))} (
|
|
13
|
+
work_id text not null references ${sql(table)} (work_id) on delete cascade,
|
|
14
|
+
${sql.csv(keys.map((key) => sql`${sql(key)} integer not null check (${sql(key)} >= 0)`))},
|
|
15
|
+
${sql.csv(fields)}, primary key (work_id, ${sql.csv(keys.map((key) => sql`${sql(key)}`))})
|
|
16
|
+
)`;
|
|
17
|
+
if (collection.path.at(-1) === "attempts") {
|
|
18
|
+
yield* sql`create index on ${sql(childTable(namespace, collection.path))} (${sql("operationId")})`;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
});
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { preparationV12 } from "#storage/preparationV12.ts";
|
|
2
|
+
import type { Shape } from "#storage/recordShape.ts";
|
|
3
|
+
import { decisionV12, responsesV12, supersededDecisionsV12 } from "#storage/typedDecisionsV12.ts";
|
|
4
|
+
|
|
5
|
+
export const cycleV12 = {
|
|
6
|
+
fields: {
|
|
7
|
+
admissionReady: "boolean",
|
|
8
|
+
areas: { array: "string" },
|
|
9
|
+
attentionOwner: "string",
|
|
10
|
+
blocker: "string",
|
|
11
|
+
boardContext: "string",
|
|
12
|
+
boardRevision: "string",
|
|
13
|
+
boardSourcePath: "string",
|
|
14
|
+
checks: {
|
|
15
|
+
fields: {
|
|
16
|
+
evidence: { array: "string" },
|
|
17
|
+
failedChecks: { array: "string" },
|
|
18
|
+
head: "string",
|
|
19
|
+
passed: "boolean",
|
|
20
|
+
pending: "boolean",
|
|
21
|
+
repairPrompt: "string",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
completedAt: "number",
|
|
25
|
+
conflictRepairs: { array: "string" },
|
|
26
|
+
cwd: "string",
|
|
27
|
+
decision: decisionV12,
|
|
28
|
+
decisionAcknowledged: "boolean",
|
|
29
|
+
decisionPublished: "boolean",
|
|
30
|
+
deliverable: "string",
|
|
31
|
+
integrationRetry: {
|
|
32
|
+
fields: {
|
|
33
|
+
error: "string",
|
|
34
|
+
failures: "number",
|
|
35
|
+
retryAt: "number",
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
launch: {
|
|
39
|
+
fields: {
|
|
40
|
+
effort: "string",
|
|
41
|
+
model: "string",
|
|
42
|
+
serviceTier: "string",
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
launchRetry: {
|
|
46
|
+
fields: {
|
|
47
|
+
prompt: "string",
|
|
48
|
+
rejectedAt: "number",
|
|
49
|
+
rejections: "number",
|
|
50
|
+
retryAt: "number",
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
mergeAreasReleased: "boolean",
|
|
54
|
+
mergeReadyAt: "number",
|
|
55
|
+
mergeReadyHead: "string",
|
|
56
|
+
outcome: {
|
|
57
|
+
fields: {
|
|
58
|
+
evidence: { array: "string" },
|
|
59
|
+
head: "string",
|
|
60
|
+
revision: "string",
|
|
61
|
+
url: "string",
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
pendingAnswers: { array: "string" },
|
|
65
|
+
preparation: preparationV12,
|
|
66
|
+
prompt: "string",
|
|
67
|
+
releaseReason: "string",
|
|
68
|
+
report: {
|
|
69
|
+
fields: {
|
|
70
|
+
itemId: "string",
|
|
71
|
+
receipt: {
|
|
72
|
+
fields: {
|
|
73
|
+
sessionId: "string",
|
|
74
|
+
turnId: "string",
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
revision: "string",
|
|
78
|
+
sourcePath: "string",
|
|
79
|
+
workRevision: "string",
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
responses: responsesV12,
|
|
83
|
+
result: {
|
|
84
|
+
fields: {
|
|
85
|
+
evidence: { array: "string" },
|
|
86
|
+
head: "string",
|
|
87
|
+
kind: "string",
|
|
88
|
+
paths: { array: "string" },
|
|
89
|
+
pr: "string",
|
|
90
|
+
prNumber: "number",
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
resultObservations: {
|
|
94
|
+
array: {
|
|
95
|
+
fields: {
|
|
96
|
+
evidence: { array: "string" },
|
|
97
|
+
head: "string",
|
|
98
|
+
kind: "string",
|
|
99
|
+
paths: { array: "string" },
|
|
100
|
+
pr: "string",
|
|
101
|
+
prNumber: "number",
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
review: {
|
|
106
|
+
fields: {
|
|
107
|
+
evidence: { array: "string" },
|
|
108
|
+
findings: { array: "string" },
|
|
109
|
+
head: "string",
|
|
110
|
+
receipt: {
|
|
111
|
+
fields: {
|
|
112
|
+
sessionId: "string",
|
|
113
|
+
turnId: "string",
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
repairPrompt: "string",
|
|
117
|
+
verdict: "string",
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
stage: "string",
|
|
121
|
+
stageEnteredAt: "number",
|
|
122
|
+
supersededDecisions: supersededDecisionsV12,
|
|
123
|
+
updatedAt: "number",
|
|
124
|
+
},
|
|
125
|
+
} as const satisfies Shape;
|
|
@@ -1,21 +1,13 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { Migrator, SqlClient } from "effect/sql";
|
|
3
3
|
import { backfillDecisionCodes } from "#storage/backfillDecisionCodes.ts";
|
|
4
|
-
import {
|
|
4
|
+
import { modelTables } from "#storage/modelTables.ts";
|
|
5
5
|
import { pruneEmptyCycles } from "#storage/pruneEmptyCycles.ts";
|
|
6
6
|
import { recordTimeColumns } from "#storage/recordTimes.ts";
|
|
7
|
+
import { typedTables } from "#storage/typedTables.ts";
|
|
7
8
|
|
|
8
9
|
const releaseReasonColumn = { kind: "string", name: "releaseReason" } as const;
|
|
9
10
|
|
|
10
|
-
// PostgreSQL text cannot distinguish scalar strings from serialized JSON.
|
|
11
|
-
export const fleetMigrationColumns = {
|
|
12
|
-
...modelTableColumns,
|
|
13
|
-
[releaseReasonColumn.name]: releaseReasonColumn.kind,
|
|
14
|
-
...recordTimeColumns,
|
|
15
|
-
integrationRetry: "json",
|
|
16
|
-
pendingAnswers: "json",
|
|
17
|
-
} as const;
|
|
18
|
-
|
|
19
11
|
export const fleetMigrations = Effect.fn("FleetStore.fleetMigrations")(function* (namespace: string, legacyOnly = false) {
|
|
20
12
|
const sql = yield* SqlClient.SqlClient;
|
|
21
13
|
return yield* Migrator.fromRecord({
|
|
@@ -55,6 +47,7 @@ export const fleetMigrations = Effect.fn("FleetStore.fleetMigrations")(function*
|
|
|
55
47
|
"9_integration_retry": sql`alter table ${sql(`${namespace}_records`)} add column ${sql("integrationRetry")} text`,
|
|
56
48
|
"10_prune_empty_cycles": pruneEmptyCycles(namespace),
|
|
57
49
|
"11_pending_answers": sql`alter table ${sql(`${namespace}_records`)} add column ${sql("pendingAnswers")} text`,
|
|
50
|
+
"12_typed_tables": typedTables(namespace),
|
|
58
51
|
}),
|
|
59
52
|
});
|
|
60
53
|
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { modelTableColumns } from "#storage/modelTables.ts";
|
|
2
|
+
|
|
3
|
+
// PostgreSQL text cannot distinguish scalar strings from serialized JSON.
|
|
4
|
+
export const legacyColumns = {
|
|
5
|
+
...modelTableColumns,
|
|
6
|
+
completedAt: "number",
|
|
7
|
+
integrationRetry: "json",
|
|
8
|
+
pendingAnswers: "json",
|
|
9
|
+
releaseReason: "string",
|
|
10
|
+
stageEnteredAt: "number",
|
|
11
|
+
updatedAt: "number",
|
|
12
|
+
} as const;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { SqlClient } from "effect/sql";
|
|
3
|
+
import { makeRepository } from "@shivaedev/effect-sql/repository.ts";
|
|
4
|
+
import { fleetRecords } from "#fleetRecords.ts";
|
|
5
|
+
import { makeFleetTransaction } from "#storage/makeFleetTransaction.ts";
|
|
6
|
+
import { ForeignReservationRow } from "#storage/model.ts";
|
|
7
|
+
|
|
8
|
+
export const makeForeignReservations = Effect.fn("FleetStore.makeForeignReservations")(function* (namespace: string) {
|
|
9
|
+
const sql = yield* SqlClient.SqlClient;
|
|
10
|
+
const commit = yield* makeFleetTransaction;
|
|
11
|
+
const reservations = yield* makeRepository(ForeignReservationRow, {
|
|
12
|
+
idColumn: "owner",
|
|
13
|
+
spanPrefix: "FleetForeign",
|
|
14
|
+
tableName: `${namespace}_foreign_reservations`,
|
|
15
|
+
});
|
|
16
|
+
const lock = sql`select pg_advisory_xact_lock(hashtextextended(${`work_fleet_admission:${namespace}`}, 0))`;
|
|
17
|
+
return {
|
|
18
|
+
foreignReservations: () => reservations.findMany({ orderBy: { direction: "asc", field: "owner" } }),
|
|
19
|
+
releaseForeign: (owner: string) =>
|
|
20
|
+
commit(
|
|
21
|
+
[fleetRecords.list],
|
|
22
|
+
Effect.gen(function* () {
|
|
23
|
+
yield* lock;
|
|
24
|
+
yield* reservations.delete(owner);
|
|
25
|
+
}),
|
|
26
|
+
),
|
|
27
|
+
reserveForeign: (owner: string, occupancy: { readonly executing: boolean; readonly backlog: boolean } = { backlog: true, executing: true }) =>
|
|
28
|
+
commit(
|
|
29
|
+
[fleetRecords.list],
|
|
30
|
+
Effect.gen(function* () {
|
|
31
|
+
yield* lock;
|
|
32
|
+
const existing = yield* reservations.findMany({ where: { owner } });
|
|
33
|
+
if (existing.length === 0) {
|
|
34
|
+
yield* reservations.insertVoid({ owner, ...occupancy });
|
|
35
|
+
} else {
|
|
36
|
+
yield* reservations.updateVoid({ owner, ...occupancy });
|
|
37
|
+
}
|
|
38
|
+
}),
|
|
39
|
+
),
|
|
40
|
+
};
|
|
41
|
+
});
|