@knpkv/herdr-work 0.7.2 → 0.9.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/README.md +1 -1
- package/dist/model.d.ts +26 -0
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +19 -0
- package/dist/model.js.map +1 -1
- package/dist/request-decision.d.ts +70 -0
- package/dist/request-decision.d.ts.map +1 -0
- package/dist/request-decision.js +29 -0
- package/dist/request-decision.js.map +1 -0
- package/dist/service.d.ts +30 -1
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +2 -0
- package/dist/service.js.map +1 -1
- package/dist/store.d.ts +37 -1
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +71 -14
- package/dist/store.js.map +1 -1
- package/dist/view.d.ts +10 -1
- package/dist/view.d.ts.map +1 -1
- package/dist/view.js +205 -27
- package/dist/view.js.map +1 -1
- package/dist/work-triage.d.ts +15 -9
- package/dist/work-triage.d.ts.map +1 -1
- package/dist/work-triage.js +39 -11
- package/dist/work-triage.js.map +1 -1
- package/package.json +3 -3
- package/src/styles.css +35 -0
package/dist/store.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Crypto, Effect, Option, Schema } from "effect";
|
|
|
2
2
|
import { WorkAdmissionConflictError, WorkAgentBindingAuthorityError, WorkAgentBindingConflictError, WorkCheckpointConflictError, WorkCoordinatorHandoffConflictError, WorkDecisionAuthorityConflictError, WorkDecisionHandoffConflictError, WorkDecisionRevisionConflictError, WorkGoalAbandonmentConflictError, WorkGoalAgentTargetConflictError, WorkGoalBindingRequiresAgentError, WorkGoalLaneActiveError, WorkGoalOwnerMismatchError, WorkGoalReassignmentConflictError, WorkGoalRevisionConflictError, WorkGoalTerminalError, WorkLaneClaimConflictError, WorkLaneGoalConflictError, WorkLaneOperationConflictError, WorkProjectionError, WorkPullRequestLinkError, WorkStoreError, WorkTransactionConflictError } from "./errors.js";
|
|
3
3
|
import { workAgentBindingMaximumSnapshotBytes } from "./internal/agent-binding-admission.js";
|
|
4
4
|
import { WorkAdmissionTarget, WorkAgentBinding, WorkAgentBindingRequest, WorkDecisionHandoff, WorkGoalAbandoned, WorkGoalCheckpoint, WorkGoalReassigned, WorkLaneClaim, WorkLaneClaimed, WorkObservationEnvelope, WorkPullRequestLink, WorkReconcileOptions, WorkRecoveryTarget } from "./model.js";
|
|
5
|
-
import type { WorkActivity as WorkActivityType, WorkAdmissionPreflight as WorkAdmissionPreflightType, WorkAdmissionTarget as WorkAdmissionTargetType, WorkAgentBinding as WorkAgentBindingType, WorkAgentBindingRequest as WorkAgentBindingRequestType, WorkExistingGoalRecovery as WorkExistingGoalRecoveryType, WorkGoalAbandoned as WorkGoalAbandonedType, WorkGoalAbandonment as WorkGoalAbandonmentType, WorkGoalCheckpoint as WorkGoalCheckpointType, WorkGoalReassigned as WorkGoalReassignedType, WorkGoalReassignment as WorkGoalReassignmentType, WorkObservationEnvelope as WorkObservationEnvelopeType, WorkObservedAdmission as WorkObservedAdmissionType, WorkObservedFact as WorkObservedFactType, WorkObservedFailure as WorkObservedFailureType, WorkObserveReport, WorkProspectiveAdmission as WorkProspectiveAdmissionType, WorkPullRequestLink as WorkPullRequestLinkType, WorkReconcileOutcome, WorkRecoveryPreflight as WorkRecoveryPreflightType, WorkRecoveryTarget as WorkRecoveryTargetType } from "./model.js";
|
|
5
|
+
import type { WorkActivity as WorkActivityType, WorkAdmissionPreflight as WorkAdmissionPreflightType, WorkAdmissionTarget as WorkAdmissionTargetType, WorkAgentBinding as WorkAgentBindingType, WorkAgentBindingRequest as WorkAgentBindingRequestType, WorkExistingGoalRecovery as WorkExistingGoalRecoveryType, WorkGoalAbandoned as WorkGoalAbandonedType, WorkGoalAbandonment as WorkGoalAbandonmentType, WorkGoalCheckpoint as WorkGoalCheckpointType, WorkGoalReassigned as WorkGoalReassignedType, WorkGoalReassignment as WorkGoalReassignmentType, WorkObservationEnvelope as WorkObservationEnvelopeType, WorkObservedAdmission as WorkObservedAdmissionType, WorkObservedFact as WorkObservedFactType, WorkObservedFailure as WorkObservedFailureType, WorkObserveReport, WorkProspectiveAdmission as WorkProspectiveAdmissionType, WorkPullRequestLink as WorkPullRequestLinkType, WorkReconcileOutcome, WorkReconcilePlanStep, WorkRecoveryPreflight as WorkRecoveryPreflightType, WorkRecoveryTarget as WorkRecoveryTargetType } from "./model.js";
|
|
6
6
|
import { type WorkApprovedActivity } from "./observed.js";
|
|
7
7
|
type ReassignRejection = WorkGoalAgentTargetConflictError | WorkGoalBindingRequiresAgentError | WorkGoalOwnerMismatchError | WorkGoalReassignmentConflictError | WorkGoalRevisionConflictError | WorkProjectionError | WorkStoreError;
|
|
8
8
|
type AbandonRejection = WorkGoalAbandonmentConflictError | WorkGoalLaneActiveError | WorkGoalOwnerMismatchError | WorkGoalRevisionConflictError | WorkGoalTerminalError | WorkProjectionError | WorkStoreError;
|
|
@@ -44,6 +44,8 @@ export interface WorkStoreService {
|
|
|
44
44
|
* facts are ever written to goal history; everything else stays an overlay.
|
|
45
45
|
*/
|
|
46
46
|
readonly reconcile: (options: WorkReconcileOptions) => Effect.Effect<ReadonlyArray<WorkReconcileOutcome>, WorkCheckpointConflictError | WorkProjectionError | WorkStoreError>;
|
|
47
|
+
/** What `reconcile` would do now, running its checks and writing nothing. */
|
|
48
|
+
readonly planReconcile: (options: WorkReconcileOptions) => Effect.Effect<ReadonlyArray<WorkReconcilePlanStep>, WorkCheckpointConflictError | WorkProjectionError | WorkStoreError>;
|
|
47
49
|
/** Atomically reads projection history, observed facts, and the coordinator-owned logical-time boundary. */
|
|
48
50
|
readonly snapshotInput: () => Effect.Effect<{
|
|
49
51
|
readonly events: ReadonlyArray<WorkGoalCheckpointType>;
|
|
@@ -1055,6 +1057,11 @@ export declare class WorkStore implements WorkStoreService {
|
|
|
1055
1057
|
* succeeds), so a writer that planned from the head cannot bury a newer
|
|
1056
1058
|
* owner checkpoint.
|
|
1057
1059
|
*/
|
|
1060
|
+
/**
|
|
1061
|
+
* Appends one checkpoint. With `mode` `check`, every check runs in the same
|
|
1062
|
+
* transaction and it is rolled back instead of written: the checkpoint is
|
|
1063
|
+
* returned when it would have been appended.
|
|
1064
|
+
*/
|
|
1058
1065
|
private readonly appendAt;
|
|
1059
1066
|
readonly appendMany: (this: WorkStore, transactionId: string, events: readonly WorkGoalCheckpoint[]) => Effect.Effect<{
|
|
1060
1067
|
readonly version: "herdr.work.event.v1";
|
|
@@ -1326,6 +1333,11 @@ export declare class WorkStore implements WorkStoreService {
|
|
|
1326
1333
|
readonly goalId: string;
|
|
1327
1334
|
}[];
|
|
1328
1335
|
}, WorkStoreError, never>;
|
|
1336
|
+
/**
|
|
1337
|
+
* The steps `reconcile` takes, shared by `reconcile` (`write`) and
|
|
1338
|
+
* `planReconcile` (`check`, which runs every check and writes nothing).
|
|
1339
|
+
*/
|
|
1340
|
+
private readonly reconcileSteps;
|
|
1329
1341
|
readonly reconcile: (this: WorkStore, request: WorkReconcileOptions) => Effect.Effect<({
|
|
1330
1342
|
readonly _tag: "applied";
|
|
1331
1343
|
readonly goalId: string;
|
|
@@ -1339,6 +1351,30 @@ export declare class WorkStore implements WorkStoreService {
|
|
|
1339
1351
|
readonly goalId: string;
|
|
1340
1352
|
readonly eventId: string;
|
|
1341
1353
|
})[], WorkCheckpointConflictError | WorkProjectionError | WorkStoreError, never>;
|
|
1354
|
+
/**
|
|
1355
|
+
* What `reconcile` would do now with the same confirmations, writing
|
|
1356
|
+
* nothing: every check it makes before writing runs, each in a transaction
|
|
1357
|
+
* that is rolled back at once, with each step checked against the
|
|
1358
|
+
* checkpoints earlier steps planned.
|
|
1359
|
+
*/
|
|
1360
|
+
readonly planReconcile: (this: WorkStore, request: WorkReconcileOptions) => Effect.Effect<({
|
|
1361
|
+
readonly _tag: "conflict";
|
|
1362
|
+
readonly goalId: string;
|
|
1363
|
+
readonly reason: "checkpoint" | "revision";
|
|
1364
|
+
} | {
|
|
1365
|
+
readonly _tag: "recorded";
|
|
1366
|
+
readonly goalId: string;
|
|
1367
|
+
readonly eventId: string;
|
|
1368
|
+
} | {
|
|
1369
|
+
readonly _tag: "would_apply";
|
|
1370
|
+
readonly goalId: string;
|
|
1371
|
+
readonly eventId: string;
|
|
1372
|
+
readonly state: "abandoned" | "completed";
|
|
1373
|
+
readonly subject: string;
|
|
1374
|
+
readonly observationId: string & import("effect/Brand").Brand<"WorkObservationId">;
|
|
1375
|
+
readonly goalEventId: string;
|
|
1376
|
+
readonly goalUpdatedAt: number;
|
|
1377
|
+
})[], WorkCheckpointConflictError | WorkProjectionError | WorkStoreError, never>;
|
|
1342
1378
|
readonly observe: (this: WorkStore, envelopes: readonly WorkObservationEnvelope[]) => Effect.Effect<WorkObserveReport, WorkStoreError, never>;
|
|
1343
1379
|
private secureFiles;
|
|
1344
1380
|
close(): void;
|
package/dist/store.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAOA,OAAO,EAAS,MAAM,EAAE,MAAM,EAAS,MAAM,EAAU,MAAM,EAAE,MAAM,QAAQ,CAAA;AAI7E,OAAO,EACL,0BAA0B,EAC1B,8BAA8B,EAC9B,6BAA6B,EAC7B,2BAA2B,EAC3B,mCAAmC,EACnC,kCAAkC,EAClC,gCAAgC,EAChC,iCAAiC,EACjC,gCAAgC,EAChC,gCAAgC,EAChC,iCAAiC,EACjC,uBAAuB,EACvB,0BAA0B,EAC1B,iCAAiC,EACjC,6BAA6B,EAC7B,qBAAqB,EACrB,0BAA0B,EAC1B,yBAAyB,EACzB,8BAA8B,EAC9B,mBAAmB,EACnB,wBAAwB,EACxB,cAAc,EACd,4BAA4B,EAC7B,MAAM,aAAa,CAAA;AAEpB,OAAO,EAIL,oCAAoC,EAGrC,MAAM,uCAAuC,CAAA;
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
package/dist/store.js
CHANGED
|
@@ -2053,7 +2053,7 @@ export class WorkStore {
|
|
|
2053
2053
|
{
|
|
2054
2054
|
id: jobId,
|
|
2055
2055
|
kind: "status",
|
|
2056
|
-
summary: workReassignActivitySummary(decoded
|
|
2056
|
+
summary: workReassignActivitySummary(decoded),
|
|
2057
2057
|
occurredAt: at
|
|
2058
2058
|
}
|
|
2059
2059
|
],
|
|
@@ -2284,7 +2284,7 @@ export class WorkStore {
|
|
|
2284
2284
|
{
|
|
2285
2285
|
id: jobId,
|
|
2286
2286
|
kind: "status",
|
|
2287
|
-
summary: workAbandonActivitySummary(decoded
|
|
2287
|
+
summary: workAbandonActivitySummary(decoded),
|
|
2288
2288
|
occurredAt: at
|
|
2289
2289
|
}
|
|
2290
2290
|
],
|
|
@@ -2812,7 +2812,15 @@ export class WorkStore {
|
|
|
2812
2812
|
* succeeds), so a writer that planned from the head cannot bury a newer
|
|
2813
2813
|
* owner checkpoint.
|
|
2814
2814
|
*/
|
|
2815
|
-
|
|
2815
|
+
/**
|
|
2816
|
+
* Appends one checkpoint. With `mode` `check`, every check runs in the same
|
|
2817
|
+
* transaction and it is rolled back instead of written: the checkpoint is
|
|
2818
|
+
* returned when it would have been appended.
|
|
2819
|
+
*/
|
|
2820
|
+
appendAt = Effect.fn("WorkStore.append")(function* (event, guard, mode = "write",
|
|
2821
|
+
// In a check, the checkpoints earlier steps of the same plan would have
|
|
2822
|
+
// written: limits are checked as if they were already stored.
|
|
2823
|
+
planned = []) {
|
|
2816
2824
|
const decoded = yield* Schema.decodeUnknownEffect(WorkGoalCheckpoint)(event).pipe(Effect.mapError(storeError("append.decode")));
|
|
2817
2825
|
// The reconciler's event and activity ids are its provenance; no other
|
|
2818
2826
|
// writer may use them.
|
|
@@ -2827,11 +2835,12 @@ export class WorkStore {
|
|
|
2827
2835
|
const decision = yield* Effect.try({
|
|
2828
2836
|
try: () => {
|
|
2829
2837
|
let transaction = false;
|
|
2838
|
+
const abort = () => this.#database.exec("ROLLBACK");
|
|
2830
2839
|
try {
|
|
2831
2840
|
this.#database.exec("BEGIN IMMEDIATE");
|
|
2832
2841
|
transaction = true;
|
|
2833
2842
|
const reject = (error) => {
|
|
2834
|
-
|
|
2843
|
+
abort();
|
|
2835
2844
|
transaction = false;
|
|
2836
2845
|
return { _tag: "rejected", error };
|
|
2837
2846
|
};
|
|
@@ -2840,7 +2849,7 @@ export class WorkStore {
|
|
|
2840
2849
|
WHERE event_id = ? OR (goal_id = ? AND occurred_at = ?)`)
|
|
2841
2850
|
.all(decoded.eventId, decoded.goal.id, decoded.occurredAt)).map(({ record }) => Schema.decodeUnknownSync(WorkGoalCheckpoint)(JSON.parse(record)));
|
|
2842
2851
|
if (collisions.length > 0 && collisions.every((existing) => Equal.equals(existing, decoded))) {
|
|
2843
|
-
|
|
2852
|
+
abort();
|
|
2844
2853
|
transaction = false;
|
|
2845
2854
|
return { _tag: "replayed", event: decoded };
|
|
2846
2855
|
}
|
|
@@ -2868,7 +2877,7 @@ export class WorkStore {
|
|
|
2868
2877
|
}));
|
|
2869
2878
|
}
|
|
2870
2879
|
const count = Schema.decodeUnknownSync(CountRow)(this.#database.prepare("SELECT COUNT(*) AS count FROM work_goal_events").get()).count;
|
|
2871
|
-
if (count + 1 > workHistoryMaxEvents - guard.reserve) {
|
|
2880
|
+
if (count + planned.length + 1 > workHistoryMaxEvents - guard.reserve) {
|
|
2872
2881
|
return reject(new WorkProjectionError({
|
|
2873
2882
|
cause: count,
|
|
2874
2883
|
detail: `the reconciler leaves ${guard.reserve} of ${workHistoryMaxEvents} checkpoints free`,
|
|
@@ -2884,14 +2893,15 @@ export class WorkStore {
|
|
|
2884
2893
|
}));
|
|
2885
2894
|
}
|
|
2886
2895
|
const eventCount = Schema.decodeUnknownSync(CountRow)(this.#database.prepare("SELECT COUNT(*) AS count FROM work_goal_events").get()).count;
|
|
2887
|
-
if (eventCount >= workHistoryMaxEvents) {
|
|
2896
|
+
if (eventCount + planned.length >= workHistoryMaxEvents) {
|
|
2888
2897
|
return reject(new WorkProjectionError({
|
|
2889
2898
|
cause: decoded,
|
|
2890
2899
|
detail: `work history cannot exceed ${workHistoryMaxEvents} checkpoints`,
|
|
2891
2900
|
reason: "capacity_exceeded"
|
|
2892
2901
|
}));
|
|
2893
2902
|
}
|
|
2894
|
-
const history = Schema.decodeUnknownSync(StoredEventRows)(this.#database.prepare("SELECT record FROM work_goal_events").all()).map(({ record }) => Schema.decodeUnknownSync(WorkGoalCheckpoint)(JSON.parse(record)))
|
|
2903
|
+
const history = Schema.decodeUnknownSync(StoredEventRows)(this.#database.prepare("SELECT record FROM work_goal_events").all()).map(({ record }) => Schema.decodeUnknownSync(WorkGoalCheckpoint)(JSON.parse(record)))
|
|
2904
|
+
.concat(planned);
|
|
2895
2905
|
const familyError = validateGoalFamilyHistory([...history, decoded]);
|
|
2896
2906
|
if (familyError !== undefined)
|
|
2897
2907
|
return reject(familyError);
|
|
@@ -2930,6 +2940,11 @@ export class WorkStore {
|
|
|
2930
2940
|
}));
|
|
2931
2941
|
}
|
|
2932
2942
|
}
|
|
2943
|
+
if (mode === "check") {
|
|
2944
|
+
abort();
|
|
2945
|
+
transaction = false;
|
|
2946
|
+
return { _tag: "checked" };
|
|
2947
|
+
}
|
|
2933
2948
|
const result = this.#database.prepare("INSERT INTO work_goal_events (event_id, goal_id, occurred_at, record) VALUES (?, ?, ?, ?)").run(decoded.eventId, decoded.goal.id, decoded.occurredAt, JSON.stringify(decoded));
|
|
2934
2949
|
// The reconciler's own record of what it wrote: its authorship and its
|
|
2935
2950
|
// once-per-goal rule come from this table, never from an id's spelling.
|
|
@@ -2942,7 +2957,7 @@ export class WorkStore {
|
|
|
2942
2957
|
}
|
|
2943
2958
|
catch (error) {
|
|
2944
2959
|
if (transaction)
|
|
2945
|
-
|
|
2960
|
+
abort();
|
|
2946
2961
|
throw error;
|
|
2947
2962
|
}
|
|
2948
2963
|
},
|
|
@@ -2952,6 +2967,8 @@ export class WorkStore {
|
|
|
2952
2967
|
return yield* decision.error;
|
|
2953
2968
|
if (decision._tag === "replayed")
|
|
2954
2969
|
return decision.event;
|
|
2970
|
+
if (decision._tag === "checked")
|
|
2971
|
+
return decoded;
|
|
2955
2972
|
if (decision.changes !== 1 && decision.changes !== 1n) {
|
|
2956
2973
|
return yield* storeError("append.insert.count")(decision.changes);
|
|
2957
2974
|
}
|
|
@@ -4041,7 +4058,11 @@ export class WorkStore {
|
|
|
4041
4058
|
reconcilerEvents
|
|
4042
4059
|
};
|
|
4043
4060
|
});
|
|
4044
|
-
|
|
4061
|
+
/**
|
|
4062
|
+
* The steps `reconcile` takes, shared by `reconcile` (`write`) and
|
|
4063
|
+
* `planReconcile` (`check`, which runs every check and writes nothing).
|
|
4064
|
+
*/
|
|
4065
|
+
reconcileSteps = Effect.fn("WorkStore.reconcileSteps")(function* (request, mode) {
|
|
4045
4066
|
const options = yield* Schema.decodeUnknownEffect(WorkReconcileOptions)(request).pipe(Effect.mapError(storeError("reconcile.options")));
|
|
4046
4067
|
const source = yield* this.snapshotInput();
|
|
4047
4068
|
if (workHistoryMaxEvents - source.events.length < workReconcilerHeadroom) {
|
|
@@ -4063,7 +4084,13 @@ export class WorkStore {
|
|
|
4063
4084
|
const stamped = new Map(source.reconcilerEvents.map(({ eventId, goalId }) => [goalId, eventId]));
|
|
4064
4085
|
const cryptoService = this.#cryptoService;
|
|
4065
4086
|
const now = yield* Clock.currentTimeMillis;
|
|
4066
|
-
|
|
4087
|
+
// A plan holds no transaction between steps: each check rolls back at once,
|
|
4088
|
+
// and later steps are checked against the checkpoints earlier ones planned.
|
|
4089
|
+
const planned = [];
|
|
4090
|
+
const appendAt = (checkpoint, guard) => this.appendAt(checkpoint, guard, mode, planned).pipe(Effect.tap(() => Effect.sync(() => {
|
|
4091
|
+
if (mode === "check")
|
|
4092
|
+
planned.push(checkpoint);
|
|
4093
|
+
})));
|
|
4067
4094
|
return yield* Effect.forEach(terminalCandidates(source.events, source.facts, source.failures, new Set(options.confirmed.map(({ observationId, subject }) => `${subject}\u0000${observationId}`))), Effect.fnUntraced(function* (candidate) {
|
|
4068
4095
|
const goalId = candidate.head.goal.id;
|
|
4069
4096
|
const previous = stamped.get(goalId);
|
|
@@ -4076,7 +4103,7 @@ export class WorkStore {
|
|
|
4076
4103
|
// holds the reconciler's id, a timestamp past the bound) is left for
|
|
4077
4104
|
// its owner: reported as a conflict, never failing the other goals.
|
|
4078
4105
|
if (Result.isFailure(checkpoint))
|
|
4079
|
-
return { _tag: "conflict", goalId };
|
|
4106
|
+
return { _tag: "conflict", goalId, reason: "checkpoint" };
|
|
4080
4107
|
return yield* appendAt(checkpoint.success, {
|
|
4081
4108
|
fact: { observationId: candidate.fact.observationId, subject: candidate.fact.subject },
|
|
4082
4109
|
head: candidate.head,
|
|
@@ -4085,10 +4112,40 @@ export class WorkStore {
|
|
|
4085
4112
|
_tag: "applied",
|
|
4086
4113
|
eventId,
|
|
4087
4114
|
goalId,
|
|
4088
|
-
state: candidate.pullRequest.state === "merged" ? "completed" : "abandoned"
|
|
4089
|
-
|
|
4115
|
+
state: candidate.pullRequest.state === "merged" ? "completed" : "abandoned",
|
|
4116
|
+
candidate
|
|
4117
|
+
}), Effect.catchTag("WorkGoalRevisionConflictError", () => Effect.succeed({ _tag: "conflict", goalId, reason: "revision" })));
|
|
4090
4118
|
}));
|
|
4091
4119
|
});
|
|
4120
|
+
reconcile = Effect.fn("WorkStore.reconcile")(function* (request) {
|
|
4121
|
+
const steps = yield* this.reconcileSteps(request, "write");
|
|
4122
|
+
return steps.map((step) => step._tag === "applied"
|
|
4123
|
+
? { _tag: "applied", eventId: step.eventId, goalId: step.goalId, state: step.state }
|
|
4124
|
+
: step._tag === "recorded"
|
|
4125
|
+
? step
|
|
4126
|
+
: { _tag: "conflict", goalId: step.goalId });
|
|
4127
|
+
});
|
|
4128
|
+
/**
|
|
4129
|
+
* What `reconcile` would do now with the same confirmations, writing
|
|
4130
|
+
* nothing: every check it makes before writing runs, each in a transaction
|
|
4131
|
+
* that is rolled back at once, with each step checked against the
|
|
4132
|
+
* checkpoints earlier steps planned.
|
|
4133
|
+
*/
|
|
4134
|
+
planReconcile = Effect.fn("WorkStore.planReconcile")(function* (request) {
|
|
4135
|
+
const steps = yield* this.reconcileSteps(request, "check");
|
|
4136
|
+
return steps.map((step) => step._tag === "applied"
|
|
4137
|
+
? {
|
|
4138
|
+
_tag: "would_apply",
|
|
4139
|
+
eventId: step.eventId,
|
|
4140
|
+
goalId: step.goalId,
|
|
4141
|
+
state: step.state,
|
|
4142
|
+
subject: step.candidate.fact.subject,
|
|
4143
|
+
observationId: step.candidate.fact.observationId,
|
|
4144
|
+
goalEventId: step.candidate.head.eventId,
|
|
4145
|
+
goalUpdatedAt: step.candidate.head.goal.updatedAt
|
|
4146
|
+
}
|
|
4147
|
+
: step);
|
|
4148
|
+
});
|
|
4092
4149
|
observe = Effect.fn("WorkStore.observe")(function* (envelopes) {
|
|
4093
4150
|
const decoded = yield* Schema.decodeUnknownEffect(Schema.Array(WorkObservationEnvelope).check(Schema.isMaxLength(workObservedFactMaxRecords)))(envelopes).pipe(Effect.mapError(storeError("observe.decode")));
|
|
4094
4151
|
const cryptoService = this.#cryptoService;
|