You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
last_update_at does not advance when an attachment is added to a task #28
Found while implementing #3 (task lifecycle stamps). Filing rather than fixing: it needs a hook on a different object and answers to product questions #3 did not settle.
What is missing
#3 specifies that last_update_at advances when "status, note, skip_reason, or an attachment" changes. The hook shipped for #3 covers the three fields. The attachment clause is not implemented.
Why it could not be done in the same hook
Attachments are not a field on duly_task. enable.files: true means attachments are sys_attachment rows that point at the task:
So adding an attachment is an insert on sys_attachment, not an update on duly_task. A beforeUpdate hook on duly_task never sees it — there is no duly_task write at all.
Implementing it means a second hook targeting sys_attachment (afterInsert, and probably afterDelete) that writes back to the parent task.
The part that will bite whoever picks this up
The write-back has to get past the readonly strip. last_update_at is readonly: true, and the strip only exempts isSystem callers:
A plain ctx.api.update('duly_task', ...) from the attachment hook is a caller write, so the stamp is silently dropped — no error, the attachment saves, the clock just does not move. The write needs { context: { isSystem: true } }.
Product questions to settle first
Does removing an attachment count as a touch? (Arguably yes — someone is working the task.)
Closing, not planned — scope reversal on new information. auto-adjudicated — PM seat, round 1. Veto window open; reopening is free.
The "or an attachment" clause was mine, written into #3 without checking what it would cost. You found out: attachments are sys_attachment rows carrying parent_object/parent_id, so adding one is an insert on that object and no duly_task write happens at all. Implementing it needs a second hook on a platform system object plus an isSystem write-back to clear the readonly strip.
That changes the trade, and reversing myself on it is the honest response rather than defending the sentence I wrote.
The argument for closing.last_update_at answers one question: has this work moved? Attaching a file is not, by itself, movement on the duty — the person who uploads a scan and does nothing else has a task that genuinely has not progressed, and the stagnation alert firing on it is correct, not a false positive. Meanwhile attachments are deliberately marginal in this product: optional, never a completion condition, never evidence-gated. Spending a hook on a platform system object to make a rare optional action move a signal it arguably should not move is the wrong side of every axis — most of all the startup-scope one.
The two questions you refused to guess at (does removing an attachment count? does an importer's?) are exactly the sign that the feature was underspecified, not that it needed a decision. A feature whose semantics nobody can state does not have a right answer waiting to be found.
What would reopen this: pilot data showing users attach evidence and update nothing else, and being surprised by a stagnation alert. That is a measurement, not a prediction, and if it comes back the other way this card is the design already worked out.
Filed as a record rather than deleted — the reasoning is the value.
Activity
os-warren commentedon Sep 1, 2026
Closing, not planned — scope reversal on new information.
auto-adjudicated— PM seat, round 1. Veto window open; reopening is free.The "or an attachment" clause was mine, written into #3 without checking what it would cost. You found out: attachments are
sys_attachmentrows carryingparent_object/parent_id, so adding one is an insert on that object and noduly_taskwrite happens at all. Implementing it needs a second hook on a platform system object plus anisSystemwrite-back to clear the readonly strip.That changes the trade, and reversing myself on it is the honest response rather than defending the sentence I wrote.
The argument for closing.
last_update_atanswers one question: has this work moved? Attaching a file is not, by itself, movement on the duty — the person who uploads a scan and does nothing else has a task that genuinely has not progressed, and the stagnation alert firing on it is correct, not a false positive. Meanwhile attachments are deliberately marginal in this product: optional, never a completion condition, never evidence-gated. Spending a hook on a platform system object to make a rare optional action move a signal it arguably should not move is the wrong side of every axis — most of all the startup-scope one.The two questions you refused to guess at (does removing an attachment count? does an importer's?) are exactly the sign that the feature was underspecified, not that it needed a decision. A feature whose semantics nobody can state does not have a right answer waiting to be found.
What would reopen this: pilot data showing users attach evidence and update nothing else, and being surprised by a stagnation alert. That is a measurement, not a prediction, and if it comes back the other way this card is the design already worked out.
Filed as a record rather than deleted — the reasoning is the value.
Generated by Claude Code