fix(done): suppress on-modify hooks for recursively completed descendants - #19
Conversation
…ants When 'task <parent> done' auto-completes child tasks, the on-modify hook was firing for each child in addition to the parent. Disable hooks around the descendant completion loop so only the parent triggers hook callbacks.
|
pr-review-lead (round 3): PR Review: fix(done): suppress on-modify hooks for recursively completed descendantsCritical Issues (1)[CmdDone.cpp:109-119] Exception-unsafe hook state restoration The manual save/restore pattern is not exception-safe: auto oldHooks = Context::getContext().hooks.enable(false);
// ... loop ...
Context::getContext().hooks.enable(oldHooks); // ← never runs if loop throws
Fix: Use a RAII guard. The struct HooksGuard {
Hooks& hooks;
bool saved;
explicit HooksGuard(Hooks& h, bool val) : hooks(h), saved(h.enable(val)) {}
~HooksGuard() { hooks.enable(saved); }
HooksGuard(const HooksGuard&) = delete;
HooksGuard& operator=(const HooksGuard&) = delete;
};
// Usage:
HooksGuard hooksGuard(Context::getContext().hooks, false);
auto desc = Context::getContext().tdb2.descendants(task.get("uuid"));
// ... loop — restore is automatic at scope exit, even on throwImportant Issues (2)[hooks.on-modify.test.py:186] UUID extraction has trailing period parent_uuid = out.strip().split()[-1]The verbose output format is [CmdDone.cpp:111-118] Partial completion leaves inconsistent state with confusing error If the loop throws mid-iteration (e.g. on descendant 3 of 5), the first N descendants are already written to storage while the rest are not. The top-level catch in Suggestions (3)
Strengths
Verdict: Needs WorkFix the RAII issue (critical — real exception-safety bug) and the UUID trailing-period issue (important — likely causes test failures) before merge. |
Replace manual save/restore with a RAII HooksGuard struct so hooks are always re-enabled even if tdb2.modify() throws mid-loop. Test improvements: use export-based UUID lookup (no trailing-period bug), add grandchild depth coverage, and assert the hook fired for the parent's UUID specifically.
|
coder (round 4): Triage UpdateFixed
Deferred
|
|
pr-review-lead (round 5): Re-review: fix(done) suppress on-modify hooks for descendantsFixed ✅
Deferred (accepted)
VERDICT: LGTM 🟢Implementation is correct and exception-safe. Test coverage is thorough for the changed behavior. |
Summary
task <parent> donewas triggering the on-modify hook for every recursively completed child task, causing N+1 hook invocations (and notification spam) when completing a parent with N childrenCmdDone.cppwithhooks.enable(false)/hooks.enable(oldHooks)so only the parent's completion fires the hookhooks.on-modify.test.py: verifies the hook fires exactly once and both parent and child are completed in the DBTest plan
make)test_recursive_done_suppresses_child_hookspasses: hook fires exactly once, both tasks marked completedTestHooksOnModifytests continue to pass