- DC-160: /catalog/:appId read app.image/ports/env/volumes which live under
app.docker.* — every detail response was empty. Now reads docker.* and
surfaces defaultPort/subdomain/healthCheck/mediaMount/claimToken/difficulty/
setupInstructions for the deploy form. List/search use the templates own
category field (old hand-rolled CATEGORY_MAP mis-categorized apps).
- Shield (routes/shield.js + 5-line app.js mount) committed to source after
weeks as prod-only drift; regression test asserts the mount exists.
- New composition-root e2e suite: boots REAL createApp() on an ephemeral
port, probes the historically-broken routes through the REAL mount table
(wizard wiring, shield, catalog detail, deploys bridge) — the class of bug
all 3 P7 dogfood findings belonged to. 5 tests.
- Full suite 3499/3499 (155 suites); table-driven DC-160 test covers all 73
image templates.
Dogfood finding #3: upsertPerson resolved existing records by id only.
The wizard upserts a bootstrap admin AFTER a provider sync has already
created a person for the same Tailscale user (no id passed), so the same
providerUserId was duplicated into two records. Resolve existing by
providerUserId when no id is given; bootstrap Admin group + protectedAt are
preserved on the merge. New regression test; full suite 3414/3414.
- routes/ca.js: declare format before pfx/pem/crt dispatch (was ReferenceError
on every request that passed validation); add CA_CERT_FORMATS single source
of truth + hardened format extraction (string-coerce, whitelist)
- routes/caddycode.js: fix upstream-validation regexes (control-char classes)
- routes/logs.js: SSE/validation lint fixes
- routes/openclaw.js: remove useless regex escape in ALLOWED_PATH_RE
- fleet-validation.js + http-caddy-admin-origin test: eslint-disable for
intentional control-regex security sentinels
- ca-dc076.routes.test.js: regression test for declared format + behavioral
coverage of format validation (now pre-PKI)
Judge: Qwen lane (qwen3.8-max) grade B, 0 blocking, verdict
/tmp/judge-batch1-verdict.json. API suite 2859/2859 green.
The host-side uptime watchdog and on-host cron jobs curl Caddy with a stock
curl/8.5.0 UA from loopback and the host tailscale IP — ~300 GET /api/health
401 warn-events/day burying real perimeter signal (census: 339+20 of 5000
access.log lines). Dropping on UA alone would blind the store to external
curl scanners, so generic tool UAs (curl/) are now dropped ONLY when the
source remote_ip is one of this host's own addresses (DASHCADDY_SELF_IPS,
default loopback; start.sh derives 127.0.0.1 + tailscale ip -4, empty-safe).
remote_ip (TCP peer) is used, never the spoofable client_ip. DashCaddy-*
probe UAs stay unconditionally dropped. 9 regression pins cover the full
conjunction matrix incl. external-IP+curl KEPT and spoofed-XFF KEPT.
2858/2858 green (128 suites).
Judge: glm-4.6@zai-coding-paas cold-read round 1 = A clean (0 blocking),
both polish notes folded. URN urn:ump:s2sgitfepze65crtp57dpdw4gk4w7upsoi4tqcvfwahcsicyepba
- query().total: full-scan true count (was capped at offset+limit by an
early break — dashboard 24h stat read ≤1000 vs real ~46k)
- trim trigger/curer mismatch: byte trigger + line curer never converged
when avg line > ~524B (live avg 355B); now keeps maxDisk lines OR
≤80% byte budget, whichever retains fewer (TRIM_TARGET_FACTOR);
budget env-overridable via SECURITY_EVENT_TRIM_BYTES / opts.trimSizeLimit
- trim/append race: trim renamed over the file mid-append losing events
to the unlinked inode; now single-flight, queue-empty gated, holds the
write lock, error paths always release + lazily re-kick (no hot loop)
Judge: glm-4.6@zai-coding-paas adversarial cold-read, grade B clean
(0 blocking, 4 polish — 2 folded, 1 already-satisfied, 1 deferred as
judge-endorsed safer). 127 suites / 2849 tests green.
The caddy tail worker (DC-112) was 100% dead in prod: no /var/log/caddy
mount, no CADDY_ACCESS_LOG env, no global access log in the Caddyfile.
Store census 45,912 events, 100% source_type 'api', ZERO 'caddy'.
- createTail: firstStartMaxBytes (5 MiB) bounds first-ever-start replay
against a long-lived access.log; multi-chunk partial-line discard on
the jump; normal restarts resume at exact persisted offset (judge r1
fix-first fold)
- worker: self-noise filter drops our own probe UAs
(DashCaddy-Probe/1.0, DashCaddy-HealthCheck/1.0) from the derived
store — raw log keeps everything; ~50-100 events/min of probe noise
would otherwise bury perimeter signal in the 100k-cap store
- worker: metadata.host reads request.host (real caddy JSON nests it;
verified against live /var/log/caddy/seeds.log — the DC-112 read was
always null on live lines); top-level fallback kept
- worker: onAppear recovery log (DC-112 judge polish fold)
- start.sh: -v /var/log/caddy:/var/log/caddy:ro + CADDY_ACCESS_LOG env
- README: dead caddy-api/ dir refs -> dashcaddy-api/ (queue item e)
- tests: +12 DC-113 pins (hermetic, real worker + store); DC-112
fixtures corrected to the real nested request.host shape
126 suites / 2841 tests green. Judge: GLM-5.3 round-1 B, round-2 A
(SHIP). Verdict urn:ump:mccln523fptotuvrmddlqpf4zpkrxf273tg4kyytuyy3776rj3pq