docs: record two Command Center traps that each cost time today

Both are silent in the expensive direction, which is why they are written down
rather than remembered.

A webhook registered without the shared signing secret looks entirely healthy
in Forgejo — active:true, test deliveries accepted with 204 — and has every
delivery rejected by privacyllc.dev with 401 bad_signature. Forgejo exposes no
delivery history through its API, so nothing says so. This repository ran that
way for ten minutes today. Includes how to prove a delivery lands.

A check-in's projectId is the UUID, not the slug, unlike every other route in
that API. A slug returns a generic {"code":"unknown"} 500 that names no field
and is indistinguishable from a genuinely malformed request.

Also records that neither reconcile_all nor sync_projects forces a re-read of a
project inside its freshness window, and that the agent API has no per-project
force — so refreshed=0 means "not due", not "nothing to do".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ripley 2026-08-18 01:36:46 -05:00
parent 1d952a0170
commit 493b97e4a4
1 changed files with 41 additions and 4 deletions

View File

@ -226,6 +226,33 @@ BASE="https://privacyllc.dev/api/internal/v1"
AUTH="Authorization: Bearer $TOKEN" AUTH="Authorization: Bearer $TOKEN"
``` ```
**Two things about refreshing that are worth knowing before you need them.**
*The webhook must carry the signing secret.* `POST /repos/null/Queue-North-Website/hooks`
with a URL and no `secret` produces a hook that looks perfectly healthy in
Forgejo — `active: true`, test deliveries accepted with a 204 — and whose every
delivery is rejected by privacyllc.dev with `401 bad_signature`. Forgejo exposes
no delivery history through its API, so nothing anywhere says so. This repository
ran in exactly that state for ten minutes on 2026-08-18. The secret is
`FORGEJO_WEBHOOK_SECRET` in `~/.openclaw/credentials/privacyllc.md`. To prove a
delivery actually lands, sign a payload yourself and look for `"applied":true`:
```bash
WHSEC=$(grep '^FORGEJO_WEBHOOK_SECRET=' ~/.openclaw/credentials/privacyllc.md | cut -d= -f2-)
# HMAC-SHA256 of the body, in X-Forgejo-Signature (hex, no "sha256=" prefix).
# X-Hub-Signature-256 is NOT accepted.
```
*A reconcile does not force a re-read.* Both `reconcile_all` and `sync_projects`
skip a project that is inside its freshness window, reporting `refreshed=0
still_due=0` — which reads exactly like "nothing to do" and means "not yet due".
There is no per-project force in the agent API: `{"kind":"refresh"}` and
`{"kind":"reconcile"}` are both refused, and only `reconcile_all` and
`sync_projects` can be triggered. So a tracker change made minutes after a sweep
is not visible on the card until the next one, however many times you reconcile.
That is a wait, not a failure — but say so rather than reporting the numbers as
updated.
**Reconcile** — re-read the tracker and the pushed documents. Do this after the **Reconcile** — re-read the tracker and the pushed documents. Do this after the
push, not before: push, not before:
@ -250,13 +277,23 @@ curl -sk -X PATCH -H "$AUTH" -H "Content-Type: application/json" \
**A check-in** — a timestamped "what changed", when there is something real to **A check-in** — a timestamped "what changed", when there is something real to
report. `summary` is required and must say something; the API refuses an empty report. `summary` is required and must say something; the API refuses an empty
"no change" update, deliberately: "no change" update, deliberately.
**`projectId` here is the UUID, not the slug.** Every other route in this API
takes the slug, and this one answers a slug with `{"code":"unknown","message":
"Something went wrong."}` — a generic 500 that says nothing about which field is
wrong, and which is identical to the error for a genuinely broken request. It
cost twenty minutes on 2026-08-18 and it will cost the next person the same
unless they read this line. Read the UUID from the project first:
```bash ```bash
UUID=$(curl -sk -H "$AUTH" "$BASE/agent/projects/queue-north-website" \
| python3 -c 'import sys,json;print(json.load(sys.stdin)["project"]["id"])')
curl -sk -X POST -H "$AUTH" -H "Content-Type: application/json" \ curl -sk -X POST -H "$AUTH" -H "Content-Type: application/json" \
-d '{"projectId":"queue-north-website","health":"on_track", -d "{\"projectId\":\"$UUID\",\"health\":\"on_track\",
"summary":"<what changed>","accomplishments":"<what landed>", \"summary\":\"<what changed>\",\"accomplishments\":\"<what landed>\",
"blockers":"<what is stuck, or omit>","nextActions":"<what is next>"}' \ \"blockers\":\"<what is stuck, or omit>\",\"nextActions\":\"<what is next>\"}" \
"$BASE/agent/updates" "$BASE/agent/updates"
``` ```