tickmarkr 2.5.8 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/claude-code.js +19 -6
- package/dist/adapters/prompt.js +1 -1
- package/dist/adapters/qwen.js +30 -3
- package/dist/adapters/types.d.ts +3 -0
- package/dist/cli/commands/approve.js +15 -3
- package/dist/cli/commands/beat.d.ts +2 -0
- package/dist/cli/commands/beat.js +28 -29
- package/dist/cli/commands/compile.js +11 -0
- package/dist/cli/commands/fleet.js +61 -53
- package/dist/cli/commands/init.js +1 -1
- package/dist/cli/commands/report.js +11 -1
- package/dist/cli/commands/verify.d.ts +4 -1
- package/dist/cli/commands/verify.js +18 -5
- package/dist/cli/help.d.ts +2 -0
- package/dist/cli/help.js +6 -4
- package/dist/compile/native.js +39 -4
- package/dist/config/config.d.ts +41 -3
- package/dist/config/config.js +48 -17
- package/dist/config/fleet-overlay.js +47 -62
- package/dist/drivers/orca.d.ts +1 -1
- package/dist/drivers/orca.js +21 -4
- package/dist/gates/baseline.d.ts +67 -0
- package/dist/gates/baseline.js +172 -10
- package/dist/gates/cache.d.ts +8 -0
- package/dist/gates/cache.js +26 -13
- package/dist/gates/review.d.ts +8 -7
- package/dist/gates/review.js +83 -45
- package/dist/gates/run-gates.d.ts +4 -1
- package/dist/gates/run-gates.js +32 -12
- package/dist/gates/test-manifest.d.ts +16 -1
- package/dist/gates/test-manifest.js +127 -27
- package/dist/gates/test-reporter.js +4 -0
- package/dist/graph/graph.d.ts +1 -1
- package/dist/graph/graph.js +6 -1
- package/dist/graph/schema.d.ts +2 -0
- package/dist/graph/schema.js +2 -0
- package/dist/route/preference.d.ts +1 -1
- package/dist/route/preference.js +10 -39
- package/dist/run/daemon.d.ts +7 -1
- package/dist/run/daemon.js +237 -53
- package/dist/run/git.d.ts +10 -0
- package/dist/run/git.js +49 -1
- package/dist/run/journal.d.ts +18 -3
- package/dist/run/journal.js +141 -17
- package/dist/run/merge.d.ts +13 -2
- package/dist/run/merge.js +98 -12
- package/dist/run/protocol.d.ts +82 -0
- package/dist/run/protocol.js +35 -0
- package/dist/run/receipt-resolver.d.ts +18 -0
- package/dist/run/receipt-resolver.js +132 -0
- package/dist/run/supervision.d.ts +14 -1
- package/dist/run/supervision.js +122 -24
- package/dist/tui/cockpit/evidence-view.d.ts +10 -1
- package/dist/tui/cockpit/evidence-view.js +37 -5
- package/dist/tui/cockpit/live-runtime.d.ts +4 -0
- package/dist/tui/cockpit/live-runtime.js +37 -3
- package/dist/tui/cockpit/live-store.d.ts +2 -0
- package/dist/tui/ink/fleet-app.d.ts +12 -22
- package/dist/tui/ink/fleet-app.js +520 -131
- package/package.json +1 -1
- package/schema/rungraph.schema.json +7 -0
- package/skills/tickmarkr-overseer/SKILL.md +91 -41
- package/skills/tickmarkr-overseer/scripts/watch-context.sh +14 -2
package/package.json
CHANGED
|
@@ -62,7 +62,7 @@ through brief lineage. **An executor choice nobody made is still an executor cho
|
|
|
62
62
|
- **On herdr (`HERDR_ENV=1`)**: Every bundled `watch-*.sh` arm, including `watch-artifacts.sh`, sets `TKR_ARMING_SEAT=<seat>` and writes its own pid under
|
|
63
63
|
`<state-dir>/overseer/pids/<arming-seat>-<script>-<pid>.pid`. A seat retires only watchers it armed,
|
|
64
64
|
by reading those files and killing the exact recorded pids; it never uses `pkill -f`, `pgrep -f`, or
|
|
65
|
-
any argv/path pattern. A journal path is shared by partner tiers and therefore cannot prove ownership.
|
|
65
|
+
any argv/path pattern. The pre-arm beat probe lists unowned writers and is reconciled in the beat section; retiring a watcher this seat armed stays kill-by-recorded-pid and never that probe. A journal path is shared by partner tiers and therefore cannot prove ownership.
|
|
66
66
|
Verify each executing pid in two process-table reads before acting, kill-by-pid, arm the replacement,
|
|
67
67
|
then verify its new pid in two process-table reads. A stand-down order inventories both sets: the
|
|
68
68
|
ordering seat's recorded pids to retire, and the partner's watchers armed on the ordering seat that
|
|
@@ -72,7 +72,7 @@ through brief lineage. **An executor choice nobody made is still an executor cho
|
|
|
72
72
|
and nothing had been watching either file.
|
|
73
73
|
- **On Orca (`TERM_PROGRAM=Orca` and non-empty `ORCA_TERMINAL_HANDLE`)**: File and journal watchers record
|
|
74
74
|
owner pid and arm id beside the evidence files; a seat retires only watchers it armed, by those
|
|
75
|
-
recorded pids. It never uses `pkill -f`, `pgrep -f`, or any argv/path pattern. Verify each executing
|
|
75
|
+
recorded pids. It never uses `pkill -f`, `pgrep -f`, or any argv/path pattern. The pre-arm beat probe lists unowned writers and is reconciled in the beat section; retiring a watcher this seat armed stays kill-by-recorded-pid and never that probe. Verify each executing
|
|
76
76
|
pid in two process-table reads before acting. A stand-down inventories this seat's recorded pids
|
|
77
77
|
and the partner's watchers that must survive it.
|
|
78
78
|
**An adopted seat ANNOUNCES itself, in the same act as re-arming:** tell the adopted orchestrator the
|
|
@@ -614,6 +614,11 @@ run the Herdr pane commands or Herdr context watcher below.
|
|
|
614
614
|
verify every new pid twice, preserve the partner-owned watchers the stand-down lists, then confirm."
|
|
615
615
|
```
|
|
616
616
|
|
|
617
|
+
**Log every open per CITE-IS-NOT-READ:** the moment the returning seat opens `<handoff>` or
|
|
618
|
+
`<brief>`, append `opened <path>` to the append-only log `.tickmarkr/overseer/opened-files.log`
|
|
619
|
+
(create it if absent; never truncate or rewrite an existing line). On both hosts this log — not the
|
|
620
|
+
transcript — is the record a later handoff is measured against (OBS-1102).
|
|
621
|
+
|
|
617
622
|
⚠ **Steps 3 and 4 are two sends, never one.** A pointer batched with the clear lands *during* it and is
|
|
618
623
|
lost with the context it was meant to survive. Verify the clear landed by reading the prompt line
|
|
619
624
|
and re-reading the banner percentage below its pre-clear value before sending the pointer — the same
|
|
@@ -801,6 +806,12 @@ they are left implicit:
|
|
|
801
806
|
report INSIDE the worktree and to commit nothing — the overseer commits from the main checkout — or give the work to a
|
|
802
807
|
claude seat, or to a throwaway CLONE (a real `.git` directory). A brief that tells a codex-in-worktree seat to commit
|
|
803
808
|
buys a stall, not a commit.
|
|
809
|
+
|
|
810
|
+
**Every one-shot `codex exec` from an agent shell closes stdin (D-307-pre).** This skill has no
|
|
811
|
+
`codex exec` recipe — cross-vendor seats are spawned interactive — and the seat's ad-hoc one-shot
|
|
812
|
+
did not close stdin on that command. The agent shell left stdin open, and `codex exec` then
|
|
813
|
+
blocks on reading additional input from stdin (`Reading additional input from stdin…`) until the
|
|
814
|
+
pipe ends (42 minutes, measured). Run it as `codex exec … < /dev/null`.
|
|
804
815
|
4. **Gate every exec lane with the shipped battery, not hand-rolled greps.**
|
|
805
816
|
`tickmarkr verify --base <ref> --criteria <file>` is the standalone form of the engine's own gates —
|
|
806
817
|
build/test/lint diffed against a recorded baseline, evidence, scope, plus the semantic judges — one
|
|
@@ -821,8 +832,13 @@ they are left implicit:
|
|
|
821
832
|
- **Verified send protocol**:
|
|
822
833
|
- **On herdr (`HERDR_ENV=1`)**: `herdr agent send` writes WITHOUT Enter, and `pane run`'s Enter can be swallowed
|
|
823
834
|
by bracketed-paste on long payloads. Robust sequence: read the pane (bare prompt required) → send-text →
|
|
824
|
-
sleep 2–3s → send-keys Enter
|
|
825
|
-
|
|
835
|
+
sleep 2–3s → read back. Send `send-keys Enter` only when that read-back shows the staged text on the
|
|
836
|
+
composer and no permission prompt or numbered choice holds focus — an Enter sent onto an active prompt
|
|
837
|
+
approves it or picks a choice instead of submitting the brief (OBS-1119). When a prompt or choice holds
|
|
838
|
+
focus instead, resolve it first, then re-read before retrying. After a submitted Enter, read back once
|
|
839
|
+
more and confirm the composer is empty or the agent shows `working` — the pre-Enter read only proved
|
|
840
|
+
Enter was safe to send, not that the brief was submitted. Never report "briefed" without
|
|
841
|
+
both read-backs. Long content goes in a brief file, never pane text. `scripts/seat-send.sh` encodes
|
|
826
842
|
this whole path — size guard, atomic prompt, prompt-line read-back, optional interrupt — and never
|
|
827
843
|
auto-resends. Each adapter declares its prompt glyph beside its input-box matchers; `seat-send.sh` reads
|
|
828
844
|
that declaration rather than assuming Claude's `❯`.
|
|
@@ -997,49 +1013,69 @@ tier's state from a beat file the tier itself writes, so a seat that never beats
|
|
|
997
1013
|
run: `orchestrator ARMED / overseer ABSENT / watch ABSENT` for the whole milestone, with a live overseer
|
|
998
1014
|
watching it. Two thirds of that line were constants, not measurements.
|
|
999
1015
|
|
|
1000
|
-
The beat is one shipped command and
|
|
1001
|
-
`
|
|
1016
|
+
The beat is one shipped command and it arms through two explicit verbs, `--new-arm` and `--loop` —
|
|
1017
|
+
never a bare invocation. `--loop` already implies `--new-arm`: it creates a durable arm and beats in
|
|
1018
|
+
this process every 10 seconds, exiting on its own within one interval after a stand-down. Run it from
|
|
1019
|
+
the repo root as its own `run_in_background` Bash call:
|
|
1002
1020
|
|
|
1003
1021
|
```bash
|
|
1004
|
-
cd <repo> &&
|
|
1005
|
-
tickmarkr beat overseer --seat <overseer-agent-or-pane> --stand-down #
|
|
1022
|
+
cd <repo> && tickmarkr beat overseer --seat <overseer-agent-or-pane> --loop
|
|
1023
|
+
cd <repo> && tickmarkr beat overseer --seat <overseer-agent-or-pane> --stand-down # deliberately hand off; --loop exits
|
|
1006
1024
|
```
|
|
1007
1025
|
|
|
1008
|
-
The
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1026
|
+
**The legacy wrapper loop, `while :; do tickmarkr beat overseer --seat <pane>; sleep 10; done`, is the
|
|
1027
|
+
UNSAFE form and must not be used.** It is a bare one-shot call repeated by a shell loop the product
|
|
1028
|
+
cannot see, and it is the shape that re-armed a recorded stand-down (OBS-583, OBS-1088): a bare beat
|
|
1029
|
+
reuses whatever durable arm is already on disk instead of acknowledging the marker a stand-down just
|
|
1030
|
+
wrote, so a stray shell loop left running by a predecessor seat kept a stood-down tier reading ARMED.
|
|
1031
|
+
`--new-arm` and `--loop` are the only verbs that acknowledge a stand-down; a bare beat, wrapped in
|
|
1032
|
+
shell or not, never does. The pre-2.1.3 forms `while :; do tickmarkr beat overseer; sleep 10; done`
|
|
1033
|
+
and `tickmarkr beat overseer --stand-down` are preserved here only as older migration warnings: both
|
|
1034
|
+
are now rejected outright because neither declares which seat the tier speaks for. Do not copy or
|
|
1035
|
+
run either legacy form.
|
|
1036
|
+
|
|
1037
|
+
One beat per LIVE PROCESS, deliberately: `--loop`'s recorded pid is that process's own, so the tier's
|
|
1038
|
+
liveness is exactly as verifiable as the process table — stop the loop, or let it die, and the
|
|
1014
1039
|
tier ages to `STALE` (never `ABSENT`) within six beats, which is the state that says *armed, then lost*.
|
|
1015
1040
|
Stand down explicitly when you hand off, or a deliberate exit reads as a death. Same rule as rule 29
|
|
1016
1041
|
below, now with a conventional path the other tier already reads: `tickmarkr status` shows it.
|
|
1017
1042
|
|
|
1018
|
-
⚠
|
|
1043
|
+
⚠ **`--loop` NAMES A SEAT BUT STILL BINDS ITS LIFETIME TO A PROCESS — and that distinction is
|
|
1019
1044
|
load-bearing.** The command refuses an anonymous beat, and `status` renders the declared seat beside
|
|
1020
1045
|
the tier state; a legacy tier+pid+instant record cannot be attributed and reads `UNREADABLE`, never
|
|
1021
|
-
`ARMED`. Naming the seat does not
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1046
|
+
`ARMED`. Naming the seat does not prove that the named seat is still alive: its `--loop` process can
|
|
1047
|
+
outlive the seat's clear, re-brief, or replacement while that process remains alive. The current loop
|
|
1048
|
+
does not re-arm after stand-down: it observes the recorded marker and exits within one interval.
|
|
1049
|
+
|
|
1050
|
+
Measured 2026-08-24 (OBS-583), the now-unsafe legacy wrapper loop left a **2d20h** orphan from a
|
|
1051
|
+
predecessor seat holding `orchestrator ARMED` through a **three-hour window in which no orchestrator
|
|
1052
|
+
was alive**; that wrapper could also re-arm a recorded stand-down. On the same sweep the overseer tier
|
|
1053
|
+
had three beat writers, one owned by an unrelated session. The shipped `--loop` supersedes that wrapper,
|
|
1054
|
+
but its process ownership still needs a live check. So:
|
|
1055
|
+
|
|
1028
1056
|
- **Split the liveness reads.** A tier's liveness is read from beat freshness in the repository status
|
|
1029
|
-
path
|
|
1030
|
-
beat <tier> --seat <seat
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1057
|
+
path. The loop's liveness is read from the live process payload of both arm forms: the loop arm
|
|
1058
|
+
(`tickmarkr beat <tier> --seat <seat> --loop` in this repo) and the legacy wrapper
|
|
1059
|
+
(`while :; do tickmarkr beat <tier> --seat <seat>; sleep 10; done`). Neither liveness claim is read from a recorded pid:
|
|
1060
|
+
a pid recorded earlier can be stale, reused, or detached from the beat now holding the tier green.
|
|
1061
|
+
- **At every adopt, clear, or re-brief, sweep for pre-existing beat writers on YOUR tier before
|
|
1062
|
+
arming one** (`pgrep -f "tickmarkr beat <tier>"`, **read twice and intersected** — this exact probe
|
|
1063
|
+
returned its own shell as pid 14680 on 2026-08-31). **The PRIMARY target is the legacy
|
|
1064
|
+
`while … tickmarkr beat <tier>` wrapper**, which is why the pattern carries no `--loop` qualifier:
|
|
1065
|
+
a `--loop` exits by itself once your new arm replaces its own, but the wrapper's bare tick beats
|
|
1066
|
+
whatever arm is on disk, so it survives your re-arm and never exits on its own. Trace each survivor
|
|
1067
|
+
to its parent session. Stop an unowned writer only — never its parent — then verify the parent survived.
|
|
1068
|
+
**Reconcile this probe with the recorded-pid ownership rule.** That rule retires watchers this seat
|
|
1069
|
+
armed by the exact recorded pid, and it never uses `pkill -f`, `pgrep -f`, or an argv pattern. This
|
|
1070
|
+
probe is the listing of unowned legacy writers that have no pid file; the pattern stays
|
|
1071
|
+
`pgrep -f "tickmarkr beat <tier>"` with no `--loop` qualifier. A stop is kill-by-pid of an unowned
|
|
1072
|
+
survivor after the two reads. The probe does not retire a recorded pid.
|
|
1036
1073
|
- **`ARMED (<seat>)` is an attributable claim, not proof that the named seat is still alive.** Before
|
|
1037
|
-
trusting it, ask whose session owns the beater;
|
|
1038
|
-
(rule 11's outliving-its-trigger failure, in beat form).
|
|
1039
|
-
- Stand-down
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
until it ships, this sweep is the guard.
|
|
1074
|
+
trusting it, ask whose session owns the beater; a still-running `--loop` can keep naming a departed
|
|
1075
|
+
seat (rule 11's outliving-its-trigger failure, in beat form).
|
|
1076
|
+
- **Stand down with `--stand-down` and verify the `--loop` exits within one interval.** Do not use the
|
|
1077
|
+
legacy bare shell wrapper: unlike `--loop`, it cannot observe the marker and was the form that
|
|
1078
|
+
re-armed a stand-down.
|
|
1043
1079
|
|
|
1044
1080
|
Arm the bundled watcher as its OWN Bash call with `run_in_background` — chaining it after other commands
|
|
1045
1081
|
with `&` orphans it from the wake chain. It prints one wake reason and exits; re-arm after every wake.
|
|
@@ -1188,7 +1224,7 @@ orchestrator turn boundary.
|
|
|
1188
1224
|
|
|
1189
1225
|
### On Orca (`TERM_PROGRAM=Orca` and non-empty `ORCA_TERMINAL_HANDLE`) — supervision instruments
|
|
1190
1226
|
|
|
1191
|
-
At seat spawn, arm file/journal watchers for artifact completion, run events, missing progress and context evidence. Record each watcher owner and bounded expiry; renew on every wake and stop on stand-down. Read `orca terminal read --terminal <handle> --screen --json` on each wake to detect blocked or pending input. For a human gate, write a checkpoint evidence file and announce it through verified terminal send. Use Orca notifications only when the installed host advertises a notification capability; the current CLI has no `notification` command, so the file and terminal receipt remain the delivery path. A notification or accepted input alone never proves delivery or completion. A seat-liveness watcher on the ORCHESTRATOR handle is mandatory, not optional: poll `orca terminal read --terminal <handle> --screen --json` on a bounded interval
|
|
1227
|
+
At seat spawn, arm file/journal watchers for artifact completion, run events, missing progress and context evidence. Record each watcher owner and bounded expiry; renew on every wake and stop on stand-down. Read `orca terminal read --terminal <handle> --screen --json` on each wake to detect blocked or pending input. For a human gate, write a checkpoint evidence file and announce it through verified terminal send; the moment a successor opens that file (or any other cited file) back, log the open per CITE-IS-NOT-READ (`opened <path>` appended to `.tickmarkr/overseer/opened-files.log`). Use Orca notifications only when the installed host advertises a notification capability; the current CLI has no `notification` command, so the file and terminal receipt remain the delivery path. A notification or accepted input alone never proves delivery or completion. A seat-liveness watcher on the ORCHESTRATOR handle is mandatory, not optional: poll `orca terminal read --terminal <handle> --screen --json` on a bounded interval and key liveness on `result.terminal.status === "running"` — never on the envelope's own `ok`. `ok: true` proves only that the READ command executed; a closed seat's read still returns that same `ok: true` with `result.terminal.status: "exited"`, and a matcher keyed on `ok` reads that exited seat as alive and never fires (OBS-1087). Treat `result.terminal.status !== "running"`, `terminal_handle_stale`, or a missing terminal as seat death, and re-resolve by title before re-arming (OBS-1050 — the orchestrator seat exited silently and the daemon ran unsupervised to a PARTIAL run-end).
|
|
1192
1228
|
|
|
1193
1229
|
## Specialist pipeline rules
|
|
1194
1230
|
|
|
@@ -1353,10 +1389,11 @@ Create specialist seats using `orca terminal create --worktree path:<repo> --com
|
|
|
1353
1389
|
— the entry survived, but nothing had checked. `grep -c '^## OBS-<id>'` for each id the diff
|
|
1354
1390
|
introduced. A citation pointing at nothing is the defect the ledger itself files (OBS-604), shipped
|
|
1355
1391
|
into `src/`.
|
|
1356
|
-
- **
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1392
|
+
- **STAND DOWN THE BEAT THROUGH `--stand-down`, THEN VERIFY THE `--loop` EXITS.** The shipped loop
|
|
1393
|
+
observes the recorded marker and exits within one interval; it does not re-arm after the stand-down.
|
|
1394
|
+
Verify `status` reads `DISARMED` — which means *handed off*, distinct from `STALE` (armed then died)
|
|
1395
|
+
and `ABSENT` (never armed). A bare legacy shell wrapper is unsafe because it cannot observe that
|
|
1396
|
+
marker; do not substitute one for `--loop`.
|
|
1360
1397
|
- **RECORD YOUR WATCHERS AS DYING WITH THIS SESSION — never as "armed".** A written stand-down or
|
|
1361
1398
|
handoff may NOT carry the bare wording *"watcher armed"* for anything this seat owns: that form
|
|
1362
1399
|
states an act and lets the successor read a fact, and it survived into a handoff exactly once before
|
|
@@ -1411,7 +1448,12 @@ twice.** They are mission-independent on purpose: nothing here names a task, a l
|
|
|
1411
1448
|
|
|
1412
1449
|
1. **CITE-IS-NOT-READ.** A queue, handoff, finding, or brief that cites an observation does not prove its
|
|
1413
1450
|
author opened it. Before acting on a cited premise, open the primary record, quote the operative bytes,
|
|
1414
|
-
and state the qualifier or falsifier the citation would otherwise hide.
|
|
1451
|
+
and state the qualifier or falsifier the citation would otherwise hide. **On BOTH hosts, log the open:**
|
|
1452
|
+
append one line, `opened <path>`, to the append-only log `.tickmarkr/overseer/opened-files.log` (create
|
|
1453
|
+
it if absent; never truncate or rewrite an existing line) for every cited file this rule makes you open.
|
|
1454
|
+
Nothing else records which cited files a successor actually opened after a clear (OBS-1102) — this log
|
|
1455
|
+
is the record a later handoff is measured against: a claimed read with no matching line here did not
|
|
1456
|
+
happen.
|
|
1415
1457
|
2. **EXECUTING-FORM PROBE.** Process ownership starts from the watcher pid file. Where legacy discovery is
|
|
1416
1458
|
unavoidable, match the executing form — interpreter plus exact script path and arguments — not a journal
|
|
1417
1459
|
path or name substring, resolve the candidate's cwd/parent, read the arm log for startup failure, then
|
|
@@ -1522,6 +1564,14 @@ twice.** They are mission-independent on purpose: nothing here names a task, a l
|
|
|
1522
1564
|
the same root read the other way: a DETACHED loop outlives its seat and holds a tier `ARMED` with
|
|
1523
1565
|
nobody home (OBS-583). Neither direction may be assumed; the lifetime is a property of how the watcher
|
|
1524
1566
|
was launched, and it belongs in writing next to every claim that one is armed.
|
|
1567
|
+
**A seat's background tasks are bound to the seat's life (D-302 add.3).** An ad-hoc background task —
|
|
1568
|
+
an analysis heredoc, a one-shot shell — dies with the seat that launched it. Record its pid and kill
|
|
1569
|
+
that pid at stand-down, the same recorded-pid act as any other task this seat owns. Leave it attached
|
|
1570
|
+
to the seat so it is not reparented to pid 1 and left running after the seat is gone. A watcher this
|
|
1571
|
+
skill explicitly labels detached, with its heartbeat file, is the process that may outlive the seat.
|
|
1572
|
+
**Forbid the home-wide recursive glob by name:** `glob.glob('~/**/.tickmarkr/runs/*/journal.jsonl', recursive=True)`.
|
|
1573
|
+
That heredoc walked the whole home (`~/**`, every worktree, `node_modules`, Library) and ran orphaned
|
|
1574
|
+
for 30 hours at 100% CPU after its seat was gone. No seat glob starts at `~` or `$HOME`.
|
|
1525
1575
|
**And EVERY process-table probe has an idiom that defeats it, so the rule above needs the one test
|
|
1526
1576
|
that survives all of them. Lead with this; it is not the last resort, it is the first move:**
|
|
1527
1577
|
|
|
@@ -95,9 +95,21 @@ SEAT="$TARGET"
|
|
|
95
95
|
# would emit one before any successful read and break rule 2 outright, and a probe that parses the
|
|
96
96
|
# usage banner binds this script to another command's help text. Beating is what we do anyway, so it
|
|
97
97
|
# perturbs nothing — and because a beat only ever follows a successful read, rule 2 still holds.
|
|
98
|
+
# OBS-583/OBS-1088: a bare `tickmarkr beat` reuses whatever durable arm is already on disk, so a fresh
|
|
99
|
+
# script instance beating a tier a PRIOR instance stood down would either silently re-arm the stand-down
|
|
100
|
+
# (pre-fence) or, now that a stand-down fences the old arm, sit refused forever. The skill's beat recipe
|
|
101
|
+
# names that bare-call shape the unsafe legacy form for the same reason; this loop arms through the same
|
|
102
|
+
# explicit verb: `--new-arm` on the first beat only, so this instance's arm always acknowledges whatever
|
|
103
|
+
# marker is current before settling into ordinary per-tick beats.
|
|
98
104
|
beat_refused=0
|
|
105
|
+
armed=0
|
|
99
106
|
beat() {
|
|
100
|
-
|
|
107
|
+
new_arm=""
|
|
108
|
+
[ "$armed" -eq 0 ] && new_arm="--new-arm"
|
|
109
|
+
if tickmarkr beat "$TIER" --seat "$SEAT" $new_arm >/dev/null 2>&1; then
|
|
110
|
+
armed=1
|
|
111
|
+
return 0
|
|
112
|
+
fi
|
|
101
113
|
if [ "$beat_refused" -eq 0 ]; then
|
|
102
114
|
beat_refused=1
|
|
103
115
|
echo "TIER_UNREGISTERED ${TIER} — the product refused this tier (its set: src/run/supervision.ts:45)"
|
|
@@ -106,7 +118,7 @@ beat() {
|
|
|
106
118
|
fi
|
|
107
119
|
return 0
|
|
108
120
|
}
|
|
109
|
-
stand_down() { tickmarkr beat "$TIER" --stand-down --seat "$SEAT" >/dev/null 2>&1; return 0; }
|
|
121
|
+
stand_down() { armed=0; tickmarkr beat "$TIER" --stand-down --seat "$SEAT" >/dev/null 2>&1; return 0; }
|
|
110
122
|
# EVERY terminal exit — act, unsafe-act, cap — leaves through here, so none of them can forget to
|
|
111
123
|
# record the hand-off. A killed watcher never runs it, which is the one case that must read STALE.
|
|
112
124
|
cleanup() { stand_down; clear_pid; }
|