@oneie/claude 0.8.0 → 0.10.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 (230) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/agents/abm-strategist.md +67 -1
  3. package/agents/ads-meta.md +67 -1
  4. package/agents/analyst.md +67 -1
  5. package/agents/animator.md +108 -0
  6. package/agents/architect.md +269 -20
  7. package/agents/brand-guardian.md +67 -1
  8. package/agents/brand-strategist.md +67 -1
  9. package/agents/campaign-content.md +67 -1
  10. package/agents/campaign-email.md +67 -1
  11. package/agents/campaign-sms.md +67 -1
  12. package/agents/campaign-social.md +67 -1
  13. package/agents/cco.md +83 -2
  14. package/agents/ceo.md +108 -11
  15. package/agents/chairman.md +197 -0
  16. package/agents/cmo.md +82 -2
  17. package/agents/community-greeter.md +67 -1
  18. package/agents/community-moderator.md +67 -1
  19. package/agents/compliance.md +67 -1
  20. package/agents/copywriter.md +67 -1
  21. package/agents/creative-strategist.md +67 -1
  22. package/agents/cro.md +81 -1
  23. package/agents/cto.md +266 -28
  24. package/agents/customer-interviewer.md +67 -1
  25. package/agents/customer-researcher.md +67 -1
  26. package/agents/customer-success-manager.md +67 -1
  27. package/agents/customer-trainer.md +67 -1
  28. package/agents/cxo.md +82 -1
  29. package/agents/demand-creator.md +67 -1
  30. package/agents/demo-mover.md +67 -1
  31. package/agents/demo-specialist.md +67 -1
  32. package/agents/demo-thai-family-law.md +67 -1
  33. package/agents/designer.md +67 -1
  34. package/agents/discovery-caller.md +67 -1
  35. package/agents/doctor.md +269 -0
  36. package/agents/educate-coach.md +67 -1
  37. package/agents/elevate-tutor.md +67 -1
  38. package/agents/email-lifecycle-marketer.md +67 -1
  39. package/agents/engage-specialist.md +67 -1
  40. package/agents/events-coordinator.md +67 -1
  41. package/agents/foundation-builder.md +67 -1
  42. package/agents/funnel-architect.md +67 -1
  43. package/agents/gift-creator.md +67 -1
  44. package/agents/google-ads.md +67 -1
  45. package/agents/guide.md +67 -1
  46. package/agents/helpdesk-dispatcher.md +67 -1
  47. package/agents/hook-specialist.md +67 -1
  48. package/agents/identify-optimizer.md +67 -1
  49. package/agents/implementer.md +313 -45
  50. package/agents/incident-commander.md +67 -1
  51. package/agents/insights-lead.md +87 -1
  52. package/agents/journey-runner.md +67 -1
  53. package/agents/linkedin-ads.md +67 -1
  54. package/agents/live-sales-chat.md +67 -1
  55. package/agents/market-researcher.md +67 -1
  56. package/agents/media-buyer.md +67 -1
  57. package/agents/memory-keeper.md +195 -0
  58. package/agents/movers-customer-researcher.md +67 -1
  59. package/agents/movers-foundation-builder.md +67 -1
  60. package/agents/movers-market-researcher.md +67 -1
  61. package/agents/movers-pricing-strategist.md +67 -1
  62. package/agents/nurture-architect.md +67 -1
  63. package/agents/offer-architect.md +67 -1
  64. package/agents/onboarder.md +67 -1
  65. package/agents/onboarding-specialist.md +67 -1
  66. package/agents/operations-dashboard.md +87 -1
  67. package/agents/perf-engineer.md +333 -37
  68. package/agents/playbook-writer.md +67 -1
  69. package/agents/plg-strategist.md +67 -1
  70. package/agents/positioning-architect.md +67 -1
  71. package/agents/press-officer.md +67 -1
  72. package/agents/pricing-strategist.md +67 -1
  73. package/agents/privacy-officer.md +67 -1
  74. package/agents/referral-manager.md +67 -1
  75. package/agents/refine-analyst.md +67 -1
  76. package/agents/release-manager.md +446 -39
  77. package/agents/renewals-upsell-rep.md +67 -1
  78. package/agents/review-engineer.md +319 -45
  79. package/agents/rewards-steward.md +67 -1
  80. package/agents/sales-call-coach.md +67 -1
  81. package/agents/sales-closer.md +67 -1
  82. package/agents/security-auditor.md +343 -48
  83. package/agents/sell-closer.md +67 -1
  84. package/agents/share-amplifier.md +67 -1
  85. package/agents/social-media-manager.md +67 -1
  86. package/agents/storyteller.md +301 -0
  87. package/agents/strategist.md +67 -1
  88. package/agents/strategy-aligner.md +67 -1
  89. package/agents/support-agent.md +67 -1
  90. package/agents/tagger.md +327 -0
  91. package/agents/tech-writer.md +195 -22
  92. package/agents/test-engineer.md +398 -29
  93. package/agents/tiktok-ads.md +67 -1
  94. package/agents/tracking-engineer.md +67 -1
  95. package/agents/trailkeeper.md +181 -0
  96. package/agents/upsell-strategist.md +67 -1
  97. package/agents/voice.md +67 -1
  98. package/agents/w1-recon.md +1 -1
  99. package/agents/w2-decide.md +1 -1
  100. package/agents/w3-edit.md +8 -2
  101. package/agents/w4-verify.md +13 -0
  102. package/agents/workflow-optimiser.md +81 -1
  103. package/commands/close.md +916 -160
  104. package/commands/deploy.md +102 -724
  105. package/commands/do.md +58 -2
  106. package/commands/sweep.md +159 -0
  107. package/commands/tasks.md +222 -0
  108. package/hooks/scripts/dev-only.sh +135 -0
  109. package/hooks/scripts/git-add-guard.sh +37 -2
  110. package/hooks/scripts/session-start.sh +32 -4
  111. package/package.json +1 -1
  112. package/rules/scripts.md +85 -0
  113. package/scripts/CLAUDE.md +315 -0
  114. package/scripts/ad-copy-lint.sh +656 -0
  115. package/scripts/agent-actor-parity.sh +129 -0
  116. package/scripts/blocks-manifest-cached.sh +100 -0
  117. package/scripts/chat-context-check.sh +89 -0
  118. package/scripts/chrome.mjs +18 -0
  119. package/scripts/close-metrics.sh +587 -0
  120. package/scripts/close-owner.sh +326 -0
  121. package/scripts/db-sync-lock-check.sh +116 -0
  122. package/scripts/deploy-emit.sh +311 -0
  123. package/scripts/deploy-gate-check.sh +155 -0
  124. package/scripts/deploy-ready.sh +78 -0
  125. package/scripts/deploy-record.sh +605 -0
  126. package/scripts/deploy-schema-check.sh +58 -0
  127. package/scripts/deploy.sh +393 -243
  128. package/scripts/do-auto.sh +127 -26
  129. package/scripts/do-board.sh +429 -0
  130. package/scripts/do-close.sh +1184 -0
  131. package/scripts/do-consumer-sweep.sh +18 -1
  132. package/scripts/do-decide.sh +476 -0
  133. package/scripts/do-fleet.sh +8 -2
  134. package/scripts/do-plan-json.mjs +110 -12
  135. package/scripts/do-prove-selftest.sh +108 -0
  136. package/scripts/do-prove.sh +86 -10
  137. package/scripts/do-rank.py +200 -3
  138. package/scripts/do-reconcile.sh +73 -12
  139. package/scripts/do-signal.sh +101 -23
  140. package/scripts/do-smoke.sh +18 -1
  141. package/scripts/do-w4-gates.sh +11 -1
  142. package/scripts/do-world-check.sh +153 -0
  143. package/scripts/download-stats.sh +172 -0
  144. package/scripts/factory-brief-check.sh +330 -0
  145. package/scripts/factory-check.sh +18 -1
  146. package/scripts/factory-close-check.sh +257 -0
  147. package/scripts/factory-emit.sh +211 -0
  148. package/scripts/factory-executor-check.mjs +353 -0
  149. package/scripts/factory-peak.sh +301 -0
  150. package/scripts/factory-repo.sh +71 -0
  151. package/scripts/factory-review-check.mjs +61 -0
  152. package/scripts/factory-tasks-check.sh +18 -1
  153. package/scripts/fixtures/factory-brief-real.md +44 -0
  154. package/scripts/flywheel-outcome.sh +63 -0
  155. package/scripts/gate-reaper-check.sh +98 -0
  156. package/scripts/gate-reaper.sh +9 -0
  157. package/scripts/gate-watchdog.sh +619 -0
  158. package/scripts/gc-content-check.sh +142 -0
  159. package/scripts/gh-traffic-capture.sh +153 -0
  160. package/scripts/govern-order-check.sh +202 -0
  161. package/scripts/governor-doors-check.sh +86 -5
  162. package/scripts/health.sh +448 -0
  163. package/scripts/id-inventory.mjs +418 -0
  164. package/scripts/incident.sh +212 -0
  165. package/scripts/land.sh +755 -45
  166. package/scripts/lib/gc-finished.sh +77 -0
  167. package/scripts/livekit-ratchet.sh +18 -1
  168. package/scripts/machine-check.sh +1 -1
  169. package/scripts/memory-index-budget.sh +79 -0
  170. package/scripts/npm-downloads.sh +109 -0
  171. package/scripts/one-agents.mjs +204 -8
  172. package/scripts/one-resume.sh +31 -3
  173. package/scripts/pr-body.sh +335 -0
  174. package/scripts/preview-fd-check.sh +289 -0
  175. package/scripts/redirect-lint.sh +169 -0
  176. package/scripts/release.sh +40 -6
  177. package/scripts/resume-lost-sessions.sh +68 -0
  178. package/scripts/shoot-pages.mjs +140 -0
  179. package/scripts/signal-meta-backfill.ts +451 -0
  180. package/scripts/signal-watch.sh +63 -6
  181. package/scripts/speed-cache-check.sh +12 -2
  182. package/scripts/sweep.sh +426 -0
  183. package/scripts/task-titles-dump.ts +101 -0
  184. package/scripts/test-cached.sh +47 -10
  185. package/scripts/test-lanes.sh +14 -0
  186. package/scripts/thread-name-backfill.ts +215 -0
  187. package/scripts/triage-shape-check.sh +149 -0
  188. package/scripts/tsc-cached.sh +155 -8
  189. package/scripts/typedb-flake-check.sh +3 -1
  190. package/scripts/urls-lint.sh +8 -0
  191. package/scripts/verify-board-doors.sh +80 -0
  192. package/scripts/verify-fast.sh +159 -6
  193. package/scripts/worktree-up.sh +21 -3
  194. package/skills/astro/SKILL.md +9 -3
  195. package/skills/astro/optimize-performance.md +3 -2
  196. package/skills/cloudflare/SKILL.md +3 -2
  197. package/skills/cloudflare-security-audit/AI-AND-LLM.md +83 -0
  198. package/skills/cloudflare-security-audit/ATTACK-CLASSES.md +130 -0
  199. package/skills/cloudflare-security-audit/CLIENT-SIDE.md +83 -0
  200. package/skills/cloudflare-security-audit/CLOUD-AND-DEPLOYMENT.md +86 -0
  201. package/skills/cloudflare-security-audit/DATA-ISOLATION-AND-LIFECYCLE.md +84 -0
  202. package/skills/cloudflare-security-audit/DESKTOP-MOBILE-AND-LOCAL-IPC.md +89 -0
  203. package/skills/cloudflare-security-audit/HUNTING.md +251 -0
  204. package/skills/cloudflare-security-audit/LICENSE +21 -0
  205. package/skills/cloudflare-security-audit/MEMORY-SAFETY-AND-BINARY.md +101 -0
  206. package/skills/cloudflare-security-audit/PROTOCOLS-RPC-AND-MESSAGING.md +81 -0
  207. package/skills/cloudflare-security-audit/PROVENANCE.md +78 -0
  208. package/skills/cloudflare-security-audit/RECONNAISSANCE.md +156 -0
  209. package/skills/cloudflare-security-audit/RESOURCE-EXHAUSTION-AND-AVAILABILITY.md +78 -0
  210. package/skills/cloudflare-security-audit/SKILL.md +192 -0
  211. package/skills/cloudflare-security-audit/SUPPLY-CHAIN-AND-RELEASE.md +73 -0
  212. package/skills/cloudflare-security-audit/VALIDATION-AND-REPORTING.md +186 -0
  213. package/skills/cloudflare-security-audit/WEB-PROTOCOL-AND-AUTH.md +105 -0
  214. package/skills/cloudflare-security-audit/report-schema.json +461 -0
  215. package/skills/cloudflare-security-audit/validate-coverage-ledger.cjs +872 -0
  216. package/skills/cloudflare-security-audit/validate-coverage-ledger.test.cjs +740 -0
  217. package/skills/cloudflare-security-audit/validate-findings.cjs +773 -0
  218. package/skills/cloudflare-security-audit/validate-findings.test.cjs +652 -0
  219. package/skills/deploy/REFERENCE.md +713 -0
  220. package/skills/deploy/SKILL.md +140 -0
  221. package/skills/fleet-audit/SKILL.md +58 -0
  222. package/skills/meeting/SKILL.md +220 -0
  223. package/skills/planning/SKILL.md +256 -0
  224. package/skills/shadcn/SKILL.md +1 -1
  225. package/skills/typedb/SKILL.md +7 -0
  226. package/skills/voice/SKILL.md +94 -6
  227. package/skills/voice/corpus-check.sh +87 -0
  228. package/templates/template-agent.md +7 -1
  229. package/templates/template-feature.md +9 -0
  230. package/templates/template-todo.md +29 -0
@@ -9,6 +9,23 @@
9
9
  # default: prints one command per matched rule (no execution)
10
10
  # --exec: also runs each printed command; any non-zero exit fails the sweep
11
11
  set -euo pipefail
12
+
13
+ # _GATE — route a heavy compute through the machine governor. A gate_lock only
14
+ # dedupes IDENTICAL work; a SLOT is what bounds N worktrees each running one of
15
+ # these at once (measured 2026-09-07: three concurrent 2.5GB typecheckers, every
16
+ # lock uncontended, load 171). Empty when already inside a gate, so a nested call
17
+ # inherits the outer slot rather than taking a second one.
18
+ #
19
+ # Resolves gate-run.sh from its OWN directory, deliberately: an earlier version
20
+ # keyed off $ROOT and got inserted above the line that sets it, so _GATE was
21
+ # silently empty and every call ran ungoverned -- a fail-OPEN, which is the exact
22
+ # defect this preamble exists to close.
23
+ _GATE=()
24
+ if [ "${GOVERN_IN_GATE:-0}" != "1" ]; then
25
+ _GR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/gate-run.sh"
26
+ [ -f "$_GR" ] && _GATE=( bash "$_GR" "compute:$(basename "${BASH_SOURCE[0]}")" -- )
27
+ fi
28
+
12
29
  cd "$(dirname "${BASH_SOURCE[0]}")/../.." || exit 2
13
30
 
14
31
  EXEC=false
@@ -63,7 +80,7 @@ for f in "${FILES[@]}"; do
63
80
  [ -z "$cmd" ] && continue
64
81
  echo "[consumer-sweep] $f → $cmd"
65
82
  if $EXEC; then
66
- eval "$cmd" || { echo "[consumer-sweep] FAIL: consumer command failed for $f: $cmd" >&2; rc=1; }
83
+ "${_GATE[@]}" bash -c "$cmd" || { echo "[consumer-sweep] FAIL: consumer command failed for $f: $cmd" >&2; rc=1; }
67
84
  fi
68
85
  done <<< "$cmds"
69
86
  done
@@ -0,0 +1,476 @@
1
+ #!/usr/bin/env bash
2
+ # do-decide.sh — the layer between "a leg is open" and "a human is asked".
3
+ #
4
+ # manifest: needs-env
5
+ # Reads GATEWAY_API_KEY through ONE_ENV_FILE, exactly as do-close.sh does.
6
+ # Its one network call is a PURE READ (world:route decide:true — zero side
7
+ # effects, zero tokens, no delivery, no mark). The writer half (mark/warn) is
8
+ # the settle path, and it writes strength 1 only.
9
+ #
10
+ # WHY IT EXISTS. /close closed what it could and filed a row for the rest. Every
11
+ # row named a command and waited for a person — including the rows whose answer
12
+ # was never in doubt. A blocker that resolves the same way every time is not a
13
+ # decision; it is a chore with a human bolted to it. And a blocker that IS a
14
+ # decision was filed as bare prose: "gate unrun", no options, no recommendation,
15
+ # no cost. So the person had to re-derive the fork every time.
16
+ #
17
+ # THE CONTRACT, in one line: for every open leg, name the fork, rank the options,
18
+ # recommend one, and TAKE it when — and only when — the substrate has already
19
+ # watched that choice come good five times.
20
+ #
21
+ # CONFIDENCE IS MEASURED, NOT ASSERTED, AND IT IS NOT MINE.
22
+ # The oracle is the substrate's own routing verdict — `world:route decide:true`
23
+ # (subscriptions.ts:672), the deterministic TS twin of 0043_route_verdict.tql:
24
+ #
25
+ # highway best >= 5 (HARDEN_STRENGTH) AND best >= 2 x second -> ACT
26
+ # classified a candidate, but not a proven one -> RECOMMEND
27
+ # ceo no candidate at all -> RECOMMEND
28
+ #
29
+ # where `best` is SUM(strength) - SUM(resistance) over `claw_paths` rows from
30
+ # `tag:one:decide:close:<id>` to each option, and a path stops being a candidate
31
+ # at all once resistance >= 0.2 x strength. Measured against production
32
+ # 2026-09-09, the whole loop in three calls:
33
+ #
34
+ # 0 marks -> {"reason":"ceo","receiver":null,"rung":3}
35
+ # 5 marks of strength 1-> {"reason":"highway","receiver":"optionA","rung":1}
36
+ # + 1 warn -> {"reason":"ceo","receiver":null,"rung":3}
37
+ #
38
+ # So the first five times a fork appears, a person answers it. After that the
39
+ # substrate has the base rate and /close acts. One bad outcome takes the
40
+ # authority away again on the very next run. That is the root CLAUDE.md's "human
41
+ # gates that auto-skip when trust earns it", applied to close blockers, using the
42
+ # mechanism G4 already uses for the auto-ship gate (text/factory-do.md).
43
+ #
44
+ # WHY strength 1, ALWAYS. rankCandidates sums strength; it cannot tell 5 marks of
45
+ # 1 from 1 mark of 5. HARDEN_STRENGTH = 5 is therefore a de-facto n>=5 SAMPLE
46
+ # floor only while every writer on `tag:one:decide:close:*` writes 1. This script
47
+ # is that sole writer and `--self-test` pins it. A future writer that marks these
48
+ # sources with strength > 1 turns a single event into a highway — don't.
49
+ #
50
+ # WHY AN UNREACHABLE SUBSTRATE ASKS. The decide lane's own D1 catch falls to
51
+ # "no candidates -> ceo", and a bounded curl that never answers is read here the
52
+ # same way. Every failure direction in this file points at the human. A layer
53
+ # that acts when it cannot measure is worse than the ask it replaced.
54
+ #
55
+ # THE VETO IS NOT A CONFIDENCE NUMBER, AND CONFIDENCE CANNOT OUTRANK IT.
56
+ # Blast radius is a second axis. A vetoed fork never reaches the oracle at all —
57
+ # structurally unreachable, not reachable-and-outranked — so no amount of
58
+ # accumulated strength can ever license it. See _veto_for.
59
+ #
60
+ # USAGE
61
+ # do-decide.sh --leg <leg> --status <s> --detail <d> [--slug <s>] [--apply]
62
+ # one open leg -> a verdict line (+ act)
63
+ # do-decide.sh --settle --leg <leg> --outcome pass|open [--slug <s>]
64
+ # the closed loop: mark/warn the option
65
+ # do-decide.sh --table the decision table, as it is
66
+ # do-decide.sh --self-test fixtures + RED PROOFS
67
+ #
68
+ # OPTIONS
69
+ # --apply take the decision when the verdict is `highway`. Without it
70
+ # this script is a pure reporter — do-close.sh --dry-run and
71
+ # the self-test rely on that.
72
+ # --budget <secs> oracle + action wall clock (default: 12)
73
+ # --json one JSON object on stdout
74
+ #
75
+ # EXIT
76
+ # 0 a verdict was produced (taken OR recommended — both are success)
77
+ # 4 the fork is vetoed: it will never be automatic, and the row says why
78
+ # 5 no decision table entry for this leg+detail — the caller files as before
79
+ # 2 usage
80
+ #
81
+ # It never returns non-zero for "the substrate was down" or "confidence was low".
82
+ # Those are ordinary answers, and a closer that fails on them is a closer callers
83
+ # route around — do-close.sh's founding lesson, inherited whole.
84
+ set -uo pipefail
85
+
86
+ ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
87
+ ONE_ENV_FILE="${ONE_ENV_FILE:-${DO_ENV_FILE:-one.ie/web/.env}}"
88
+ _MONOREPO_ENV_CANDIDATES="$ROOT/one.ie/web/.env $ROOT/one.ie/web/.dev.vars"
89
+ WORKSPACE="${CC_TASKS_WORKSPACE:-one}"
90
+
91
+ LEG=""; DSTATUS=""; DETAIL=""; SLUG=""; APPLY=0; BUDGET="${DECIDE_BUDGET:-12}"
92
+ JSON=0; SETTLE=0; OUTCOME=""; TABLE=0; SELFTEST=0
93
+
94
+ while [ $# -gt 0 ]; do
95
+ case "$1" in
96
+ --leg) LEG="${2:-}"; shift 2 ;;
97
+ --status) DSTATUS="${2:-}"; shift 2 ;;
98
+ --detail) DETAIL="${2:-}"; shift 2 ;;
99
+ --slug) SLUG="${2:-}"; shift 2 ;;
100
+ --outcome) OUTCOME="${2:-}"; shift 2 ;;
101
+ --budget) BUDGET="${2:-12}"; shift 2 ;;
102
+ --apply) APPLY=1; shift ;;
103
+ --settle) SETTLE=1; shift ;;
104
+ --table) TABLE=1; shift ;;
105
+ --json) JSON=1; shift ;;
106
+ --self-test) SELFTEST=1; shift ;;
107
+ -h|--help) sed -n '/^# USAGE/,/^# EXIT/p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
108
+ *) echo "do-decide: unknown arg $1" >&2; exit 2 ;;
109
+ esac
110
+ done
111
+
112
+ _env_key() {
113
+ local _f _v
114
+ for _f in "$ONE_ENV_FILE" "$ROOT/.env" $_MONOREPO_ENV_CANDIDATES; do
115
+ [ -f "$_f" ] || continue
116
+ _v=$(grep -E "^$1=" "$_f" 2>/dev/null | head -1 | sed 's/^[^=]*=//;s/^"//;s/"$//' || true)
117
+ [ -n "$_v" ] && { printf '%s' "$_v"; return 0; }
118
+ done
119
+ printf ''
120
+ }
121
+ _base() {
122
+ if [ -n "${ONE_API_URL:-}" ]; then printf '%s' "$ONE_API_URL"; return; fi
123
+ curl -s -o /dev/null --max-time 1.5 --connect-timeout 1 "http://localhost:4321/api/health" 2>/dev/null \
124
+ && printf 'http://localhost:4321' || printf 'https://one.ie'
125
+ }
126
+ _jsonesc() { printf '%s' "${1:-}" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' | tr '\n' ' '; }
127
+
128
+ # ═══ THE DECISION TABLE ═════════════════════════════════════════════════════
129
+ # Four entries, and the fourth is a veto. This is deliberately a TABLE and not an
130
+ # engine: it was enumerated from do-close.sh's actual `_emit` call sites, not
131
+ # imagined. A fork that is not in this table is not a decision — exit 5, and the
132
+ # caller files the row exactly as it did before. Adding a row is how this grows;
133
+ # generalising it is how it starts guessing.
134
+ #
135
+ # id | fires on | options (first = the declared prior)
136
+ # ---+--------------------------------+------------------------------------
137
+ # gate-mint gate unrun, no receipt mint · file
138
+ # derives-retry derives unrun (out of clock) retry · file
139
+ # promise-retry promise unrun (exit 3 / clock) retry · file
140
+ # writeback dims|feedback|task unrun at a door file [VETO]
141
+ # task-gate task unrun, gate not pass file [VETO]
142
+ _decision_for() { # <leg> <status> <detail> -> "<id> <opt1> <opt2>" or ""
143
+ local leg="$1" st="$2" d="$3"
144
+ [ "$st" = "unrun" ] || { printf ''; return; } # a `fail` is a verdict, not a fork
145
+ case "$leg" in
146
+ gate) case "$d" in *"no full-suite receipt"*) printf 'gate-mint mint file' ;; *) printf '' ;; esac ;;
147
+ derives) case "$d" in *"exceeded"*) printf 'derives-retry retry file' ;; *) printf '' ;; esac ;;
148
+ promise) case "$d" in
149
+ *"UNVERIFIABLE"*|*"exceeded"*) printf 'promise-retry retry file' ;;
150
+ *) printf '' ;; esac ;;
151
+ dims|feedback) printf 'writeback file' ;;
152
+ task) printf 'task-gate file' ;;
153
+ *) printf '' ;;
154
+ esac
155
+ }
156
+
157
+ # ═══ THE VETO ═══════════════════════════════════════════════════════════════
158
+ # Checked BEFORE the oracle is called, so a vetoed fork is structurally
159
+ # unreachable rather than reachable-but-outranked. Two standing vetoes, each with
160
+ # its measured reason, plus the blanket class.
161
+ _veto_for() { # <id> -> reason, or empty
162
+ case "$1" in
163
+ writeback)
164
+ # THE SELF-POISONING VETO, and it is the sharpest rule in this file.
165
+ # dims, feedback and task write THROUGH doors (mark-dims, loop:feedback,
166
+ # tasks:status). Their `unrun` is curl exit 7: the request timed out with
167
+ # the answer UNKNOWN — the write may well have landed. A retry that
168
+ # double-writes deposits strength twice on exactly the `claw_paths` rows
169
+ # this script reads back as confidence. An auto-retry here would inflate
170
+ # its own evidence, and the more it fired the more certain it would look.
171
+ # No confidence number may buy that. Ever.
172
+ printf 'an ambiguous WRITE cannot be retried — a double mark inflates the very weights this layer reads as confidence' ;;
173
+ task-gate)
174
+ # The repo's most expensive scar, named twice in do-close.sh's own header:
175
+ # cycles closed green at 0.92 with "tsc not measured, box saturated".
176
+ # The task<-gate edge is the thing that stopped it happening again.
177
+ printf 'the board write must never be decided around its gate — cycles once closed green at 0.92 with the suite unmeasured' ;;
178
+ *) printf '' ;;
179
+ esac
180
+ }
181
+
182
+ # The blanket class, independent of the table: an action string that ships,
183
+ # deploys, pushes, deletes, force-writes, spends, or touches the shared main tree
184
+ # is never taken by this script, whatever the table or the oracle says. Applied
185
+ # to the COMMAND about to run, so a table row edited to smuggle one in still
186
+ # cannot fire.
187
+ _action_forbidden() { # <command> -> reason, or empty
188
+ case "$1" in
189
+ *"release.sh"*|*"deploy.sh"*|*"./deploy"*|*"wrangler deploy"*|*" ship"*)
190
+ printf 'ships or deploys' ;;
191
+ *"git push"*|*"--force"*|*"-f "*|*"git reset --hard"*|*"git clean"*)
192
+ printf 'rewrites or discards history' ;;
193
+ *"rm -rf"*|*"DROP "*|*"undefine"*|*"secret put"*)
194
+ printf 'deletes or rotates' ;;
195
+ *) printf '' ;;
196
+ esac
197
+ }
198
+
199
+ # ═══ THE ACTIONS ════════════════════════════════════════════════════════════
200
+ # Every option is one line, and `file` is always the null action: it is what
201
+ # /close already did, so choosing it changes nothing and can break nothing.
202
+ _command_for() { # <id> <option> -> the command, or empty for the null action
203
+ local s="${SLUG:-<slug>}"
204
+ case "$1:$2" in
205
+ gate-mint:mint) printf 'cd %s/one.ie/web && FULL_VERIFY=1 bun run verify' "$ROOT" ;;
206
+ derives-retry:retry) printf 'bash %s/.claude/scripts/do-derives-check.sh %s' "$ROOT" "$s" ;;
207
+ promise-retry:retry) printf 'bash %s/.claude/scripts/do-promise-settle.sh %s' "$ROOT" "$s" ;;
208
+ *:file) printf '' ;;
209
+ *) printf '' ;;
210
+ esac
211
+ }
212
+
213
+ # What taking the option costs, so a recommendation carries its price and a
214
+ # reader can disagree with it on the evidence rather than on faith.
215
+ _cost_for() { # <id> <option>
216
+ case "$1:$2" in
217
+ gate-mint:mint) printf '~87s + one governor gate slot' ;;
218
+ derives-retry:retry) printf 'a bounded re-read, no gate slot' ;;
219
+ promise-retry:retry) printf 'the promise proof, re-run bounded' ;;
220
+ *:file) printf 'nothing — this is what /close already does' ;;
221
+ *) printf 'unknown' ;;
222
+ esac
223
+ }
224
+
225
+ # gate-mint is the one option with a machine precondition: minting takes a gate
226
+ # slot, and taking the last slot on a saturated box is how this repo once ran six
227
+ # concurrent tsc at load 57. Confidence says the choice is right; headroom says
228
+ # whether NOW is the moment. Both must hold.
229
+ _precondition_for() { # <id> <option> -> reason it cannot run now, or empty
230
+ [ "$1:$2" = "gate-mint:mint" ] || { printf ''; return; }
231
+ local hr=99
232
+ if [ -r "$ROOT/.claude/scripts/lib/govern.sh" ]; then
233
+ hr=$( . "$ROOT/.claude/scripts/lib/govern.sh" >/dev/null 2>&1
234
+ command -v gate_headroom >/dev/null 2>&1 && gate_headroom 2>/dev/null || echo 99 )
235
+ fi
236
+ case "$hr" in ''|*[!0-9]*) hr=99 ;; esac
237
+ # A broken sensor reads 99 and must never silently block — govern.sh's own rule.
238
+ [ "$hr" -lt 1 ] && printf 'no gate headroom (%s) — minting now would take the last slot on a saturated box' "$hr" || printf ''
239
+ }
240
+
241
+ # ═══ THE ORACLE ═════════════════════════════════════════════════════════════
242
+ # One bounded POST, a pure read. `workspace` must be nominated in the payload:
243
+ # world:route refuses with `forbidden: authentication required` when ctx.ownerSlug
244
+ # is unset, and a service key alone sets no slug (ask/[...receiver].ts:238 —
245
+ # a VERIFIED service caller may nominate one, nobody else may). Measured: without
246
+ # it, every verdict was `forbidden` and this layer would have asked forever.
247
+ _verdict() { # <id> -> "<reason> <receiver>"
248
+ local key resp cfg reason recv
249
+ key="$(_env_key GATEWAY_API_KEY)"
250
+ [ -n "$key" ] || { printf 'ceo -'; return; }
251
+ cfg="$(mktemp)"; chmod 600 "$cfg"
252
+ printf 'header = "Authorization: Bearer %s"\n' "$key" > "$cfg"
253
+ resp=$(curl -s --max-time "$BUDGET" --connect-timeout 2 -X POST \
254
+ "$(_base)/api/ask/world:route" -H 'Content-Type: application/json' --config "$cfg" \
255
+ -d "{\"data\":{\"workspace\":\"$WORKSPACE\",\"tags\":[\"decide:close:$1\"],\"decide\":true}}" 2>/dev/null)
256
+ rm -f "$cfg"
257
+ reason=$(printf '%s' "$resp" | sed -n 's/.*"reason":"\([a-z]*\)".*/\1/p')
258
+ recv=$(printf '%s' "$resp" | sed -n 's/.*"receiver":"\([^"]*\)".*/\1/p')
259
+ # No answer, a malformed answer, or an error body all land on `ceo`. Every
260
+ # failure direction in this file points at the human.
261
+ case "$reason" in highway|classified|ceo) ;; *) reason=ceo; recv="" ;; esac
262
+ printf '%s %s' "$reason" "${recv:--}"
263
+ }
264
+
265
+ # ═══ THE SETTLE — Rule 1, closed ════════════════════════════════════════════
266
+ # A decision taken is not a decision proven. The evidence this layer reads is
267
+ # written HERE, on the next close, from what actually happened to the leg:
268
+ # pass -> mark (the option came good; strength 1, five of them make a highway)
269
+ # open -> warn (it did not; one warn takes the authority straight back)
270
+ # Never from "the command exited 0" — that measures the command, not the choice.
271
+ _settle() { # <id> <option> <outcome>
272
+ local verb key edge cfg
273
+ case "$3" in pass) verb=mark ;; *) verb=warn ;; esac
274
+ key="$(_env_key GATEWAY_API_KEY)"; [ -n "$key" ] || return 1
275
+ edge=$(printf 'tag:one:decide:close:%s→%s' "$1" "$2" \
276
+ | sed 's/:/%3A/g; s/→/%E2%86%92/g')
277
+ cfg="$(mktemp)"; chmod 600 "$cfg"
278
+ printf 'header = "Authorization: Bearer %s"\n' "$key" > "$cfg"
279
+ # strength 1, ALWAYS — the sample floor depends on it (see the header).
280
+ curl -s -o /dev/null --max-time "$BUDGET" --connect-timeout 2 -X POST \
281
+ "$(_base)/api/$verb/$edge" -H 'Content-Type: application/json' \
282
+ --config "$cfg" -d '{"strength":1}' 2>/dev/null
283
+ local rc=$?; rm -f "$cfg"; return $rc
284
+ }
285
+
286
+ # ═══ --table ════════════════════════════════════════════════════════════════
287
+ if [ "$TABLE" -eq 1 ]; then
288
+ printf '%-14s %-26s %-18s %s\n' ID FIRES-ON OPTIONS VETO
289
+ for row in "gate-mint|gate unrun, no receipt|mint · file" \
290
+ "derives-retry|derives unrun (clock)|retry · file" \
291
+ "promise-retry|promise unrun (3/clock)|retry · file" \
292
+ "writeback|dims/feedback/task door|file" \
293
+ "task-gate|task unrun, gate not pass|file"; do
294
+ id="${row%%|*}"; rest="${row#*|}"; fires="${rest%%|*}"; opts="${rest#*|}"
295
+ printf '%-14s %-26s %-18s %s\n' "$id" "$fires" "$opts" "$(_veto_for "$id" | cut -c1-60)"
296
+ done
297
+ exit 0
298
+ fi
299
+
300
+ # ═══ --settle ═══════════════════════════════════════════════════════════════
301
+ if [ "$SETTLE" -eq 1 ]; then
302
+ [ -n "$LEG" ] && [ -n "$OUTCOME" ] || { echo "do-decide: --settle needs --leg and --outcome" >&2; exit 2; }
303
+ spec="$(_decision_for "$LEG" unrun "${DETAIL:-}")"
304
+ [ -n "$spec" ] || exit 5
305
+ id="${spec%% *}"; opt="${DSTATUS:-$(printf '%s' "$spec" | awk '{print $2}')}"
306
+ if _settle "$id" "$opt" "$OUTCOME"; then
307
+ echo "decide: settled $id→$opt as $OUTCOME ($([ "$OUTCOME" = pass ] && echo mark || echo warn))"
308
+ else
309
+ echo "decide: settle unreachable for $id→$opt — the path keeps its old weight"
310
+ fi
311
+ exit 0
312
+ fi
313
+
314
+ # ═══ --self-test ════════════════════════════════════════════════════════════
315
+ if [ "$SELFTEST" -eq 1 ]; then
316
+ fails=0
317
+ echo "── do-decide --self-test ──"
318
+
319
+ # 1. A fork with no table row is not a decision.
320
+ out=$(bash "$0" --leg dims --status fail --detail "refused" 2>&1); rc=$?
321
+ [ "$rc" -eq 5 ] && echo "ok: a leg with no table row exits 5 — the caller files as before" \
322
+ || { echo "FAIL: expected exit 5 for an untabled fork (rc=$rc)"; fails=$((fails+1)); }
323
+
324
+ # 2. A vetoed fork exits 4 and NAMES why — before any oracle call.
325
+ out=$(bash "$0" --leg task --status unrun --detail "gate=unrun" 2>&1); rc=$?
326
+ if [ "$rc" -eq 4 ] && printf '%s' "$out" | grep -q '0.92'; then
327
+ echo "ok: the task←gate fork is vetoed (exit 4) and the row names the scar"
328
+ else echo "FAIL: task-gate veto did not fire (rc=$rc): $out"; fails=$((fails+1)); fi
329
+
330
+ # 3. The write-door veto fires with its self-poisoning reason.
331
+ out=$(bash "$0" --leg feedback --status unrun --detail "signal door did not answer" 2>&1); rc=$?
332
+ if [ "$rc" -eq 4 ] && printf '%s' "$out" | grep -qi 'double mark'; then
333
+ echo "ok: an ambiguous write door is vetoed, naming the self-poisoning reason"
334
+ else echo "FAIL: writeback veto did not fire (rc=$rc): $out"; fails=$((fails+1)); fi
335
+
336
+ # 4. RED PROOF for 2+3 — gut _veto_for and both must go green (i.e. stop vetoing).
337
+ gut="$(mktemp)"; sed 's/^_veto_for() { # <id> -> reason, or empty/_veto_for() { printf ""; return; } _veto_dead() {/' "$0" > "$gut"
338
+ rc=0; bash "$gut" --leg task --status unrun --detail "gate=unrun" >/dev/null 2>&1 || rc=$?
339
+ [ "$rc" -ne 4 ] && echo "ok: RED PROOF — a gutted _veto_for stops vetoing (checks 2-3 measure something)" \
340
+ || { echo "FAIL: RED PROOF — veto still fired with _veto_for gutted"; fails=$((fails+1)); }
341
+
342
+ # 5. No oracle answer ⇒ ceo ⇒ RECOMMEND, never take. Point it at a dead door.
343
+ out=$(ONE_API_URL="http://127.0.0.1:1" DECIDE_BUDGET=2 bash "$0" --leg gate --status unrun \
344
+ --detail "no full-suite receipt — 0/2 lane(s)" --apply 2>&1); rc=$?
345
+ if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q 'RECOMMEND' && ! printf '%s' "$out" | grep -q 'TAKEN'; then
346
+ echo "ok: an unreachable oracle reads ceo and RECOMMENDS — it never acts blind"
347
+ else echo "FAIL: dead oracle did not fall to recommend (rc=$rc): $out"; fails=$((fails+1)); fi
348
+
349
+ # 6. The blanket action veto outranks any verdict — a forbidden command cannot
350
+ # be taken even with `highway` forced. This is the check that proves
351
+ # confidence does not buy blast radius. The gut is an inserted early-return
352
+ # (a header rewrite mangles multi-line bodies — measured).
353
+ _gut() { # <file> <fn> <body> -> a temp copy with that function short-circuited
354
+ local f; f="$(mktemp)"
355
+ awk -v fn="$2" -v body="$3" '$0 ~ "^"fn"\\(\\) \\{" {print; print " "body; next} {print}' "$1" > "$f"
356
+ printf '%s' "$f"
357
+ }
358
+ gut2="$(_gut "$0" _verdict 'printf "highway mint"; return 0;')"
359
+ gut2b="$(_gut "$gut2" _command_for 'printf "bash .claude/scripts/release.sh ship"; return 0;')"
360
+ out=$(bash "$gut2b" --leg gate --status unrun --detail "no full-suite receipt" --apply 2>&1); rc=$?
361
+ if printf '%s' "$out" | grep -q 'ships or deploys' && ! printf '%s' "$out" | grep -q 'TAKEN'; then
362
+ echo "ok: a forbidden action is refused even on a forced highway verdict"
363
+ else echo "FAIL: forbidden action was not refused under highway (rc=$rc): $out"; fails=$((fails+1)); fi
364
+
365
+ # 7. RED PROOF for 6 — gut _action_forbidden and the same forced highway takes it.
366
+ gut3="$(_gut "$gut2b" _action_forbidden 'printf ""; return 0;')"
367
+ out=$(DECIDE_DRYCMD=1 bash "$gut3" --leg gate --status unrun --detail "no full-suite receipt" --apply 2>&1)
368
+ if printf '%s' "$out" | grep -q 'TAKEN'; then
369
+ echo "ok: RED PROOF — a gutted _action_forbidden lets it through (check 6 measures something)"
370
+ else echo "FAIL: RED PROOF — action still refused with the guard gutted: $out"; fails=$((fails+1)); fi
371
+
372
+ # 8. strength 1, always — the n>=5 sample floor depends on this one literal.
373
+ if grep -q "d '{\"strength\":1}'" "$0"; then
374
+ echo "ok: the settle writes strength 1 — HARDEN_STRENGTH stays an n>=5 sample floor"
375
+ else echo "FAIL: the settle no longer writes strength 1 — one event could become a highway"; fails=$((fails+1)); fi
376
+
377
+ # 9. Without --apply this script cannot act at all, whatever the verdict says.
378
+ gut4="$(_gut "$0" _verdict 'printf "highway mint"; return 0;')"
379
+ out=$(bash "$gut4" --leg gate --status unrun --detail "no full-suite receipt" 2>&1)
380
+ printf '%s' "$out" | grep -q 'TAKEN' \
381
+ && { echo "FAIL: acted without --apply"; fails=$((fails+1)); } \
382
+ || echo "ok: without --apply a highway verdict still only reports — dry-run is structural"
383
+
384
+ rm -f "$gut" "$gut2" "$gut2b" "$gut3" "$gut4"
385
+ echo "── $([ "$fails" -eq 0 ] && echo 'all checks pass' || echo "$fails FAILED") ──"
386
+ [ "$fails" -eq 0 ]; exit $?
387
+ fi
388
+
389
+ # ═══ one fork ═══════════════════════════════════════════════════════════════
390
+ [ -n "$LEG" ] || { echo "do-decide: --leg required" >&2; exit 2; }
391
+ SPEC="$(_decision_for "$LEG" "$DSTATUS" "$DETAIL")"
392
+ [ -n "$SPEC" ] || exit 5
393
+ ID="${SPEC%% *}"; OPTS="${SPEC#* }"
394
+ PREFER="$(printf '%s' "$OPTS" | awk '{print $1}')"
395
+
396
+ # The veto, before the oracle. A vetoed fork is reported with its options and its
397
+ # reason — the person still gets the ranking, they just also get told this one is
398
+ # theirs by rule, not by a number that happened to be low today.
399
+ VETO="$(_veto_for "$ID")"
400
+ if [ -n "$VETO" ]; then
401
+ if [ "$JSON" -eq 1 ]; then
402
+ printf '{"id":"%s","leg":"%s","verdict":"veto","reason":"%s","options":"%s","action":"none"}\n' \
403
+ "$ID" "$LEG" "$(_jsonesc "$VETO")" "$(_jsonesc "$OPTS")"
404
+ else
405
+ printf ' decide %-14s VETO %s\n' "$ID" "$VETO"
406
+ printf ' %-21s stays human by rule — no confidence buys it\n' ""
407
+ fi
408
+ exit 4
409
+ fi
410
+
411
+ REASON=""; RECV=""
412
+ read -r REASON RECV <<EOF
413
+ $(_verdict "$ID")
414
+ EOF
415
+ [ "$RECV" = "-" ] && RECV=""
416
+
417
+ # `highway` is the ONLY verdict that licenses acting, and the substrate must have
418
+ # picked an option this table actually knows. A highway pointing at an unknown
419
+ # target is stale evidence, not a mandate.
420
+ CHOICE="$PREFER"; TAKE=0
421
+ if [ "$REASON" = "highway" ] && [ -n "$RECV" ]; then
422
+ case " $OPTS " in *" $RECV "*) CHOICE="$RECV"; TAKE=1 ;; esac
423
+ fi
424
+
425
+ CMD="$(_command_for "$ID" "$CHOICE")"
426
+ FORBIDDEN="$(_action_forbidden "$CMD")"
427
+ PRECOND="$(_precondition_for "$ID" "$CHOICE")"
428
+ NOTE=""; RESULT=recommend
429
+
430
+ if [ "$TAKE" -eq 1 ] && [ -n "$FORBIDDEN" ]; then
431
+ TAKE=0; NOTE="refused: the action $FORBIDDEN — blast radius is not a confidence number"
432
+ elif [ "$TAKE" -eq 1 ] && [ -n "$PRECOND" ]; then
433
+ TAKE=0; NOTE="held: $PRECOND"
434
+ elif [ "$TAKE" -eq 1 ] && [ -z "$CMD" ]; then
435
+ # The null action (`file`) won the highway. Taking it means doing what /close
436
+ # already does — report it as chosen, run nothing.
437
+ NOTE="the null action — /close files the row, which is the proven choice here"
438
+ RESULT=taken
439
+ elif [ "$TAKE" -eq 1 ] && [ "$APPLY" -eq 0 ]; then
440
+ TAKE=0; NOTE="would take it — re-run with --apply (or without --dry-run)"
441
+ fi
442
+
443
+ if [ "$TAKE" -eq 1 ] && [ -n "$CMD" ] && [ "$APPLY" -eq 1 ]; then
444
+ if [ -n "${DECIDE_DRYCMD:-}" ]; then RESULT=taken; NOTE="(DECIDE_DRYCMD — command not run)"
445
+ else
446
+ rc=0; ( eval "$CMD" ) >/dev/null 2>&1 || rc=$?
447
+ RESULT=taken
448
+ NOTE="ran: exit $rc"
449
+ fi
450
+ fi
451
+
452
+ # The undo line is not a nicety. Auto-taking moves the human's veto from BEFORE
453
+ # the action to AFTER it, and that trade is only honest while the reversal is
454
+ # actually in their hand — so it ships with every taken decision, always.
455
+ UNDO="bash .claude/scripts/do-decide.sh --settle --leg $LEG --status $CHOICE --outcome open${SLUG:+ --slug $SLUG} # warn the path; the next close asks again"
456
+
457
+ if [ "$JSON" -eq 1 ]; then
458
+ printf '{"id":"%s","leg":"%s","verdict":"%s","confidence":"%s","choice":"%s","options":"%s","result":"%s","note":"%s","command":"%s","undo":"%s"}\n' \
459
+ "$ID" "$LEG" "$RESULT" "$REASON" "$CHOICE" "$(_jsonesc "$OPTS")" "$RESULT" \
460
+ "$(_jsonesc "$NOTE")" "$(_jsonesc "$CMD")" "$(_jsonesc "$UNDO")"
461
+ exit 0
462
+ fi
463
+
464
+ if [ "$RESULT" = "taken" ]; then
465
+ printf ' decide %-14s TAKEN %s (confidence: %s — the substrate has watched this choice come good)\n' "$ID" "$CHOICE" "$REASON"
466
+ [ -n "$NOTE" ] && printf ' %-21s %s\n' "" "$NOTE"
467
+ printf ' %-21s undo: %s\n' "" "$UNDO"
468
+ else
469
+ printf ' decide %-14s RECOMMEND %s (confidence: %s — not yet proven; a person decides)\n' "$ID" "$CHOICE" "$REASON"
470
+ for o in $OPTS; do
471
+ _m=" "; [ "$o" = "$CHOICE" ] && _m="→"
472
+ printf ' %-21s %s %-6s %s\n' "" "$_m" "$o" "$(_cost_for "$ID" "$o")"
473
+ done
474
+ [ -n "$NOTE" ] && printf ' %-21s %s\n' "" "$NOTE"
475
+ fi
476
+ exit 0
@@ -33,7 +33,7 @@ WT_BASE="$ROOT/.do-worktrees"
33
33
 
34
34
  # Worktree branches cut from trunk, never HEAD — a shared tree parked on a
35
35
  # feature branch must not seed fleet plans with its commits. DO_BASE_REF overrides.
36
- BASE_REF="${DO_BASE_REF:-main}"
36
+ BASE_REF="${DO_BASE_REF:-dev}"
37
37
  git -C "$ROOT" show-ref --verify --quiet "refs/heads/$BASE_REF" || BASE_REF=HEAD
38
38
 
39
39
  GO=false
@@ -221,9 +221,15 @@ claim_task() { # claim_task <slug> → 0 ok to launch, 1 already claimed elsewh
221
221
  [ -n "$secret" ] && break
222
222
  done
223
223
  [ -z "$secret" ] && return 0
224
+ # A mirrored plan (do-board.sh) hangs its cycle rows off the plan row, and the
225
+ # claim gate refuses a parent with open children — so lease the FIRST OPEN CYCLE's
226
+ # row when there is one (its own batch predecessors gate it), the plan row otherwise.
227
+ local addr tid
228
+ tid=$(bash "$ROOT/.claude/scripts/do-plan-json.sh" "$slug" 2>/dev/null | jq -r '.cycleRows[.openCycles[0]] // empty' 2>/dev/null || true)
229
+ if [ -n "$tid" ]; then addr="\"tid\":\"$tid\""; else addr="\"slug\":\"$slug\""; fi
224
230
  resp=$(curl -sf -X POST "${DO_SIGNAL_URL:-https://one.ie}/api/ask/tasks:claim" \
225
231
  -H "Content-Type: application/json" -H "Authorization: Bearer $secret" \
226
- -d "{\"data\":{\"slug\":\"$slug\",\"workspace\":\"${CC_TASKS_WORKSPACE:-one}\"}}" 2>/dev/null || true)
232
+ -d "{\"data\":{$addr,\"workspace\":\"${CC_TASKS_WORKSPACE:-one}\"}}" 2>/dev/null || true)
227
233
  case "$resp" in
228
234
  *'"ok":true'*) return 0 ;; # lease held by us — launch
229
235
  *'"error":"already-claimed"'*) echo " ~ $slug — claimed by another actor, skipping" >&2; return 1 ;;