flower
/
All briefs
complete feedback flower
from feedback #27 · Handle removed/orphaned worktrees gracefully (regist...

Feedback #27: Handle removed/orphaned worktrees gracefully (registry↔filesystem drift) — a missing worktree dir should not break ingest

canonical · plan

Spec

markdown

hand-off · dispatch

Dispatch

Auto-dispatch

when it reaches planned

Design-loop

design pass before build

This brief is complete — dispatch is closed.

#88 done fresh flower · flower/140-orphaned-worktrees
agent: claude
You are being dispatched from flower Brief #140: Feedback #27: Handle removed/orphaned worktrees gracefully (registry↔filesystem drift) — a missing worktree dir should not break ingest

Recall pointer:
- Use recall_brief with id 140 for the full folder if you need provenance.

Target:
- project: flower (/Users/mikeferrara/Documents/code/flower)
- branch: flower/140-orphaned-worktrees
- worktree: not specified
- kind: fresh

Current brief spec:
(no spec yet)

This is a direct request, not a fully-specced plan. If it's clear, resolve it. If you hit a blocking ambiguity, call brief_ask (or brief_append) with your questions and flip the brief to `refining` before proceeding — don't guess.

Recent/key trace events:
[1] participant_joined operator:mike: (no body)
[2] note_added operator:mike: Feedback #27
Authority: OPERATOR APPROVAL REQUIRED
Funnel: A - operator approved brief
Gate: this brief must not be dispatchable until the operator approves it.
Kind: idea
Source: flower-ops

Summary:
Handle removed/orphaned worktrees gracefully (registry↔filesystem drift) — a missing worktree dir should not break ingest

Detail:
Worktrees get removed in many normal scenarios (worktree-manager remove, manual rm, merged+cleaned branches), leaving the worktree DB row orphaned — registry↔filesystem drift. Today an orphaned row breaks flower:ingest-commits: CommitIngestService.php:35 Process::path($path)->run() throws on a missing cwd (no is_dir guard), aborting the WHOLE ingest batch (surfaced as FLOWER-12 / FLOWER-9). The immediate is_dir guard is already routed (todo 681, preventive/low-urgency). THIS item is the LONG-TERM graceful handling, to refine before building: (a) guard ALL worktree-path consumers against missing dirs (ingest-commits, ingest-docs, harness/session scan — anything iterating worktrees->path); (b) reconcile/prune orphaned worktree rows (e.g. in ScanProjects) with an explicit auto-prune-vs-mark-stale policy; (c) decide per-scenario whether a missing worktree should be skipped, deregistered, or flagged. Good first candidate for the feedback→brief funnel (see the feedback-funnels brief).


Context JSON:
{
    "scope": "long-term graceful handling; refine before build",
    "related_sentry": [
        "FLOWER-12",
        "FLOWER-9"
    ],
    "immediate_fix_spec": 1025,
    "immediate_fix_todo": 681
}
[3] note_added operator:mike: Operator approved this feedback-born brief for dispatch.
[4] status_change operator:mike: (no body)

Recommended linked context:
{
    "todos": [],
    "scratchpads": []
}

Execution notes:
- Treat the brief as the source of truth.
- Keep work scoped to this dispatch request.
- Use brief_append / brief_update_status when reporting material progress; as your final dispatched-worker step, call brief_dispatch_complete with dispatch_request_id (or brief_id) and actor_ref.
- Codex workers should verify mutating Flower tools with tool_search query `brief_append brief_dispatch_complete flower_feedback` (limit 20) when tool availability is in doubt; report raw SEE/LOAD vs NOT visible instead of silently using local fallbacks.
- Add a git commit trailer `Brief: #140` to every commit for this brief so flower can exact-link commits back to the brief.

provenance · append-only

Trace

live
or paste a screenshot uploading…
  1. link added 1d ago
    agent · system:commit-trailer
  2. link added 1d ago
    agent · system:commit-trailer
  3. participant joined 1d ago
    system · system:commit-trailer
  4. merged 1d ago

    Merged to master by flower-orchestrator (daemon 29). Worker commit 1c3bce2 (branch flower/140-orphaned-worktrees). Centralized fix at ScansHarnessSessions::indexedPathsForProject() (feeds flower:watch/ingest/ingest-commits/ingest-docs/reprice-usage): worktrees.missing_at mark-stale column (ran on MAIN MySQL, 132ms) — stamped when a registered path vanishes, cleared when it reappears; NEVER auto-prune, so sessions/commits/briefs keep attribution + it's reversible. Worktree model gained isMissing()/existsOnFilesystem()/reconcileFilesystemPresence() (idempotent). Guard reconciles per worktree then skips + Log::warning on missing ones so the rest keep ingesting. ScanProjects catalog pass flags orphans even without an ingest run. Adversarial review PASS: migration sqlite-portable (nullable + index, ->after() no-op); additive-only, no MAIN edits. Full suite green on MAIN: 973 tests / 971 passed / 2 skipped / 0 failed. The guard is command-code (run fresh each scheduler cycle) → live without a Horizon reload; defensive fix, only triggers when a worktree dir is actually missing.

    agent · flower-orchestrator
  5. status change 1d ago
    agent · flower-140-orphaned-worktrees-worker
  6. dispatched 1d ago

    Dispatch request #88 marked done.

    agent · flower-140-orphaned-worktrees-worker
  7. note added 1d ago

    Done. Branch flower/140-orphaned-worktrees (off master), commit 1c3bce2. Idle — not merging; orchestrator reviews. What changed (registry↔filesystem drift → ingest never breaks on a vanished worktree dir): - DB: new nullable `worktrees.missing_at` (+ index) — migration 2026_07_04_120000. Stamped when the recorded path no longer exists on disk, cleared when it reappears. Mark-stale, NEVER auto-prune, so sessions/commits/briefs keep attribution (chose flag over deregister for the auto-prune-vs-mark-stale policy). - app/Models/Worktree.php: `isMissing()`, `existsOnFilesystem()`, `reconcileFilesystemPresence()` (stamp/clear missing_at, returns existence; idempotent — only writes on flag flip). The drift policy lives on the model per the task. - app/Console/Commands/Concerns/ScansHarnessSessions.php::indexedPathsForProject — the single chokepoint feeding flower:watch, flower:ingest, flower:ingest-commits, flower:ingest-docs, flower:reprice-usage. Now reconciles each worktree and skips + Log::warning("Skipping missing worktree path during ingest scan") on missing ones, so the other worktrees keep ingesting instead of throwing. CommitIngestService's existing is_dir guard (FLOWER-12 / todo 681) stays as defense-in-depth. - app/Console/Commands/ScanProjects.php: catalog pass reconciles all rows per project so orphans get flagged even without an ingest run, and reappeared ones un-flag (brief item b). Coverage: verified every worktree-path-iterating scheduled consumer routes through indexedPathsForProject (Watch/Ingest/IngestCommits/IngestDocs/RepriceUsage); IngestBacklog doesn't touch worktree paths. Tests (tests/Feature/IngestCommitsCommandTest.php): (1) orphaned worktree flagged (missing_at set + isMissing()) + skipped while root and a live worktree still ingest, no throw; (2) reappeared worktree clears missing_at on next scan. Gates: MEILISEARCH_KEY=LARAVEL-HERD ~/bin/php artisan test → 967 passed / 1 pre-existing skip. Pint clean on all changed files. Isolated worktree DB; no daemons started; did not touch MAIN or its DB (orchestrator runs the migration on merge).

    agent · flower-140-orphaned-worktrees-worker
  8. participant joined 1d ago
    system · flower-140-orphaned-worktrees-worker
  9. dispatched 1d ago

    Dispatch request #88 queued for flower.

    agent · flower-orchestrator
  10. status change 1d ago
    agent · flower-orchestrator
  11. participant joined 1d ago
    system · flower-orchestrator
  12. status change 1d ago
    agent · operator:mike
  13. note added 1d ago

    Operator approved this feedback-born brief for dispatch.

    operator · operator:mike
  14. note added 2d ago

    Feedback #27 Authority: OPERATOR APPROVAL REQUIRED Funnel: A - operator approved brief Gate: this brief must not be dispatchable until the operator approves it. Kind: idea Source: flower-ops Summary: Handle removed/orphaned worktrees gracefully (registry↔filesystem drift) — a missing worktree dir should not break ingest Detail: Worktrees get removed in many normal scenarios (worktree-manager remove, manual rm, merged+cleaned branches), leaving the worktree DB row orphaned — registry↔filesystem drift. Today an orphaned row breaks flower:ingest-commits: CommitIngestService.php:35 Process::path($path)->run() throws on a missing cwd (no is_dir guard), aborting the WHOLE ingest batch (surfaced as FLOWER-12 / FLOWER-9). The immediate is_dir guard is already routed (todo 681, preventive/low-urgency). THIS item is the LONG-TERM graceful handling, to refine before building: (a) guard ALL worktree-path consumers against missing dirs (ingest-commits, ingest-docs, harness/session scan — anything iterating worktrees->path); (b) reconcile/prune orphaned worktree rows (e.g. in ScanProjects) with an explicit auto-prune-vs-mark-stale policy; (c) decide per-scenario whether a missing worktree should be skipped, deregistered, or flagged. Good first candidate for the feedback→brief funnel (see the feedback-funnels brief). Context JSON: { "scope": "long-term graceful handling; refine before build", "related_sentry": [ "FLOWER-12", "FLOWER-9" ], "immediate_fix_spec": 1025, "immediate_fix_todo": 681 }

    agent · operator:mike
  15. participant joined 2d ago
    system · operator:mike

epic · dependencies

Relationships

epic parent

depends on

No dependencies — dispatchable once planned.

agents · waves

Participants

  • operator:mike participant · active
  • flower-orchestrator participant · active
  • flower-140-orphaned-worktrees-worker participant · active
  • system:commit-trailer participant · active

trace · graph

Links

  • Commit #3967 execution
  • Commit #3969 execution

scope

Projects

  • flower · primary

dogfood · read-only

Agent’s-eye view

The literal recall_brief payload an agent gets — same service path as the MCP tool.