jinaga-server 3.7.5 → 3.8.1

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 (48) hide show
  1. package/.claude/skills/degrees-of-freedom/.openskills.json +7 -0
  2. package/.claude/skills/degrees-of-freedom/SKILL.md +18 -0
  3. package/.claude/skills/degrees-of-freedom/degrees-of-freedom-constitution.md +142 -0
  4. package/.claude/skills/night-shift-setup/.openskills.json +7 -0
  5. package/.claude/skills/night-shift-setup/SKILL.md +95 -0
  6. package/.claude/skills/night-shift-setup/configuring-a-repository.md +111 -0
  7. package/.claude/skills/night-shift-setup/creating-the-log.md +59 -0
  8. package/.claude/skills/night-shift-setup/creating-the-routines.md +80 -0
  9. package/.claude/skills/night-shift-setup/log-model.factual +971 -0
  10. package/.claude/skills/night-shift-worker/.openskills.json +7 -0
  11. package/.claude/skills/night-shift-worker/SKILL.md +199 -0
  12. package/.claude/skills/night-shift-worker/night-shift-log.md +72 -0
  13. package/.claude/skills/night-shift-worker/scripts/register-stack.sh +173 -0
  14. package/.claude/skills/night-shift-worker/stacking.md +57 -0
  15. package/.claude/skills/night-shift-worker/verifying-a-merged-fix.md +16 -0
  16. package/.claude/skills/refining-issues/.openskills.json +7 -0
  17. package/.claude/skills/refining-issues/SKILL.md +327 -0
  18. package/.claude/skills/refining-issues/references/worked-example.md +234 -0
  19. package/.github/workflows/main.yml +2 -2
  20. package/.night-shift/config.md +84 -0
  21. package/.night-shift/skills.md +17 -0
  22. package/README.md +21 -0
  23. package/dist/http/router.js +19 -23
  24. package/dist/http/router.js.map +1 -1
  25. package/dist/http/stream.d.ts +0 -1
  26. package/dist/http/stream.js +6 -17
  27. package/dist/http/stream.js.map +1 -1
  28. package/dist/jinaga-server.js +74 -7
  29. package/dist/jinaga-server.js.map +1 -1
  30. package/dist/postgres/postgres-store.js +18 -4
  31. package/dist/postgres/postgres-store.js.map +1 -1
  32. package/dist/postgres/purge-sql.d.ts +10 -0
  33. package/dist/postgres/purge-sql.js +77 -50
  34. package/dist/postgres/purge-sql.js.map +1 -1
  35. package/integration-test/jinaga-test/package-lock.json +4 -4
  36. package/integration-test/jinaga-test/package.json +1 -1
  37. package/integration-test/jinaga-test/postgres-keystore-race.test.js +9 -7
  38. package/integration-test/jinaga-test/purge.test.js +52 -1
  39. package/package.json +2 -2
  40. package/src/http/router.ts +31 -39
  41. package/src/http/stream.ts +21 -36
  42. package/src/jinaga-server.ts +92 -4
  43. package/src/postgres/postgres-store.ts +19 -5
  44. package/src/postgres/purge-sql.ts +89 -55
  45. package/test/http/streamLogVolumeSpec.ts +284 -0
  46. package/test/jinaga-server/poolConfigurationSpec.ts +147 -0
  47. package/test/jinaga-server/tracePoolSpec.ts +368 -0
  48. package/test/postgres/purgeSqlSpec.ts +123 -22
@@ -0,0 +1,971 @@
1
+ // Night Shift Log — the application the night-shift protocol records into.
2
+ //
3
+ // Send these statements to `execute` IN FILE ORDER. Do not reorder them: fact
4
+ // types come before the specifications that walk them, specifications before
5
+ // the actions that write them, and the manifest last because it names every
6
+ // action and view. Within the fact types, each one follows every type it names
7
+ // as a predecessor.
8
+ //
9
+ // Four batches, marked below. `execute` stops a batch at its first failure, so
10
+ // sending them separately makes a failure name its layer. See creating-the-log.md
11
+ // for the full ceremony, including `create application` before batch 1 and
12
+ // `publish` between batches 3 and 4.
13
+
14
+ // ---- batch 1 of 4: fact types ----
15
+
16
+ fact NightShift.Practice {
17
+ owner: Jinaga.User;
18
+ }
19
+
20
+ fact NightShift.Administrator {
21
+ practice: NightShift.Practice;
22
+ user: Jinaga.User;
23
+ }
24
+
25
+ fact NightShift.PracticeDeletion {
26
+ practice: NightShift.Practice;
27
+ deletedAt: date;
28
+ }
29
+
30
+ fact NightShift.Repository {
31
+ practice: NightShift.Practice;
32
+ key: string;
33
+ }
34
+
35
+ fact NightShift.GitHubRepository {
36
+ repository: NightShift.Repository;
37
+ githubId: number;
38
+ }
39
+
40
+ fact NightShift.RepositoryName {
41
+ repository: NightShift.Repository;
42
+ name: string;
43
+ prior: NightShift.RepositoryName*;
44
+ }
45
+
46
+ fact NightShift.Sweep {
47
+ startedAt: date;
48
+ headCommit: string?;
49
+ repository: NightShift.Repository;
50
+ }
51
+
52
+ fact NightShift.Consideration {
53
+ issueNumber: number;
54
+ issueTitle: string?;
55
+ sweep: NightShift.Sweep;
56
+ }
57
+
58
+ fact NightShift.OpenPullRequestFound {
59
+ number: number;
60
+ consideration: NightShift.Consideration;
61
+ }
62
+
63
+ fact NightShift.MergedPullRequestFound {
64
+ number: number;
65
+ consideration: NightShift.Consideration;
66
+ }
67
+
68
+ fact NightShift.ClosedPullRequestFound {
69
+ number: number;
70
+ consideration: NightShift.Consideration;
71
+ }
72
+
73
+ fact NightShift.BranchFound {
74
+ branch: string;
75
+ consideration: NightShift.Consideration;
76
+ }
77
+
78
+ fact NightShift.NoPriorWorkFound {
79
+ consideration: NightShift.Consideration;
80
+ }
81
+
82
+ fact NightShift.Dispatch {
83
+ branch: string;
84
+ sessionId: string?;
85
+ sequence: number?;
86
+ rationale: string?;
87
+ consideration: NightShift.Consideration;
88
+ }
89
+
90
+ fact NightShift.Skipped {
91
+ rationale: string;
92
+ consideration: NightShift.Consideration;
93
+ }
94
+
95
+ fact NightShift.Correction {
96
+ detail: string;
97
+ recordedAt: date;
98
+ corrected: NightShift.Consideration;
99
+ discoveredIn: NightShift.Consideration?;
100
+ }
101
+
102
+ fact NightShift.PullRequestOpened {
103
+ number: number;
104
+ summary: string;
105
+ recordedAt: date;
106
+ dispatch: NightShift.Dispatch;
107
+ }
108
+
109
+ fact NightShift.Question {
110
+ text: string;
111
+ recordedAt: date;
112
+ dispatch: NightShift.Dispatch;
113
+ }
114
+
115
+ fact NightShift.NoChangeFound {
116
+ summary: string;
117
+ recordedAt: date;
118
+ dispatch: NightShift.Dispatch;
119
+ }
120
+
121
+ fact NightShift.Answer {
122
+ text: string;
123
+ recordedAt: date;
124
+ question: NightShift.Question;
125
+ }
126
+
127
+ // ---- batch 2 of 4: specifications ----
128
+
129
+ specification practicesForAdministrator = ($user: Jinaga.User) {
130
+ $administrator: NightShift.Administrator [
131
+ $administrator->user: Jinaga.User = $user
132
+ ]
133
+ $practice: NightShift.Practice [
134
+ $practice = $administrator->practice: NightShift.Practice
135
+ !E {
136
+ $deletion: NightShift.PracticeDeletion [
137
+ $deletion->practice: NightShift.Practice = $practice
138
+ ]
139
+ }
140
+ ]
141
+ } => {
142
+ practiceRef = &$practice
143
+ repositories = {
144
+ $repository: NightShift.Repository [
145
+ $repository->practice: NightShift.Practice = $practice
146
+ ]
147
+ } => {
148
+ repositoryRef = &$repository
149
+ currentNames = {
150
+ $n: NightShift.RepositoryName [
151
+ $n->repository: NightShift.Repository = $repository
152
+ !E {
153
+ $next: NightShift.RepositoryName [
154
+ $next->prior: NightShift.RepositoryName = $n
155
+ ]
156
+ }
157
+ ]
158
+ } => {
159
+ name = $n.name
160
+ nameRef = &$n
161
+ }
162
+ }
163
+ }
164
+
165
+ specification repositoriesInPractice = ($practice: NightShift.Practice) {
166
+ $repository: NightShift.Repository [
167
+ $repository->practice: NightShift.Practice = $practice
168
+ ]
169
+ } => {
170
+ repositoryRef = &$repository
171
+ gitHubBindings = {
172
+ $binding: NightShift.GitHubRepository [
173
+ $binding->repository: NightShift.Repository = $repository
174
+ ]
175
+ } => {
176
+ githubId = $binding.githubId
177
+ }
178
+ currentNames = {
179
+ $n: NightShift.RepositoryName [
180
+ $n->repository: NightShift.Repository = $repository
181
+ !E {
182
+ $next: NightShift.RepositoryName [
183
+ $next->prior: NightShift.RepositoryName = $n
184
+ ]
185
+ }
186
+ ]
187
+ } => {
188
+ name = $n.name
189
+ nameRef = &$n
190
+ }
191
+ }
192
+
193
+ specification sweepsInRepository = ($repository: NightShift.Repository) {
194
+ $sweep: NightShift.Sweep [
195
+ $sweep->repository: NightShift.Repository = $repository
196
+ ]
197
+ } => {
198
+ startedAt = $sweep.startedAt
199
+ headCommit = $sweep.headCommit
200
+ sweepRef = &$sweep
201
+ }
202
+
203
+ specification considerationsInSweep = ($sweep: NightShift.Sweep) {
204
+ $consideration: NightShift.Consideration [
205
+ $consideration->sweep: NightShift.Sweep = $sweep
206
+ ]
207
+ } => {
208
+ issueNumber = $consideration.issueNumber
209
+ issueTitle = $consideration.issueTitle
210
+ considerationRef = &$consideration
211
+ openPullRequestsFound = {
212
+ $f: NightShift.OpenPullRequestFound [
213
+ $f->consideration: NightShift.Consideration = $consideration
214
+ ]
215
+ } => {
216
+ number = $f.number
217
+ }
218
+ mergedPullRequestsFound = {
219
+ $f: NightShift.MergedPullRequestFound [
220
+ $f->consideration: NightShift.Consideration = $consideration
221
+ ]
222
+ } => {
223
+ number = $f.number
224
+ }
225
+ closedPullRequestsFound = {
226
+ $f: NightShift.ClosedPullRequestFound [
227
+ $f->consideration: NightShift.Consideration = $consideration
228
+ ]
229
+ } => {
230
+ number = $f.number
231
+ }
232
+ branchesFound = {
233
+ $f: NightShift.BranchFound [
234
+ $f->consideration: NightShift.Consideration = $consideration
235
+ ]
236
+ } => {
237
+ branch = $f.branch
238
+ }
239
+ noPriorWork = {
240
+ $f: NightShift.NoPriorWorkFound [
241
+ $f->consideration: NightShift.Consideration = $consideration
242
+ ]
243
+ } => {
244
+ confirmed = #$f
245
+ }
246
+ skips = {
247
+ $skip: NightShift.Skipped [
248
+ $skip->consideration: NightShift.Consideration = $consideration
249
+ ]
250
+ } => {
251
+ rationale = $skip.rationale
252
+ }
253
+ corrections = {
254
+ $correction: NightShift.Correction [
255
+ $correction->corrected: NightShift.Consideration = $consideration
256
+ ]
257
+ } => {
258
+ detail = $correction.detail
259
+ recordedAt = $correction.recordedAt
260
+ }
261
+ dispatches = {
262
+ $dispatch: NightShift.Dispatch [
263
+ $dispatch->consideration: NightShift.Consideration = $consideration
264
+ ]
265
+ } => {
266
+ branch = $dispatch.branch
267
+ sessionId = $dispatch.sessionId
268
+ sequence = $dispatch.sequence
269
+ rationale = $dispatch.rationale
270
+ dispatchRef = &$dispatch
271
+ pullRequestsOpened = {
272
+ $pr: NightShift.PullRequestOpened [
273
+ $pr->dispatch: NightShift.Dispatch = $dispatch
274
+ ]
275
+ } => {
276
+ number = $pr.number
277
+ summary = $pr.summary
278
+ recordedAt = $pr.recordedAt
279
+ }
280
+ questions = {
281
+ $q: NightShift.Question [
282
+ $q->dispatch: NightShift.Dispatch = $dispatch
283
+ ]
284
+ } => {
285
+ text = $q.text
286
+ recordedAt = $q.recordedAt
287
+ questionRef = &$q
288
+ answers = {
289
+ $a: NightShift.Answer [
290
+ $a->question: NightShift.Question = $q
291
+ ]
292
+ } => {
293
+ text = $a.text
294
+ recordedAt = $a.recordedAt
295
+ }
296
+ }
297
+ noChanges = {
298
+ $nc: NightShift.NoChangeFound [
299
+ $nc->dispatch: NightShift.Dispatch = $dispatch
300
+ ]
301
+ } => {
302
+ summary = $nc.summary
303
+ recordedAt = $nc.recordedAt
304
+ }
305
+ }
306
+ }
307
+
308
+ specification unansweredQuestions = ($practice: NightShift.Practice) {
309
+ $repository: NightShift.Repository [
310
+ $repository->practice: NightShift.Practice = $practice
311
+ ]
312
+ $sweep: NightShift.Sweep [
313
+ $sweep->repository: NightShift.Repository = $repository
314
+ ]
315
+ $consideration: NightShift.Consideration [
316
+ $consideration->sweep: NightShift.Sweep = $sweep
317
+ ]
318
+ $dispatch: NightShift.Dispatch [
319
+ $dispatch->consideration: NightShift.Consideration = $consideration
320
+ ]
321
+ $question: NightShift.Question [
322
+ $question->dispatch: NightShift.Dispatch = $dispatch
323
+ !E {
324
+ $answer: NightShift.Answer [
325
+ $answer->question: NightShift.Question = $question
326
+ ]
327
+ }
328
+ ]
329
+ } => {
330
+ issueNumber = $consideration.issueNumber
331
+ issueTitle = $consideration.issueTitle
332
+ text = $question.text
333
+ askedAt = $question.recordedAt
334
+ branch = $dispatch.branch
335
+ questionRef = &$question
336
+ repositoryNames = {
337
+ $n: NightShift.RepositoryName [
338
+ $n->repository: NightShift.Repository = $repository
339
+ !E {
340
+ $next: NightShift.RepositoryName [
341
+ $next->prior: NightShift.RepositoryName = $n
342
+ ]
343
+ }
344
+ ]
345
+ } => {
346
+ name = $n.name
347
+ }
348
+ }
349
+
350
+ specification skippedIssues = ($practice: NightShift.Practice) {
351
+ $repository: NightShift.Repository [
352
+ $repository->practice: NightShift.Practice = $practice
353
+ ]
354
+ $sweep: NightShift.Sweep [
355
+ $sweep->repository: NightShift.Repository = $repository
356
+ ]
357
+ $consideration: NightShift.Consideration [
358
+ $consideration->sweep: NightShift.Sweep = $sweep
359
+ ]
360
+ $skip: NightShift.Skipped [
361
+ $skip->consideration: NightShift.Consideration = $consideration
362
+ ]
363
+ } => {
364
+ issueNumber = $consideration.issueNumber
365
+ issueTitle = $consideration.issueTitle
366
+ rationale = $skip.rationale
367
+ startedAt = $sweep.startedAt
368
+ considerationRef = &$consideration
369
+ repositoryNames = {
370
+ $n: NightShift.RepositoryName [
371
+ $n->repository: NightShift.Repository = $repository
372
+ !E {
373
+ $next: NightShift.RepositoryName [
374
+ $next->prior: NightShift.RepositoryName = $n
375
+ ]
376
+ }
377
+ ]
378
+ } => {
379
+ name = $n.name
380
+ }
381
+ }
382
+
383
+ specification correctedVerdicts = ($practice: NightShift.Practice) {
384
+ $repository: NightShift.Repository [
385
+ $repository->practice: NightShift.Practice = $practice
386
+ ]
387
+ $sweep: NightShift.Sweep [
388
+ $sweep->repository: NightShift.Repository = $repository
389
+ ]
390
+ $consideration: NightShift.Consideration [
391
+ $consideration->sweep: NightShift.Sweep = $sweep
392
+ ]
393
+ $correction: NightShift.Correction [
394
+ $correction->corrected: NightShift.Consideration = $consideration
395
+ ]
396
+ } => {
397
+ issueNumber = $consideration.issueNumber
398
+ detail = $correction.detail
399
+ recordedAt = $correction.recordedAt
400
+ discoveredIn = {
401
+ $source: NightShift.Consideration [
402
+ $source = $correction->discoveredIn: NightShift.Consideration
403
+ ]
404
+ } => {
405
+ issueNumber = $source.issueNumber
406
+ }
407
+ repositoryNames = {
408
+ $n: NightShift.RepositoryName [
409
+ $n->repository: NightShift.Repository = $repository
410
+ !E {
411
+ $next: NightShift.RepositoryName [
412
+ $next->prior: NightShift.RepositoryName = $n
413
+ ]
414
+ }
415
+ ]
416
+ } => {
417
+ name = $n.name
418
+ }
419
+ }
420
+
421
+ specification consideredIssuesWithMergedWork = ($practice: NightShift.Practice) {
422
+ $repository: NightShift.Repository [
423
+ $repository->practice: NightShift.Practice = $practice
424
+ ]
425
+ $sweep: NightShift.Sweep [
426
+ $sweep->repository: NightShift.Repository = $repository
427
+ ]
428
+ $consideration: NightShift.Consideration [
429
+ $consideration->sweep: NightShift.Sweep = $sweep
430
+ ]
431
+ $found: NightShift.MergedPullRequestFound [
432
+ $found->consideration: NightShift.Consideration = $consideration
433
+ ]
434
+ } => {
435
+ issueNumber = $consideration.issueNumber
436
+ issueTitle = $consideration.issueTitle
437
+ mergedPullRequest = $found.number
438
+ startedAt = $sweep.startedAt
439
+ repositoryNames = {
440
+ $n: NightShift.RepositoryName [
441
+ $n->repository: NightShift.Repository = $repository
442
+ !E {
443
+ $next: NightShift.RepositoryName [
444
+ $next->prior: NightShift.RepositoryName = $n
445
+ ]
446
+ }
447
+ ]
448
+ } => {
449
+ name = $n.name
450
+ }
451
+ }
452
+
453
+ // ---- batch 3 of 4: actions ----
454
+
455
+ action createPractice ($admin: Jinaga.User) {
456
+ singleUse $owner {
457
+ let $practice = new NightShift.Practice($owner);
458
+ new NightShift.Administrator($practice, $admin);
459
+ }
460
+ }
461
+
462
+ action deletePractice ($practice: NightShift.Practice) {
463
+ let $deletion = new NightShift.PracticeDeletion($practice, now());
464
+ }
465
+
466
+ action registerGitHubRepository ($practice: NightShift.Practice, $githubId: number, $name: string) {
467
+ let $repository = new NightShift.Repository($practice, uuid());
468
+ let $binding = new NightShift.GitHubRepository($repository, $githubId);
469
+ let $repositoryName = new NightShift.RepositoryName($repository, $name, []);
470
+ }
471
+
472
+ action renameRepository ($repository: NightShift.Repository, $name: string, $prior: NightShift.RepositoryName) {
473
+ let $repositoryName = new NightShift.RepositoryName($repository, $name, [$prior]);
474
+ }
475
+
476
+ action startSweep ($repository: NightShift.Repository, $headCommit: string) {
477
+ let $sweep = new NightShift.Sweep(now(), $headCommit, $repository);
478
+ }
479
+
480
+ action considerIssue ($sweep: NightShift.Sweep, $issueNumber: number, $issueTitle: string) {
481
+ let $consideration = new NightShift.Consideration($issueNumber, $issueTitle, $sweep);
482
+ }
483
+
484
+ action findOpenPullRequest ($consideration: NightShift.Consideration, $number: number) {
485
+ let $found = new NightShift.OpenPullRequestFound($number, $consideration);
486
+ }
487
+
488
+ action findMergedPullRequest ($consideration: NightShift.Consideration, $number: number) {
489
+ let $found = new NightShift.MergedPullRequestFound($number, $consideration);
490
+ }
491
+
492
+ action findClosedPullRequest ($consideration: NightShift.Consideration, $number: number) {
493
+ let $found = new NightShift.ClosedPullRequestFound($number, $consideration);
494
+ }
495
+
496
+ action findBranch ($consideration: NightShift.Consideration, $branch: string) {
497
+ let $found = new NightShift.BranchFound($branch, $consideration);
498
+ }
499
+
500
+ action findNoPriorWork ($consideration: NightShift.Consideration) {
501
+ let $found = new NightShift.NoPriorWorkFound($consideration);
502
+ }
503
+
504
+ action dispatchWork ($consideration: NightShift.Consideration, $branch: string, $sessionId: string, $sequence: number, $rationale: string) {
505
+ let $dispatch = new NightShift.Dispatch($branch, $sessionId, $sequence, $rationale, $consideration);
506
+ }
507
+
508
+ action skipIssue ($consideration: NightShift.Consideration, $rationale: string) {
509
+ let $skip = new NightShift.Skipped($rationale, $consideration);
510
+ }
511
+
512
+ action openPullRequest ($dispatch: NightShift.Dispatch, $number: number, $summary: string) {
513
+ let $pullRequest = new NightShift.PullRequestOpened($number, $summary, now(), $dispatch);
514
+ }
515
+
516
+ action raiseQuestion ($dispatch: NightShift.Dispatch, $text: string) {
517
+ let $question = new NightShift.Question($text, now(), $dispatch);
518
+ }
519
+
520
+ action findNoChange ($dispatch: NightShift.Dispatch, $summary: string) {
521
+ let $noChange = new NightShift.NoChangeFound($summary, now(), $dispatch);
522
+ }
523
+
524
+ action answerQuestion ($question: NightShift.Question, $text: string) {
525
+ let $answer = new NightShift.Answer($text, now(), $question);
526
+ }
527
+
528
+ action correctVerdict ($corrected: NightShift.Consideration, $detail: string) {
529
+ let $correction = new NightShift.Correction($detail, now(), $corrected, null);
530
+ }
531
+
532
+ action correctVerdictFromWork ($corrected: NightShift.Consideration, $discoveredIn: NightShift.Consideration, $detail: string) {
533
+ let $correction = new NightShift.Correction($detail, now(), $corrected, $discoveredIn);
534
+ }
535
+
536
+ // ---- batch 4 of 4: manifest ----
537
+ //
538
+ // Send this batch after `publish`, then publish again. Without it the
539
+ // application has no routing, so nothing can discover it, and no argument
540
+ // guidance, so nothing can drive it.
541
+
542
+ manifest routing <<MD
543
+ purpose: Record what an unattended night-shift agent did on each sweep of a
544
+ tracked repository's labelled issue queue — which issues it considered, what
545
+ prior work it found for each, what it dispatched or skipped, what came of it,
546
+ and how open questions were later answered or verdicts corrected.
547
+ use_when: A night-shift session or a person wants to record or review a sweep of
548
+ labelled issues in a tracked repository — what prior work was found for an
549
+ issue, why it was skipped or dispatched, what a dispatched session produced,
550
+ an answer to a recorded question, or a correction to an earlier verdict. Also
551
+ covers registering a repository to track, and recording a rename. Does NOT
552
+ trigger on deciding what is currently available to work; the hosting platform
553
+ is the queue and the only authority on that.
554
+ examples:
555
+ - Start a sweep of this repository's ready issues
556
+ - Track a new repository for the night shift
557
+ - That issue already had a merged pull request, so we verified instead of fixing
558
+ - Dispatched issue 14, second in the chain
559
+ - That issue produced no defect, only regression coverage
560
+ - That verdict was wrong, the pull request we credited was not the reason it passed
561
+ - What questions are still unanswered across all my repositories?
562
+ - Which issues did we skip last week and why?
563
+ - The repository was renamed
564
+ MD
565
+
566
+ manifest guide <<MD
567
+ ## Guide
568
+
569
+ A **Practice** is one person's night-shift setup. It roots at a single-use owner, so administrators reach it through `practicesForAdministrator` rather than by owning it. One practice covers every repository tracked.
570
+
571
+ A **Repository** is platform-neutral and carries a generated key as its identity. What binds it to a hosting platform is a successor — today only `GitHubRepository`, holding GitHub's numeric repository id. An Azure DevOps binding would be a sibling fact type on the same Repository, so nothing recorded beneath a sweep has a platform baked into its identity. The repository's **name** is a Mutable Property, superseded through `prior`, because a rename or transfer must not orphan history.
572
+
573
+ Each run is a **Sweep** of one repository, stamped with the head commit it read. Every issue examined gets one **Consideration**. Issue numbers are scoped by ownership, so the same number in two repositories never collides.
574
+
575
+ **Findings and decisions are fact types, not field values.** What the claim check turned up is recorded by creating the matching fact — `OpenPullRequestFound`, `MergedPullRequestFound`, `ClosedPullRequestFound`, `BranchFound`, or `NoPriorWorkFound`. What was decided is recorded the same way — a `Dispatch` means the issue was worked, a `Skipped` means it was passed over. There is no `finding` string and no `decision` string to compare against, because a specification cannot filter on a field value. It filters on structure, so every question the log is meant to answer is a join.
576
+
577
+ The same holds for outcomes. A dispatch produces a `PullRequestOpened`, a `Question`, or a `NoChangeFound` — three types, not one type with a kind. `unansweredQuestions` finds `Question` facts with no `Answer` successor, which is a real structural filter rather than a string comparison the caller has to trust.
578
+
579
+ Nothing is ever edited. A wrong conclusion is corrected by adding a `Correction` against the consideration it was recorded under, ideally with `correctVerdictFromWork` naming the consideration whose work turned up the disproof.
580
+
581
+ Availability is never stored here. The hosting platform is the queue and the only authority on what is currently ready. This application records what was observed and decided, and when.
582
+ MD
583
+
584
+ manifest actions.createPractice <<MD
585
+ when: Setting up night-shift tracking for the first time. One practice covers
586
+ every repository you track; check practicesForAdministrator first, because a
587
+ second call mints a second unrelated practice.
588
+ args:
589
+ admin:
590
+ type: Jinaga.User
591
+ from: the caller's own identity — pass $me
592
+ required: true
593
+ MD
594
+
595
+ manifest actions.deletePractice <<MD
596
+ when: Retiring a practice that was created by mistake or superseded. Rare —
597
+ check that it holds no repositories you still care about, because this hides
598
+ it from the entry point.
599
+ args:
600
+ practice:
601
+ type: NightShift.Practice
602
+ from: the practice to retire
603
+ required: true
604
+ MD
605
+
606
+ manifest actions.registerGitHubRepository <<MD
607
+ when: Adding a GitHub repository to the practice, once, before its first sweep.
608
+ Check repositoriesInPractice first so you do not register the same repository
609
+ twice.
610
+ guide: >
611
+ Creates a platform-neutral Repository with a generated key, binds it to GitHub
612
+ by numeric repository id, and records its current name. The numeric id is what
613
+ survives a rename or a transfer; the name is a mutable property, not identity.
614
+ A future Azure DevOps repository is a sibling binding on the same neutral
615
+ Repository, so nothing recorded under a sweep has a platform baked into it.
616
+ args:
617
+ practice:
618
+ type: NightShift.Practice
619
+ from: the practice to add the repository to
620
+ required: true
621
+ githubId:
622
+ type: number
623
+ from: GitHub's numeric repository id, from the id field of the repository API
624
+ response
625
+ required: true
626
+ name:
627
+ type: string
628
+ from: the current owner/name, such as acme/widgets
629
+ required: true
630
+ MD
631
+
632
+ manifest actions.renameRepository <<MD
633
+ when: A tracked repository was renamed or transferred, so its owner/name changed.
634
+ guide: >
635
+ Writes a new name that supersedes the prior one. Identity is unaffected —
636
+ every sweep, consideration and outcome stays attached. Query
637
+ repositoriesInPractice for the current name and pass its nameRef as prior. If
638
+ that query returns more than one current name, two writers raced; collapse the
639
+ fork with a console-level new NightShift.RepositoryName naming every leaf,
640
+ since this action takes only one.
641
+ args:
642
+ repository:
643
+ type: NightShift.Repository
644
+ from: the repository being renamed
645
+ required: true
646
+ name:
647
+ type: string
648
+ from: the new owner/name
649
+ required: true
650
+ prior:
651
+ type: NightShift.RepositoryName
652
+ from: the current name being superseded — the nameRef from repositoriesInPractice
653
+ required: true
654
+ MD
655
+
656
+ manifest actions.startSweep <<MD
657
+ when: A night-shift run begins for one repository, before any issue is examined.
658
+ One Sweep per repository per run.
659
+ args:
660
+ repository:
661
+ type: NightShift.Repository
662
+ from: the repository being swept — query repositoriesInPractice and pass the
663
+ row's repositoryRef
664
+ required: true
665
+ headCommit:
666
+ type: string
667
+ from: the SHA of the default branch when the sweep started
668
+ required: true
669
+ MD
670
+
671
+ manifest actions.considerIssue <<MD
672
+ when: An issue from the queue is about to be examined. Record this before
673
+ recording what was found.
674
+ args:
675
+ sweep:
676
+ type: NightShift.Sweep
677
+ from: the sweep this consideration belongs to
678
+ required: true
679
+ issueNumber:
680
+ type: number
681
+ from: the issue number
682
+ required: true
683
+ issueTitle:
684
+ type: string
685
+ from: the issue title as read
686
+ required: true
687
+ MD
688
+
689
+ manifest actions.findOpenPullRequest <<MD
690
+ when: The claim check found an open pull request referencing the issue, meaning
691
+ someone is already working it.
692
+ args:
693
+ consideration:
694
+ type: NightShift.Consideration
695
+ from: the consideration this finding belongs to
696
+ required: true
697
+ number:
698
+ type: number
699
+ from: the pull request number found
700
+ required: true
701
+ MD
702
+
703
+ manifest actions.findMergedPullRequest <<MD
704
+ when: The claim check found a merged pull request referencing the issue, meaning
705
+ a fix already landed and the job is verification rather than repair.
706
+ args:
707
+ consideration:
708
+ type: NightShift.Consideration
709
+ from: the consideration this finding belongs to
710
+ required: true
711
+ number:
712
+ type: number
713
+ from: the pull request number found
714
+ required: true
715
+ MD
716
+
717
+ manifest actions.findClosedPullRequest <<MD
718
+ when: The claim check found a closed but unmerged pull request, meaning an
719
+ attempt was abandoned and its reasoning is worth reading.
720
+ args:
721
+ consideration:
722
+ type: NightShift.Consideration
723
+ from: the consideration this finding belongs to
724
+ required: true
725
+ number:
726
+ type: number
727
+ from: the pull request number found
728
+ required: true
729
+ MD
730
+
731
+ manifest actions.findBranch <<MD
732
+ when: The claim check found a branch referencing the issue with no pull request
733
+ attached.
734
+ args:
735
+ consideration:
736
+ type: NightShift.Consideration
737
+ from: the consideration this finding belongs to
738
+ required: true
739
+ branch:
740
+ type: string
741
+ from: the branch name found
742
+ required: true
743
+ MD
744
+
745
+ manifest actions.findNoPriorWork <<MD
746
+ when: The claim check found nothing — no pull request and no branch — so the
747
+ issue is genuinely available.
748
+ args:
749
+ consideration:
750
+ type: NightShift.Consideration
751
+ from: the consideration this finding belongs to
752
+ required: true
753
+ MD
754
+
755
+ manifest actions.dispatchWork <<MD
756
+ when: A considered issue has been handed to a working session. Recording this IS
757
+ the decision to work it; there is no separate decision value.
758
+ args:
759
+ consideration:
760
+ type: NightShift.Consideration
761
+ from: the consideration that led to this dispatch
762
+ required: true
763
+ branch:
764
+ type: string
765
+ from: the pattern the session's branch will match, such as
766
+ claude/issue-14-*, because the slug is the working session's to choose and
767
+ the dispatcher cannot know it. This is the only branch the log holds. No
768
+ fact records the branch a session actually pushed, so what ties a dispatch
769
+ to the work that came of it is the pull request number on openPullRequest.
770
+ required: true
771
+ sessionId:
772
+ type: string
773
+ from: the working session's identifier
774
+ required: true
775
+ sequence:
776
+ type: number
777
+ from: 1-based position in this sweep's ordering
778
+ required: true
779
+ rationale:
780
+ type: string
781
+ from: why this issue was worked, and why in this position — the ordering
782
+ argument belongs here
783
+ required: true
784
+ MD
785
+
786
+ manifest actions.skipIssue <<MD
787
+ when: A considered issue was passed over. Recording this IS the decision to
788
+ skip; there is no separate decision value.
789
+ args:
790
+ consideration:
791
+ type: NightShift.Consideration
792
+ from: the consideration being skipped
793
+ required: true
794
+ rationale:
795
+ type: string
796
+ from: why it was passed over
797
+ required: true
798
+ MD
799
+
800
+ manifest actions.openPullRequest <<MD
801
+ when: A dispatched session produced a pull request.
802
+ args:
803
+ dispatch:
804
+ type: NightShift.Dispatch
805
+ from: the dispatch this outcome belongs to
806
+ required: true
807
+ number:
808
+ type: number
809
+ from: the pull request number
810
+ required: true
811
+ summary:
812
+ type: string
813
+ from: what the pull request concluded, in a sentence or two
814
+ required: true
815
+ MD
816
+
817
+ manifest actions.raiseQuestion <<MD
818
+ when: A dispatched session hit a blocker it could not settle and recorded a
819
+ question instead of guessing.
820
+ args:
821
+ dispatch:
822
+ type: NightShift.Dispatch
823
+ from: the dispatch that raised the question
824
+ required: true
825
+ text:
826
+ type: string
827
+ from: the question as posed, including the candidate answers
828
+ required: true
829
+ MD
830
+
831
+ manifest actions.findNoChange <<MD
832
+ when: A dispatched session concluded there was nothing to fix. A real result,
833
+ not a failure.
834
+ args:
835
+ dispatch:
836
+ type: NightShift.Dispatch
837
+ from: the dispatch that reached this conclusion
838
+ required: true
839
+ summary:
840
+ type: string
841
+ from: what was tested and what established that nothing needed changing
842
+ required: true
843
+ MD
844
+
845
+ manifest actions.answerQuestion <<MD
846
+ when: A recorded question gets an answer. This is what takes it off the
847
+ unansweredQuestions list.
848
+ args:
849
+ question:
850
+ type: NightShift.Question
851
+ from: the question being answered — take questionRef from unansweredQuestions
852
+ required: true
853
+ text:
854
+ type: string
855
+ from: the answer
856
+ required: true
857
+ MD
858
+
859
+ manifest actions.correctVerdict <<MD
860
+ when: An earlier conclusion about an issue turns out to have been wrong, and no
861
+ later piece of work is the source.
862
+ args:
863
+ corrected:
864
+ type: NightShift.Consideration
865
+ from: the consideration whose verdict was wrong
866
+ required: true
867
+ detail:
868
+ type: string
869
+ from: what was wrong and what is true instead
870
+ required: true
871
+ MD
872
+
873
+ manifest actions.correctVerdictFromWork <<MD
874
+ when: Work on one issue disproved a conclusion recorded about another. The most
875
+ valuable thing this log holds, because it is how the ordering and attribution
876
+ heuristics get better.
877
+ args:
878
+ corrected:
879
+ type: NightShift.Consideration
880
+ from: the consideration whose verdict was wrong
881
+ required: true
882
+ discoveredIn:
883
+ type: NightShift.Consideration
884
+ from: the consideration whose work turned up the disproof
885
+ required: true
886
+ detail:
887
+ type: string
888
+ from: what was wrong and what is true instead
889
+ required: true
890
+ MD
891
+
892
+ manifest views.practicesForAdministrator <<MD
893
+ when: Find the practice the caller administers, with the repositories in it and
894
+ their current names. The entry point — run this first.
895
+ args:
896
+ user:
897
+ type: Jinaga.User
898
+ from: the caller's own identity — pass $me
899
+ required: true
900
+ MD
901
+
902
+ manifest views.repositoriesInPractice <<MD
903
+ when: List the repositories tracked by a practice, with each one's current name
904
+ and its GitHub binding. Run this to get a repositoryRef before starting a
905
+ sweep.
906
+ args:
907
+ practice:
908
+ type: NightShift.Practice
909
+ from: the practice to list repositories for
910
+ required: true
911
+ MD
912
+
913
+ manifest views.sweepsInRepository <<MD
914
+ when: List the runs recorded for one repository.
915
+ args:
916
+ repository:
917
+ type: NightShift.Repository
918
+ from: the repository to list sweeps for
919
+ required: true
920
+ MD
921
+
922
+ manifest views.considerationsInSweep <<MD
923
+ when: Review one run in full — every issue examined, what was found, what was
924
+ dispatched or skipped, and what came of it.
925
+ args:
926
+ sweep:
927
+ type: NightShift.Sweep
928
+ from: the sweep to review
929
+ required: true
930
+ MD
931
+
932
+ manifest views.unansweredQuestions <<MD
933
+ when: List questions that have no answer yet. This is how a blocking question
934
+ stays visible after its queue label has been cleared. Filtered by structure,
935
+ so every row really is an open question.
936
+ args:
937
+ practice:
938
+ type: NightShift.Practice
939
+ from: the practice to check
940
+ required: true
941
+ MD
942
+
943
+ manifest views.skippedIssues <<MD
944
+ when: List issues that were examined and passed over, with the reason. The
945
+ evidence that the claim rule is doing its job.
946
+ args:
947
+ practice:
948
+ type: NightShift.Practice
949
+ from: the practice to check
950
+ required: true
951
+ MD
952
+
953
+ manifest views.correctedVerdicts <<MD
954
+ when: List conclusions that a later run disproved, and where the disproof came
955
+ from. Read this before trusting an ordering or attribution heuristic.
956
+ args:
957
+ practice:
958
+ type: NightShift.Practice
959
+ from: the practice to check
960
+ required: true
961
+ MD
962
+
963
+ manifest views.consideredIssuesWithMergedWork <<MD
964
+ when: List issues where a merged pull request was found during the claim check —
965
+ the stale-label cases the queue label alone would have missed.
966
+ args:
967
+ practice:
968
+ type: NightShift.Practice
969
+ from: the practice to check
970
+ required: true
971
+ MD