What we shipped on 2026-07-14
Today's release notes read like a night watchman's log -- five different flavors of "nobody noticed this was broken," found and closed in the same sitting.
The most alarming one: qa.vision's dedicated Ollama instance, poindexter-ollama-vision-gpu1 on port 11435, had been dead for over a day. GlitchTip issue #877 was climbing -- APIConnectionError: OllamaException counts ticking 95→105 and up -- and the box hadn't crashed, it just quietly stopped answering. Root cause was almost funny once we found it: the scheduled task from background-services.ps1 only triggers AtLogOn, and ollama.exe serve had exited clean (code 0) during a host reboot on 2026-07-13. Windows' RestartCount/RestartInterval only re-arms on a nonzero exit, so a graceful death was invisible to its own safety net. vision_gate is required_to_pass=false, so no posts got blocked -- but the final visual reviewer had been silently absent the whole time, and every pipeline run was logging one more Sentry exception into the noise. Install-Services now re-triggers on the repeating schedule instead of trusting logon events (PR #2500).
That same "silent pass that isn't a pass" shape showed up in the QA gates themselves. multi_model_qa.py::_run_gate_prompt had two branches that swallowed real failures: a completion that comes back non-None but with empty text, and a regex-extracted JSON candidate that still fails to parse on a second attempt -- both returned None without a peep, indistinguishable from a gate that just decided to skip. The issue's framing stuck with us: "a crashed gate looks like a disabled/passing gate." Behavior's unchanged, gates still skip on failure -- but now both paths log a warning, closing the last two sites from the original no-silent-failures sweep (PR #2504).
The nicest bug of the day was buried in markdown-fence stripping. Three different places in the codebase reimplemented "strip the
json fence off this string," and one of them -- `generate_video_shot_list.py::_extract_json_object` -- used a non-greedy regex that matches the *shortest* span to the next triple-backtick. Feed it a director response containing an embedded code example like `wrap code like` ``
this
`for emphasis`, and the parser truncates right there, silently dropping the entire shot list. Genuinely latent, not just style drift -- we reproduced it with a regression test before consolidating all three call sites onto one canonical `strip_markdown_fence` in `services/llm_text.py` (PR #2499).
Two more from the same family of "the code and the docs disagreed and nobody had checked": `writer_core.py` was calling `self_review_and_revise` inline *and* letting the dedicated `writer_self_review` graph node run it again -- for anyone with `enable_writer_self_review=true`, every draft got reviewed twice for zero benefit, just double the latency and cost. And `rag_hybrid_enabled` had been documented as live-on-prod in CLAUDE.md while defaulting `false` in code -- pure SQL (BM25 tsvector plus pgvector RRF fusion), no reason for the drift, so we flipped the default to match reality (PR #2507).
On the security side: `gsc_main`/`ga4_main`'s Google OAuth `client_secret` and `refresh_token` had been sitting in plaintext inside `external_taps.config`'s unencrypted jsonb column -- readable by any SQL session or DB dump. `app_settings.is_secret=true` plus `SiteConfig.get_secret()` is already the established pattern everywhere else; this closed the one place that hadn't adopted it. `tap.singer_subprocess` now takes a `secret_fields` map, resolves each key immediately before the subprocess spawns, and merges it into a copy so the resolved value never touches `row.config`. A forward-only migration salvages any still-plaintext secret into `app_settings` first, then strips it (PR #2502).
Smaller wins rounded out the release: `list_categories`/`list_tags` were fetching every row and slicing in Python -- now they push `LIMIT`/`OFFSET` into SQL with `COUNT(*) OVER ()`, matching the pattern `list_posts` already used (PR #2501). `probe_traffic_anomaly` was comparing partial-day views since midnight UTC against a full 24h average -- for the first nine or ten hours of any day that reads as a 60-100% traffic "drop" no matter what's actually happening -- now it compares rolling trailing-24h windows instead (PR #2498). And on the feature side, `tasks add-image`/`remove-image` finally close the CLI's image-editing gap: no more pasting raw `<img>` tags to remove an inline image, no more needing a URL just to null the featured slot (PR #2503).
None of these were dramatic on their own. Together they're the theme of the day: several places where the system was quietly wrong and nothing was loud enough to tell us. 0.103.0 (PR #2511) ships all of it at once -- the value wasn't in any single fix, it was in going looking for the other four.
_Auto-compiled by Poindexter from today's commits and PRs. [See the work: github.com/Glad-Labs/poindexter](https://github.com/Glad-Labs/poindexter)._
## Sources
- <https://github.com/Glad-Labs/poindexter>
Top comments (0)