@knpkv/herdr-work 0.5.3 → 0.6.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.
Files changed (55) hide show
  1. package/README.md +86 -0
  2. package/dist/display-state.d.ts +10 -0
  3. package/dist/display-state.d.ts.map +1 -0
  4. package/dist/display-state.js +5 -0
  5. package/dist/display-state.js.map +1 -0
  6. package/dist/errors.d.ts +21 -0
  7. package/dist/errors.d.ts.map +1 -1
  8. package/dist/errors.js +12 -0
  9. package/dist/errors.js.map +1 -1
  10. package/dist/index.d.ts +1 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +1 -0
  13. package/dist/index.js.map +1 -1
  14. package/dist/internal/legacy-lane-claim.d.ts +74 -0
  15. package/dist/internal/legacy-lane-claim.d.ts.map +1 -0
  16. package/dist/internal/legacy-lane-claim.js +81 -0
  17. package/dist/internal/legacy-lane-claim.js.map +1 -0
  18. package/dist/internal/session-index.d.ts +18 -0
  19. package/dist/internal/session-index.d.ts.map +1 -0
  20. package/dist/internal/session-index.js +23 -0
  21. package/dist/internal/session-index.js.map +1 -0
  22. package/dist/internal/terminal-reconcile.d.ts +29 -0
  23. package/dist/internal/terminal-reconcile.d.ts.map +1 -0
  24. package/dist/internal/terminal-reconcile.js +79 -0
  25. package/dist/internal/terminal-reconcile.js.map +1 -0
  26. package/dist/model.d.ts +909 -29
  27. package/dist/model.d.ts.map +1 -1
  28. package/dist/model.js +236 -7
  29. package/dist/model.js.map +1 -1
  30. package/dist/observed.d.ts +77 -0
  31. package/dist/observed.d.ts.map +1 -0
  32. package/dist/observed.js +240 -0
  33. package/dist/observed.js.map +1 -0
  34. package/dist/projection.d.ts +192 -12
  35. package/dist/projection.d.ts.map +1 -1
  36. package/dist/service.d.ts +121 -992
  37. package/dist/service.d.ts.map +1 -1
  38. package/dist/service.js +13 -3
  39. package/dist/service.js.map +1 -1
  40. package/dist/sql.d.ts.map +1 -1
  41. package/dist/sql.js +76 -3
  42. package/dist/sql.js.map +1 -1
  43. package/dist/store.d.ts +193 -11
  44. package/dist/store.d.ts.map +1 -1
  45. package/dist/store.js +687 -37
  46. package/dist/store.js.map +1 -1
  47. package/dist/view.d.ts.map +1 -1
  48. package/dist/view.js +169 -103
  49. package/dist/view.js.map +1 -1
  50. package/dist/work-triage.d.ts +72 -0
  51. package/dist/work-triage.d.ts.map +1 -0
  52. package/dist/work-triage.js +114 -0
  53. package/dist/work-triage.js.map +1 -0
  54. package/package.json +3 -3
  55. package/src/styles.css +229 -237
package/README.md CHANGED
@@ -12,6 +12,92 @@ The store preserves safe caller-owned state-directory modes, but rejects
12
12
  group- or world-writable POSIX directories and substituted database paths before
13
13
  opening the authority database.
14
14
 
15
+ `observe` stores observed facts for the Work tab: a pull request's state, head,
16
+ review and checks as GitHub reported them, or an agent's Herdr status. One
17
+ latest fact is kept per subject (`github:<repo>#<n>`, `herdr:<host>/<agentId>`).
18
+ The same facts again keep their first-seen time (`observedAt`) and move their
19
+ last confirmation (`confirmedAt`); facts older than the last confirmation are
20
+ skipped, and so are facts stamped more than five minutes ahead of the store's
21
+ clock, which would otherwise outrank every real reading; a fact stamped less
22
+ than that ahead counts as read now. An `unknown` observation (a source that could not be read) never
23
+ replaces a fact: it starts or continues the subject's run of failures, whose
24
+ `since` stays at the first failure until a good read newer than every failure
25
+ ends it (a delayed good read inside the run restarts it at its latest failure). Hostd names the
26
+ failed subject the same way as its facts (`pullRequestSubject`, `agentSubject`). Facts are not goal
27
+ history: they never write a checkpoint, never count against the history bound,
28
+ and are not part of any approval token, so observing cannot invalidate a pending
29
+ approval. Facts and failures each have their own bounds (4,096 rows, 2 MiB); beyond them
30
+ the rows read least recently go first. Pull request subjects lowercase the repository, since GitHub names are
31
+ case-insensitive. `snapshots` merges the facts into the `now` window, for each
32
+ goal something was observed about, as
33
+ `observed` entries: the matching facts, the oldest current failure among the
34
+ goal's own subjects as `unknown` (with `lastGoodAt`, the last confirmation of
35
+ that subject's facts), and a derived `displayState` (a recorded
36
+ terminal state, then a merged or closed pull request, then the owner's blocker,
37
+ then the agent's working or blocked status, then an open pull request as
38
+ `review`, then the goal's own state) and a `stale` flag for an owner whose agent
39
+ has been gone for more than 24 hours on unfinished work. Entries are kept, most
40
+ recently updated goals first, while the encoded snapshots fit the 1 MiB response
41
+ budget; any left out are counted in `observedOmitted`. `observed` is always
42
+ present, empty when nothing was observed; when not even that fits, the `now`
43
+ window carries no overlay keys, which means live state is not available. The overlay keeps only the latest
44
+ facts per subject, not their history, so a snapshot taken at an explicit time
45
+ shows a subject's current facts only if they were first seen by then (with
46
+ their latest confirmation if it was made by then, else their first sighting),
47
+ and a failure only if its latest failed read was by then. Facts that were
48
+ replaced later are not shown at all. Failure subjects are spelled the same way
49
+ as fact subjects; a failure that names another source's subject is rejected.
50
+ Earlier windows stay as recorded. A goal's agent is its agent hierarchy, or its
51
+ connect target on older goals; host and repository letter case never makes a
52
+ new fact.
53
+
54
+ `reconcile` turns the one kind of observed fact that is final into goal
55
+ history: a goal whose pull request is observed merged becomes `completed`
56
+ (delivery `merged`), and one closed without merging becomes `abandoned`. The
57
+ checkpoint is stamped with the pull request's close time, never later than the
58
+ store's clock and one millisecond after the goal's latest checkpoint when an
59
+ owner wrote later. It is written only if, inside the write's transaction, the
60
+ goal's latest checkpoint and the pull request's fact are still the ones it was
61
+ planned from (otherwise that goal is reported as a conflict), and 256
62
+ checkpoints of history stay free. A goal is stamped at most once, by the
63
+ reconciler's own record of what it wrote, so a goal its owner reopens stays
64
+ reopened. The checkpoint adds a `reconciler.` activity unless the goal's
65
+ activity list is full; owner activity is never dropped to make room.
66
+ `abandon` applies an approved `work.abandon` job. The goal, owned by exactly the
67
+ approved owner and still at the approved head, becomes `abandoned`: its blocker
68
+ is cleared, and a status activity naming the job is added, credited to the
69
+ approval, unless the goal's activity list is full; owner activity is never
70
+ dropped to make room. A goal with an active (not shipped) lane is refused with
71
+ `WorkGoalLaneActiveError`, which names the lane, so abandoning never releases
72
+ anyone's lane. A goal that has already finished is refused with
73
+ `WorkGoalTerminalError`. An exact replay of the job returns the stored result.
74
+ `isTerminalWorkState`
75
+ names the finished states: `completed`, `deployed` and `abandoned`.
76
+
77
+ `admitObserved` admits a worker the reconciler observed, without an approval.
78
+ It makes the same goal, lane and binding write as `admitExistingOwner`, checked
79
+ against the same absence token inside the transaction, but records
80
+ `observedAdmission` (actor `reconciler`, the observation id) on the binding
81
+ instead of `prospectiveAdmission`. The caller (hostd) checks what the store
82
+ can't see: the pane is on this host with agent lineage, and its worktree is the
83
+ canonical toplevel on the PR branch at the PR head, with an origin equal to the
84
+ PR's repository. An exact replay of the same observation returns the stored link;
85
+ another observation, or an approved job, over the same binding is a conflict.
86
+ Its admission activity is credited to the reconciler, and the goal can still take
87
+ its terminal checkpoint when its pull request merges or closes.
88
+
89
+ The `now` window also says who wrote each activity that is not the owner's:
90
+ `activityProvenance` lists reconciler and approved-job activities (with the
91
+ job id). An activity is credited only when the checkpoint that started its
92
+ current unchanged run is the writer's own: an approved operation's checkpoint
93
+ (whose event id is the activity id), one in the reconciler's record, or an
94
+ observed admission's checkpoint. A later
95
+ owner rewrite or re-creation is the owner's. Authorship never comes from an id's
96
+ spelling, and `activityProvenanceGoals` lists the goals whose such activities
97
+ are all present. In a covered goal an unlisted activity is the owner's; a goal
98
+ left out to stay within the response budget is counted in
99
+ `activityProvenanceOmitted` and its provenance is unknown.
100
+
15
101
  `WorkStore.appendMany` validates a whole checkpoint batch before one SQLite
16
102
  transaction. Reusing its transaction ID with the same batch replays it. A
17
103
  changed event with an existing event ID or goal/timestamp returns
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Browser-safe reads of a snapshot's observed overlay, for the Work tab. Imports
3
+ * types only, so a view can use them without pulling in the store or Fleet.
4
+ */
5
+ import type { WorkDisplayState, WorkGoal, WorkGoalObserved, WorkSnapshot } from "./model.js";
6
+ /** The overlay entry for one goal, or null when nothing was observed about it (or the overlay is absent). */
7
+ export declare const observedFor: (snapshot: Pick<WorkSnapshot, "observed">, goalId: string) => WorkGoalObserved | null;
8
+ /** What the tab shows for a goal: the overlay's display state when there is one, otherwise the goal's own state. */
9
+ export declare const displayStateOf: (snapshot: Pick<WorkSnapshot, "observed">, goal: WorkGoal) => WorkDisplayState;
10
+ //# sourceMappingURL=display-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display-state.d.ts","sourceRoot":"","sources":["../src/display-state.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE5F,6GAA6G;AAC7G,eAAO,MAAM,WAAW,aAAc,IAAI,CAAC,YAAY,EAAE,UAAU,CAAC,UAAU,MAAM,KAAG,gBAAgB,GAAG,IACrC,CAAA;AAErE,oHAAoH;AACpH,eAAO,MAAM,cAAc,aAAc,IAAI,CAAC,YAAY,EAAE,UAAU,CAAC,QAAQ,QAAQ,KAAG,gBAC9B,CAAA"}
@@ -0,0 +1,5 @@
1
+ /** The overlay entry for one goal, or null when nothing was observed about it (or the overlay is absent). */
2
+ export const observedFor = (snapshot, goalId) => snapshot.observed?.find((entry) => entry.goalId === goalId) ?? null;
3
+ /** What the tab shows for a goal: the overlay's display state when there is one, otherwise the goal's own state. */
4
+ export const displayStateOf = (snapshot, goal) => observedFor(snapshot, goal.id)?.displayState ?? goal.state;
5
+ //# sourceMappingURL=display-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display-state.js","sourceRoot":"","sources":["../src/display-state.ts"],"names":[],"mappings":"AAMA,6GAA6G;AAC7G,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,QAAwC,EAAE,MAAc,EAA2B,EAAE,CAC/G,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,IAAI,IAAI,CAAA;AAErE,oHAAoH;AACpH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,QAAwC,EAAE,IAAc,EAAoB,EAAE,CAC3G,WAAW,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,YAAY,IAAI,IAAI,CAAC,KAAK,CAAA"}
package/dist/errors.d.ts CHANGED
@@ -137,6 +137,27 @@ declare const WorkGoalReassignmentConflictError_base: Schema.Class<WorkGoalReass
137
137
  /** The approval job id already names a different reassignment or another durable record. */
138
138
  export declare class WorkGoalReassignmentConflictError extends WorkGoalReassignmentConflictError_base {
139
139
  }
140
+ declare const WorkGoalAbandonmentConflictError_base: Schema.Class<WorkGoalAbandonmentConflictError, Schema.TaggedStruct<"WorkGoalAbandonmentConflictError", {
141
+ readonly approvalJobId: Schema.String;
142
+ readonly reason: Schema.Literals<readonly ["payload_mismatch", "identifier_in_use"]>;
143
+ }>, import("effect/Cause").YieldableError>;
144
+ /** An abandonment job id was already used: by a different abandonment, or by another durable Work record. */
145
+ export declare class WorkGoalAbandonmentConflictError extends WorkGoalAbandonmentConflictError_base {
146
+ }
147
+ declare const WorkGoalLaneActiveError_base: Schema.Class<WorkGoalLaneActiveError, Schema.TaggedStruct<"WorkGoalLaneActiveError", {
148
+ readonly goalId: Schema.String;
149
+ readonly laneId: Schema.String;
150
+ }>, import("effect/Cause").YieldableError>;
151
+ /** The goal still holds an active (not shipped) lane; abandoning it never releases the lane. */
152
+ export declare class WorkGoalLaneActiveError extends WorkGoalLaneActiveError_base {
153
+ }
154
+ declare const WorkGoalTerminalError_base: Schema.Class<WorkGoalTerminalError, Schema.TaggedStruct<"WorkGoalTerminalError", {
155
+ readonly goalId: Schema.String;
156
+ readonly state: Schema.String;
157
+ }>, import("effect/Cause").YieldableError>;
158
+ /** The goal is already finished (`completed`, `deployed` or `abandoned`). */
159
+ export declare class WorkGoalTerminalError extends WorkGoalTerminalError_base {
160
+ }
140
161
  declare const WorkGoalBindingRequiresAgentError_base: Schema.Class<WorkGoalBindingRequiresAgentError, Schema.TaggedStruct<"WorkGoalBindingRequiresAgentError", {
141
162
  readonly goalId: Schema.String;
142
163
  readonly laneId: Schema.String;
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;;;;;AAE/B,qBAAa,wBAAyB,SAAQ,6BAM7C;CAAG;;;;;;AAEJ,qBAAa,mBAAoB,SAAQ,wBAaxC;CAAG;;;;;AAEJ,qBAAa,cAAe,SAAQ,mBAGnC;CAAG;;;;;;AAEJ,qBAAa,2BAA4B,SAAQ,gCAOhD;CAAG;;;;AAEJ,qBAAa,4BAA6B,SAAQ,iCAGjD;CAAG;;;;;;AAEJ,qBAAa,0BAA2B,SAAQ,+BAO/C;CAAG;;;;AAEJ,qBAAa,8BAA+B,SAAQ,mCAGnD;CAAG;;;;;;AAEJ,qBAAa,yBAA0B,SAAQ,8BAG9C;CAAG;;;;AAEJ,qBAAa,gCAAiC,SAAQ,qCAGrD;CAAG;;;;;AAEJ,qBAAa,kCAAmC,SAAQ,uCAGvD;CAAG;;;;;;AAEJ,qBAAa,iCAAkC,SAAQ,sCAGtD;CAAG;;;;AAEJ,qBAAa,mCAAoC,SAAQ,wCAGxD;CAAG;;;;;AAEJ,qBAAa,gCAAiC,SAAQ,qCAGrD;CAAG;;;;AAEJ,qBAAa,6BAA8B,SAAQ,kCAGlD;CAAG;;;;;;;AAEJ,qBAAa,8BAA+B,SAAQ,mCAQnD;CAAG;;;;;;AAEJ,qBAAa,wBAAyB,SAAQ,6BAoB7C;CAAG;;;;;;AAEJ,qBAAa,0BAA2B,SAAQ,+BAG/C;CAAG;;;;;;;;;;;;;AAEJ,oGAAoG;AACpG,qBAAa,0BAA2B,SAAQ,+BAQ/C;CAAG;;;;;;;;AAEJ,6GAA6G;AAC7G,qBAAa,6BAA8B,SAAQ,kCASlD;CAAG;;;;;AAEJ,4FAA4F;AAC5F,qBAAa,iCAAkC,SAAQ,sCAMtD;CAAG;;;;;;AAEJ,qHAAqH;AACrH,qBAAa,iCAAkC,SAAQ,sCAGtD;CAAG;;;;;;;AAEJ;;;;;;GAMG;AACH,qBAAa,gCAAiC,SAAQ,qCAQrD;CAAG"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;;;;;AAE/B,qBAAa,wBAAyB,SAAQ,6BAM7C;CAAG;;;;;;AAEJ,qBAAa,mBAAoB,SAAQ,wBAaxC;CAAG;;;;;AAEJ,qBAAa,cAAe,SAAQ,mBAGnC;CAAG;;;;;;AAEJ,qBAAa,2BAA4B,SAAQ,gCAOhD;CAAG;;;;AAEJ,qBAAa,4BAA6B,SAAQ,iCAGjD;CAAG;;;;;;AAEJ,qBAAa,0BAA2B,SAAQ,+BAO/C;CAAG;;;;AAEJ,qBAAa,8BAA+B,SAAQ,mCAGnD;CAAG;;;;;;AAEJ,qBAAa,yBAA0B,SAAQ,8BAG9C;CAAG;;;;AAEJ,qBAAa,gCAAiC,SAAQ,qCAGrD;CAAG;;;;;AAEJ,qBAAa,kCAAmC,SAAQ,uCAGvD;CAAG;;;;;;AAEJ,qBAAa,iCAAkC,SAAQ,sCAGtD;CAAG;;;;AAEJ,qBAAa,mCAAoC,SAAQ,wCAGxD;CAAG;;;;;AAEJ,qBAAa,gCAAiC,SAAQ,qCAGrD;CAAG;;;;AAEJ,qBAAa,6BAA8B,SAAQ,kCAGlD;CAAG;;;;;;;AAEJ,qBAAa,8BAA+B,SAAQ,mCAQnD;CAAG;;;;;;AAEJ,qBAAa,wBAAyB,SAAQ,6BAoB7C;CAAG;;;;;;AAEJ,qBAAa,0BAA2B,SAAQ,+BAG/C;CAAG;;;;;;;;;;;;;AAEJ,oGAAoG;AACpG,qBAAa,0BAA2B,SAAQ,+BAQ/C;CAAG;;;;;;;;AAEJ,6GAA6G;AAC7G,qBAAa,6BAA8B,SAAQ,kCASlD;CAAG;;;;;AAEJ,4FAA4F;AAC5F,qBAAa,iCAAkC,SAAQ,sCAMtD;CAAG;;;;;AAEJ,6GAA6G;AAC7G,qBAAa,gCAAiC,SAAQ,qCAMrD;CAAG;;;;;AAEJ,gGAAgG;AAChG,qBAAa,uBAAwB,SAAQ,4BAG5C;CAAG;;;;;AAEJ,6EAA6E;AAC7E,qBAAa,qBAAsB,SAAQ,0BAG1C;CAAG;;;;;;AAEJ,qHAAqH;AACrH,qBAAa,iCAAkC,SAAQ,sCAGtD;CAAG;;;;;;;AAEJ;;;;;;GAMG;AACH,qBAAa,gCAAiC,SAAQ,qCAQrD;CAAG"}
package/dist/errors.js CHANGED
@@ -99,6 +99,18 @@ export class WorkGoalReassignmentConflictError extends Schema.TaggedError()("Wor
99
99
  reason: Schema.Literals(["payload_mismatch", "identifier_in_use"])
100
100
  }) {
101
101
  }
102
+ /** An abandonment job id was already used: by a different abandonment, or by another durable Work record. */
103
+ export class WorkGoalAbandonmentConflictError extends Schema.TaggedError()("WorkGoalAbandonmentConflictError", {
104
+ approvalJobId: Schema.String,
105
+ reason: Schema.Literals(["payload_mismatch", "identifier_in_use"])
106
+ }) {
107
+ }
108
+ /** The goal still holds an active (not shipped) lane; abandoning it never releases the lane. */
109
+ export class WorkGoalLaneActiveError extends Schema.TaggedError()("WorkGoalLaneActiveError", { goalId: Schema.String, laneId: Schema.String }) {
110
+ }
111
+ /** The goal is already finished (`completed`, `deployed` or `abandoned`). */
112
+ export class WorkGoalTerminalError extends Schema.TaggedError()("WorkGoalTerminalError", { goalId: Schema.String, state: Schema.String }) {
113
+ }
102
114
  /** The goal's active lane has a started-worker binding, so a reassignment must name the agent that takes it over. */
103
115
  export class WorkGoalBindingRequiresAgentError extends Schema.TaggedError()("WorkGoalBindingRequiresAgentError", { goalId: Schema.String, laneId: Schema.String, dispatchRequestId: Schema.String }) {
104
116
  }
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export * from "./agent-binding.js";
2
2
  export * from "./errors.js";
3
3
  export * from "./model.js";
4
4
  export * from "./navigation.js";
5
+ export * from "./observed.js";
5
6
  export * from "./projection.js";
6
7
  export * from "./service.js";
7
8
  export * from "./sql.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAA;AAClC,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,cAAc,CAAA;AAC5B,cAAc,UAAU,CAAA;AACxB,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAC7D,cAAc,WAAW,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAA;AAClC,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,cAAc,CAAA;AAC5B,cAAc,UAAU,CAAA;AACxB,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAC7D,cAAc,WAAW,CAAA"}
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@ export * from "./agent-binding.js";
2
2
  export * from "./errors.js";
3
3
  export * from "./model.js";
4
4
  export * from "./navigation.js";
5
+ export * from "./observed.js";
5
6
  export * from "./projection.js";
6
7
  export * from "./service.js";
7
8
  export * from "./sql.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAA;AAClC,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,cAAc,CAAA;AAC5B,cAAc,UAAU,CAAA;AACxB,OAAO,EAAE,SAAS,EAAyB,MAAM,YAAY,CAAA;AAC7D,cAAc,WAAW,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAA;AAClC,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,cAAc,CAAA;AAC5B,cAAc,UAAU,CAAA;AACxB,OAAO,EAAE,SAAS,EAAyB,MAAM,YAAY,CAAA;AAC7D,cAAc,WAAW,CAAA"}
@@ -0,0 +1,74 @@
1
+ import { Schema } from "effect";
2
+ import { WorkLaneClaimed } from "../model.js";
3
+ /**
4
+ * How a pre-session lane claim migrates. A legacy claim has no operation id,
5
+ * so it takes the lane id, unless a running binding recorded the lane at the
6
+ * claim's own revision: the claim then becomes that lane, because every later
7
+ * open checks a current binding's lane against the claim exactly. The binding
8
+ * writer set the claim to exactly its lane, so a well-formed pair differs only
9
+ * in the ids the legacy record lacked; any other difference, or a second bound lane (lane CAS
10
+ * allows one binding per revision), means an inconsistent file. A claim that moved past
11
+ * every binding keeps its own fields and the lane-id operation, with the one goal its
12
+ * lane's bindings recorded; bindings that disagree on that goal mean an inconsistent file.
13
+ */
14
+ export type LegacyLaneClaim = {
15
+ readonly _tag: "claim";
16
+ readonly lane: WorkLaneClaimed;
17
+ } | {
18
+ readonly _tag: "ambiguous";
19
+ readonly bound: ReadonlyArray<WorkLaneClaimed>;
20
+ readonly lane: WorkLaneClaimed;
21
+ } | {
22
+ readonly _tag: "mismatch";
23
+ readonly bound: WorkLaneClaimed;
24
+ readonly lane: WorkLaneClaimed;
25
+ };
26
+ /**
27
+ * Resolves `legacy` (already given `operationId = laneId`) against the lanes
28
+ * of the running bindings its handoffs reference.
29
+ */
30
+ export declare const resolveLegacyLaneClaim: (legacy: WorkLaneClaimed, bindingLanes: ReadonlyArray<WorkLaneClaimed>) => LegacyLaneClaim;
31
+ export declare const LaneOperationLedgerRow: Schema.Struct<{
32
+ readonly operationId: Schema.Union<readonly [Schema.String, Schema.Number, Schema.Uint8Array]>;
33
+ readonly laneId: Schema.Union<readonly [Schema.String, Schema.Number, Schema.Uint8Array]>;
34
+ readonly goalId: Schema.Union<readonly [Schema.String, Schema.Number, Schema.Uint8Array]>;
35
+ readonly phase: Schema.Union<readonly [Schema.String, Schema.Number, Schema.Uint8Array]>;
36
+ readonly revision: Schema.Union<readonly [Schema.String, Schema.Number, Schema.Uint8Array]>;
37
+ readonly record: Schema.Union<readonly [Schema.String, Schema.Number, Schema.Uint8Array]>;
38
+ }>;
39
+ export type LaneOperationRow = typeof LaneOperationLedgerRow.Type;
40
+ /** The ledger's row count and encoded bytes, counted the way its totals trigger counts them. */
41
+ export declare const LaneOperationTotalsRow: Schema.Struct<{
42
+ readonly count: Schema.Number;
43
+ readonly bytes: Schema.Number;
44
+ }>;
45
+ /**
46
+ * How the migrated claims enter the operation ledger: insert the absent ones,
47
+ * or fail because a row already holds one of their operation ids with a
48
+ * different claim (an exact replay would then conflict), or because the new
49
+ * rows would take the ledger past its bounds.
50
+ */
51
+ export type LegacyLaneOperations = {
52
+ readonly _tag: "record";
53
+ readonly inserts: ReadonlyArray<WorkLaneClaimed>;
54
+ } | {
55
+ readonly _tag: "collision";
56
+ readonly lane: WorkLaneClaimed;
57
+ readonly existing: LaneOperationRow;
58
+ } | {
59
+ readonly _tag: "capacity";
60
+ readonly count: number;
61
+ readonly bytes: number;
62
+ };
63
+ /**
64
+ * Plans the ledger rows for `claims` against the rows already holding their
65
+ * operation ids and the ledger's current totals.
66
+ */
67
+ export declare const planLegacyLaneOperations: (claims: ReadonlyArray<WorkLaneClaimed>, existing: ReadonlyMap<string, LaneOperationRow>, totals: {
68
+ readonly count: number;
69
+ readonly bytes: number;
70
+ }, limits: {
71
+ readonly records: number;
72
+ readonly bytes: number;
73
+ }) => LegacyLaneOperations;
74
+ //# sourceMappingURL=legacy-lane-claim.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"legacy-lane-claim.d.ts","sourceRoot":"","sources":["../../src/internal/legacy-lane-claim.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,MAAM,EAAE,MAAM,QAAQ,CAAA;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE7C;;;;;;;;;;GAUG;AACH,MAAM,MAAM,eAAe,GACvB;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAA;CAAE,GAC1D;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAA;CAAE,GAC9G;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAA;CAAE,CAAA;AAElG;;;GAGG;AACH,eAAO,MAAM,sBAAsB,WACzB,eAAe,gBACT,aAAa,CAAC,eAAe,CAAC,KAC3C,eA4BF,CAAA;AAOD,eAAO,MAAM,sBAAsB;;;;;;;EAOjC,CAAA;AACF,MAAM,MAAM,gBAAgB,GAAG,OAAO,sBAAsB,CAAC,IAAI,CAAA;AAEjE,gGAAgG;AAChG,eAAO,MAAM,sBAAsB;;;EAAgE,CAAA;AAEnG;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAC5B;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,eAAe,CAAC,CAAA;CAAE,GAC7E;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAA;CAAE,GACnG;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAejF;;;GAGG;AACH,eAAO,MAAM,wBAAwB,WAC3B,aAAa,CAAC,eAAe,CAAC,YAC5B,WAAW,CAAC,MAAM,EAAE,gBAAgB,CAAC,UACvC;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,UAClD;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,KAC3D,oBAeF,CAAA"}
@@ -0,0 +1,81 @@
1
+ import { Equal, Predicate, Schema } from "effect";
2
+ import { WorkLaneClaimed } from "../model.js";
3
+ /**
4
+ * Resolves `legacy` (already given `operationId = laneId`) against the lanes
5
+ * of the running bindings its handoffs reference.
6
+ */
7
+ export const resolveLegacyLaneClaim = (legacy, bindingLanes) => {
8
+ const bound = bindingLanes
9
+ .filter(({ laneId, revision }) => laneId === legacy.laneId && revision === legacy.revision)
10
+ .reduce((distinct, lane) => distinct.some((seen) => Equal.equals(seen, lane)) ? distinct : [...distinct, lane], []);
11
+ const [only, ...rest] = bound;
12
+ if (only === undefined) {
13
+ // The claim moved past its bindings: it keeps its own fields and the
14
+ // lane-id operation, but the lane's goal never changes, so it takes the
15
+ // goal every earlier binding of this lane recorded.
16
+ const earlier = bindingLanes.filter(({ laneId }) => laneId === legacy.laneId);
17
+ const goals = [...new Set(earlier.map(({ goalId }) => goalId))];
18
+ const [goalId, ...otherGoals] = goals;
19
+ if (goalId === undefined)
20
+ return { _tag: "claim", lane: legacy };
21
+ if (otherGoals.length > 0)
22
+ return { _tag: "ambiguous", bound: earlier, lane: legacy };
23
+ return { _tag: "claim", lane: Schema.decodeUnknownSync(WorkLaneClaimed)({ ...legacy, goalId }) };
24
+ }
25
+ if (rest.length > 0)
26
+ return { _tag: "ambiguous", bound, lane: legacy };
27
+ // The legacy record had neither id, so only the fields it did record must agree.
28
+ // Decode, not spread, so Equal compares two WorkLaneClaimed values.
29
+ const expected = Schema.decodeUnknownSync(WorkLaneClaimed)({
30
+ ...legacy,
31
+ goalId: only.goalId,
32
+ operationId: only.operationId
33
+ });
34
+ return Equal.equals(only, expected) ? { _tag: "claim", lane: only } : { _tag: "mismatch", bound: only, lane: legacy };
35
+ };
36
+ /** One `work_lane_operations` row, as both drivers read it. */
37
+ // SQLite keeps whatever type a row was written with, so every column may be
38
+ // text, a number or a blob; a row of the wrong shape is a collision, not a
39
+ // decode error.
40
+ const LedgerValue = Schema.Union([Schema.String, Schema.Number, Schema.Uint8Array]);
41
+ export const LaneOperationLedgerRow = Schema.Struct({
42
+ operationId: LedgerValue,
43
+ laneId: LedgerValue,
44
+ goalId: LedgerValue,
45
+ phase: LedgerValue,
46
+ revision: LedgerValue,
47
+ record: LedgerValue
48
+ });
49
+ /** The ledger's row count and encoded bytes, counted the way its totals trigger counts them. */
50
+ export const LaneOperationTotalsRow = Schema.Struct({ count: Schema.Number, bytes: Schema.Number });
51
+ const sameOperation = (lane, row) => {
52
+ if (row.operationId !== lane.operationId ||
53
+ row.laneId !== lane.laneId || row.goalId !== lane.goalId || row.phase !== lane.phase ||
54
+ row.revision !== lane.revision)
55
+ return false;
56
+ if (!Predicate.isString(row.record))
57
+ return false;
58
+ const decoded = Schema.decodeUnknownOption(Schema.fromJsonString(WorkLaneClaimed))(row.record);
59
+ return decoded._tag === "Some" && Equal.equals(decoded.value, lane);
60
+ };
61
+ const utf8 = new TextEncoder();
62
+ /**
63
+ * Plans the ledger rows for `claims` against the rows already holding their
64
+ * operation ids and the ledger's current totals.
65
+ */
66
+ export const planLegacyLaneOperations = (claims, existing, totals, limits) => {
67
+ const inserts = [];
68
+ for (const lane of claims) {
69
+ const row = existing.get(lane.operationId);
70
+ if (row === undefined)
71
+ inserts.push(lane);
72
+ else if (!sameOperation(lane, row))
73
+ return { _tag: "collision", existing: row, lane };
74
+ }
75
+ const count = totals.count + inserts.length;
76
+ const bytes = inserts.reduce((sum, lane) => sum + utf8.encode(lane.operationId).byteLength + utf8.encode(JSON.stringify(lane)).byteLength, totals.bytes);
77
+ return count > limits.records || bytes > limits.bytes
78
+ ? { _tag: "capacity", bytes, count }
79
+ : { _tag: "record", inserts };
80
+ };
81
+ //# sourceMappingURL=legacy-lane-claim.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"legacy-lane-claim.js","sourceRoot":"","sources":["../../src/internal/legacy-lane-claim.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { Schema } from "effect";
2
+ /**
3
+ * Reads the definition of `work_decision_handoffs_session`: no row when it is absent.
4
+ * Both WorkStore and the SQL bridge run it before deciding whether to rebuild it.
5
+ */
6
+ export declare const sessionIndexDefinitionQuery = "\n SELECT list.\"unique\" AS \"unique\", list.partial AS partial,\n (SELECT group_concat(info.name) FROM pragma_index_info(list.name) AS info) AS columns\n FROM pragma_index_list('work_decision_handoffs') AS list\n WHERE list.name = 'work_decision_handoffs_session'\n";
7
+ export declare const SessionIndexDefinition: Schema.Struct<{
8
+ readonly columns: Schema.NullOr<Schema.String>;
9
+ readonly partial: Schema.Number;
10
+ readonly unique: Schema.Number;
11
+ }>;
12
+ /**
13
+ * Only a unique, non-partial index on `session_id` alone enforces one handoff per
14
+ * session. A composite or partial index under this name reports `unique = 1` too,
15
+ * so the flag alone is not enough.
16
+ */
17
+ export declare const enforcesOneHandoffPerSession: (definition: typeof SessionIndexDefinition.Type) => boolean;
18
+ //# sourceMappingURL=session-index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-index.d.ts","sourceRoot":"","sources":["../../src/internal/session-index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE/B;;;GAGG;AACH,eAAO,MAAM,2BAA2B,sRAKvC,CAAA;AAED,eAAO,MAAM,sBAAsB;;;;EAIjC,CAAA;AAEF;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,eAAgB,OAAO,sBAAsB,CAAC,IAAI,KAAG,OACF,CAAA"}
@@ -0,0 +1,23 @@
1
+ import { Schema } from "effect";
2
+ /**
3
+ * Reads the definition of `work_decision_handoffs_session`: no row when it is absent.
4
+ * Both WorkStore and the SQL bridge run it before deciding whether to rebuild it.
5
+ */
6
+ export const sessionIndexDefinitionQuery = `
7
+ SELECT list."unique" AS "unique", list.partial AS partial,
8
+ (SELECT group_concat(info.name) FROM pragma_index_info(list.name) AS info) AS columns
9
+ FROM pragma_index_list('work_decision_handoffs') AS list
10
+ WHERE list.name = 'work_decision_handoffs_session'
11
+ `;
12
+ export const SessionIndexDefinition = Schema.Struct({
13
+ columns: Schema.NullOr(Schema.String),
14
+ partial: Schema.Number,
15
+ unique: Schema.Number
16
+ });
17
+ /**
18
+ * Only a unique, non-partial index on `session_id` alone enforces one handoff per
19
+ * session. A composite or partial index under this name reports `unique = 1` too,
20
+ * so the flag alone is not enough.
21
+ */
22
+ export const enforcesOneHandoffPerSession = (definition) => definition.unique === 1 && definition.partial === 0 && definition.columns === "session_id";
23
+ //# sourceMappingURL=session-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-index.js","sourceRoot":"","sources":["../../src/internal/session-index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE/B;;;GAGG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG;;;;;CAK1C,CAAA;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC,MAAM,CAAC;IAClD,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC,MAAM;IACtB,MAAM,EAAE,MAAM,CAAC,MAAM;CACtB,CAAC,CAAA;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,UAA8C,EAAW,EAAE,CACtG,UAAU,CAAC,MAAM,KAAK,CAAC,IAAI,UAAU,CAAC,OAAO,KAAK,CAAC,IAAI,UAAU,CAAC,OAAO,KAAK,YAAY,CAAA"}
@@ -0,0 +1,29 @@
1
+ import { type Result, Schema } from "effect";
2
+ import type { WorkGoal, WorkGoalCheckpoint as WorkGoalCheckpointType, WorkObservedFact, WorkPullRequestObservation } from "../model.js";
3
+ /** A goal whose pull request is observed merged or closed, and the head checkpoint it was planned from. */
4
+ export interface TerminalCandidate {
5
+ readonly head: WorkGoalCheckpointType;
6
+ readonly fact: WorkObservedFact;
7
+ readonly pullRequest: WorkPullRequestObservation;
8
+ }
9
+ /**
10
+ * Goals not yet terminal whose pull request's latest observed fact is merged
11
+ * or closed. Goals with no pull request, or already finished, are left alone.
12
+ */
13
+ export declare const terminalCandidates: (events: ReadonlyArray<WorkGoalCheckpointType>, facts: ReadonlyArray<WorkObservedFact>) => ReadonlyArray<TerminalCandidate>;
14
+ /** The most activities a goal holds; a terminal transition never drops one to fit its own note. */
15
+ export declare const goalActivityLimit = 128;
16
+ /**
17
+ * The terminal checkpoint for one candidate. It is stamped with the pull
18
+ * request's own close time, or one millisecond after the goal's head when an
19
+ * owner wrote after the close, so it is the head of history; a close time
20
+ * later than `now` is clamped to it. A blocker cannot outlive a
21
+ * finished goal, so it is cleared; the activity names the observation.
22
+ */
23
+ export declare const terminalCheckpoint: (candidate: TerminalCandidate, eventId: string, now: number) => Result.Result<WorkGoalCheckpointType, Schema.SchemaError>;
24
+ /**
25
+ * A goal with no blocker in either representation, as every finished goal
26
+ * must be: `blocker` null and, when the goal has a `blockers` list, an empty one.
27
+ */
28
+ export declare const withoutBlockers: (goal: WorkGoal) => WorkGoal;
29
+ //# sourceMappingURL=terminal-reconcile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal-reconcile.d.ts","sourceRoot":"","sources":["../../src/internal/terminal-reconcile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE5C,OAAO,KAAK,EAEV,QAAQ,EACR,kBAAkB,IAAI,sBAAsB,EAC5C,gBAAgB,EAChB,0BAA0B,EAC3B,MAAM,aAAa,CAAA;AAGpB,2GAA2G;AAC3G,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAA;IACrC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAA;IAC/B,QAAQ,CAAC,WAAW,EAAE,0BAA0B,CAAA;CACjD;AAcD;;;GAGG;AACH,eAAO,MAAM,kBAAkB,WACrB,aAAa,CAAC,sBAAsB,CAAC,SACtC,aAAa,CAAC,gBAAgB,CAAC,KACrC,aAAa,CAAC,iBAAiB,CAUjC,CAAA;AAED,mGAAmG;AACnG,eAAO,MAAM,iBAAiB,MAAM,CAAA;AAEpC;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,cAClB,iBAAiB,WACnB,MAAM,OACV,MAAM,KACV,MAAM,CAAC,MAAM,CAAC,sBAAsB,EAAE,MAAM,CAAC,WAAW,CAiC1D,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,SAAU,QAAQ,KAAG,QACoD,CAAA"}
@@ -0,0 +1,79 @@
1
+ import { Schema } from "effect";
2
+ import { isTerminalWorkState, WorkGoalCheckpoint } from "../model.js";
3
+ import { goalPullRequestSubject } from "../observed.js";
4
+ const latestPerGoal = (events) => {
5
+ const latest = new Map();
6
+ for (const event of events) {
7
+ const current = latest.get(event.goal.id);
8
+ if (current === undefined || event.occurredAt > current.occurredAt ||
9
+ (event.occurredAt === current.occurredAt && event.eventId > current.eventId))
10
+ latest.set(event.goal.id, event);
11
+ }
12
+ return [...latest.values()];
13
+ };
14
+ /**
15
+ * Goals not yet terminal whose pull request's latest observed fact is merged
16
+ * or closed. Goals with no pull request, or already finished, are left alone.
17
+ */
18
+ export const terminalCandidates = (events, facts) => {
19
+ const factBySubject = new Map(facts.map((fact) => [fact.subject, fact]));
20
+ return latestPerGoal(events).flatMap((head) => {
21
+ if (isTerminalWorkState(head.goal.state))
22
+ return [];
23
+ const subject = goalPullRequestSubject(head.goal);
24
+ const fact = subject === null ? undefined : factBySubject.get(subject);
25
+ if (fact === undefined || fact.observation._tag !== "pull_request")
26
+ return [];
27
+ const pullRequest = fact.observation;
28
+ return pullRequest.state === "open" ? [] : [{ fact, head, pullRequest }];
29
+ });
30
+ };
31
+ /** The most activities a goal holds; a terminal transition never drops one to fit its own note. */
32
+ export const goalActivityLimit = 128;
33
+ /**
34
+ * The terminal checkpoint for one candidate. It is stamped with the pull
35
+ * request's own close time, or one millisecond after the goal's head when an
36
+ * owner wrote after the close, so it is the head of history; a close time
37
+ * later than `now` is clamped to it. A blocker cannot outlive a
38
+ * finished goal, so it is cleared; the activity names the observation.
39
+ */
40
+ export const terminalCheckpoint = (candidate, eventId, now) => {
41
+ const { head, pullRequest } = candidate;
42
+ const merged = pullRequest.state === "merged";
43
+ // A provider's close time is trusted only up to the store's clock: a bad
44
+ // future date must not become the head of the goal's history.
45
+ const occurredAt = Math.max(Math.min(pullRequest.closedAt ?? 0, now), head.goal.updatedAt + 1);
46
+ const url = `https://github.com/${pullRequest.repository}/pull/${pullRequest.pullRequest}`;
47
+ const observed = {
48
+ id: eventId,
49
+ kind: merged ? "shipment" : "status",
50
+ summary: merged
51
+ ? `Observed by the reconciler: ${url} merged`
52
+ : `Observed by the reconciler: ${url} closed without merging`,
53
+ occurredAt
54
+ };
55
+ // Never drop the owner's activity to fit this note: a goal whose activity is
56
+ // full takes the checkpoint without it (the reconciler's own record still
57
+ // marks the checkpoint).
58
+ const existing = head.goal.activity ?? [];
59
+ const activity = existing.length >= goalActivityLimit ? existing : [...existing, observed];
60
+ const goal = {
61
+ ...withoutBlockers(head.goal),
62
+ state: merged ? "completed" : "abandoned",
63
+ delivery: merged ? "merged" : head.goal.delivery,
64
+ activity,
65
+ updatedAt: occurredAt
66
+ };
67
+ return Schema.decodeUnknownResult(WorkGoalCheckpoint)({
68
+ version: "herdr.work.event.v1",
69
+ eventId,
70
+ occurredAt,
71
+ goal
72
+ });
73
+ };
74
+ /**
75
+ * A goal with no blocker in either representation, as every finished goal
76
+ * must be: `blocker` null and, when the goal has a `blockers` list, an empty one.
77
+ */
78
+ export const withoutBlockers = (goal) => goal.blockers === undefined ? { ...goal, blocker: null } : { ...goal, blocker: null, blockers: [] };
79
+ //# sourceMappingURL=terminal-reconcile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal-reconcile.js","sourceRoot":"","sources":["../../src/internal/terminal-reconcile.ts"],"names":[],"mappings":"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"}