From the three-lens deep review (review-remediation). Theme: make the error envelope total.
Problem
The README promises every failure is a stable {error:{code,message,details}} envelope, machine-parseable under --json. Today:
- A single malformed-frontmatter task file crashes nearly every command (
list/board/show/next/mv/set/rm/summary) with a raw YAMLParseError stack trace and no envelope, even under --json (src/task-file.ts:31,175,236) — a store-wide DoS writable by any human or agent.
- There is no top-level error boundary (
src/cli.ts:65), so any non-TasksError (corrupt/transient git) escapes the same way and leaks absolute paths.
list/export/summary emit undocumented codes (UNKNOWN_COLUMN, INVALID_ARG) that contradict README (INVALID_COLUMN is documented for the same failure).
Slices
8. Malformed task files degrade gracefully (finding #5)
Guard every on-disk YAML/frontmatter parse; skip-or-surface as a structured error (mirroring how validateEnums already wraps its parse).
9. Top-level error boundary, no path leaks (findings #6, #11)
Add a top-level boundary in the CLI entrypoint that converts any non-TasksError into a sanitized INTERNAL_ERROR envelope; stop re-throwing unknown errors in failFromError; keep absolute home/store paths out of envelope messages and details.
10. Error codes and messages match the README contract (findings #7, #15)
list/export unknown-column emits INVALID_COLUMN (not UNKNOWN_COLUMN); summary's invalid --recent/--stale emit documented codes (not INVALID_ARG). Unify the NOT_INITIALIZED message across list/board/export/summary. Update tests asserting the old codes.
Method
TDD outside-in at the CLI boundary. One commit per green. Error codes come verbatim from the README envelope list.
From the three-lens deep review (review-remediation). Theme: make the error envelope total.
Problem
The README promises every failure is a stable
{error:{code,message,details}}envelope, machine-parseable under--json. Today:list/board/show/next/mv/set/rm/summary) with a rawYAMLParseErrorstack trace and no envelope, even under--json(src/task-file.ts:31,175,236) — a store-wide DoS writable by any human or agent.src/cli.ts:65), so any non-TasksError(corrupt/transient git) escapes the same way and leaks absolute paths.list/export/summaryemit undocumented codes (UNKNOWN_COLUMN,INVALID_ARG) that contradict README (INVALID_COLUMNis documented for the same failure).Slices
8. Malformed task files degrade gracefully (finding #5)
Guard every on-disk YAML/frontmatter parse; skip-or-surface as a structured error (mirroring how
validateEnumsalready wraps its parse).list/board/show/next/summaryand the mutating commands exit with a structured{error:{code,message,details}}envelope, and valid JSON under--json, never a stack trace.9. Top-level error boundary, no path leaks (findings #6, #11)
Add a top-level boundary in the CLI entrypoint that converts any non-
TasksErrorinto a sanitizedINTERNAL_ERRORenvelope; stop re-throwing unknown errors infailFromError; keep absolute home/store paths out of envelope messages anddetails.TasksError(e.g. corrupt git HEAD duringsummary) yields anINTERNAL_ERRORenvelope in both text and--jsonmode, exit 1, no stack trace.detailsfield contains an absolute home/store path.failFromErrorno longer re-throws unknown errors.INTERNAL_ERRORis listed in the README error-code table.10. Error codes and messages match the README contract (findings #7, #15)
list/exportunknown-column emitsINVALID_COLUMN(notUNKNOWN_COLUMN);summary's invalid--recent/--staleemit documented codes (notINVALID_ARG). Unify theNOT_INITIALIZEDmessage across list/board/export/summary. Update tests asserting the old codes.list/exportunknown column emitsINVALID_COLUMN;summaryarg errors emit documented codes.NOT_INITIALIZEDemits one consistent message across all four commands.UNKNOWN_COLUMN/INVALID_ARGare updated.Method
TDD outside-in at the CLI boundary. One commit per green. Error codes come verbatim from the README envelope list.