Summary
taskwrite.py add --id <value> accepts a --id with more than two dot-separated parts and silently mints a 4-segment task ID (e.g. mvp1.store.0002.0001). That ID is then un-targetable by start/done and invisible to validate_id/lint_board, so the task can never be flipped or surfaced as malformed via the blessed tooling.
Environment
- codeArbiter
ca v2.6.1 (plugin cache), Windows, stock Python.
Repro
taskwrite.py add --id mvp1.store.0002 --boundaries store -- "Fix X"
# -> board entry: - [ ] mvp1.store.0002.0001 - Fix X
taskwrite.py done -- "mvp1.store.0002.0001"
# -> "no change: 'mvp1.store.0002.0001' not found or already done"
taskwrite.py done -- "mvp1.store.0002"
# -> also "not found"
The task can never be marked done through the tool.
Root cause (two compounding defects)
-
taskwrite.py (add verb), lines ~87-88 — no validation of --id:
if args.gid and "." in args.gid:
group, typ = args.gid.split(".", 1) # "mvp1.store.0002" -> ("mvp1", "store.0002")
split(".", 1) on a 3-part value yields typ="store.0002", and add_entry then mints {group}.{typ}.{seq:04d} = mvp1.store.0002.0001. A --id that is not exactly GROUP.TYPE is accepted instead of rejected.
-
_taskboardlib.py _IDISH_RE matches exactly three segments:
_IDISH_RE = re.compile(r"^[^\s.]+\.[^\s.]+\.[^\s.]+$")
So _split_id_title treats a 4-segment leading token as part of the title (id=None). Consequences:
set_state -> _find_task_line can't match it (no t.id, and t.title includes the id prefix), so start/done fail by both ID and title.
validate_id is never consulted (id is None) and lint_board therefore can't flag it — a malformed ID is silently swallowed rather than surfaced.
Impact
A single mistyped --id permanently strands a task in [ ]/[~] with no tool path to fix or even detect it (the hard rule forbids hand-editing the board). Harvested follow-ups are the common trigger, since callers pass an explicit --id.
Suggested fix
taskwrite.py: validate --id is exactly GROUP.TYPE (one dot, two non-empty parts); error with a clear message otherwise. Use a strict 2-part split, not split(".", 1).
_taskboardlib._IDISH_RE: accept 3+ segments (^[^\s.]+(?:\.[^\s.]+){2,}$) so a malformed ID parses as an id, is rejected by validate_id, and is surfaced by lint_board (defense in depth) and becomes targetable by set_state for repair.
- (Optional) a
taskwrite verb or lint path to repair/rename an existing malformed ID.
Workaround
Pass --id GROUP.TYPE (e.g. --id mvp1.store) and let the tool mint the seq.
Summary
taskwrite.py add --id <value>accepts a--idwith more than two dot-separated parts and silently mints a 4-segment task ID (e.g.mvp1.store.0002.0001). That ID is then un-targetable bystart/doneand invisible tovalidate_id/lint_board, so the task can never be flipped or surfaced as malformed via the blessed tooling.Environment
cav2.6.1 (plugin cache), Windows, stock Python.Repro
The task can never be marked done through the tool.
Root cause (two compounding defects)
taskwrite.py(add verb), lines ~87-88 — no validation of--id:split(".", 1)on a 3-part value yieldstyp="store.0002", andadd_entrythen mints{group}.{typ}.{seq:04d}=mvp1.store.0002.0001. A--idthat is not exactlyGROUP.TYPEis accepted instead of rejected._taskboardlib.py_IDISH_REmatches exactly three segments:So
_split_id_titletreats a 4-segment leading token as part of the title (id=None). Consequences:set_state->_find_task_linecan't match it (not.id, andt.titleincludes the id prefix), sostart/donefail by both ID and title.validate_idis never consulted (id is None) andlint_boardtherefore can't flag it — a malformed ID is silently swallowed rather than surfaced.Impact
A single mistyped
--idpermanently strands a task in[ ]/[~]with no tool path to fix or even detect it (the hard rule forbids hand-editing the board). Harvested follow-ups are the common trigger, since callers pass an explicit--id.Suggested fix
taskwrite.py: validate--idis exactlyGROUP.TYPE(one dot, two non-empty parts); error with a clear message otherwise. Use a strict 2-part split, notsplit(".", 1)._taskboardlib._IDISH_RE: accept 3+ segments (^[^\s.]+(?:\.[^\s.]+){2,}$) so a malformed ID parses as anid, is rejected byvalidate_id, and is surfaced bylint_board(defense in depth) and becomes targetable byset_statefor repair.taskwriteverb orlintpath to repair/rename an existing malformed ID.Workaround
Pass
--id GROUP.TYPE(e.g.--id mvp1.store) and let the tool mint the seq.