jinaga-server 3.7.5 → 3.8.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 (38) 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/integration-test/jinaga-test/package-lock.json +4 -4
  31. package/integration-test/jinaga-test/package.json +1 -1
  32. package/package.json +2 -2
  33. package/src/http/router.ts +31 -39
  34. package/src/http/stream.ts +21 -36
  35. package/src/jinaga-server.ts +92 -4
  36. package/test/http/streamLogVolumeSpec.ts +284 -0
  37. package/test/jinaga-server/poolConfigurationSpec.ts +147 -0
  38. package/test/jinaga-server/tracePoolSpec.ts +368 -0
@@ -0,0 +1,327 @@
1
+ ---
2
+ name: refining-issues
3
+ description: Turns a backlog issue in a night-shift repository into one that an unattended agent can implement, and turns a coupled set into a chain that stacks. Use when auditing whether an issue is ready for the queue label, when grouping issues for planning, when an issue's acceptance ends in an unmade decision, when two issues must land together, when an issue asks for a test that guards a redundancy rather than removing it or manufactures one by quoting a document, or when a change to an authority document has just changed how a set of issues is partitioned. Encodes eight checks — five that decide readiness and three that decide independence — plus the five moves that fix a failed check.
4
+ ---
5
+
6
+ # Refining issues
7
+
8
+ An issue is finished refining when an agent holding no context but the issue
9
+ body can implement it, and when landing it leaves the tree in a state somebody
10
+ would ship.
11
+
12
+ That is the bar the queue label asserts. `night-shift-worker` is what consumes
13
+ it: a scheduled agent reads the issue, the documents it cites, and works it with
14
+ nobody watching. Refining is what makes that possible. Applying the label is the
15
+ maintainer's call, never yours.
16
+
17
+ **Read `.night-shift/config.md` before you refine anything.** Three of its
18
+ headings decide how these checks run: `## Issue label` names the queue this
19
+ repository sweeps, `## Authority` names the documents an issue answers to and
20
+ what citing each one means, and `## Before you fix` says what the night shift
21
+ accepts as warrant. A missing required heading is a stop here for the same
22
+ reason it is a stop for the worker — say which one you could not find, and
23
+ refine nothing.
24
+
25
+ Eight checks decide it. Run R1 to R5 against one issue. Run I1 to I3 across a
26
+ set. Each failed check has one move.
27
+
28
+ Do not rewrite an issue that passes. A well-argued problem statement that
29
+ already carries criteria that can be shown false is done, and adding structure
30
+ to it costs review attention for nothing.
31
+
32
+ ## Readiness — run against one issue
33
+
34
+ ### R1. Criteria
35
+
36
+ Does the issue state acceptance criteria, and can each one be shown false?
37
+
38
+ A criterion names an observable change. "The importer refuses a row whose date
39
+ is not ISO-8601, naming the row and the value" is a criterion. "Add date
40
+ validation to the importer" is a task.
41
+
42
+ What shows a criterion false depends on what the issue delivers.
43
+
44
+ - **Behavior in code.** A test that drives the behavior, and can fail when
45
+ the behavior is wrong.
46
+ - **A document or a declaration.** A check that does not restate the text,
47
+ and can fail when the document is wrong. The check derives its expectation from the code the document
48
+ describes, runs the document's examples through the parser or compiler, or
49
+ reads an outcome in use, such as a live run whose recorded cost disagrees
50
+ with the declared one.
51
+ - **A document with no such check.** A reviewer reads a stated property of the
52
+ page and sees whether it holds. "The section shows the token counts and the
53
+ prices it multiplies" is a property. "The rate is derived correctly" names a
54
+ method, so no reader can see it fail.
55
+
56
+ Do not add a test to make a criterion pass R1. A test that fails only when
57
+ somebody edits the text it asserts on shows nothing false, so it cannot be what
58
+ satisfies a criterion, and `night-shift-worker` holds its regression tests to
59
+ the same bar. An acceptance that asks for one fails R5.
60
+
61
+ Fail R1 when the acceptance section is absent, or when it is a checkbox list of
62
+ work items, or when a bullet reads "resolved by a decision about X". That last
63
+ form is the most common miss, because a decision sitting in the criterion slot
64
+ looks like a criterion.
65
+
66
+ ### R2. Capability
67
+
68
+ Does the issue say what a caller can do after it lands that they cannot do now?
69
+
70
+ Read the acceptance and answer the question out loud. If the answer is a
71
+ restatement of the tasks, the issue describes work rather than an outcome.
72
+
73
+ R1 and R2 fail independently. An issue can carry twelve well-formed checkboxes
74
+ and still never say what changes.
75
+
76
+ ### R3. Premise
77
+
78
+ If the issue claims a caller *cannot* do something, find the mechanism in code
79
+ before you accept the framing.
80
+
81
+ An issue that opens with a capability gap and then offers directions has often
82
+ not proved the gap. Search the project's own user-facing documentation first —
83
+ its README and whatever `## Read first` names — because a capability that exists
84
+ is usually documented there already. Then read the source.
85
+
86
+ A wrong premise does not produce a wrong answer. It produces a correct answer
87
+ to the wrong question, and every direction under it reads as reasonable. The
88
+ cost is a large fix where a small one was needed.
89
+
90
+ **A decision already recorded is not a gap.** Where an authority document
91
+ records decisions taken, or tensions accepted as compromises, an issue whose
92
+ premise is "the project should not have decided X" is arguing with that record
93
+ rather than reporting a defect. That is a maintainer's question, not a slice:
94
+ say so and stop. What survives such an issue is whatever observable defect it
95
+ noticed in passing, scoped down to that.
96
+
97
+ ### R4. Anchor
98
+
99
+ Does the issue cite the documents `## Authority` names, in the form that
100
+ heading describes?
101
+
102
+ The night shift treats the issue body as an index into those documents, not as
103
+ a substitute for them. Authority usually comes in two roles, and a repository
104
+ may declare either, both, or neither:
105
+
106
+ - **What was decided.** A specification, an accepted design, an RFC. An issue
107
+ names the sections it answers to. Without them the agent guesses which
108
+ requirement it is implementing.
109
+ - **What decisions answer to.** A constitution, a set of principles, a review
110
+ rubric. An issue carries conformance criteria citing the ones each criterion
111
+ answers to. Without them a change can pass every test and still offend the
112
+ principle the repository holds itself to.
113
+
114
+ Fail R4 when the issue omits something `## Authority` requires. The fix is to
115
+ read the document and supply the citation, not to invent a requirement. Where no
116
+ section covers the behavior the issue wants, the issue is asking to amend the
117
+ document — which is the maintainer's decision, by the route `## Authority`
118
+ names, and never an implementation slice's to take.
119
+
120
+ **Where `## Authority` says `none`, R4 is vacuous. Record it as passed and say
121
+ why.** A repository that holds its issues to no document is a repository where
122
+ this check has nothing to read, which is not the same as an issue that skipped
123
+ it. R5 still runs: it does not depend on R4's documents.
124
+
125
+ ### R5. Remedy
126
+
127
+ Does the issue prescribe a remedy that removes the defect, or a guard that
128
+ stands over it?
129
+
130
+ Where `## Authority` names principles, R5 also asks whether the requirement
131
+ obeys the one the issue cited. That is independent of R4: an issue can cite a
132
+ principle correctly and then ask for precisely what it diagnoses. Where
133
+ `## Authority` says `none`, R5 still runs on the reasoning below, which needs no
134
+ document behind it.
135
+
136
+ The shape is a value written in more than one place, and an acceptance that asks
137
+ for a test asserting the copies agree. The redundancy is the defect. A test over
138
+ the copies leaves every copy standing, adds one more thing to maintain, and goes
139
+ red only when somebody edits one of them — so it converts a problem you could
140
+ have removed into a problem you now have to keep. The remedy is not a check that
141
+ rejects the disagreement; it is an arrangement in which the copies cannot
142
+ disagree, because there is only one.
143
+
144
+ Ask which copy is the source of truth, and whether the rest can be derived or
145
+ deleted. When they can, that deletion is the requirement, and the test that
146
+ would have guarded them has nothing left to compare.
147
+
148
+ **The shape has a second form, and it is the one that slips through.** Sometimes
149
+ the fact is written in exactly one place, and the acceptance asks for a test
150
+ that quotes it: "a test reads the built declaration and finds `byte-stable`", "a
151
+ test asserts the page names both rejection types". No pre-existing redundancy
152
+ exists to point at, so the first form does not match. The redundancy arrives
153
+ with the test. The criterion underneath is usually sound — a property of the
154
+ page that a reviewer can see hold or fail, which is what R1 asks of a document.
155
+ Only the test is the copy.
156
+
157
+ Both forms answer one question: what could this test go red for? When the answer
158
+ is "somebody reworded the thing it quotes", the acceptance is a copy — whether
159
+ it guards a redundancy that was already there or manufactures one that was not.
160
+
161
+ Fail R5 when the acceptance's subject is agreement between two representations
162
+ of one fact — a runtime validation, a lint, a CI step, or a test — rather than
163
+ the removal of one of them. Fail it too when the acceptance asks for a test
164
+ whose only possible failure is an edit to the text it quotes, even where that
165
+ text is the only copy in the tree. The move is **Remove the freedom** for both,
166
+ though the second form has less to remove.
167
+
168
+ Run R5 after R4 where `## Authority` names principles, because the cited one is
169
+ part of what R5 reads: an issue that fails R4 offers nothing to check the
170
+ requirement against. Where it says `none`, the order does not matter.
171
+
172
+ ## Independence — run across a set
173
+
174
+ ### I1. Reference
175
+
176
+ Do this issue's acceptance criteria name another issue's outcome?
177
+
178
+ That is the whole test. Two issues that edit the same file are independent when
179
+ neither one's criteria mention the other. Two issues that share no file are
180
+ coupled when one's check is satisfiable while the other's hole is open.
181
+
182
+ Coupling lives in shared invariants. A shared file is not coupling.
183
+
184
+ When the answer is yes, the coupling has to reach the issue body as a *Depends
185
+ on* line. The night shift sequences off that declaration alone and does not
186
+ infer order from the files an issue touches, so an undeclared dependency is
187
+ invisible to it: two sessions take the coupled pair, both branch from `main`,
188
+ and produce conflicting patches for one design. A declared one becomes a stack.
189
+
190
+ The reverse costs too. A *Depends on* that no criterion needs makes a free issue
191
+ wait for a blocked one, and the night shift will honor it.
192
+
193
+ ### I2. Dimension
194
+
195
+ Does the code this issue reads conflate the axis it cares about with another?
196
+
197
+ An issue inherits the dimensionality of what it reads. A predicate that ORs two
198
+ independent axes into one boolean forces every issue touching it to depend on
199
+ both, whether or not it cares about both. The dependency sits in the code rather
200
+ than in the work.
201
+
202
+ Hand-maintained consistency across two sites is one degree of freedom wearing
203
+ the costume of two, and the ripple it produces is coupling. An issue that fails
204
+ I2 has found surplus freedom in the representation. Where `## Authority` names
205
+ principles, saying which one it offends is usually the clearest statement of the
206
+ fix.
207
+
208
+ Fail I2 when the issue must wait for a decomposition rather than for a
209
+ behavior.
210
+
211
+ ### I3. Intermediate
212
+
213
+ For each order of a coupled pair, is there a state worth shipping in between?
214
+
215
+ Write the criterion for the halfway point. Usually one order has a coherent
216
+ intermediate and the reverse does not, and that asymmetry is the ordering.
217
+
218
+ The danger this check catches is specific. Whichever issue of a coupled pair
219
+ lands first ships a green test suite asserting a partial invariant, and a
220
+ passing test that claims coverage it does not have goes into every committed
221
+ baseline as real signal.
222
+
223
+ Once the order is written down, the pair costs nothing in wall-clock: the upper
224
+ layer branches from the lower one's branch and opens a stacked pull request, so
225
+ neither waits for the other to merge. Ordering is what the night shift needs;
226
+ serialization is not.
227
+
228
+ ## The five moves
229
+
230
+ **Extract a decision.** Several issues stalling on "Directions:" or "Decide
231
+ first" are often stalling on one decision in different words. Record it once,
232
+ outside all of them, in a design note kept wherever this repository keeps them.
233
+ Every issue that depended
234
+ on it becomes independent with no change to its scope. Answering separately
235
+ produces answers that need not agree. When the decision is one the spec already
236
+ owns — a default, a vocabulary choice, a division of responsibility — the note
237
+ is not yours to write: it is an amendment, and it lands by the route
238
+ `## Authority` names, by the maintainer.
239
+
240
+ **Remove the freedom.** When R5 fails, name the source of truth and rewrite the
241
+ acceptance as the deletion or derivation of every other copy. The guard the
242
+ issue asked for goes with them: with one statement left there is nothing to
243
+ compare. The guard does not need removing separately; it becomes vacuous.
244
+
245
+ Write two consequences into the issue. Say that no test asserting agreement is
246
+ to be added, because an agent reaching for evidence will otherwise supply one
247
+ and restore the freedom the issue just removed. And where one of the copies
248
+ lives in a document `## Authority` names, deleting it is an amendment, so the
249
+ issue has to declare itself one in its title and its acceptance. The night shift
250
+ stops and asks rather than guessing which kind of issue it holds.
251
+
252
+ Where the acceptance manufactures the copy rather than guarding one, there is
253
+ nothing to delete and the move is smaller: strike the test and keep the
254
+ criterion as a property a reviewer checks, or replace the test with one that
255
+ derives. A derived criterion names something the *code* can
256
+ falsify — a documented example that compiles against the shipped build, a
257
+ documented path that resolves against the filesystem, a default read back out of
258
+ the object the factory built. Each fails when the code changes, which is the
259
+ failure a document cannot produce on its own.
260
+
261
+ Where nothing derives, say so in the issue: the documentation stands on review,
262
+ and no test is to be added. That sentence is load-bearing for the same reason it
263
+ is in the first form. An agent held to a regression test, reading an acceptance
264
+ that names a sentence, will quote the sentence back.
265
+
266
+ **Decompose the axis.** When I2 fails, the fix belongs to whichever issue owns
267
+ the separation rather than to the issue that noticed it. Decomposing the predicate is
268
+ what makes the other issues perpendicular, so it is scope for the owner rather
269
+ than a new issue.
270
+
271
+ **Define the intermediate criterion.** When I3 finds a coherent halfway state,
272
+ give it to the issue that lands first. This converts a must-land-together pair
273
+ into a sequence, and it moves the shared invariant out of the gap and into an
274
+ issue that owns it. A note reading "whichever lands second must not reopen this"
275
+ is prose, and prose does not run.
276
+
277
+ **Split.** An issue holding more than one concern splits, even when the parts
278
+ share a file. Prefer the split when one part is unblocked today and another
279
+ waits on a dependency, because bundling makes the free part wait.
280
+
281
+ ## Worked example
282
+
283
+ `references/worked-example.md` runs R1 to R3, R5, and I1 to I3 plus both
284
+ structural moves over one backlog, and closes each with the shape to recognize. The domain
285
+ is invented so nothing in it decays as a real backlog is worked. Read it when a
286
+ check's description is not enough to recognize what is in front of you.
287
+
288
+ R4 has no shape section because it is a presence check: the sections are named
289
+ or they are not.
290
+
291
+ ## Writing the refined issue
292
+
293
+ Write the title as the defect, then "so", then the consequence. "`start()` has
294
+ no bound, so an unreachable server holds a boot path open."
295
+
296
+ Body leads with what happened or what the mechanism is, cites the code by path
297
+ and line, and closes with acceptance. A serviceable order: the mechanism in
298
+ prose; **Measured** or **Demonstrated**, showing the behavior against something
299
+ real; **Build** or **Proposal**; **Tests**; **Conformance**, naming what each
300
+ criterion answers to; **Depends on**. Drop **Conformance** where `## Authority`
301
+ says `none` — a heading with nothing to cite is a heading that gets filled in
302
+ with something invented.
303
+
304
+ A documentation slice may carry no **Tests** entry at all: its criteria are
305
+ properties a reviewer checks, which R1 accepts. Every entry that is there has to
306
+ be able to fail for a reason other than an edit to its own subject. This is the
307
+ sentence R5 most often catches too late: a documentation slice feels like it
308
+ needs a test, a quotation is the only one available, and writing it here is what
309
+ puts it in the suite. The night shift implements the acceptance it is given.
310
+
311
+ Name the interaction with any issue that shares an invariant, and say which one
312
+ must not reopen the gap.
313
+
314
+ Say plainly what the issue no longer claims when a check removed part of it. A
315
+ reader who remembers the old framing needs to know it is gone, and the removed
316
+ argument does not belong in the body. This is `CLAUDE.md`'s no-reversed-decision
317
+ rule applied to a tracker: the refined issue describes only what is wrong now.
318
+
319
+ Refining destroys the evidence. An issue that passes the checks no longer shows
320
+ the defect that made it fail them, and a tracker keeps no body history a later
321
+ reader can reach. GitHub's timeline API returns `renamed` and `labeled` events
322
+ and never the previous body.
323
+
324
+ So an issue is a poor place to point somebody who needs to learn a shape. It is
325
+ also a decaying one, because the code a good example quotes is usually the code
326
+ the issue deletes. Teach from a constructed case that holds the shape, and keep
327
+ the issue number as provenance for a reader who wants the original.
@@ -0,0 +1,234 @@
1
+ # Worked example
2
+
3
+ One backlog. The project is a deployment CLI: it builds an artifact, deploys it
4
+ to staging, and promotes a staging build to production.
5
+ It has an auth check on its deploy API, a `--dry-run` flag, and a `help`
6
+ command.
7
+
8
+ The domain is invented so the shapes stay legible outside any one codebase.
9
+ The shapes are not. See Provenance at the end.
10
+
11
+ ## R1 Criteria — a decision in the criterion slot
12
+
13
+ An issue lists four confusing error messages and closes with acceptance. Three
14
+ bullets can be shown false. The fourth:
15
+
16
+ > - Case 4 is resolved by a decision about which registry format the artifact
17
+ > digest uses, and the `help` text matches that decision.
18
+
19
+ It has the grammar of a criterion. It names no observable change and cannot be
20
+ shown false, because what it requires is that somebody choose. Three quarters
21
+ of the issue is implementable and the fourth quarter is a question wearing a
22
+ criterion's clothes.
23
+
24
+ **The shape:** an acceptance bullet whose verb is *decide*, *resolve*,
25
+ *determine*, or *clarify*.
26
+
27
+ ## R2 Capability — a task list that never states an outcome
28
+
29
+ An issue about unvalidated deploy manifests carries eleven checkboxes across
30
+ design, implementation, and rollout, plus a stated fix ordering. It reads as
31
+ the most complete issue in the backlog. One bullet:
32
+
33
+ > - [ ] Add `validateManifest` to `src/deploy/manifest.ts`, sibling to
34
+ > `loadManifest`: walk the parsed tree and check every referenced image tag
35
+ > resolves in the registry.
36
+
37
+ That is a precise task. Nowhere does the issue say what an operator can do
38
+ afterward that they cannot do now. The criterion it lacks is one sentence:
39
+ *deploy refuses a manifest that references an image tag the registry does not
40
+ hold, naming the tag.*
41
+
42
+ **The shape:** an issue you could hand to an implementer that leaves a reviewer
43
+ unable to say what changed. R1 passes, R2 fails, and the two fail
44
+ independently.
45
+
46
+ ## R3 Premise — a capability gap that was not there
47
+
48
+ An issue titled "An operator cannot see what a deploy will change without
49
+ running it" opens:
50
+
51
+ > This issue is a request for a strategy rather than a patch, because the two
52
+ > candidate patches pull against each other.
53
+
54
+ and offers four directions, the largest of which restructures how the CLI holds
55
+ a plan.
56
+
57
+ The premise is false. `deploy --dry-run` prints the plan and exits, and
58
+ `help deploy` documents it. All four directions solve a problem that does not
59
+ exist.
60
+
61
+ One real defect the issue mentions in passing survives: the dry-run output
62
+ omits image digests, so an operator cannot tell two builds of the same tag
63
+ apart. The issue scopes down to that.
64
+
65
+ **The shape:** an issue that opens with "the caller cannot X" and proceeds to
66
+ directions without ever showing the code that refuses. Check the product's own
67
+ help text before the handler, because a capability that exists is usually
68
+ documented there already.
69
+
70
+ ## R5 Remedy — a guard where the freedom should have been removed
71
+
72
+ The promote timeout is written in three places: `help promote` prints it in
73
+ prose, `config/defaults.yml` sets it, and the deploy API client hard-codes the
74
+ same number as its own fallback. Nothing ties them together, and they agree
75
+ today by hand. An issue notices this and closes with:
76
+
77
+ > - A test reads the timeout from all three and asserts they agree.
78
+
79
+ The criterion is observable and can be shown false, so R1 passes. It names an
80
+ outcome, so R2 passes. The drift is real and demonstrated, so R3 passes. It cites
81
+ the principle its repository holds duplication to, so R4 passes. And it asks for
82
+ exactly what that principle diagnoses.
83
+
84
+ Three independent variables stand where the problem has one, and the acceptance
85
+ adds a fourth thing to maintain rather than removing two. The remedy is to name
86
+ `config/defaults.yml` the source, have the client read it instead of carrying a
87
+ fallback, and have `help promote` print the value instead of spelling it. Then
88
+ no test has anything left to compare.
89
+
90
+ **The shape:** an acceptance whose subject is agreement between copies. The
91
+ issue has found surplus freedom and asked for a guard to stand over it.
92
+
93
+ ## R5 Remedy — a copy the acceptance creates
94
+
95
+ `promote --wait` blocks until the deploy settles, and its help text does not say
96
+ that cancelling the wait leaves the deploy running. An issue adds the sentence
97
+ and closes with:
98
+
99
+ > - `promote --wait`'s help text says that cancelling the wait does not cancel
100
+ > the deploy.
101
+ > - A test reads `promote --help` and asserts it contains that sentence.
102
+
103
+ Nothing is written twice here. The help text is the only place that fact lives,
104
+ and the issue is right that it belongs there. The first bullet is a criterion,
105
+ a property a reviewer can see hold or fail, so R1 passes. It names an outcome, so R2
106
+ passes. An operator really did cancel a wait and assume the deploy stopped, so
107
+ R3 passes. The principle about keeping an explanation in one place is cited,
108
+ correctly, so R4 passes.
109
+
110
+ The second bullet is not a criterion about the product at all. It prescribes a
111
+ test, and the test is the copy that arrives with the acceptance. It can go red
112
+ for one reason: somebody rewords the sentence. It cannot notice that cancelling
113
+ now *does* cancel the deploy, which is the only thing worth knowing. It freezes
114
+ the wording and leaves the behavior unguarded.
115
+
116
+ What derives here is the flag, not the sentence. A check that every flag the
117
+ parser registers appears in `--help`, and that nothing else does, fails when
118
+ somebody adds or renames a flag without documenting it — a failure the code
119
+ produces. The refined acceptance keeps the criterion, strikes the test, and
120
+ says no test is to be added for the sentence: it stands on review.
121
+
122
+ **The shape:** an acceptance that quotes a document back to itself. The first
123
+ form guards a redundancy that exists; this one manufactures one that did not,
124
+ which is why reading for surplus freedom does not find it.
125
+
126
+ ## I1 Reference — a shared invariant across no shared file
127
+
128
+ Issue A adds an authorization check to the deploy API route. Issue B removes an
129
+ internal scheduler that calls the deploy handler directly, bypassing the route.
130
+
131
+ They edit different files. They are not independent. A's criteria are all
132
+ satisfiable while the scheduler still reaches the handler, so an unauthorized
133
+ deploy still happens and A's tests are green.
134
+
135
+ **The shape:** two issues whose criteria are each complete and whose
136
+ conjunction is the actual invariant. Neither body has to mention the other for
137
+ the coupling to be real, which is why the check reads the criteria rather than
138
+ the file list.
139
+
140
+ ## I2 Dimension — waiting on a decomposition rather than a behavior
141
+
142
+ An issue makes `status` report whether the working tree is safe to switch
143
+ branches. Its first draft:
144
+
145
+ > - The answer is derived from the state `status` already reports. No new
146
+ > stored field.
147
+
148
+ The second sentence is right and the first is wrong. `status` reports one
149
+ boolean that ORs two independent axes:
150
+
151
+ ```
152
+ pending = hasUncommittedEdits() || hasUnpushedCommits()
153
+ ```
154
+
155
+ Branch safety depends on the first alone, and the disjunction loses it in
156
+ exactly the ordinary case:
157
+
158
+ | `pending` | unpushed | uncommitted edits |
159
+ |---|---|---|
160
+ | false | any | false |
161
+ | true | 0 | true |
162
+ | true | above 0 | unknown |
163
+
164
+ The third row is the common one. So the dependency is not on another behavior.
165
+ It is on a predicate being split along the axis this issue cares about, and
166
+ that split belongs to whichever issue owns separating the two.
167
+
168
+ **The shape:** an issue that cannot be stated cleanly because a value it must
169
+ read conflates two things. The dependency sits in the code rather than in the
170
+ work.
171
+
172
+ ## I3 Intermediate — the order falls out of the halfway state
173
+
174
+ Take the coupled pair from I1 and write the criterion for each order.
175
+
176
+ **B first.** The intermediate is *every deploy path goes through the route*,
177
+ true by removal alone. Worth shipping on its own. A then adds *the route
178
+ authorizes the caller*.
179
+
180
+ **A first.** The intermediate is *the route authorizes, except the path that
181
+ skips it*. Not worth shipping, and worse than not shipping, because it lands a
182
+ green test suite over an open hole and that green goes into every later
183
+ baseline as real signal.
184
+
185
+ Only one order has a coherent halfway state. That asymmetry is the ordering.
186
+
187
+ ## Split — one issue, three concerns
188
+
189
+ One issue holds four confusing error messages and two stale help topics. Sorted
190
+ by what each part actually is:
191
+
192
+ - Three message fixes, extending a pattern that already exists, blocked on
193
+ nothing.
194
+ - One format change with a compatibility rationale, coupled to another issue
195
+ under I1.
196
+ - Two help topics that are stale because a newer flag replaced what they
197
+ describe, wrong today for a reason unrelated to either.
198
+
199
+ Three issues. The message fixes stop waiting on a decision that is not theirs,
200
+ and the help fix stops waiting on both.
201
+
202
+ **The shape:** a single issue whose parts have different blockers. Bundling
203
+ makes the free part wait for the blocked one.
204
+
205
+ ## Extract — four issues, one decision
206
+
207
+ Four issues each end without a decision:
208
+
209
+ - Which component owns retry policy for a failed deploy?
210
+ - Which component owns retry policy for a failed registry push?
211
+ - Should a partial rollout retry the failed shards or the whole batch?
212
+ - Where does the retry budget live?
213
+
214
+ Four phrasings of one question: which layer owns retry, and against what
215
+ budget. Recording the answer once, in a design note outside all four, makes
216
+ every one of them independent without changing any of their scope. Answered
217
+ separately, they produce four answers that need not agree.
218
+
219
+ ## Provenance
220
+
221
+ Every shape here was found in a real backlog audit of `jinaga/factual-mcp` in
222
+ September 2026, across issues 351, 373, 377, 404, 405, 406, 412, 415, and 416.
223
+ The R5 shapes came from `jinaga/jinaga-worker`: the first from #52 in the same
224
+ month, the second from #19, #22 and #39, whose acceptance sections each asked
225
+ for a test quoting a document back to itself and got one.
226
+
227
+ The real cases are not reproduced, for two reasons. They carry domain
228
+ vocabulary that costs a reader more than the shape is worth. And each one
229
+ quotes code that the issue describing it deletes, so a faithful transcript
230
+ starts decaying the moment the backlog is worked.
231
+
232
+ Read the issues if you want the originals. Expect them to have been refined,
233
+ and expect no previous body to be reachable: a tracker keeps no history of an
234
+ issue's text, so what made an issue fail a check is gone once it passes.
@@ -4,11 +4,11 @@ name: CI
4
4
 
5
5
  # Controls when the workflow will run
6
6
  on:
7
- # Triggers the workflow on push or pull request events but only for the main branch
7
+ # Triggers on pushes to main, and on every pull request whatever its base,
8
+ # so each layer of a stacked chain gets its own check runs
8
9
  push:
9
10
  branches: [ main ]
10
11
  pull_request:
11
- branches: [ main ]
12
12
 
13
13
  # Allows you to run this workflow manually from the Actions tab
14
14
  workflow_dispatch:
@@ -0,0 +1,84 @@
1
+ # Night shift configuration
2
+
3
+ The `night-shift-worker`, `night-shift-coordinator`, and `refining-issues`
4
+ skills read this file. Every `##` heading below except `## Branch prefix` is
5
+ required. A missing heading is an error, not a default: stop and name the
6
+ heading you could not find. Anything that is not one of these headings is
7
+ protocol, and protocol lives in the skill.
8
+
9
+ ## Visibility
10
+
11
+ `public`
12
+
13
+ There is nothing to withhold here. One sibling repository in this practice is
14
+ private, so never carry its contents into an issue or pull request in this one.
15
+
16
+ ## Issue label
17
+
18
+ `ready`
19
+
20
+ ## Read first
21
+
22
+ - `CLAUDE.md` — commands, layers, storage implementations, and where the
23
+ Specification-to-SQL translation lives.
24
+ - The documents under `## Authority`, at the articles the issue cites.
25
+
26
+ ## Authority
27
+
28
+ - `.claude/skills/degrees-of-freedom/degrees-of-freedom-constitution.md` — the
29
+ principles a design answers to. An issue's **Conformance** section cites the
30
+ article each criterion answers to. An amendment to it is the maintainer's
31
+ decision and never lands in an implementation slice.
32
+
33
+ ## Before you fix
34
+
35
+ Reproduce first. An issue's repro may have been reconstructed rather than
36
+ verified by its reporter, so a repro that fails is a finding, not a failure.
37
+ Report it and open no pull request.
38
+
39
+ Much of this server's behavior comes from the `jinaga` library it depends on.
40
+ A defect may live there rather than here, and may already be fixed in a newer
41
+ `jinaga` release. Check which side of that boundary the defect is on before
42
+ changing code in this repository.
43
+
44
+ ## Verification commands
45
+
46
+ Green before every push, in this order.
47
+
48
+ ```
49
+ npm ci
50
+ npm run build
51
+ npm test
52
+ ```
53
+
54
+ The container starts with no `node_modules`, so `npm ci` is not optional, and a
55
+ stale `node_modules` fails the build against types the current `jinaga`
56
+ exports. `npm test` type-checks and runs Jest without a database.
57
+
58
+ `npm run integration` needs Docker and PostgreSQL and is not part of the bar.
59
+
60
+ ## CI workflow
61
+
62
+ `main.yml`
63
+
64
+ Read runs for this file; it is the merge gate. It runs on a bare
65
+ `pull_request:` with no `branches:` filter, so every layer of a stack gets
66
+ check runs from its own pull request event.
67
+
68
+ `publish.yml` and `upgrade-jinaga.yml` do not gate a pull request. Address the
69
+ workflow by this file name rather than by its display name, `CI`.
70
+
71
+ ## After the pull request
72
+
73
+ `none`
74
+
75
+ ## What is different about this repository
76
+
77
+ This is a published npm package whose queue is mostly defects reported against
78
+ released versions. An issue may not reproduce at all, and saying so with
79
+ evidence is the whole result. Do not manufacture a fix to justify the session.
80
+
81
+ `upgrade-jinaga.yml` opens a pull request daily when a new `jinaga` is
82
+ published, on a branch named `upgrade/jinaga-<version>`. Those pull requests
83
+ are not night-shift work and are not prior work for an issue, unless the issue
84
+ is the upgrade itself.
@@ -0,0 +1,17 @@
1
+ # Installed skills
2
+
3
+ These skills are installed here as committed copies. They are not fetched at run
4
+ time: an upstream edit would otherwise change what an unattended run does
5
+ without anyone reviewing it, and a network install adds a failure mode at
6
+ whatever hour the run wakes.
7
+
8
+ | Skill | Source | Upstream commit |
9
+ |---|---|---|
10
+ | `night-shift-worker` | `factoryengineering/skills` | `2fb85d8297c0a3059365bd809b8242f5657f2740` |
11
+ | `refining-issues` | `factoryengineering/skills` | `2fb85d8297c0a3059365bd809b8242f5657f2740` |
12
+ | `degrees-of-freedom` | `michaellperry/skills` | `3722c778facbfccc609a928d25ffb22e1ba461e6` |
13
+ | `night-shift-setup` | `factoryengineering/skills` | `2fb85d8297c0a3059365bd809b8242f5657f2740` |
14
+
15
+ To take an upstream change, re-copy the skill directory from its source, update
16
+ its commit above, and read the diff before you push. Local edits to an installed
17
+ skill belong upstream instead, or the next update silently reverts them.