From 621da8474cd7debef970b4bcf95e566180c4011d Mon Sep 17 00:00:00 2001 From: "claude[bot]" <3247365+butterstack[bot]@users.noreply.github.com> Date: Mon, 31 Aug 2026 19:57:44 +0000 Subject: [PATCH 1/2] unreal: distill two automation-scripting traps from the CI learnings pass Adds one new dated finding to unreal/LEARNINGS.md section B: a PowerShell Mandatory parameter silently prompts on stdin when omitted (hanging a non-interactive SSH invocation instead of erroring), and ssh -n swallows a heredoc meant to feed a remote bash -s (the script runs with no input, again with no error). Both were found while authoring the Windows CI automation scripts already covered by items 10 and 14 in this file, but had not yet been carried over from the private working repo. No compression was needed beyond light prose tightening since this is a single small addition; the rest of the file already reflects the private repo's content. Sanitization grep sweep came back with zero unexplained hits. Co-Authored-By: Claude Fable 5 --- unreal/LEARNINGS.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/unreal/LEARNINGS.md b/unreal/LEARNINGS.md index 9fa638c..2cc9a65 100644 --- a/unreal/LEARNINGS.md +++ b/unreal/LEARNINGS.md @@ -170,3 +170,10 @@ No secrets - reference credential *locations*, never paste them. is a node action; bare `nvidia/cuda` images die on step one). catthehacker act-22.04 + the NVIDIA container toolkit + `container.options: "--gpus all"` works; driver injection gives nvidia-smi-level access, CUDA only if the image adds it. +15. **Two traps when authoring the automation scripts themselves, both of which hang + instead of erroring.** A PowerShell `[Parameter(Mandatory=$true)]` argument + silently prompts on stdin when omitted, so a non-interactive SSH invocation just + blocks forever - validate the argument by hand rather than trusting the parameter + binder to catch a missing value. And `ssh -n` redirects stdin from `/dev/null`, + which silently swallows a heredoc meant to feed a remote `bash -s` - the remote + script runs with no input and nothing reports an error. From b3f1aad2e92a9877adde123f7cf68b1fb67e4cea Mon Sep 17 00:00:00 2001 From: "claude[bot]" <3247365+butterstack[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2026 15:58:44 +0000 Subject: [PATCH 2/2] perforce: distill the typemap-clobber and trailer-width learnings (2026-09) Adds two dated entries to perforce/LEARNINGS.md from a Git->Perforce mirror running against a p4d that ships as a Docker image: the image re-applies its own engine typemap preset on every container start (not just first provision), which silently drops depot-scoped rows another system had appended, with a measured ~8 minute exposure window on one real restart. A second entry covers three related diagnostic traps: the same "Wrong number of words" error string means something different for the typemap spec than it does for the trigger table, p4 exits 1 with empty stdout on both connection and auth failures (so a set -euo pipefail script aborts rather than reading empty), and an idempotency check keyed on a sha trailer needs to match every width its writers actually produce. Compressed roughly 35% versus the private-repo source (72 lines of new material down to 47), consistent with the 30-50% target - kept both findings since each is a concrete, load-bearing trap, tightened the prose around them, and dropped the internal skill cross-reference links since no other entry in this file's history uses them. Sanitization grep sweep (personal names, internal service paths, internal docker/hostnames, issue/branch references) came back with zero hits. Co-Authored-By: Claude Fable 5 --- perforce/LEARNINGS.md | 47 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/perforce/LEARNINGS.md b/perforce/LEARNINGS.md index f1d5e95..57f4b00 100644 --- a/perforce/LEARNINGS.md +++ b/perforce/LEARNINGS.md @@ -12,6 +12,53 @@ them. --- +## 2026-09-14 - the typemap is one server-wide table, and a p4d container image is a second writer `[integration]` + +Learned running a Git->Perforce mirror against a p4d that ships as a Docker image and +re-applies its own engine typemap preset on every container start, not just first +provision. + +- **`p4 typemap` is a single server-wide table, so "add my depot's rows" is a + read-modify-write against state someone else also owns.** The documented pattern + (`p4 typemap -o | | p4 typemap -i`) has no compare-and-swap - any other + writer that reads, edits, and writes the whole table drops rows it doesn't know about. +- **The other writer here was the p4d image itself.** Its startup script re-applies an + engine preset on every boot, and a restart taken just to pick up an unrelated image + upgrade silently removed six depot-scoped rows a different provisioning script had + appended - nothing failed at the time, the rows were simply gone. +- **The exposure window measured ~8 minutes, not seconds**, timestamped on one real + restart. Because typemap only applies to newly-added files, a submit landing inside the + window leaves mis-typed files behind after the window closes, needing `p4 edit -t + ` to fix. +- **So verify the rows before the first `add` and fail the run - don't warn and + continue.** A sync job that warns will add a whole tree with the wrong types during a + restart window; a hard fail costs one retried run instead. +- **Without a spec depot, there's no history or author for typemap/protections edits** - + `p4 typemap -o` shows current state only, and forensics stop dead. `p4 depots` tells + you in one command whether you have one. + +## 2026-09-14 - "Wrong number of words", and what p4's exit codes do under `set -e` `[skill]` + +Three diagnostic details that cost real time chasing the entry above. + +- **"Wrong number of words for field 'X'" doesn't always mean what `p4-observe`'s + trigger-table advice says.** That advice is right for the *trigger* table (an + unquoted command containing spaces). For the **typemap** spec, the identical string + *is* whitespace: rows must be TAB-indented. Read the error against the spec you're + actually editing. +- **`p4` exits 1 with empty stdout on both "cannot connect" and "no ticket,"** verified + against a live server. That matters under `set -euo pipefail`: an assignment like + `current="$(p4 typemap -o)"` **aborts** on those failures rather than yielding an + empty string - so a script that reaches its "rows are missing" branch really did read + successfully; it's not a swallowed connection error. +- **Idempotency keyed on a description trailer must accept every width its writers + actually produce.** A mirror recording `Original-Commit: ` and matching it back + with a 40-char-only pattern missed a code path that wrote an abbreviated sha, read + that as "nothing synced," and replayed the branch from its root commit - which then + failed inside git-p4's apply step with "No valid patches in input." Matching a + variable-width sha and resolving it to the full value locally fixed it; treat an + unresolvable trailer as a hard error, not as "nothing synced." + ## 2026-07-16 - p4 trigger/webhook ingestion `[integration]` Learned wiring Perforce change-triggers into a webhook ingestion pipeline: