live: heartbeat sync 2026-10-19T15:24:41-07:00 (Refs #11)

This commit is contained in:
Frank committed 2026-10-19 15:24:41 -07:00
1 parent 6e3e5594eb
commit c14c64d6c0
12 files changed
+452 -129

No files matched your search

@@ -1,9 +1,11 @@
---
name: gitea-merge-form-encoded
description: "Use when a Gitea API merge on Dankclaw (192.168.0.143:3000) returns HTTP 422 \"[Do]: Required\" — the merge endpoint needs form-encoded fields with the lowercase field name do, not the JSON body that PR creation accepts."
description: "Use when a Gitea API merge on Dankclaw (192.168.0.143:3000) returns HTTP 422 \"[Do]: Required\" or 405 \"Please try again later\" — the merge endpoint needs form-encoded fields with the lowercase field name do, and a behind-main branch must be merged forward before it will merge."
---
Gitea on Dankclaw (192.168.0.143:3000) — merge quirk, measured 2026-10-19 on `dank/serverAppConfigs` and again on `dank/dankvoice`.
Gitea on Dankclaw (192.168.0.143:3000) — merge quirks, measured 2026-10-19 on `dank/serverAppConfigs` and again on `dank/dankvoice`, re-earned the same day on serverAppConfigs PR #27.
## 1. The payload: form-encoded, lowercase `do`
Creating a PR accepts a JSON body. **Merging does not**: `POST /api/v1/repos/{owner}/{repo}/pulls/{n}/merge` with a JSON body (`{"merge_style":"no-ff", ...}`) or with those values as request headers returns `422 {"message":"[Do]: Required"}` — four variants of that all fail identically, so do not "fix" it by changing the style name or moving the headers around.
@@ -12,7 +14,7 @@ Creating a PR accepts a JSON body. **Merging does not**: `POST /api/v1/repos/{ow
Working call (form-encoded):
```bash
tok=$(sed -n 's|http://[^:]*:\([^@]*\)@.*|\1|p' ~/.config/secrets/gitea | head -1) # git credential.helper store file
tok=$(sed -n 's|^https\{0,1\}://[^:]*:\([^@]*\)@192\.168\.0\.143.*$|\1|p' ~/.config/secrets/gitea | head -1) # git credential.helper store file
curl -sS -X POST -w 'http %{http_code}\n' -K <(printf 'header = "Authorization: token %s"\n' "$tok") \
--data-urlencode 'do=merge' \
--data-urlencode 'merge_style=no-ff' \
@@ -25,6 +27,38 @@ curl -sS -X POST -w 'http %{http_code}\n' -K <(printf 'header = "Authorization:
- Verify by fast-forwarding a checkout (`git fetch && git merge --ff-only origin/main`) rather than re-reading the PR.
- Fleet law still applies: never merge without an explicit current OK from Frank, and open the PR URL in his browser (`xdg-open`) the moment it exists.
## 2. `405 {"message":"Please try again later"}` = the branch is behind main
A correctly formed merge call returns **405**, not 422, when Gitea cannot test-merge the head into the base. Read it as "merge main forward", not "retry later" — no sleep-retry ever clears it.
Confirm first: `GET /pulls/{n}` shows `"mergeable": false` (and `merged: false`, `state: open`) for exactly this state.
The fix is the repo's own trunk-based law — merge forward, never rebase:
```bash
git worktree add ../wt-prN -B prN <head-branch>
cd ../wt-prN && git merge --no-edit origin/main # resolve, see below
./tests/run.sh # the seam is the arbiter, run it on the RESOLVED tree
git push -q origin prN:refs/heads/<head-branch> # same branch name; Gitea reuses the open PR
# then re-POST the merge — 200 this time
```
Notes earned on PR #27 (2026-10-19):
- A `git worktree` per PR keeps the deployed checkout untouched; clean up with `git worktree remove --force ../wt-prN && git branch -D prN`.
- `git status --short` during a merge lists every incoming file as staged — that is the merge commit's content, not a dirty tree.
- Push a local branch to the PR's branch name with an explicit refspec (`prN:refs/heads/docs/…`); the push output prints `Visit the existing pull request`, which is how you confirm you hit the right head.
- Gitea needs a few seconds after the push to recompute mergeability; a `sleep 3` before re-POSTing avoids a second 405.
## 3. Resolving vault conflicts against a compaction wave
When main has run a docs compaction (page deletions, description shortening), two conflict shapes recur:
- **`description:`** — `scripts/check-okf.py` enforces **DESC: ≤ 120 chars**. A branch's longer description must be shortened, not argued for; keep main's shape and fold the new topic into the wording.
- **A `[[Page]]` link whose target page main destroyed** — `git ls-tree -r --name-only origin/main -- serverAppConfigs-docs | grep -i '<page>'` settles it. Drop the dead link; do not resurrect a page. Compaction left link-stripped stub bullets behind (`- the compile fix for …`, dash + two spaces): `git grep -nE '^- [A-Z]' origin/main -- 'serverAppConfigs-docs/**/*.md'` counts them, and the seam cannot see them because a stub is no longer a link to validate.
After any frontmatter change, regenerate: `./scripts/gen-vault-index.py serverAppConfigs-docs` and commit the index rows — the `vault indices are generated, not hand-carried` seam diffs regeneration against the checkout. The sub-index sync can emit one extra space after `|` for a quoted description; commit what the generator emits, since the seam compares against the generator.
## Credential-store token extraction (same file, adjacent trap)
`~/.config/secrets/gitea` holds one line shaped `http://user:token@192.168.0.143:3000`. Splitting it with `awk -F'/'` puts the host in `$3`, not `$2`, and `awk -F'/' '{print $NF}'` yields the host+path, not the token — an empty/garbage token makes **private repos answer `404 not found`** (Gitea hides them from anonymous), which reads like a wrong URL rather than an auth failure. Extract with: