fix: replace partial pattern in readProcessBytes with explicit case
Build and Deploy / build-and-deploy (push) Successful in 1m28s

Also adds type-safety conventions to AGENTS.md: no partial patterns on
IO results, no partial functions (head/tail/fromJust), always use case
with explicit branches.
This commit is contained in:
2026-05-20 15:05:48 -04:00
parent 8d1ff6eb86
commit 6f610c5d86
2 changed files with 38 additions and 7 deletions
+25
View File
@@ -86,3 +86,28 @@ mkdir -p .stack-root
- When adding a new subproject (e.g. `roux-server`), initialize it with `./hs stack new`.
- Use `hpack` (via `./hs hpack`) for package metadata in `package.yaml` format.
- When agent-created files are owned by root, fix ownership with `sudo chown -R $(id -u):$(id -g) .`.
### Type safety and pattern matching
This project compiles with `-Wall -Werror`, including `-Wincomplete-uni-patterns`
and `-Wincomplete-record-updates`. Partial functions and irrefutable pattern
matches (`let (Just x) = ...`, `(Just x, _) <- ...`) will fail at runtime or
be rejected by the compiler.
**Rules:**
- **Never** use irrefutable/partial pattern matches on `Maybe`, `Either`, or
tuple results from `IO` actions. Always use `case` with an explicit branch
for each constructor, or use pattern-matching helpers (`maybe`, `either`).
- **Never** call partial functions: `head`, `tail`, `init`, `last`, `fromJust`,
`read` (use `readMaybe`), `succ`, `pred`, `(!!)`. Use total alternatives:
`foldl'` for `head`/`tail` on lists, `Data.Map.lookup` for map access,
`take 1` or pattern matching on `NonEmpty`.
- **Never** use `error`, `undefined`, or `panic` for recoverable failures.
Use `Either`, `Maybe`, or explicit `IO` error handling (`ioError`,
`Control.Exception.throwIO`).
- **Always** fully handle all constructors in case expressions. Use a wildcard
(`_ ->`) only when you genuinely don't care about the value, and add a
comment explaining why.
- **Prefer** `case` over `<-` pattern binds in `do` notation when the pattern
could conceivably fail at runtime.
+13 -7
View File
@@ -243,13 +243,19 @@ readProcessBytes cmd args = do
{ std_out = CreatePipe
, std_err = CreatePipe
}
(Just outH, Just errH, _, ph) <- createProcess process
hSetBinaryMode outH True
hSetBinaryMode errH True
out <- LB.hGetContents outH
err <- LB.hGetContents errH
ec <- waitForProcess ph
return (ec, out, err)
result <- createProcess process
case result of
(Just outH, Just errH, _, ph) -> do
hSetBinaryMode outH True
hSetBinaryMode errH True
out <- LB.hGetContents outH
err <- LB.hGetContents errH
ec <- waitForProcess ph
pure (ec, out, err)
_ ->
ioError $
userError $
"[roux] createProcess did not return std_out/std_err pipes for " <> cmd
-- | Locate the scrape-recipe script: check PATH first, then relative to project.
findScrapeScript :: IO FilePath