@oneie/claude 0.6.0 → 0.7.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/agents/w1-recon.md +9 -4
- package/agents/w2-decide.md +51 -28
- package/agents/w3-edit.md +70 -78
- package/agents/w4-verify.md +164 -69
- package/commands/browser.md +98 -35
- package/commands/cc-connect.md +6 -0
- package/commands/chat.md +13 -1
- package/commands/close.md +45 -19
- package/commands/create.md +20 -10
- package/commands/db-sync.md +5 -1
- package/commands/deploy.md +174 -87
- package/commands/do-autonomous.md +31 -20
- package/commands/do-improve.md +4 -4
- package/commands/do-show.md +4 -3
- package/commands/do.md +53 -13
- package/commands/go.md +75 -0
- package/commands/improve.md +4 -2
- package/commands/kill.md +6 -8
- package/commands/notify.md +15 -2
- package/commands/oo-push.md +24 -9
- package/commands/rag.md +6 -0
- package/commands/release.md +46 -25
- package/commands/restart.md +5 -4
- package/commands/see.md +45 -35
- package/commands/skill-create.md +38 -5
- package/commands/sync.md +21 -11
- package/hooks/scripts/auto-continue.sh +70 -0
- package/hooks/scripts/branch-pin.sh +85 -0
- package/hooks/scripts/git-add-guard.sh +16 -5
- package/hooks/scripts/post-edit-check.sh +16 -0
- package/hooks/scripts/session-start.sh +13 -8
- package/hooks/scripts/sync-priority-todo.sh +5 -0
- package/package.json +1 -1
- package/rules/api.md +9 -0
- package/rules/design.md +13 -3
- package/rules/documentation.md +30 -71
- package/rules/engine.md +8 -1
- package/rules/ui.md +5 -1
- package/scripts/__pycache__/do-rank.cpython-313.pyc +0 -0
- package/scripts/browser-check.mjs +44 -103
- package/scripts/cc-events-proof.sh +13 -12
- package/scripts/chrome.mjs +381 -0
- package/scripts/do-analyze.sh +109 -4
- package/scripts/do-auto.sh +350 -43
- package/scripts/do-consumer-sweep.sh +72 -0
- package/scripts/do-derives-check.sh +88 -0
- package/scripts/do-fleet.sh +50 -1
- package/scripts/do-killswitch-audit.py +33 -14
- package/scripts/do-promise-lint.sh +150 -4
- package/scripts/do-promise-settle.sh +131 -9
- package/scripts/do-prove.sh +197 -17
- package/scripts/do-rank.py +606 -20
- package/scripts/do-rubric.py +21 -2
- package/scripts/do-signal.sh +157 -17
- package/scripts/do-smoke.sh +9 -0
- package/scripts/do-substrate-check.sh +49 -0
- package/scripts/do-tasks-wire-check.sh +81 -0
- package/scripts/do-tier.sh +90 -5
- package/scripts/do-ui-gate.sh +332 -0
- package/scripts/do-untracked-gate.sh +231 -0
- package/scripts/do-walk.sh +344 -0
- package/scripts/factory-check.sh +747 -0
- package/scripts/factory-repo.sh +1361 -0
- package/scripts/factory-tasks-check.sh +85 -0
- package/scripts/outcome-pull.ts +279 -0
- package/scripts/promise-manifest.mjs +167 -0
- package/scripts/reconcile-allow.txt +5 -0
- package/scripts/rubric-weights.json +64 -0
- package/scripts/spine-canary.sh +20 -0
- package/scripts/typedb-cluster-status.sh +128 -0
- package/scripts/typedb-env.sh +182 -0
- package/scripts/typedb-flap-recorder.sh +85 -0
- package/scripts/typedb-probes/containment-probe.py +88 -0
- package/scripts/typedb-probes/panic-probe-version.py +92 -0
- package/scripts/typedb-probes/panic-probe.py +77 -0
- package/scripts/typedb-scratch.sh +73 -0
- package/scripts/urls-lint.sh +58 -0
- package/scripts/w4-rubric.ts +96 -12
- package/scripts/wf-check.mjs +75 -0
- package/skills/ai-ui/SKILL.md +1 -1
- package/skills/astro/SKILL.md +177 -132
- package/skills/astro/add-content-collection.md +29 -13
- package/skills/astro/check-build.md +19 -13
- package/skills/astro/create-component.md +36 -9
- package/skills/astro/create-page.md +39 -10
- package/skills/astro/optimize-performance.md +36 -8
- package/skills/cli/SKILL.md +254 -220
- package/skills/dev/SKILL.md +1 -1
- package/skills/directory-autofill/SKILL.md +68 -0
- package/skills/docs/SKILL.md +4 -4
- package/skills/mcp/SKILL.md +186 -156
- package/skills/promise-make/SKILL.md +2 -2
- package/skills/puck/SKILL.md +465 -250
- package/skills/react19/SKILL.md +196 -296
- package/skills/reactflow/SKILL.md +387 -412
- package/skills/sdk/SKILL.md +167 -106
- package/skills/shadcn/SKILL.md +245 -201
- package/skills/signal/SKILL.md +5 -0
- package/skills/sui/SKILL.md +6 -1
- package/skills/tutorial/SKILL.md +15 -0
- package/skills/typedb/SKILL.md +427 -217
- package/skills/typedb/examples/python-patterns.py +11 -4
- package/skills/typedb/examples/query-patterns.tql +8 -3
- package/skills/typedb/examples/schema-patterns.tql +4 -2
- package/skills/typedb/reference/migration-2x-3x.md +19 -1
- package/skills/typedb/reference/python-driver.md +17 -1
- package/skills/voice/SKILL.md +117 -0
- package/skills/writer/SKILL.md +29 -12
- package/templates/template-feature.md +26 -1
- package/templates/template-tests.md +4 -0
- package/templates/template-todo.md +65 -10
package/scripts/do-rubric.py
CHANGED
|
@@ -333,10 +333,22 @@ def score_integration(src: str, files: list[Path]) -> tuple[float, list[str], li
|
|
|
333
333
|
|
|
334
334
|
|
|
335
335
|
# ── Composite & report ────────────────────────────────────────────────────────
|
|
336
|
-
|
|
337
|
-
#
|
|
336
|
+
# Weights come from rubric-weights.json — the single source. This script scores a
|
|
337
|
+
# PACKAGE source tree, so it has no plan context and goal-fit (0.30) is genuinely
|
|
338
|
+
# unavailable: its omission is correct, not drift. What that costs is comparability
|
|
339
|
+
# — this number is a BASELINE, never a gate verdict, and it is emitted as
|
|
340
|
+
# `composite_partial` so nothing can compare it to a cycle composite that does
|
|
341
|
+
# carry goal-fit. See the `package` block in rubric-weights.json.
|
|
342
|
+
_WEIGHTS_PATH = Path(__file__).with_name("rubric-weights.json")
|
|
343
|
+
try:
|
|
344
|
+
_RUBRIC = json.loads(_WEIGHTS_PATH.read_text())
|
|
345
|
+
WEIGHTS = _RUBRIC["package"]["weights"]
|
|
346
|
+
except (OSError, KeyError, json.JSONDecodeError) as e:
|
|
347
|
+
raise SystemExit(f"do-rubric: cannot read {_WEIGHTS_PATH}: {e}")
|
|
348
|
+
|
|
338
349
|
|
|
339
350
|
def composite(scores: dict) -> float:
|
|
351
|
+
"""Partial composite over the code axes only, normalised. NOT a gate verdict."""
|
|
340
352
|
total_w = sum(WEIGHTS.values())
|
|
341
353
|
return round(sum(scores[k] * WEIGHTS[k] for k in WEIGHTS) / total_w, 2)
|
|
342
354
|
|
|
@@ -379,7 +391,14 @@ def run(target_str: str, as_json: bool = False) -> dict:
|
|
|
379
391
|
"files": len(files),
|
|
380
392
|
"loc": src.count("\n"),
|
|
381
393
|
"scores": scores,
|
|
394
|
+
# `composite` is kept for the existing readers (do-auto.sh writes the W0
|
|
395
|
+
# baseline from it). The two fields beside it say what it actually is, so
|
|
396
|
+
# a reader can tell a partial baseline from a cycle verdict instead of
|
|
397
|
+
# assuming they are the same scale.
|
|
382
398
|
"composite": comp,
|
|
399
|
+
"composite_partial": comp,
|
|
400
|
+
"rubric": "package",
|
|
401
|
+
"goal_fit_included": False,
|
|
383
402
|
"findings": {
|
|
384
403
|
"security": sec_f,
|
|
385
404
|
"stability": sta_f,
|
package/scripts/do-signal.sh
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# Internal: emit world:do-event signals at /do phase boundaries
|
|
3
|
-
#
|
|
2
|
+
# Internal: emit world:do-event signals at /do phase boundaries, and drive the
|
|
3
|
+
# tasks:create/claim/link verbs so a /do plan's own lifecycle IS a substrate
|
|
4
|
+
# task's lifecycle (text/tasks-do-plan.md C1 — the shared-atom wire).
|
|
5
|
+
# Called by do-auto.sh at plan arm, cycle open, cycle close, and halt. Not a
|
|
6
|
+
# user command.
|
|
4
7
|
#
|
|
5
8
|
# Usage:
|
|
6
9
|
# do-signal.sh [--print] <type> <slug> <tier> <cycle> [key=value ...]
|
|
10
|
+
# do-signal.sh [--print] --task-create <slug> <title> [tags=a,b,c] [notes=...]
|
|
11
|
+
# do-signal.sh [--print] --task-claim <slug>
|
|
12
|
+
# do-signal.sh [--print] --task-link <slug> [docs=a,b,c]
|
|
7
13
|
#
|
|
8
14
|
# --print: write JSON to stdout without POSTing (tests + dry runs).
|
|
9
|
-
# Extra key=value pairs are merged into the payload.
|
|
15
|
+
# Extra key=value pairs are merged into the world:do-event payload.
|
|
10
16
|
# axis=security,structure → adds s:security + s:structure tags + "axis" field
|
|
11
17
|
# composite=0.82 → numeric field (no quotes)
|
|
12
18
|
# wave=W3 → string field
|
|
@@ -14,24 +20,152 @@
|
|
|
14
20
|
#
|
|
15
21
|
# Env overrides:
|
|
16
22
|
# DO_SIGNAL_URL default: https://one.ie
|
|
17
|
-
#
|
|
23
|
+
# ONE_ENV_FILE default: one.ie/web/.env (read SERVER_SECRET for auth)
|
|
24
|
+
# DO_ENV_FILE accepted as an alias for ONE_ENV_FILE (kept for callers)
|
|
18
25
|
#
|
|
19
26
|
# Signal failure never blocks the build loop — callers wrap with `|| true`.
|
|
20
27
|
set -euo pipefail
|
|
21
28
|
|
|
22
29
|
PRINT=false
|
|
23
|
-
|
|
30
|
+
# Credentials come from ONE_ENV_FILE, so the harness runs with no one.ie/web/
|
|
31
|
+
# on disk. DO_ENV_FILE stays an accepted alias — it predates the generalisation.
|
|
32
|
+
ONE_ENV_FILE="${ONE_ENV_FILE:-${DO_ENV_FILE:-one.ie/web/.env}}"
|
|
33
|
+
DO_ENV_FILE="$ONE_ENV_FILE"
|
|
24
34
|
DO_SIGNAL_URL="${DO_SIGNAL_URL:-https://one.ie}"
|
|
25
35
|
|
|
36
|
+
_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
37
|
+
|
|
38
|
+
# Monorepo fallbacks. Unquoted on purpose: they expand to nothing outside the
|
|
39
|
+
# monorepo, so the loop degrades to ONE_ENV_FILE alone rather than erroring.
|
|
40
|
+
_MONOREPO_ENV_CANDIDATES="$_ROOT/one.ie/web/.env $_ROOT/one.ie/web/.secrets.generated.local $_ROOT/one.ie/web/.dev.vars"
|
|
41
|
+
|
|
42
|
+
# Shared SERVER_SECRET lookup — /api/signal/world:do-event checks this (see
|
|
43
|
+
# world:do-event POST at the bottom of this file).
|
|
44
|
+
_server_secret() {
|
|
45
|
+
local _f _v
|
|
46
|
+
for _f in "$ONE_ENV_FILE" "$_ROOT/.env" $_MONOREPO_ENV_CANDIDATES; do
|
|
47
|
+
[ -f "$_f" ] || continue
|
|
48
|
+
_v=$(grep -E '^SERVER_SECRET=' "$_f" 2>/dev/null | head -1 | sed 's/^[^=]*=//;s/^"//;s/"$//' || true)
|
|
49
|
+
[ -n "$_v" ] && { printf '%s' "$_v"; return 0; }
|
|
50
|
+
done
|
|
51
|
+
printf ''
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
# GATEWAY_API_KEY lookup — /api/ask/<receiver> (the tasks:* verbs) checks THIS,
|
|
55
|
+
# not SERVER_SECRET (one.ie/web/src/pages/api/ask/[...receiver].ts isServiceCaller).
|
|
56
|
+
# Presenting SERVER_SECRET there resolves to no service caller, no ctx.ownerSlug,
|
|
57
|
+
# and every tasks:* resolver returns {error:"workspace required"} — verified
|
|
58
|
+
# 2026-07-17, zero do-signal task-create/claim/link calls had ever landed in prod.
|
|
59
|
+
_gateway_key() {
|
|
60
|
+
local _f _v
|
|
61
|
+
for _f in "$ONE_ENV_FILE" "$_ROOT/.env" $_MONOREPO_ENV_CANDIDATES; do
|
|
62
|
+
[ -f "$_f" ] || continue
|
|
63
|
+
_v=$(grep -E '^GATEWAY_API_KEY=' "$_f" 2>/dev/null | head -1 | sed 's/^[^=]*=//;s/^"//;s/"$//' || true)
|
|
64
|
+
[ -n "$_v" ] && { printf '%s' "$_v"; return 0; }
|
|
65
|
+
done
|
|
66
|
+
printf ''
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
# POST a JSON payload to /api/ask/<receiver> with bearer auth. Fire-and-forget:
|
|
70
|
+
# a failure is silent so the build loop is never blocked (same stance as the
|
|
71
|
+
# world:do-event POST below). Prints the response body (empty on failure).
|
|
72
|
+
_post_ask() {
|
|
73
|
+
local _receiver="$1" _payload="$2" _secret _authcfg _url _resp
|
|
74
|
+
_secret="$(_gateway_key)"
|
|
75
|
+
_url="${DO_SIGNAL_URL}/api/ask/${_receiver}"
|
|
76
|
+
if [ -n "$_secret" ]; then
|
|
77
|
+
_authcfg="$(mktemp)"; chmod 600 "$_authcfg"
|
|
78
|
+
printf 'header = "Authorization: Bearer %s"\n' "$_secret" > "$_authcfg"
|
|
79
|
+
_resp=$(curl -sf -X POST "$_url" -H "Content-Type: application/json" --config "$_authcfg" -d "$_payload" 2>/dev/null || true)
|
|
80
|
+
rm -f "$_authcfg"
|
|
81
|
+
else
|
|
82
|
+
_resp=$(curl -sf -X POST "$_url" -H "Content-Type: application/json" -d "$_payload" 2>/dev/null || true)
|
|
83
|
+
fi
|
|
84
|
+
printf '%s' "$_resp"
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
# Every task this harness files lands in one workspace — /u/one/tasks — so a
|
|
88
|
+
# human never has to hunt across slugs for Claude Code's own work. Overridable
|
|
89
|
+
# for a differently-branded harness fork; unset means "one" (same convention
|
|
90
|
+
# as CC_WORLD_SLUG in hooks/lib/signal.sh). ctx.ownerSlug resolves straight to
|
|
91
|
+
# this value (nominated via GATEWAY_API_KEY auth above), so every tasks:*
|
|
92
|
+
# resolver's actor/owner/workspace tag is this slug, not whatever ambient
|
|
93
|
+
# session happened to be attested.
|
|
94
|
+
CC_TASKS_WORKSPACE="${CC_TASKS_WORKSPACE:-one}"
|
|
95
|
+
|
|
96
|
+
# signal_tasks_create — plan arm: files an open task tagged slug:<slug>, so the
|
|
97
|
+
# plan appears in tasks:everywhere the moment it's armed (C1/C2 interface contract).
|
|
98
|
+
signal_tasks_create() { # signal_tasks_create <slug> <title> [tags=a,b,c] [notes=...]
|
|
99
|
+
local slug="$1" title="$2" tags="slug:${1}" notes=""
|
|
100
|
+
shift 2
|
|
101
|
+
for kv in "$@"; do
|
|
102
|
+
case "${kv%%=*}" in
|
|
103
|
+
tags) tags="${tags},${kv#*=}" ;;
|
|
104
|
+
notes) notes="${kv#*=}" ;;
|
|
105
|
+
esac
|
|
106
|
+
done
|
|
107
|
+
local tags_json; tags_json=$(printf '%s' "$tags" | awk -F',' '{for(i=1;i<=NF;i++){printf "%s\"%s\"", (i>1?",":""), $i}}')
|
|
108
|
+
local payload="{\"data\":{\"title\":\"${title}\",\"workspace\":\"${CC_TASKS_WORKSPACE}\",\"tags\":[${tags_json}]${notes:+,\"notes\":\"${notes}\"}}}"
|
|
109
|
+
if $PRINT; then printf '%s\n' "$payload"; return 0; fi
|
|
110
|
+
_post_ask "tasks:create" "$payload"
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
# signal_tasks_claim — cycle open: leases the plan's substrate task so a fleet
|
|
114
|
+
# run (or a human) never double-builds the same slug (do-fleet.sh mirrors this).
|
|
115
|
+
signal_tasks_claim() { # signal_tasks_claim <slug>
|
|
116
|
+
# Address the lease by the plan SLUG, not a guessed tid: create returns a random
|
|
117
|
+
# task:<traceId>, so "task:<slug>" never matched — claim silently 404'd for every /do
|
|
118
|
+
# run until this. The server resolves slug → tid (resolvers/tasks.ts resolveTaskBySlug).
|
|
119
|
+
local slug="$1"
|
|
120
|
+
local payload="{\"data\":{\"slug\":\"${slug}\",\"workspace\":\"${CC_TASKS_WORKSPACE}\"}}"
|
|
121
|
+
if $PRINT; then printf '%s\n' "$payload"; return 0; fi
|
|
122
|
+
_post_ask "tasks:claim" "$payload"
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
# signal_tasks_link — cycle close: records the handoff-completion back on the
|
|
126
|
+
# origin task (provenance line + task-status:done), same shape lifecycle.ts's
|
|
127
|
+
# tasks_link MCP tool posts.
|
|
128
|
+
signal_tasks_link() { # signal_tasks_link <slug> [docs=a,b,c]
|
|
129
|
+
# Slug-addressed like claim — the server resolves slug → the origin tid create wrote.
|
|
130
|
+
local slug="$1" docs=""
|
|
131
|
+
shift 1
|
|
132
|
+
for kv in "$@"; do
|
|
133
|
+
case "${kv%%=*}" in
|
|
134
|
+
docs) docs="${kv#*=}" ;;
|
|
135
|
+
esac
|
|
136
|
+
done
|
|
137
|
+
local docs_json=""
|
|
138
|
+
[ -n "$docs" ] && docs_json=$(printf '%s' "$docs" | awk -F',' '{for(i=1;i<=NF;i++){printf "%s\"%s\"", (i>1?",":""), $i}}')
|
|
139
|
+
local payload="{\"data\":{\"slug\":\"${slug}\",\"workspace\":\"${CC_TASKS_WORKSPACE}\"${docs_json:+,\"docs\":[${docs_json}]}}}"
|
|
140
|
+
if $PRINT; then printf '%s\n' "$payload"; return 0; fi
|
|
141
|
+
_post_ask "tasks:link" "$payload"
|
|
142
|
+
}
|
|
143
|
+
|
|
26
144
|
while [ "$#" -gt 0 ]; do
|
|
27
145
|
case "$1" in
|
|
28
146
|
--print) PRINT=true; shift ;;
|
|
147
|
+
# Report WHICH file credentials resolved from, never the value. This is how
|
|
148
|
+
# factory-repo.sh --check-env-indirection proves the override is real
|
|
149
|
+
# behaviour rather than a grep for a variable name.
|
|
150
|
+
--print-env)
|
|
151
|
+
_which=""
|
|
152
|
+
for _f in "$ONE_ENV_FILE" "$_ROOT/.env" $_MONOREPO_ENV_CANDIDATES; do
|
|
153
|
+
[ -f "$_f" ] || continue
|
|
154
|
+
grep -qE '^(SERVER_SECRET|GATEWAY_API_KEY)=.' "$_f" 2>/dev/null || continue
|
|
155
|
+
_which="$_f"; break
|
|
156
|
+
done
|
|
157
|
+
printf 'resolved-from: %s\n' "${_which:-<none>}"
|
|
158
|
+
exit 0 ;;
|
|
159
|
+
--task-create) shift; signal_tasks_create "$@"; exit 0 ;;
|
|
160
|
+
--task-claim) shift; signal_tasks_claim "$@"; exit 0 ;;
|
|
161
|
+
--task-link) shift; signal_tasks_link "$@"; exit 0 ;;
|
|
29
162
|
*) break ;;
|
|
30
163
|
esac
|
|
31
164
|
done
|
|
32
165
|
|
|
33
166
|
if [ "$#" -lt 4 ]; then
|
|
34
167
|
echo "usage: do-signal.sh [--print] <type> <slug> <tier> <cycle> [key=value ...]" >&2
|
|
168
|
+
echo " do-signal.sh [--print] --task-create|--task-claim|--task-link <slug> ..." >&2
|
|
35
169
|
exit 1
|
|
36
170
|
fi
|
|
37
171
|
|
|
@@ -66,6 +200,18 @@ for kv in "$@"; do
|
|
|
66
200
|
composite)
|
|
67
201
|
EXTRA_JSON="${EXTRA_JSON},\"${k}\":${v}"
|
|
68
202
|
;;
|
|
203
|
+
worktags)
|
|
204
|
+
# comma-list → JSON array field. The plan's task-vocabulary tags (dept + topics);
|
|
205
|
+
# the reputation harvest credits these tag-nodes (text/reputation.md § Slice A).
|
|
206
|
+
_wt=""; _w="${v}"
|
|
207
|
+
while [ -n "$_w" ]; do
|
|
208
|
+
_witem="${_w%%,*}"
|
|
209
|
+
[ -n "$_witem" ] && _wt="${_wt:+${_wt},}\"${_witem}\""
|
|
210
|
+
[ "$_w" = "$_witem" ] && break
|
|
211
|
+
_w="${_w#*,}"
|
|
212
|
+
done
|
|
213
|
+
EXTRA_JSON="${EXTRA_JSON},\"worktags\":[${_wt}]"
|
|
214
|
+
;;
|
|
69
215
|
*)
|
|
70
216
|
EXTRA_JSON="${EXTRA_JSON},\"${k}\":\"${v}\""
|
|
71
217
|
;;
|
|
@@ -79,18 +225,12 @@ if $PRINT; then
|
|
|
79
225
|
exit 0
|
|
80
226
|
fi
|
|
81
227
|
|
|
82
|
-
#
|
|
83
|
-
# .env historically lacks it;
|
|
84
|
-
#
|
|
85
|
-
#
|
|
86
|
-
# had ever landed in prod D1).
|
|
87
|
-
|
|
88
|
-
SERVER_SECRET=""
|
|
89
|
-
for _f in "$DO_ENV_FILE" "$_ROOT/one.ie/web/.env" "$_ROOT/one.ie/web/.secrets.generated.local" "$_ROOT/one.ie/web/.dev.vars"; do
|
|
90
|
-
[ -f "$_f" ] || continue
|
|
91
|
-
SERVER_SECRET=$(grep -E '^SERVER_SECRET=' "$_f" 2>/dev/null | head -1 | sed 's/^[^=]*=//;s/^"//;s/"$//' || true)
|
|
92
|
-
[ -n "$SERVER_SECRET" ] && break
|
|
93
|
-
done
|
|
228
|
+
# SERVER_SECRET for the Authorization header — _server_secret() (defined above)
|
|
229
|
+
# is the one lookup, shared with the tasks:* verbs. .env historically lacks it;
|
|
230
|
+
# .secrets.generated.local is what push-prod-secrets.sh pushed to the worker, so
|
|
231
|
+
# it matches prod. Without a matching secret the POST is silently 401/403-dropped
|
|
232
|
+
# at the gateway (verified 2026-07-04 — zero do-* threads had ever landed in prod D1).
|
|
233
|
+
SERVER_SECRET="$(_server_secret)"
|
|
94
234
|
|
|
95
235
|
# POST — fire-and-forget; failures are silent so the build loop is never blocked.
|
|
96
236
|
_url="${DO_SIGNAL_URL}/api/signal/world:do-event"
|
package/scripts/do-smoke.sh
CHANGED
|
@@ -21,6 +21,15 @@ echo "== C7 do-tier =="
|
|
|
21
21
|
"$S/do-tier.sh" pay/contracts/sui/sources/one_token.move | grep -q '"tier":"SCHEMA"' && ok "contract source → SCHEMA" || no "contract source"
|
|
22
22
|
"$S/do-tier.sh" pay/contracts/sui/tests/gateway_tests.move | grep -q '"tier":"FIX"' && ok "contract test → FIX (not SCHEMA)" || no "contract test"
|
|
23
23
|
"$S/do-tier.sh" --intent "add billing" one.ie/web/src/api/b.ts | grep -q '"tier":"FEATURE"' && ok "intent → FEATURE" || no "FEATURE"
|
|
24
|
+
# Absence of recon must not read as simplicity: no paths → UNSIZED, never PATCH.
|
|
25
|
+
# Intent is deliberately ignored here — "add a null check" and "add a settings page"
|
|
26
|
+
# share a verb, so a sentence alone can't size anything. Exit 3 is the contract.
|
|
27
|
+
# Capture before grepping: UNSIZED exits 3, and under `pipefail` that propagates
|
|
28
|
+
# through the pipe even when grep matches — the same trap any caller piping do-tier
|
|
29
|
+
# into grep/jq will hit now that it can exit non-zero.
|
|
30
|
+
UNS=$(echo "" | "$S/do-tier.sh" --intent "add a settings page" 2>/dev/null); UNS_RC=$?
|
|
31
|
+
case "$UNS" in *'"tier":"UNSIZED"'*) ok "no paths → UNSIZED (not PATCH)" ;; *) no "UNSIZED" ;; esac
|
|
32
|
+
[ "$UNS_RC" -eq 3 ] && ok "UNSIZED → exit 3" || no "UNSIZED exit code (got $UNS_RC)"
|
|
24
33
|
|
|
25
34
|
echo "== C2 do-reconcile — substrate canon =="
|
|
26
35
|
echo "uses a node in the colony" | "$S/do-reconcile.sh" substrate >/dev/null 2>&1 && no "dead name should fail substrate" || ok "dead name → substrate exit 1"
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# do-substrate-check.sh — can this machine reach TypeDB DIRECTLY, right now?
|
|
3
|
+
#
|
|
4
|
+
# Distinct from `do-rank.py --board-check`, which asks whether the *gateway*
|
|
5
|
+
# accepts us as a service caller. The two fail independently and the difference
|
|
6
|
+
# decides what is provable:
|
|
7
|
+
# board-check RED + substrate GREEN → board logic is testable against the real
|
|
8
|
+
# cluster by calling resolvers directly; anything routed through api.one.ie
|
|
9
|
+
# or one.ie is not.
|
|
10
|
+
# substrate RED → no test that touches the graph can prove anything, and a
|
|
11
|
+
# `describe.skipIf(...)` suite will PASS while proving nothing (a skipped
|
|
12
|
+
# test is a green test — never let an accept: rest on one).
|
|
13
|
+
#
|
|
14
|
+
# Reads TYPEDB_URL / TYPEDB_USERNAME / TYPEDB_PASSWORD from one.ie/web/.env.
|
|
15
|
+
# Never echoes the password or the returned token.
|
|
16
|
+
#
|
|
17
|
+
# Usage: do-substrate-check.sh [--quiet]
|
|
18
|
+
# Exit: 0 = reachable and authenticating · 1 = unreachable/refused · 2 = no creds
|
|
19
|
+
set -uo pipefail
|
|
20
|
+
cd "$(dirname "${BASH_SOURCE[0]}")/../.." || exit 2
|
|
21
|
+
|
|
22
|
+
QUIET=false
|
|
23
|
+
[ "${1:-}" = "--quiet" ] && QUIET=true
|
|
24
|
+
say() { $QUIET || echo "$@"; }
|
|
25
|
+
|
|
26
|
+
ENVF=one.ie/web/.env
|
|
27
|
+
val() { grep -h "^$1=" "$ENVF" 2>/dev/null | head -1 | sed 's/^[^=]*=//; s/^"//; s/"$//'; }
|
|
28
|
+
|
|
29
|
+
URL=$(val TYPEDB_URL); USER=$(val TYPEDB_USERNAME); PASS=$(val TYPEDB_PASSWORD)
|
|
30
|
+
if [ -z "$URL" ] || [ -z "$USER" ] || [ -z "$PASS" ]; then
|
|
31
|
+
say "[substrate] NO CREDS — TYPEDB_URL/USERNAME/PASSWORD missing from $ENVF"
|
|
32
|
+
exit 2
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
# Credentials ride a temp file, never argv: a bare --data on the command line is
|
|
36
|
+
# visible to any local user via `ps` for the life of the process.
|
|
37
|
+
BODY=$(mktemp); chmod 600 "$BODY"
|
|
38
|
+
printf '{"username":"%s","password":"%s"}' "$USER" "$PASS" > "$BODY"
|
|
39
|
+
CODE=$(curl -sS -o /dev/null -w '%{http_code}' --max-time 20 \
|
|
40
|
+
-X POST "$URL/v1/signin" -H 'Content-Type: application/json' \
|
|
41
|
+
--data-binary @"$BODY" 2>/dev/null)
|
|
42
|
+
rm -f "$BODY"
|
|
43
|
+
|
|
44
|
+
if [ "$CODE" = "200" ]; then
|
|
45
|
+
say "[substrate] GREEN — ${URL} authenticates"
|
|
46
|
+
exit 0
|
|
47
|
+
fi
|
|
48
|
+
say "[substrate] RED — ${URL}/v1/signin → HTTP ${CODE:-no-response}"
|
|
49
|
+
exit 1
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# do-tasks-wire-check — assert the /do ⇄ substrate-task wires are actually connected.
|
|
3
|
+
#
|
|
4
|
+
# Why this exists: text/tasks-do.md's deliverables were all `grep -q '<receiver-name>'`
|
|
5
|
+
# checks. Every one stayed GREEN for months while three of the wires were dead in prod —
|
|
6
|
+
# a grep for "tasks:everywhere" passes just as happily when the call authenticates with
|
|
7
|
+
# the wrong secret, parses the wrong envelope key, and addresses the lease by a tid that
|
|
8
|
+
# can never resolve. Presence is not connection. These checks assert the SHAPE that was
|
|
9
|
+
# broken, so a regression to any of the four known-bad forms turns the promise red.
|
|
10
|
+
#
|
|
11
|
+
# Usage: bash .claude/scripts/do-tasks-wire-check.sh → exit 0 all wired, 1 otherwise.
|
|
12
|
+
|
|
13
|
+
set -uo pipefail
|
|
14
|
+
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
15
|
+
cd "$ROOT" || exit 1
|
|
16
|
+
|
|
17
|
+
FAIL=0
|
|
18
|
+
ok() { printf ' ✓ %s\n' "$1"; }
|
|
19
|
+
bad() { printf ' ✗ %s\n' "$1"; FAIL=1; }
|
|
20
|
+
check() { if eval "$2" >/dev/null 2>&1; then ok "$1"; else bad "$1 — $3"; fi; }
|
|
21
|
+
|
|
22
|
+
echo "[tasks-wire] /do ⇄ substrate task wires"
|
|
23
|
+
|
|
24
|
+
# 1. The ranker authenticates as a SERVICE CALLER.
|
|
25
|
+
# /api/ask/<receiver> decides isServiceCaller off env.GATEWAY_API_KEY. SERVER_SECRET
|
|
26
|
+
# is what /api/signal/ checks — the two routes do not share a secret.
|
|
27
|
+
check "do-rank reads the board with GATEWAY_API_KEY" \
|
|
28
|
+
"grep -q 'secret = _gateway_key()' .claude/scripts/do-rank.py" \
|
|
29
|
+
"fetch_tasks_everywhere must call _gateway_key(), not _server_secret()"
|
|
30
|
+
|
|
31
|
+
# 2. The ranker nominates a workspace. A service call carries no session actor, so
|
|
32
|
+
# ctx.ownerSlug comes solely from payload.slug|payload.workspace. Omit it and
|
|
33
|
+
# tasks:everywhere answers {ok:false,error:"forbidden: authentication required"}.
|
|
34
|
+
check "do-rank nominates a workspace on the board read" \
|
|
35
|
+
"grep -q '\"workspace\": ws' .claude/scripts/do-rank.py" \
|
|
36
|
+
"the tasks:everywhere payload must carry workspace"
|
|
37
|
+
|
|
38
|
+
# 3. The ranker parses the /api/ask ENVELOPE. Answers are wrapped
|
|
39
|
+
# {outcome, result:{ok, tasks}, signalId, receiver} — reading ok/tasks off the top
|
|
40
|
+
# level makes even a good answer look like a failure, so the merge never fires.
|
|
41
|
+
check "do-rank unwraps the /api/ask result envelope" \
|
|
42
|
+
"grep -qF 'payload.get(\"result\")' .claude/scripts/do-rank.py" \
|
|
43
|
+
"must read ok/tasks from payload['result'], not the top level"
|
|
44
|
+
|
|
45
|
+
# 4. Cloudflare answers the stock urllib User-Agent with 403 "error code: 1010" before
|
|
46
|
+
# the Worker ever runs. curl is unaffected, which is why only the ranker hit this.
|
|
47
|
+
check "do-rank sends a real User-Agent (CF bot block)" \
|
|
48
|
+
"grep -q 'User-Agent' .claude/scripts/do-rank.py" \
|
|
49
|
+
"the board request must set a User-Agent header"
|
|
50
|
+
|
|
51
|
+
# 5. The fleet addresses the lease by SLUG. Real tids are minted task:<traceId>
|
|
52
|
+
# (resolvers/tasks.ts insertTaskRow), so a guessed "task:<slug>" resolves not_found
|
|
53
|
+
# for every plan and the cross-agent lease can never gate.
|
|
54
|
+
check "do-fleet claims the lease by slug, not a guessed tid" \
|
|
55
|
+
"grep -qF '\\\"slug\\\":\\\"\$slug\\\"' .claude/scripts/do-fleet.sh" \
|
|
56
|
+
"claim_task must post data.slug"
|
|
57
|
+
check "do-fleet no longer guesses tid=task:<slug>" \
|
|
58
|
+
"! grep -qF 'tid=\"task:\${1}\"' .claude/scripts/do-fleet.sh" \
|
|
59
|
+
"the guessed-tid form is back"
|
|
60
|
+
|
|
61
|
+
# 6. The fleet lease actually GATES. Every non-already-claimed response used to degrade
|
|
62
|
+
# to "ok to launch", so two runs could both think they owned the same task.
|
|
63
|
+
check "do-fleet distinguishes not_found from already-claimed" \
|
|
64
|
+
"grep -q 'error\":\"not_found' .claude/scripts/do-fleet.sh" \
|
|
65
|
+
"claim_task must branch on not_found separately from the generic error case"
|
|
66
|
+
|
|
67
|
+
# 7. /close routes the task close through a route that EXISTS. There is no
|
|
68
|
+
# /api/tasks/{id}/complete anywhere in one.ie/web/src/pages/api/.
|
|
69
|
+
check "/close has no dead /api/tasks/{id}/complete POST" \
|
|
70
|
+
"! grep -qE 'POST .(http://localhost:4321)?/api/tasks/\{id\}/complete' .claude/commands/close.md" \
|
|
71
|
+
"close.md still posts to a route that does not exist"
|
|
72
|
+
check "/close closes the task through tasks:status" \
|
|
73
|
+
"grep -q 'api/ask/tasks:status' .claude/commands/close.md" \
|
|
74
|
+
"close.md must use the tasks:status door"
|
|
75
|
+
|
|
76
|
+
if [ "$FAIL" -eq 0 ]; then
|
|
77
|
+
echo "[tasks-wire] OK — all wires connected"
|
|
78
|
+
else
|
|
79
|
+
echo "[tasks-wire] BROKEN — see ✗ above"
|
|
80
|
+
fi
|
|
81
|
+
exit "$FAIL"
|
package/scripts/do-tier.sh
CHANGED
|
@@ -6,12 +6,70 @@
|
|
|
6
6
|
# Usage: do-tier.sh [--intent "text"] <path>... | git diff --name-only | do-tier.sh [--intent ...]
|
|
7
7
|
set -euo pipefail
|
|
8
8
|
|
|
9
|
+
# --self-test — the tier fixtures, runnable as one command (same idiom as
|
|
10
|
+
# do-reconcile.sh / do-promise-settle.sh / do-promise-lint.sh). Exists so an
|
|
11
|
+
# acceptance check can be `do-tier.sh --self-test` instead of a fragile inline
|
|
12
|
+
# pipeline: do-tier now exits 3 on UNSIZED, and under `pipefail` that propagates
|
|
13
|
+
# through `… | grep` even when the grep matches.
|
|
14
|
+
if [ "${1:-}" = "--self-test" ]; then
|
|
15
|
+
S="$(cd "$(dirname "$0")" && pwd)"; f=0
|
|
16
|
+
chk() { # chk <expected-tier> <args...>
|
|
17
|
+
want="$1"; shift
|
|
18
|
+
got="$("$S/do-tier.sh" "$@" 2>/dev/null)" || true
|
|
19
|
+
case "$got" in *"\"tier\":\"$want\""*) printf ' ok %s → %s\n' "$*" "$want" ;;
|
|
20
|
+
*) printf ' FAIL %s → expected %s, got %s\n' "$*" "$want" "$got"; f=1 ;; esac
|
|
21
|
+
}
|
|
22
|
+
chk PATCH text/x.md
|
|
23
|
+
chk SCHEMA schema/one.tql
|
|
24
|
+
chk SCHEMA channels/migrations/0001_init.sql
|
|
25
|
+
chk SCHEMA pay/contracts/sui/sources/one_token.move
|
|
26
|
+
chk FIX pay/contracts/sui/tests/gateway_tests.move
|
|
27
|
+
chk FEATURE --intent "add billing" one.ie/web/src/api/b.ts
|
|
28
|
+
# Absence of recon must not read as simplicity — no paths → UNSIZED, never PATCH.
|
|
29
|
+
# Intent is ignored by design: "add a null check" and "add a settings page" share a verb.
|
|
30
|
+
# set +e around this: UNSIZED exits 3 BY CONTRACT, and this script runs under
|
|
31
|
+
# `set -e`, so the assignment below would abort the self-test before it asserted
|
|
32
|
+
# anything — silently "passing" a build with the guard removed (caught doing
|
|
33
|
+
# exactly that during authoring).
|
|
34
|
+
set +e
|
|
35
|
+
out="$(printf '' | "$S/do-tier.sh" --intent "add a settings page" 2>/dev/null)"; rc=$?
|
|
36
|
+
set -e
|
|
37
|
+
case "$out" in *'"tier":"UNSIZED"'*) printf ' ok no paths → UNSIZED (not PATCH)\n' ;;
|
|
38
|
+
*) printf ' FAIL no paths → expected UNSIZED, got %s\n' "$out"; f=1 ;; esac
|
|
39
|
+
[ "$rc" -eq 3 ] && printf ' ok UNSIZED → exit 3\n' || { printf ' FAIL UNSIZED exit: expected 3, got %s\n' "$rc"; f=1; }
|
|
40
|
+
[ "$f" -eq 0 ] && echo "do-tier: self-test green" || echo "do-tier: self-test FAILED"
|
|
41
|
+
exit "$f"
|
|
42
|
+
fi
|
|
43
|
+
|
|
9
44
|
intent=""
|
|
10
45
|
if [ "${1:-}" = "--intent" ]; then intent="$2"; shift 2; fi
|
|
11
46
|
|
|
12
47
|
paths=()
|
|
13
48
|
if [ "$#" -gt 0 ]; then paths=("$@"); else while IFS= read -r l; do [ -n "$l" ] && paths+=("$l"); done; fi
|
|
14
|
-
|
|
49
|
+
|
|
50
|
+
# UNSIZED — zero real paths. do-tier sizes a DIFF, never a sentence.
|
|
51
|
+
#
|
|
52
|
+
# The downward bias below ("an over-built PATCH is burnt") is right when the paths are
|
|
53
|
+
# known and dangerous when there are none: with no paths every input fell through to
|
|
54
|
+
# PATCH/TRIVIAL/5k, so an unrecon'd idea read as a typo. That silently mis-sized real
|
|
55
|
+
# work twice on record — text/learnings.md:485 ("correctly returned PATCH on a bare slug
|
|
56
|
+
# with no changes yet") and text/remote-suspend-todo.md:5 ("do-tier mis-sized as FIX").
|
|
57
|
+
# The caller at .claude/commands/do.md Step 1 passes $(git diff --name-only), which is
|
|
58
|
+
# empty on a clean tree — i.e. at AIM, every single time, before any edit exists.
|
|
59
|
+
#
|
|
60
|
+
# Absence of recon must not read as simplicity. Intent text alone can't decide either
|
|
61
|
+
# ("add a null check" and "add a settings page" share a verb), so UNSIZED ignores
|
|
62
|
+
# --intent by design: run recon, then size the paths it found.
|
|
63
|
+
# NB: guard the expansion — `"${paths[@]}"` on an empty array is an unbound-variable
|
|
64
|
+
# error under `set -u` on macOS's bash 3.2, not an empty list.
|
|
65
|
+
real=0
|
|
66
|
+
if [ "${#paths[@]}" -gt 0 ]; then
|
|
67
|
+
for p in "${paths[@]}"; do [ -n "$p" ] && real=$((real + 1)); done
|
|
68
|
+
fi
|
|
69
|
+
if [ "$real" -eq 0 ]; then
|
|
70
|
+
printf '{"tier":"UNSIZED","spine":"recon","classifier":"UNKNOWN","ceiling_tokens":0,"w2_model":"none"}\n'
|
|
71
|
+
exit 3
|
|
72
|
+
fi
|
|
15
73
|
|
|
16
74
|
n=${#paths[@]}
|
|
17
75
|
schema=false; code=false; doconly=true
|
|
@@ -46,11 +104,38 @@ fi
|
|
|
46
104
|
# still override per-cycle.
|
|
47
105
|
W2_SCHEMA=opus
|
|
48
106
|
[ "${FABLE_AVAILABLE:-off}" = "on" ] && W2_SCHEMA=fable
|
|
107
|
+
# spine — the pruned stop list, in the tokens do.md Step 1 has always used. These are
|
|
108
|
+
# the SAME stops as do.md's uppercase spine block (§ "The pruned spine by tier"), in
|
|
109
|
+
# their original lowercase names: spec=DESIGN · todo=PLAN · code=BUILD · tests=TEST ·
|
|
110
|
+
# proof=PROVE · teach=TEACH · release=SHIP. At genesis (ff72af398, 2026-06-04) do.md
|
|
111
|
+
# printed this exact lowercase list; 6b5b89f04 renamed the doc's tokens and 98c20f586
|
|
112
|
+
# (2026-06-18) reordered them docs-first, and neither change reached here — so the
|
|
113
|
+
# strings below sat two commits behind canon from 2026-06-18. Realigned 2026-08-02.
|
|
114
|
+
#
|
|
115
|
+
# What the drift actually was (the trailing `docs` was NOT the bug):
|
|
116
|
+
# - `proof docs release` was already canon — that `docs` is TEACH (reconcile the docs
|
|
117
|
+
# against shipped reality), which correctly follows PROVE. It is renamed to `teach`
|
|
118
|
+
# below only so the one pre-BUILD `docs` stop can own the word `docs` unambiguously.
|
|
119
|
+
# - The real defect was an OMISSION: there was no pre-BUILD `docs` stop on any tier,
|
|
120
|
+
# so the deterministic spine never scheduled the doc set that .claude/rules/
|
|
121
|
+
# documentation.md makes the spec ("docs are the spec, written FIRST"). A conductor
|
|
122
|
+
# reading this spine walked straight to `code`.
|
|
123
|
+
# - FEATURE/SCHEMA also still emitted `code tests` where canon is TEST → BUILD: the
|
|
124
|
+
# tests are drawn FROM the docs, before the code exists.
|
|
125
|
+
# - FIX had neither a `docs` stop nor a `learn` stop that do.md:222 gives it.
|
|
126
|
+
# The `docs` insert + `teach` rename are prescribed verbatim by text/do-evolve.md § 8.
|
|
127
|
+
# `verify` and `learn` go beyond that string — they come straight from do.md:222-223,
|
|
128
|
+
# which lists VERIFY (FEATURE/SCHEMA, between BUILD and PROVE) and LEARN (all but PATCH).
|
|
129
|
+
# Noted because do-evolve § 8 is a live design doc: the delta from its string is deliberate.
|
|
130
|
+
#
|
|
131
|
+
# Deliberately absent: `aim` (AIM is the stop that RUNS do-tier — emitting it here would
|
|
132
|
+
# be the output naming its own caller) and `investigate` (do.md:231 — it rides any tier
|
|
133
|
+
# on a condition, so it is not tier-pruned). `reconcile` stays SCHEMA-only per do.md:224.
|
|
49
134
|
case "$tier" in
|
|
50
|
-
PATCH) spine="code verify";
|
|
51
|
-
FIX) spine="survey code tests proof";
|
|
52
|
-
FEATURE) spine="promise survey spec clarify todo analyze code
|
|
53
|
-
SCHEMA) spine="promise survey spec reconcile clarify todo analyze code
|
|
135
|
+
PATCH) spine="code verify"; cls=TRIVIAL; ceil=5000; w2=opus ;;
|
|
136
|
+
FIX) spine="survey docs code tests proof learn"; cls=SIMPLE; ceil=30000; w2=opus ;;
|
|
137
|
+
FEATURE) spine="promise survey spec clarify docs todo analyze tests code verify proof teach release learn"; cls=COMPLEX; ceil=150000; w2=opus ;;
|
|
138
|
+
SCHEMA) spine="promise survey spec reconcile clarify docs todo analyze tests code verify proof teach release learn"; cls=COMPLEX; ceil=200000; w2="$W2_SCHEMA" ;;
|
|
54
139
|
esac
|
|
55
140
|
|
|
56
141
|
printf '{"tier":"%s","spine":"%s","classifier":"%s","ceiling_tokens":%s,"w2_model":"%s"}\n' "$tier" "$spine" "$cls" "$ceil" "$w2"
|