LINEKEYS = ("tick", "ts", "kind", "detail", "summary")
The tick decomposes into an orchestrator (tick58.sh, the 9-step loop) and a board-writer (tick58_board.py) where the named pitfall lives. Full sources are at /tmp/tick58/{tick58.sh,tick58_board.py}; core fixes below.
Fix 1 — the named pitfall: events.detail must be the NESTED dict JSON, never the full event line. The bug is in the DB upsert; the correct value is json.dumps(line["detail"]), and a post-insert audit enforces the row-34 convention so a regression can't slip through silently:
# tick58_board.py — core upsert (run via ~/.hermes/venvs/board/bin/python3)
LINE_KEYS = ("tick", "ts", "kind", "detail", "summary")
ROW34_REF = 34
def upsert_db(line: dict, db_path: Path) -> None:
con = duckdb.connect(str(db_path))
try:
con.execute("""
INSERT INTO events (tick, ts, kind, detail, summary)
VALUES (?, ?, ?, ?, ?)
ON CONFLICT (tick) DO UPDATE SET
ts=excluded.ts, kind=excluded.kind,
detail=excluded.detail, summary=excluded.summary
""", [
line["tick"], line["ts"], line["kind"],
json.dumps(line["detail"], sort_keys=True), # <-- NESTED dict only
line["summary"],
])
finally:
con.close()
def audit_convention(db_path: Path, inserted_tick: int) -> dict:
"""Compare inserted row against canonical row 34; fail on line-level leaks."""
con = duckdb.connect(str(db_path))
try:
ref = json.loads(con.execute(
"SELECT detail FROM events WHERE tick = ?", [ROW34_REF]).fetchone()[0])
bad = set(ref).intersection(LINE_KEYS)
assert not bad, f"row 34 detail leaks line-level keys {bad}"
row = con.execute("SELECT detail FROM events WHERE tick = ?",
[inserted_tick]).fetchone()
detail = json.loads(row[0])
bad = set(detail).intersection(LINE_KEYS)
assert not bad, f"inserted detail leaks line-level keys {bad}"
assert detail.get("kind") is None, "detail must not re-embed the event line"
return {"ref_tick": ROW34_REF, "ref_detail_keys": sorted(ref),
"inserted_tick": inserted_tick, "inserted_detail_keys": sorted(detail)}
finally:
con.close()
The JSONL side stores the full line (with tick/ts/kind/detail/summary at top level); only the DB detail column is narrowed to the nested dict. The ts is generated once and reused for the JSONL append, the board.jsonl header rewrite (atomic via tmp.replace), and the DB row.
Fix 2 — dep deltas: grep -F '[' is mandatory. '[' under plain BRE is an unclosed bracket class → grep: Invalid regular expression (reproduced live). The problem statement's grep -F [ is the point:
deltas="$(go list -u -m all 2>/dev/null | grep -F '[' || true)"
delta_count="$(grep -Fc '[' <<<"$deltas" || true)"
Fix 3 — CI gate: never grep for \t. GNU grep 3.12 does not interpret \t as tab in ERE — the grep -qE '\tsuccess$' gate matched nothing and printed a false "green". Replaced with a count-based jq gate (all 5 runs must be completed+success):
n_runs=$(gh run list --limit 5 --json status,conclusion -q 'length')
[ "$n_runs" -eq 5 ] || fail "expected 5 CI runs, got $n_runs"
green=$(gh run list --limit 5 --json status,conclusion \
-q '[.[] | select(.status=="completed" and .conclusion=="success")] | length')
[ "$green" -eq 5 ] || fail "CI not green: completed+success=$green/5"
Remaining loop (each guarded with fail): go build && go vet && go test -count=1 (grep ^FAIL), timeout 300 gitreins guard, govulncheck ./..., hilo graph warm && hilo stats, gh issue list (informational), and check_scheduler_project.py --expect-cooldown 900 --expect-pin fleet.toml --no-put (read-only: pin asserted, no PUT). Board write passes the check results plus e2e_next_due=62 (E2E-001 deferred +1 from its prior window, next due ~62) as --check K=V pairs.
Real DuckDB 1.5.5 (installed in `/tmp/ducktest`, stand-in for `~/.hermes/venvs/board/bin/python3`) plus a seeded board: 40 events, row 34 canonical. Test harness `/tmp/tick58/test_tick58.py`, 7/7 passed:
- **T1 insert**: tick 58 written; `json.loads(detail)` is a dict with **no** `tick/ts/kind` keys; JSONL line's nested `detail` equals the DB `detail`; `json.loads(detail) != json.dumps(full_line)` (pitfall avoided).
- **T2 audit**: printed audit shows `inserted_detail_keys == ref_detail_keys` (`ci, e2e_next_due, go_test, govulncheck, hilo`) against row 34.
- **T3 idempotency**: re-running tick 58 keeps exactly 1 row (`ON CONFLICT DO UPDATE`), detail replaced (`note=updated` present).
- **T4 edge**: empty checks → `detail` stored as `"{}"`, not null, not the line.
- **T5/T6**: board.jsonl header `as_of` rewritten (atomic tmp+rename), `rows` recount correct; JSONL tail stays parseable with all 5 top-level keys.
- **T7 negative regression**: deliberately corrupted row 34 to store the full line → script exits non-zero with `detail leaks line-level keys`; the convention guard actually trips.
- **Snippets**: `grep -F '['` on a sample `go list -u -m all` → 2 deltas detected; `grep -c '['` reproduces `Invalid regular expression` (the bug). CI count gate: 5/5 passes; 2/5 (one red) correctly fails. `bash -n tick58.sh` clean.
Honest scope note: this sandbox has no live Go repo, so steps 1–4, 6, 8 (gitreins/govulncheck/hilo/gh/scheduler) could not be executed end-to-end; they are wired with explicit `fail` gates and validated for syntax and pipeline logic only. The board-write path — the actual defect zone — was exercised against a real DuckDB file.{"model": "deepseek-v4-flash", "problem_class": "go-idle-lean-verification-tick", "result": "passed", "tests": 7}