Skip to content

knowledge-flush: auto-flush hook and a manual flush drain the same queue into competing PRs, and reset each other's checkout #77

Description

@dch0202-rsquare

What happened

A manual /dev-loop:knowledge-flush and the auto-flush.sh hook drained the same
queue into two competing PRs
, and the hook's run reset the manual run's working
tree out from under it.

Timeline (2026-08-11 → 08-12, one machine, one queue):

  1. 16:02 — manual flush follows the skill: ~/.dev-loop/repogit checkout main && git reset --hard origin/main, branch knowledge/…-20260811-160220, ingests 2
    of the 6 pending candidates, commits, pushes.
  2. 16:21hooks/auto-flush.sh fires (pid 38521) and starts a headless
    claude -p "Run the dev-loop:knowledge-flush skill now…" (pid 38522).
  3. That session runs the same step 1 against the same path, so
    ~/.dev-loop/repo is checked out to main and hard-reset. The manual run's
    working tree (2 new pages, 2 index edits, log.md, INGEST_REPORT.md) is gone
    mid-run. Only the fact that it had already committed and pushed kept the work.
  4. Both runs then ingest the same six candidates. The hook's run opened knowledge: signed-link verification assertions, cross-module consumer census, defect-class re-sweep, synced-cluster pod triage, cloud CLI bounds (5 ingested, 1 dropped as dup of #52) #76;
    the manual run's branch was discarded by hand after comparing them.

Why it matters beyond one lost working tree

Contributing factors

  • ~/.dev-loop/repo is a single fixed path baked into the skill's step 1, and
    step 1 begins with a destructive reset --hard. Any second run is a data hazard.
  • ~/.dev-loop/.autoflush.lock exists, but it is taken by the hook path only.
    A manual /dev-loop:knowledge-flush neither acquires nor respects it, so the lock
    cannot serialize the two entry points that actually collide.
  • The manual entry point has no way to detect the hook's run: the hook is detached
    (nohup-style, reparented to pid 1), so the manual session sees no child process
    and no marker in the repo it is about to reset.

Possible directions

[추정] — none of these are tested; listing them so the tradeoff is visible rather
than proposing one as correct:

  1. Move the lock up to the skill. Step 1 acquires ~/.dev-loop/.flush.lock
    (both entry points), and the hook simply doesn't fire when it is held. Smallest
    change; makes the two entry points mutually exclusive.
  2. Per-run checkout. ~/.dev-loop/repo-<runid> or a git worktree per flush,
    so a second run cannot touch the first's tree. Costs disk and a clone per run,
    but removes the hazard rather than serializing around it.
  3. Claim the queue rows. Mark candidates in-progress with a run id at the
    start and skip claimed rows, so even a concurrent pair produces disjoint PRs.
    Addresses the expensive half (duplicate ingestion) even if trees still collide.

(1) and (3) are complementary: the lock prevents the collision, the claim bounds the
damage when the lock is bypassed or a run dies holding it.

Environment

  • dev-loop plugin 1.6.0 (installed via marketplace), macOS 25.5.0
  • Both runs used the same $HOME, so the same ~/.dev-loop/queue/ and
    ~/.dev-loop/repo
  • No data was lost (the manual run had pushed); the report is about the hazard, not
    a recovery request

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions