lobstah 0.6.3 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +533 -208
- package/dist/runner.js +17 -4
- package/docs/configuration.md +21 -1
- package/docs/man.md +69 -19
- package/docs/vocabulary.md +15 -6
- package/package.json +1 -1
package/dist/runner.js
CHANGED
|
@@ -739,6 +739,18 @@ function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
|
|
|
739
739
|
}
|
|
740
740
|
|
|
741
741
|
// packages/core/dist/config.js
|
|
742
|
+
var BRIEF_KINDS = ["conflict", "checks", "review", "ciFix", "rebase"];
|
|
743
|
+
function parseBriefHooks(raw) {
|
|
744
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
745
|
+
return void 0;
|
|
746
|
+
const out = {};
|
|
747
|
+
for (const kind of [...BRIEF_KINDS, "all"]) {
|
|
748
|
+
const text = raw[kind];
|
|
749
|
+
if (typeof text === "string" && text.trim())
|
|
750
|
+
out[kind] = text.trim();
|
|
751
|
+
}
|
|
752
|
+
return Object.keys(out).length ? out : void 0;
|
|
753
|
+
}
|
|
742
754
|
var ATTENTION_KINDS = ["question", "decision", "landed", "pr:draft", "pr:review", "pr:checks", "pr:conflict", "pr:ready", "report"];
|
|
743
755
|
var DEFAULT_ATTENTION_KINDS = ["question", "decision", "pr:ready", "pr:review", "pr:conflict", "pr:checks"];
|
|
744
756
|
function parseAttentionKinds(raw) {
|
|
@@ -766,7 +778,7 @@ var DEFAULT_HELM = {
|
|
|
766
778
|
armGraceSecs: 5
|
|
767
779
|
};
|
|
768
780
|
var DEFAULT_GLASS = { port: 4949 };
|
|
769
|
-
var DEFAULT_WATCH = { maxForksPerCycle: 3, autoRepair: true, conflicts: true, checks: true, maxRepairsPerPr: 2, repairSettleSecs: 600, repairTrapWaitSecs: 600 };
|
|
781
|
+
var DEFAULT_WATCH = { maxForksPerCycle: 3, autoRepair: true, conflicts: true, checks: true, maxRepairsPerPr: 2, maxRepairsWithoutProgress: 2, repairSettleSecs: 600, repairTrapWaitSecs: 600 };
|
|
770
782
|
var DEFAULT_LIMITS = {
|
|
771
783
|
maxConcurrent: 2,
|
|
772
784
|
choreConcurrent: 1,
|
|
@@ -809,7 +821,8 @@ function loadConfig() {
|
|
|
809
821
|
pushEarly: r.pushEarly === void 0 ? void 0 : Boolean(r.pushEarly),
|
|
810
822
|
draftPr: r.draftPr === void 0 ? void 0 : Boolean(r.draftPr),
|
|
811
823
|
checkpointOnStop: r.checkpointOnStop === void 0 ? void 0 : Boolean(r.checkpointOnStop),
|
|
812
|
-
humanGateChecks: Array.isArray(r.humanGateChecks) ? r.humanGateChecks.map(String).filter(Boolean) : void 0
|
|
824
|
+
humanGateChecks: Array.isArray(r.humanGateChecks) ? r.humanGateChecks.map(String).filter(Boolean) : void 0,
|
|
825
|
+
briefHooks: parseBriefHooks(r.briefHooks)
|
|
813
826
|
};
|
|
814
827
|
}
|
|
815
828
|
const groundsRaw = raw.grounds ?? {};
|
|
@@ -1728,11 +1741,11 @@ function chainPr(id, lane) {
|
|
|
1728
1741
|
// packages/core/dist/pr-repair.js
|
|
1729
1742
|
var PUSH_RETRIES = 3;
|
|
1730
1743
|
var PUSH_REJECTED = "push rejected:";
|
|
1731
|
-
function pushRule(branch, id = "<dispatch id>") {
|
|
1744
|
+
function pushRule(branch, id = "<dispatch id>", mode = "rebase") {
|
|
1732
1745
|
const b = branch ?? "the PR's head branch";
|
|
1733
1746
|
return [
|
|
1734
1747
|
`Push only to the existing branch ${b}.`,
|
|
1735
|
-
`If the push is rejected as non-fast-forward because ${b} moved, fetch ${b}, rebase your commits onto the moved head again, and push with \`--force-with-lease=${b}:<the head you just fetched>\`. Retry at most ${PUSH_RETRIES} times.`,
|
|
1748
|
+
mode === "merge" ? `If the push is rejected as non-fast-forward because ${b} moved, fetch ${b}, merge the moved head into your branch, and push again with a normal push. Retry at most ${PUSH_RETRIES} times. Never force-push.` : `If the push is rejected as non-fast-forward because ${b} moved, fetch ${b}, rebase your commits onto the moved head again, and push with \`--force-with-lease=${b}:<the head you just fetched>\`. Retry at most ${PUSH_RETRIES} times.`,
|
|
1736
1749
|
"If a push hook fails with a real test or type error, do not retry the push: fix the error, commit, and push again.",
|
|
1737
1750
|
`If you still cannot push, report \`lobstah report ${id} failed "${PUSH_REJECTED} <rejection text>; moved head <full sha of the head you fetched>"\` and leave the PR as it was.`,
|
|
1738
1751
|
"Never push to another branch. Never open a new PR."
|
package/docs/configuration.md
CHANGED
|
@@ -42,6 +42,25 @@ rather than relying on the default — left unset, a Claude session takes
|
|
|
42
42
|
`effortLevel` from the host's settings files, including the user's own
|
|
43
43
|
`~/.claude/settings.json`.
|
|
44
44
|
|
|
45
|
+
`[repos.<key>.briefHooks]` — markdown appended to the briefs lobstah
|
|
46
|
+
writes for this repo, one key per kind. Each value is a string; lobstah
|
|
47
|
+
appends it as written and does not read it.
|
|
48
|
+
|
|
49
|
+
| Key | Appended to |
|
|
50
|
+
|---|---|
|
|
51
|
+
| `conflict` | A daemon repair of a PR with a merge conflict. |
|
|
52
|
+
| `checks` | A daemon repair of a PR with failing checks. |
|
|
53
|
+
| `review` | A daemon repair of a PR with requested changes, and a pickup review-feedback round. |
|
|
54
|
+
| `ciFix` | A CI-fix continuation a PR watch forks. |
|
|
55
|
+
| `rebase` | A rebase chore from pickup's merge loop. |
|
|
56
|
+
| `all` | Every kind above, after that kind's own text. |
|
|
57
|
+
|
|
58
|
+
```toml
|
|
59
|
+
[repos.web.briefHooks]
|
|
60
|
+
all = "Before you report done, run the repo's PR refresh (`/pr-refresh`)."
|
|
61
|
+
checks = "Run `pnpm test:ci` before you push."
|
|
62
|
+
```
|
|
63
|
+
|
|
45
64
|
`lobstah repos add <path> [--pickup]` detects and appends a block (origin,
|
|
46
65
|
default branch from `origin/HEAD`, setup from the lockfile); `lobstah init
|
|
47
66
|
--scan <dir>...` does the same for every git repo found under the given
|
|
@@ -113,7 +132,8 @@ send a continuation.
|
|
|
113
132
|
| `conflicts` | `true` | Repair conflicts when `autoRepair` is on. Set `false` to show conflict attention without a repair. |
|
|
114
133
|
| `checks` | `true` | Repair failed current checks when `autoRepair` is on. Set `false` to show check attention without a repair. |
|
|
115
134
|
| `maxRepairsPerPr` | `2` | Maximum repair follow-ups for one PR head SHA. When the limit is reached and the issue remains, `pr:conflict`, `pr:checks`, or `pr:review` attention names the limit. A repair that waits is not an attempt. Below this limit, each failing check gets at most one repair round per PR and head SHA: a check that had its round and still fails on the same head waits for a new commit, with `repair.status: waiting` and `heldBy: repaired`, and raises `pr:checks` attention. A CI-fix continuation from `lobstah pick` (`autoRepair = false`) follows the same rule. Human gates (`[repos.<key>].humanGateChecks`, `report --human-gate`) get no round. |
|
|
116
|
-
| `repairSettleSecs` | `600` | A repair is queued only after the PR's head, its base branch's head, and its failing checks have been unchanged for this many seconds. Until then the PR record shows `repair.status: waiting` with `heldBy: settle` and `until`. |
|
|
135
|
+
| `repairSettleSecs` | `600` | A repair is queued only after the PR's head, its base branch's head, and its failing checks have been unchanged for this many seconds. A conflict repair also waits this many seconds after the PR's latest approval. Until then the PR record shows `repair.status: waiting` with `heldBy: settle` and `until`. |
|
|
136
|
+
| `maxRepairsWithoutProgress` | `2` | Maximum repairs in a row on one PR that end `done` while the PR stays at the head the repair pushed and does not merge. Past the cap, lobstah stops repairing that PR: the PR record shows `repair.status: gave-up`, `pr:conflict` (or `pr:checks`, `pr:review`) attention names the cap, and one `repair-stopped` notice is posted. The count resets when the PR merges or closes, when a push that is not the repair's moves the head, and on `lobstah watch release <key>` (or `--all`). |
|
|
117
137
|
| `repairTrapWaitSecs` | `600` | A daemon repair chore addressed to the PR-owning trap waits this many seconds for that trap. If still queued, it becomes headless. A person's addressed work never falls back. |
|
|
118
138
|
|
|
119
139
|
## `[grounds.*]` — helm territories
|
package/docs/man.md
CHANGED
|
@@ -192,20 +192,47 @@ with `paused --waiting-on pr` or `--waiting-on review` merges, the daemon
|
|
|
192
192
|
finishes that dispatch `done` with the note `the PR merged: <url>`. When
|
|
193
193
|
the PR closes without merge, it finishes it `failed` with `the PR closed
|
|
194
194
|
without merge: <url>`. The PR waited on is the `--link` when it names a
|
|
195
|
-
GitHub PR
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
`
|
|
200
|
-
|
|
195
|
+
GitHub PR that is not one of the dispatch's own. Otherwise the dispatch
|
|
196
|
+
waits on all of its own PRs (its evidence, which `lobstah catch` shows),
|
|
197
|
+
else its chain's PR, else the PRs of the `pr:` watches it owns. A
|
|
198
|
+
dispatch with several PRs finishes only when every one of them has merged
|
|
199
|
+
or closed: `done` when at least one merged (`the PRs merged: <urls>`, or
|
|
200
|
+
`the PRs ended — merged: <urls>; closed without merge: <urls>`), `failed`
|
|
201
|
+
when all closed without merge. Every paused dispatch waiting on those PRs
|
|
202
|
+
is finished, in the whole chain. The daemon does this after it observes PR watches and before its
|
|
203
|
+
cull pass, so `[limits].releaseOnMerge` releases the chain's worktrees in
|
|
204
|
+
the same pass. `report paused --waiting-on pr|review` registers the watch
|
|
205
|
+
of the dispatch's own PR when it has none. The daemon also reads, at
|
|
206
|
+
`[pickup].pollSecs`, each waited-on PR that no live dispatch-owned watch
|
|
207
|
+
observes (a linked PR with no watch, or a helm-owned watch), so its merge
|
|
208
|
+
or close is seen without `lobstah pick`. When lobstah knows no PR for the
|
|
209
|
+
wait, the report prints a `warning` and a merge will not finish the
|
|
210
|
+
dispatch: report again with `--link <PR url>`.
|
|
201
211
|
|
|
202
212
|
### PR state after done
|
|
203
213
|
|
|
204
214
|
A dispatch reports its PR with `report <id> <verb> --pr <url>`, which
|
|
205
215
|
registers a `pr:` watch for the chain so the PR stays observed (see the
|
|
206
216
|
PR preset in [vocabulary.md](vocabulary.md#the-pr-preset); `--no-watch`
|
|
207
|
-
opts out). A trap's PR is tracked from its first push.
|
|
208
|
-
|
|
217
|
+
opts out). A trap's PR is tracked from its first push.
|
|
218
|
+
|
|
219
|
+
A dispatch can own several PRs. `--pr` is repeatable: each PR is recorded
|
|
220
|
+
and gets its own `pr:` watch. The first is the dispatch's `prUrl`; all of
|
|
221
|
+
them are its `prUrls`. When a reported PR is part of a stack, the other PRs
|
|
222
|
+
of the stack are recorded too:
|
|
223
|
+
|
|
224
|
+
- a gh stack: the `gh-stack` state in the dispatch's checkout (from
|
|
225
|
+
`gh stack init` or `gh stack submit`) lists a stack that holds the PR;
|
|
226
|
+
- a base chain: the dispatch pushed two or more branches, and
|
|
227
|
+
`gh pr view <branch>` links their PRs to the reported one by base
|
|
228
|
+
branch.
|
|
229
|
+
|
|
230
|
+
The report prints `prs` with every PR it recorded. `lobstah catch` and
|
|
231
|
+
`lobstah status <id>` list each PR (`prs`), `man tend` lists each with its
|
|
232
|
+
state in the story's `pr` column, and the glass links each by number. Each
|
|
233
|
+
PR has its own record, so `pr:*` attention and the merged/closed notice are
|
|
234
|
+
per PR. `[limits].releaseOnMerge` keeps the worktree while another PR of
|
|
235
|
+
the dispatch is open. What you get depends on what runs:
|
|
209
236
|
|
|
210
237
|
- **Only the helm park or `man wait`** (no service): PR state badges in
|
|
211
238
|
`man tend`, `lobstah catch`, and the glass (`merged`, `draft`, `review`,
|
|
@@ -223,16 +250,21 @@ succeeds and the watch's check records `lastError`.
|
|
|
223
250
|
|
|
224
251
|
Which commands register a watch. Only these write points register one:
|
|
225
252
|
|
|
226
|
-
- `lobstah report <id> <verb> --pr <url
|
|
227
|
-
|
|
228
|
-
|
|
253
|
+
- `lobstah report <id> <verb> --pr <url> [--pr <url> ...]` registers the
|
|
254
|
+
watch for each PR the worker opened, and for the other PRs of a stack
|
|
255
|
+
that holds one of them. Any verb but `failed` does this. A PR already
|
|
256
|
+
watched is not registered again.
|
|
229
257
|
- `lobstah report <id> paused --waiting-on pr|review` registers the watch
|
|
230
|
-
for the dispatch's own PR. A `--link` to another PR registers nothing
|
|
258
|
+
for the dispatch's own PR. A `--link` to another PR registers nothing; the
|
|
259
|
+
daemon reads that PR while the dispatch waits on it.
|
|
231
260
|
- `lobstah soak beat` registers the watch for a trap's PR from its first
|
|
232
261
|
push. At most once a minute, it reads the trap's branch. When the branch
|
|
233
|
-
is not trunk
|
|
234
|
-
|
|
235
|
-
|
|
262
|
+
is not trunk, has an upstream, and its head commit is newer than the
|
|
263
|
+
dispatch's claim, it asks `gh pr view <branch>` for the PR. A trap that
|
|
264
|
+
takes new work on the branch of its last dispatch does not give that PR
|
|
265
|
+
to the new dispatch until the new dispatch commits. It records a new PR in
|
|
266
|
+
the dispatch's evidence, where `lobstah catch` and `lobstah status <id>`
|
|
267
|
+
show it.
|
|
236
268
|
- `lobstah watch add <key>` registers the watch you name.
|
|
237
269
|
- `lobstah watch backfill --apply` registers watches for PRs in old dispatch
|
|
238
270
|
history, and fetches the title of each PR record that has none (one
|
|
@@ -304,6 +336,8 @@ and the glass show the repair's PR, chore lane, worker, and trap wait.
|
|
|
304
336
|
PR whose head branch is its base branch.
|
|
305
337
|
- The PR's head, its base branch's head, or its failing checks changed less
|
|
306
338
|
than `[watch].repairSettleSecs` ago (default 600).
|
|
339
|
+
- For a conflict repair: the PR was approved less than
|
|
340
|
+
`[watch].repairSettleSecs` ago.
|
|
307
341
|
- For a checks repair: a fresh read of the latest run of each failing check
|
|
308
342
|
shows that run in progress or passed.
|
|
309
343
|
- The PR's watch is held. `lobstah cancel` on a repair dispatch holds its
|
|
@@ -322,13 +356,29 @@ in the `repairs waiting` table, the PR badge ends in `repair waits: <heldBy>`,
|
|
|
322
356
|
the glass PR modal shows the reason, and `lobstah doctor` lists it. When the
|
|
323
357
|
wait ends, the normal rules apply again.
|
|
324
358
|
|
|
359
|
+
**Repairs stop** on a PR after `[watch].maxRepairsWithoutProgress`
|
|
360
|
+
(default 2) repairs in a row that each ended `done` while the PR stayed at
|
|
361
|
+
the head the repair pushed and did not merge. lobstah then queues no repair
|
|
362
|
+
for that PR, marks its repair `gave-up`, raises `pr:conflict` (or
|
|
363
|
+
`pr:checks`, `pr:review`) attention that names the cap, and posts one
|
|
364
|
+
`repair-stopped` notice. The count resets when the PR merges or closes,
|
|
365
|
+
when a push that is not the repair's moves the head, and on
|
|
366
|
+
`lobstah watch release <key>`, which prints `repairsResumed` with the PRs it
|
|
367
|
+
resumed.
|
|
368
|
+
|
|
325
369
|
**A repair pushes** to its PR's head branch, and so does a rebase chore
|
|
326
370
|
from pickup's merge loop. The descriptor of each names its PR (`pr`), so
|
|
327
371
|
the runner pushes no branch and opens no PR for it. The brief gives the
|
|
328
|
-
worker the push rule: push only to the PR's head branch.
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
372
|
+
worker the push rule: push only to the PR's head branch. A conflict
|
|
373
|
+
repair of a **standalone** PR (its base is the repo's `trunk`) merges the
|
|
374
|
+
base into the PR branch with a merge commit and pushes normally; on a
|
|
375
|
+
non-fast-forward rejection it fetches the moved head, merges it, and
|
|
376
|
+
pushes again, never with force. A conflict repair of a **stacked** PR (its
|
|
377
|
+
base is another PR's branch) rebases onto that base and pushes with
|
|
378
|
+
`--force-with-lease`; on a rejection it rebases onto the moved head again
|
|
379
|
+
and pushes with a lease on the head just fetched. A checks or review
|
|
380
|
+
repair follows the rebase rule on a rejection. Each retries at most three
|
|
381
|
+
times. A push hook that fails with a real test or
|
|
332
382
|
type error is not retried: the worker fixes the error and pushes again.
|
|
333
383
|
For code already on main, the repair keeps main's version and only this
|
|
334
384
|
PR's own changes. It does not change behavior. If a conflict resolution
|
package/docs/vocabulary.md
CHANGED
|
@@ -83,9 +83,14 @@ Effects of `paused` with `--waiting-on`:
|
|
|
83
83
|
- With `--waiting-on pr` or `--waiting-on review`: when the PR it waits on
|
|
84
84
|
merges, the daemon finishes the dispatch `done` (`the PR merged: <url>`);
|
|
85
85
|
closed without merge, `failed`. The PR is the `--link` when it names a
|
|
86
|
-
GitHub PR
|
|
87
|
-
dispatch
|
|
88
|
-
|
|
86
|
+
GitHub PR that is not the dispatch's own. Otherwise it is every PR of the
|
|
87
|
+
dispatch (`prUrl` and `prUrls`), else its chain's PR, else the PRs of the
|
|
88
|
+
`pr:` watches the dispatch owns; the dispatch finishes when all of them
|
|
89
|
+
have ended. Every paused dispatch in the chain that waits on the PR is
|
|
90
|
+
finished. The report registers the watch of the
|
|
91
|
+
dispatch's own PR when it has none, and the daemon reads a waited-on PR
|
|
92
|
+
that no live dispatch-owned watch observes. When no PR is known, the
|
|
93
|
+
report prints a `warning`.
|
|
89
94
|
- No attention, no notice, no pet. It is a state, not a question.
|
|
90
95
|
|
|
91
96
|
Source of truth: `WAITING_ON` in `packages/core/src/types.ts`.
|
|
@@ -349,7 +354,7 @@ evidence).
|
|
|
349
354
|
| `draft` | Draft flipped (`value`). Evidence only. |
|
|
350
355
|
| `merged` / `closed` | Terminal; the check sets `done`, and the watch retires once delivered. Emitted only on an open → terminal change, never on the first observation. |
|
|
351
356
|
| evidence `pr` | `{ url, number, state, draft, reviewDecision, mergeStateStatus, headSha, checks: { total, passed, failed, pending, unknown? }, review: { unresolvedThreads, changesRequested, lastReviewAt }, observedAt }`. Check counts use only the latest run per check name and app/workflow. `CANCELLED` and `STALE` latest runs are unknown, not failed. The PR record also stores repair status, attempts, and reason. `prBadge` shows `repairing: conflict (attempt 1 of 2)` while a repair is in flight, and ends in `repair waits: <heldBy>` while a repair waits; tend, `catch`, and the glass share the badge. |
|
|
352
|
-
| waiting repair | `repair.status: waiting` on a PR record: a repair is due but is not queued. `heldBy` names the holder: `wt:<trap>` or `dispatch:<id8>` (a live worker holds the PR's head branch or the head branch of a PR below it in the stack), `helm` (the helm cancelled a repair of this PR), `hold` or `dispatch:<id8>` (`watch hold`), `settle` (the head, base head, or failing checks changed less than `[watch].repairSettleSecs` ago; `until` says when), or `checks` (the latest run of a failing check is in progress or passed). `reason` says what holds it. A wait is not an attempt and raises no attention item. |
|
|
357
|
+
| waiting repair | `repair.status: waiting` on a PR record: a repair is due but is not queued. `heldBy` names the holder: `wt:<trap>` or `dispatch:<id8>` (a live worker holds the PR's head branch or the head branch of a PR below it in the stack), `helm` (the helm cancelled a repair of this PR), `hold` or `dispatch:<id8>` (`watch hold`), `settle` (the head, base head, or failing checks changed less than `[watch].repairSettleSecs` ago, or, for a conflict repair, the PR was approved less than that ago; `until` says when), or `checks` (the latest run of a failing check is in progress or passed). `reason` says what holds it. A wait is not an attempt and raises no attention item. |
|
|
353
358
|
| repair chore | A daemon repair or rebase runs in the `chore` lane under `[limits].choreConcurrent`. A repair chore for a trap-built PR waits for its live owning trap up to `[watch].repairTrapWaitSecs` (default 600), then runs headless in its own PR-branch checkout. A headless-built PR's repair runs headless in its origin worktree when safe. No headless chore uses a trap's worktree. This bounded fallback applies only to system repair chores; a person's addressed work is sticky and never falls back. Tend, daemon status, doctor, and the glass show the PR, lane, worker, and trap wait. |
|
|
354
359
|
| live worker | An active headless dispatch, or a trap with an open catch. It holds a branch that its worktree has checked out, that its current branch tracks, or that it pushed during its current dispatch (evidence `pushes`). It holds a PR that its evidence names or that its chain owns. |
|
|
355
360
|
| evidence `pushes` | `[{ branch, at }]`: the branches a dispatch pushed, as lobstah saw them. The runner records its own pushes; the runner records a headless worker's `git push` from the harness event stream (branch names only); `soak beat` records a trap's `git push`. |
|
|
@@ -368,7 +373,11 @@ PR's head branch or a branch below it in the stack, until the PR has settled
|
|
|
368
373
|
for `[watch].repairSettleSecs`, while a failing check's latest run is in
|
|
369
374
|
progress or passed, and while the PR's watch is held. A wait is not an
|
|
370
375
|
attempt. A repair whose worker reported `failed "push rejected: ..."` is `blocked` at the
|
|
371
|
-
moved head and at the head it started from.
|
|
376
|
+
moved head and at the head it started from. After
|
|
377
|
+
`[watch].maxRepairsWithoutProgress` repairs in a row that left the PR at
|
|
378
|
+
their own push and unmerged, repairs of that PR stop (`gave-up`, a
|
|
379
|
+
`repair-stopped` notice) until it merges or closes, a push that is not the
|
|
380
|
+
repair's moves the head, or `lobstah watch release <key>`. The rest is evidence.
|
|
372
381
|
Merged and closed reach the helm as a `pr-merged` / `pr-closed` notice,
|
|
373
382
|
posted once by whichever process first records the open → terminal
|
|
374
383
|
transition on the **PR record** — not by event routing. A PR whose first
|
|
@@ -431,7 +440,7 @@ worktree is refused (the session lock); a stale one is adopted.
|
|
|
431
440
|
| defective enlistment | A stale registration that **never parked** — signed on but never listened (usually no Stop hook). Not swept: the helm gets a `trap-defective` notice with the remedy (`soak --wait`), and the registration stays so the address keeps protecting its work. |
|
|
432
441
|
| reserved trap | A trap `lobstah trap reserve` created before any session signs on as it: a name, a `wt:` id, and a one-time ticket, shown as `starting`. Work addressed to it waits. A session redeems the ticket with `soak --ticket` (or `LOBSTAH_TRAP_TICKET`) and signs on as that trap. Unredeemed past its deadline, it fails with a `trap-start-failed` notice and its work stays queued. `stow --wt <name>` withdraws it. |
|
|
433
442
|
| trap request | A trap the human asked for from the glass's **+ New trap** button: a `trap-request` request in `requests/<id>.json` with a repo and a harness. It wakes the helm as a `trap-request` event; the helm reserves it with `trap reserve --request <id>`, which closes it. |
|
|
434
|
-
| notice | The helm's attention channel for non-status events (`~/.lobstah/notices/`): reservations (`trap-starting`), reservations that did not start (`trap-start-failed`), trap requests from the glass (`trap-request`), sign-ons, first parks, sign-offs, ghosts, defective enlistments, orphaned work, bounced messages, PRs merged or closed, watches held over the fork cap (`watch-held`), failing (`watch-failing`), and recovered (`watch-recovered`), free-space holds (`disk-held`, `disk-cleared`), worktrees released after their PR merged (`worktree-released`, one per cull pass), a repair or rebase that could not push to its PR's branch (`push-failed`), and a human's answer to a decision (`decision-answer`; its ref is the request id in `~/.lobstah/requests/`). A trap leaves the registry only through a `trap-stowed` or `trap-ghosted` notice — the end-state is always explicit. Consumed by `man wait`/the park; a first park (`trap-listening`) is consumed without waking anyone. tend always shows the recent tail. |
|
|
443
|
+
| notice | The helm's attention channel for non-status events (`~/.lobstah/notices/`): reservations (`trap-starting`), reservations that did not start (`trap-start-failed`), trap requests from the glass (`trap-request`), sign-ons, first parks, sign-offs, ghosts, defective enlistments, orphaned work, bounced messages, PRs merged or closed, watches held over the fork cap (`watch-held`), failing (`watch-failing`), and recovered (`watch-recovered`), free-space holds (`disk-held`, `disk-cleared`), worktrees released after their PR merged (`worktree-released`, one per cull pass), a repair or rebase that could not push to its PR's branch (`push-failed`), repairs stopped on a PR that made no progress (`repair-stopped`), and a human's answer to a decision (`decision-answer`; its ref is the request id in `~/.lobstah/requests/`). A trap leaves the registry only through a `trap-stowed` or `trap-ghosted` notice — the end-state is always explicit. Consumed by `man wait`/the park; a first park (`trap-listening`) is consumed without waking anyone. tend always shows the recent tail. |
|
|
435
444
|
|
|
436
445
|
Delivery routes by ownership, same as watches: a continuation for a chain
|
|
437
446
|
claimed by a live trap is addressed back to that trap and stays sticky.
|