Skip to content

cairn remember: capture-time recurrence detection#47

Merged
quad341 merged 4 commits into
mainfrom
deploy/crn-jfox-gate
Jul 24, 2026
Merged

cairn remember: capture-time recurrence detection#47
quad341 merged 4 commits into
mainfrom
deploy/crn-jfox-gate

Conversation

@quad341

@quad341 quad341 commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Summary

  • cairn remember's create flow now pre-checks for an existing visible entry with an exact topic_key match (via the shared Conflicts() primitive, filtered to the topic_key signal — not the fuzzy content/Jaccard signal) before writing a new entry.
  • On a match: increments the existing entry's RecurrenceCount instead of creating a duplicate, committed through the same tier-appropriate path the entry already uses (CommitDirect for private scope, a new CommitRecurrenceToReviewBranch for shared scope re-entering an in-flight review branch).
  • On no match: create-new-entry behavior is unchanged; a near-miss (similar but non-exact topic_key) does not trigger a false-positive increment.
  • Fixes a related staleness gap: the recurrence check now force-reindexes before checking visibility, since shared-tier entries pending review don't advance the store's HEAD watermark and were otherwise invisible to the check.

Known, intentionally out-of-scope limitation

Same-scope (or scope-superset) repeat captures of the same topic are not currently detected as recurrences — only topic_key collisions between entries with incomparable scopes are caught. This is pre-existing behavior of the shared conflict-detection primitive (shadow-exemption logic), not a regression introduced by this change. Tracked separately for a possible follow-up.

Test plan

  • go build ./...
  • go vet ./...
  • gofmt -l . (0 files)
  • golangci-lint run ./... (0 issues)
  • go test ./... -race -count=1 (all packages green)

quad341 added 4 commits July 23, 2026 20:15
Covers cmd/remember.go's pre-check for an existing VISIBLE entry with an
exact topic_key match (via crn-28ge.1.3's Conflicts primitive, not a new
equality check): on a match, increments RecurrenceCount via the entry's
own tier-appropriate commit path instead of writing a duplicate.

internal/cairn: WriteBackRecurrenceCount patches recurrence_count into
on-disk frontmatter; CommitRecurrenceToReviewBranch appends a second
commit to an entry's existing remember/<id> branch, or falls back to
CommitToReviewBranch's create path when absent.

cmd: cross-call CLI tests for both tiers (shared reuses the review
branch, private commits directly), plus the near-miss/no-topic/
not-visible cases that must NOT increment. TestRememberSameScopeTopicKeyRepeatDoesNotIncrementRecurrence
documents a known gap: Conflicts' shadowExempt suppresses even the
topic_key signal for equal/superset/subset-scope pairs, so the most
intuitive recurrence (same agent, same private scope, same topic)
isn't caught by this pre-check.
….1.4)

cmd/remember.go's create flow now pre-checks for an existing VISIBLE
entry with an exact topic_key match before writing a new one:

- recurrenceMatch resolves identity, force-reindexes, then filters
  IterEntries down to Visible's ID set and runs the candidate through
  Conflicts (crn-28ge.1.3's single-candidate primitive) -- reused as
  mandated (NFR-05), not reimplemented as a second equality check.
  Only a "topic_key" finding counts; "content" (Jaccard) is a near-miss
  signal, not a repeat.
- The forced Reindex is required, not cosmetic: ensureFresh's git-HEAD
  watermark can never observe a shared-tier entry on its own, because
  CommitToReviewBranch deliberately never advances the store's own
  HEAD (the entry sits on its own remember/<id> branch pending review).
  Without it, a same-session recurrence while the first report is still
  unmerged -- the common case, not an edge case -- would be silently
  missed. Find hits the identical gap for the identical reason and is
  fixed the same way (internal/cairn/entry.go).
- On a match, recordRecurrence increments RecurrenceCount, persists it
  via the new WriteBackRecurrenceCount (patches recurrence_count into
  on-disk frontmatter, mirroring verified_at's insertion point), and
  commits through the entry's own tier-appropriate path: CommitDirect
  for private, or the new CommitRecurrenceToReviewBranch for shared
  (appends a second commit to the entry's existing review branch, or
  falls back to CommitToReviewBranch's create path when absent). No
  duplicate entry is ever written -- the candidate is discarded.
- On no match, today's create-new-entry behavior is unchanged.

Known limitation (documented via
TestRememberSameScopeTopicKeyRepeatDoesNotIncrementRecurrence): Conflicts'
shadowExempt suppresses even the topic_key signal for pairs whose scopes
are equal or in a superset/subset relationship, so the single most
intuitive recurrence -- same agent, same private scope, same topic --
is not caught by this pre-check. Flagged for reviewer follow-up.
… (refs crn-28ge.1.4)

Reviewer-requested fix: golangci-lint's nilnil check flagged the (nil, nil)
"no recurrence match" return. The sole caller already gates on `matched !=
nil` before use, so document the contract with a nolint rather than
restructure the signature.
…crn-jfox)

Covers crn-28ge.1.4, deployed off reviewed tip 24e19d2, rebased onto
origin/main via the bounded self-rebase exception (AFTER_SHA eea622c).
All 7 gate criteria green.
@quad341
quad341 merged commit 9bfa28a into main Jul 24, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant