Skip to content

Fix stale title/summary after file-only writeback (crn-bmy54) - #131

Merged
quad341 merged 4 commits into
mainfrom
deploy/crn-bmy54-gate
Aug 20, 2026
Merged

quad341 merged 4 commits into
mainfrom
deploy/crn-bmy54-gate

Conversation

@quad341

@quad341 quad341 commented Aug 20, 2026

Copy link
Copy Markdown
Owner

Summary

WriteBackBackfill and WriteBackRetrievalMetadata patch an entry's
frontmatter file directly (writeBackPatched — pure os.ReadFile/
os.WriteFile, zero git ops), without ever advancing the store's checked-out
HEAD. Because ensureFresh's staleness check is HEAD-watermark-based, it
never noticed the file-only edit, so Status (cairn prime/list) kept
serving stale title/summary indefinitely until an unrelated Reindex
happened to run.

Adds an Entry.store field (set by Find) and a syncIndexRetrievalMetadata
method that directly UPDATEs the entries table's title/summary columns
after a successful file patch, called from both WriteBackRetrievalMetadata
(always) and WriteBackBackfill (when updateRetrievalMetadata=true).
Find/recall/get were never affected — they always re-read the body file
fresh — this bug was specific to the cached index columns Status reads
from. Scoped to title/summary only, per the build bead's exit contract.

  • Deploy bead: crn-bmy54
  • Review bead: crn-x81gk, verdict: PASS
  • Build bead: crn-rott9.3 (architect: crn-rott9, child F)

Gate result

PASS (7/7) — see release-gates/crn-bmy54-gate.md
for full per-criterion evidence.

Independently re-verified on the deployer side, twice: once against the
exact reviewed commit, and again against this branch's actual tip after a
bounded self-rebase onto main (criterion 6 — main had moved on since the
review; the rebase applied clean, zero conflicts, tree-hash-confirmed
identical to the precomputed merge). Both passes: go build ./...,
go vet ./..., golangci-lint run ./... (isolated cache), golangci-lint fmt -d ./... all clean; go test ./... -race -count=1 — all 7 packages
PASS, 0 FAIL, including direct re-runs of the two diff-owned tests
(TestStatusServesStaleTitleSummaryAfterFileOnlyWriteback,
TestWriteBackRetrievalMetadataPreservesBody).

Diff scope independently confirmed single-themed: 4 files
(cmd/backfill.go, cmd/backfill_test.go, internal/cairn/entry.go,
internal/cairn/index_test.go), +118/-8, 2 source + 2 test.
assert_deploy_ancestry_scope against crn-rott9.3 — clean, no foreign
commits, no out-of-scope paths. Exactly 1 open finding on the review side
(low, non-blocking); no HIGH/blocking findings anywhere in the chain.

Merge authority

quad341/cairn — standing self-merge authorization applies (mayor ruling
gm-wisp-2yhv7u, 2026-08-19). This bead's own description carries only the
generic recycled "route to mayor" boilerplate already covered by that
ruling, nothing bead-specific. Deployer will merge directly
(gh pr merge --squash, plain, no --auto) once CI is green, then
independently verify the merge landed.

Test plan

  • go build ./...
  • go vet ./...
  • golangci-lint run ./... (isolated cache)
  • golangci-lint fmt -d ./... (no diff)
  • go test ./... -race -count=1 (all 7 packages) — re-run at both the
    reviewed SHA and the post-rebase deploy SHA
  • 2 named new/changed regression tests re-run individually
  • CI (build-test, lint) — to be confirmed green post-open

🤖 Opened by cairn/deployer on a green release gate.

cairn-reviewer-scratch added 4 commits August 20, 2026 07:14
…ry (needs live repro first) (refs crn-rott9.3)

TestStatusServesStaleTitleSummaryAfterFileOnlyWriteback reproduces the
asymmetry live: WriteBackBackfill (writeBackPatched) is pure filesystem
I/O with no git operation, so it never advances the store's HEAD.
ensureFresh's staleness check compares only the index watermark against
HEAD, so it never notices the edit -- Status (prime/list) keeps serving
the pre-edit title/summary from stale SQL columns, while Find
(recall/get) already re-reads the body fresh off disk and is unaffected.
…needs live repro first) (refs crn-rott9.3)

WriteBackRetrievalMetadata and WriteBackBackfill now sync the index's
title/summary/title_source/summary_source columns directly via SQL right
after a successful file patch, mirroring Find's existing hit_count/
last_recalled_at direct-write pattern. Find now stamps the resolved
Entry with the store root it came from so this sync has a target; an
Entry built via a bare ParseEntry (no store) is a no-op and falls back
to today's behavior (correct again after the next reindex).

This closes the gap ensureFresh's HEAD-watermark staleness check can't
see: WriteBackBackfill/WriteBackRetrievalMetadata are pure filesystem
I/O with no git operation, so patching title/summary through them never
advances HEAD, and indexStale never fires. Status (prime/list) now
reflects the edit immediately instead of waiting for an unrelated
reindex to happen to run.

Scoped to title/summary only, per this bead's exit contract -- type and
the other writeBackPatched-based fields (anchor, recurrence_count,
promoted_bead_id, review_status) are untouched.
…(refs crn-rott9.3)

golangci-lint's contextcheck flagged cmd/backfill.go:335 after the GREEN
commit: WriteBackBackfill now reaches syncIndexRetrievalMetadata, which
called context.Background() internally even though applyBackfillRecord
already had a ctx in scope. Thread ctx through both public methods
instead of manufacturing a fresh background context inside the writeback
path; call sites (the one production caller plus both tests) now pass
their own in-scope context.

No behavior change -- same index sync, just wired to the real context.
@quad341
quad341 merged commit a7f9cdc into main Aug 20, 2026
2 checks passed
@quad341
quad341 deleted the deploy/crn-bmy54-gate branch August 20, 2026 17:06
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