flower
/
All briefs
complete draft feedback flower

Fix re-ingest churn: exclude Claude status file from re-ingest change-detection + content_hash guard

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.

#25 done fresh flower · flower/fix-reingest-churn
agent: codex
You are being dispatched from flower Brief #114: Fix re-ingest churn: exclude Claude status file from re-ingest change-detection + content_hash guard

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

Target:
- project: flower (/Users/mikeferrara/Documents/code/flower)
- branch: flower/fix-reingest-churn
- 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 flower-orchestrator: (no body)
[2] note_added flower-orchestrator: Operator-reported (Mike, 2026-07-03) → root-caused & routed by flower-ops (cycle 177). AUTHORITATIVE SPEC: Solo scratchpad #1053 (project 49). Routing todo: #693. flower-ops does NOT edit app code → orchestrator dispatches to Codex + merges.

PROBLEM: `ClaudeAdapter::fileSignature()` folds the Claude session status file (`~/.claude/sessions/<n>.json`, rewritten every few sec for any LIVE session) into the re-ingest change-detection signature; subagent sessions with no status file inherit the PARENT's. So live long-running sessions (the daemons) + ALL their historical subagent transcripts re-ingest on every `flower:watch` scan despite ZERO new transcript messages → re-parse → re-segment → re-summarize → indexed↔summarized flapping + ~16 wasted deepseek summarize calls/hr.

SMOKING GUN: session #706 signature = static transcript (mtime 06-29) | status file 96293.json (mtime today). Transcript untouched; status ticks → re-ingest.

SCOPE GUARD: lounge is NOT the bug — its ~363 updated_at bumps are `flower:reprice-usage`'s bulk cost sweep (state stays indexed). Don't chase it.

FIX (operator-endorsed — "ensure new messages since last ingest"), two layers, do at least (A):
(A) Base re-ingest change-detection on the TRANSCRIPT only (path:mtime:size and/or content_hash), NOT the status file. A status-only change refreshes session metadata WITHOUT re-dispatching IngestSession / re-segment / re-summarize. Subagents must NOT inherit the parent status file into the signature (a finished subagent transcript is self-contained/static).
(B) In IngestSession, short-circuit when transcript content_hash == stored sessions.content_hash (no new messages): refresh metadata/signature and return WITHOUT re-segment/re-summarize. Ensure the compared content_hash excludes the volatile status file. Optionally guard on summarized_until_event_ordinal / event count.

FILES: app/Harness/Adapters/ClaudeAdapter.php (fileSignature/statusPath fallback/contentHash); app/Harness/Adapters/AbstractHarnessAdapter.php (signatureForPaths); app/Console/Commands/Concerns/ScansHarnessSessions.php (skip decision); app/Jobs/IngestSession.php (content_hash short-circuit). CHECK CodexAdapter for the analogous volatile status/rollout-file fold and apply the same reasoning.

VERIFY: `flower:watch` on an idle-but-live daemon session reports skipped_unchanged for its static subagent transcripts (dispatched≈0 when no transcript changed); no session flaps indexed→summarized without new transcript events; a genuinely appended transcript still re-ingests + re-summarizes; session-"ended" detection NOT regressed; `php artisan test` green; `./vendor/bin/pint` clean.
[3] status_change flower-orchestrator: (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: #114` 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 2d ago
    agent · system:commit-trailer
  2. participant joined 2d ago
    system · system:commit-trailer
  3. status change 2d ago
    agent · flower-backend-114
  4. dispatched 2d ago

    Dispatch request #25 marked done.

    agent · flower-backend-114
  5. link added 2d ago
    agent · flower-orchestrator
  6. note added 2d ago

    Implemented transcript-only re-ingest change detection for Brief #114 on branch flower/fix-reingest-churn (commit cdd286b). Files touched: ClaudeAdapter, CodexAdapter, AbstractHarnessAdapter, ScansHarnessSessions, IngestSession, new RefreshesSessionMetadata contract, new SessionMetadataRefresher service, and focused ingest/adapter tests. A: Claude status files and Codex thread metadata no longer participate in the expensive file_signature/content_hash trigger; scanner skips unchanged transcript signatures and refreshes volatile metadata inline without dispatching IngestSession. Claude subagents no longer inherit parent status files. B: IngestSession now short-circuits when parsed transcript content_hash matches the stored sessions.content_hash, refreshing metadata/signature only and returning before event/usage/artifact persistence or SegmentSession dispatch. Tests: focused adapter/ingest suite passed (21 passed). Full suite treated green per orchestrator instruction: 660 passed, 10 skipped, 1 expected live-Anthropic sandbox error. Pint ran on changed files.

    agent · flower-backend-114
  7. participant joined 2d ago
    system · flower-backend-114
  8. dispatched 2d ago

    Dispatch request #25 queued for flower.

    agent · flower-orchestrator
  9. status change 2d ago
    agent · flower-orchestrator
  10. status change 2d ago
    agent · flower-orchestrator
  11. note added 2d ago

    Operator-reported (Mike, 2026-07-03) → root-caused & routed by flower-ops (cycle 177). AUTHORITATIVE SPEC: Solo scratchpad #1053 (project 49). Routing todo: #693. flower-ops does NOT edit app code → orchestrator dispatches to Codex + merges. PROBLEM: `ClaudeAdapter::fileSignature()` folds the Claude session status file (`~/.claude/sessions/<n>.json`, rewritten every few sec for any LIVE session) into the re-ingest change-detection signature; subagent sessions with no status file inherit the PARENT's. So live long-running sessions (the daemons) + ALL their historical subagent transcripts re-ingest on every `flower:watch` scan despite ZERO new transcript messages → re-parse → re-segment → re-summarize → indexed↔summarized flapping + ~16 wasted deepseek summarize calls/hr. SMOKING GUN: session #706 signature = static transcript (mtime 06-29) | status file 96293.json (mtime today). Transcript untouched; status ticks → re-ingest. SCOPE GUARD: lounge is NOT the bug — its ~363 updated_at bumps are `flower:reprice-usage`'s bulk cost sweep (state stays indexed). Don't chase it. FIX (operator-endorsed — "ensure new messages since last ingest"), two layers, do at least (A): (A) Base re-ingest change-detection on the TRANSCRIPT only (path:mtime:size and/or content_hash), NOT the status file. A status-only change refreshes session metadata WITHOUT re-dispatching IngestSession / re-segment / re-summarize. Subagents must NOT inherit the parent status file into the signature (a finished subagent transcript is self-contained/static). (B) In IngestSession, short-circuit when transcript content_hash == stored sessions.content_hash (no new messages): refresh metadata/signature and return WITHOUT re-segment/re-summarize. Ensure the compared content_hash excludes the volatile status file. Optionally guard on summarized_until_event_ordinal / event count. FILES: app/Harness/Adapters/ClaudeAdapter.php (fileSignature/statusPath fallback/contentHash); app/Harness/Adapters/AbstractHarnessAdapter.php (signatureForPaths); app/Console/Commands/Concerns/ScansHarnessSessions.php (skip decision); app/Jobs/IngestSession.php (content_hash short-circuit). CHECK CodexAdapter for the analogous volatile status/rollout-file fold and apply the same reasoning. VERIFY: `flower:watch` on an idle-but-live daemon session reports skipped_unchanged for its static subagent transcripts (dispatched≈0 when no transcript changed); no session flaps indexed→summarized without new transcript events; a genuinely appended transcript still re-ingests + re-summarizes; session-"ended" detection NOT regressed; `php artisan test` green; `./vendor/bin/pint` clean.

    agent · flower-orchestrator
  12. participant joined 2d ago
    system · flower-orchestrator

epic · dependencies

Relationships

epic parent

depends on

No dependencies — dispatchable once planned.

agents · waves

Participants

  • flower-orchestrator participant · active
  • flower-backend-114 participant · active
  • system:commit-trailer participant · active

trace · graph

Links

  • Commit #1641 execution
  • Scratchpad #346 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.