diff --git a/docs/hygiene-history/ticks/2026/05/16/0350Z.md b/docs/hygiene-history/ticks/2026/05/16/0350Z.md new file mode 100644 index 000000000..eb4df5d6b --- /dev/null +++ b/docs/hygiene-history/ticks/2026/05/16/0350Z.md @@ -0,0 +1,76 @@ +# Tick 2026-05-16T03:50Z — Otto-CLI + +**Surface**: Otto-CLI (Claude Code, Opus 4.7 1M context, autonomous-loop tick) +**Parent tick**: 2026-05-16T03:44Z (PR #3717, still in queue at tick-start) + +## What landed this tick + +PR #3715 (0340Z shard) MERGED 03:43:37Z. PR #3716 (check-shard-before-push helper) attracted 6 Copilot threads — 3 real fixes pushed as `38c4b58`; all 6 resolved. + +| PR | Action | Result | +|----|--------|--------| +| ~~#3715~~ | (carry-over) | MERGED 03:43:37Z | +| [#3716](https://github.com/Lucent-Financial-Group/Zeta/pull/3716) | 6 threads → fixup `38c4b58` → resolved | OPEN, armed, 0 unresolved | +| [#3717](https://github.com/Lucent-Financial-Group/Zeta/pull/3717) (0344Z shard) | OPEN, armed | OPEN | + +## The 6 PR #3716 findings — 3 real + 3 duplicates/optional + +### L114 (substring fragility) — REAL + +`runRelativePathAudit` used `out.includes("0 broken relative-path links")` as the success signal. Two problems: + +1. Fragile to future wording tweaks in the audit script's output +2. Ignored `r.status` entirely — a crash, argument error, or future enforcement-mode non-zero exit could be silent-failed + +Fix: 3-tier check — (1) `r.status !== 0` is unambiguous failure (echo stdout+stderr+status); (2) parse `"N broken relative-path links"` count via regex (`/;\s*(\d+)\s+broken relative-path links/`); (3) unrecognized output format → fail loud + echo, don't silent-pass. + +### L69 + L74/L75 (fenced-code MD032) — REAL (3 threads, same finding) + +The `checkMd032` scan didn't track `\`\`\`...\`\`\`` fence state. A `- ` line inside a fenced code block was flagged as a false-positive MD032 violation — exactly what `markdownlint-cli2` correctly ignores. + +Fix: add `buildCodeFenceFlags` (same pattern as `audit-tick-shard-relative-paths.ts` already uses). Verified with synthetic shard containing a bullet inside a fence — reports OK post-fix; reported FAIL pre-fix. + +### L124 (parseArgs process.exit) — REAL + +`parseArgs(argv)` called `process.exit(64)` directly on empty argv, blocking the no-args branch from being unit-tested even though `main` is exported. + +Fix: typed `ParseResult` discriminated union — `{ok: true, args}` or `{ok: false, exitCode: 64, message}`. `main` inspects the result and exits itself. Tests can call `main([])` and observe the return code without process-exit cascade. + +### L86 (multi-file spawn batching) — OPTIONAL, deferred + +Markdownlint-cli2 + the audit script both accept multi-file args; spawning once-per-file in a loop is N spawns. For N=1 typical usage it's irrelevant. Filing as future iteration if multi-shard usage materializes; out of scope for this PR. + +## The fixup approach + +3 lines worth thinking about: + +1. **Tier-3 fallback** for the audit-output parse: if the regex doesn't match, fail loud with "audit produced unrecognized output format" rather than silent-pass. Same shape as the `--baseline` schema validation: prefer structured errors over silent partial-success. +2. **`buildCodeFenceFlags` reuse**: the audit script already had this; the helper was missing it. Cross-file consistency is now an explicit convention worth carrying forward. +3. **Typed ParseResult**: replacing `process.exit` from `parseArgs` is a small but meaningful API-shape change. Worth promoting the pattern to the audit script too in a future tick (the same observation applies there). + +## State at tick end + +| PR | State | +|----|-------| +| [#3716](https://github.com/Lucent-Financial-Group/Zeta/pull/3716) | OPEN, armed, 0 unresolved (3 fixup commits total) | +| [#3717](https://github.com/Lucent-Financial-Group/Zeta/pull/3717) | OPEN, armed, 0 unresolved | +| (this shard) | shard PR pending | + +GraphQL: 142 remaining at tick end (was 209 at tick start); resets at 03:55:31Z (~5 min). + +## Operational notes + +### The thread-resolution tmpfile pattern catches IFS quirks + +Today I tried `for tid in $THREADS; do` with a space-separated string; the loop fired only ONCE with the entire string as `$tid` (the variable expansion didn't word-split in that shell context). The tmpfile + `while IFS= read -r` pattern (from tick 9) reliably iterates regardless. Worth standardizing on the tmpfile pattern. + +### Holding-discipline state + +Concrete code substrate (3 real fixes) + thread cleanup. Counter resets. + +## Next-tick candidates + +1. **Monitor #3716 + #3717 to merge** +2. ~~B-0545 renumber-sweep~~ — done on main (`status: done`, `completed: 2026-05-16`, `completed_by: otto-cli`); the "claim still active until 2026-05-17T01:44Z" note in earlier ticks was stale (peer-Otto-CLI completed the sweep in parallel) +3. **Promote `ParseResult` typed-discriminated-union pattern to `audit-tick-shard-relative-paths.ts`** (same `process.exit` from `parseArgs` issue applies; not blocking, but cross-file consistency) +4. **Document the suspect-Copilot-finding patterns** (4-time table-pipe `||` hallucination + the fixed-but-recurring tests-disable false positive class) in `.claude/rules/blocked-green-ci-investigate-threads.md` as an extension