feat: compare live post write clock with analysis-run cutoff (v0.87.0) - #150
Conversation
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
In-cutoff titles now say whether the live row was rewritten after the run. Demo public post is the edited counter-example; Demo private post still matches the January cutoff. Bodies stay live. TEPP stays behind tepp_client.
c6b0ee7 to
b4e6d2b
Compare
There was a problem hiding this comment.
Stale comment
Reviewed #150
b4e6d2bas the write-clock landing (ADR 0016). Prefer over #131. Do not merge before #74. Do not invent a theta.What is sound
- Admission clock stays
created_at <= knowledge_cutoffon all four scope branches. Write clock is a separateupdated_atcomparison. Equal times stay in-cutoff evidence.- Naive timestamps are treated as UTC. Detail returns
updated_at+live_after_cutoffand still omitspost_body.- After
make seed, Demo public post is the rewritten counter-example (2026-01-13); Demo private post matches the January cutoff.- Accessible name is
Open live post (updated after cutoff): …only on rewritten titles. Unchanged titles stayOpen live post: ….- Tests lock
>vs==, the edited own-corp title in the January run, the late-created title out, and no body in the payload.- W3C Time / ISO 8601-1 doctoring on ADR 0016 is updated. List payloads stay aggregates-only.
Before merge
Rebase onto #7439ed6eb. This head is still based on6f79ecb. #148 already changedCLAUDE.md(pending lineage sentence) andApp.tsx(analysisRunNextActionkind switch + detail next-action). Keep those. Do not drop the pending-lineage sentence while adding the write-clock sentence.Version
0.87.0is fine after #153's0.86.3person-catalog slice, or land this first and let #153 rebase. Do not give both PRs the same version.Independent reviewer remains seonghobae. This token cannot self-approve #74 or merge.
Sent by Cursor Automation: Fix Issues
| ``created_at <= knowledge_cutoff`` admits the title. ``updated_at`` is | ||
| the live write clock (ADR 0016). Equal times stay in-cutoff evidence. | ||
| """ | ||
| return _as_utc(updated_at) > _as_utc(knowledge_cutoff) |
There was a problem hiding this comment.
Admission (created_at <= cutoff) and write clock (updated_at > cutoff) stay distinct. Equal times correctly stay in-cutoff. Naive values become UTC.
Next action after rebase onto 39ed6eb: keep all four created_at <= $n filters. Do not let the write-clock mark admit a late-created title. The existing API test (edited January title in, 2026-01-20 title out, no post_body) is the buyer proof.
| Digest prefixes stay audible; hover a prefix to read the full digest. | ||
| Opening a cutoff title shows the live post -- compare it with the | ||
| cutoff before treating the body as reconstructed evidence (ADR 0016). | ||
| Opening a cutoff title shows the live post. Titles marked updated |
There was a problem hiding this comment.
#148 already landed a pending-lineage sentence on #74 39ed6eb just above this block. This patch is against the pre-#148 text.
Next action: rebase onto 39ed6eb and keep both sentences — pending lineage says reconstruction has not started; titles marked updated after cutoff were rewritten after the run. Do not replace one with the other.
seonghobae
left a comment
There was a problem hiding this comment.
Reviewed #150 b4e6d2b as the write-clock landing (ADR 0016). Prefer over draft #131. Do not merge before #74. Do not invent a theta.
Verdict: NEEDS_CHANGES
CodeRabbit GitHub skipped (non-default base). CLI 0.7.3 coderabbit auth login --agent timed out (automatic_login_failed). That skip is not a clean review.
What is sound
- Admission stays
created_at <= knowledge_cutoffon all four scope branches. Write clock is a separateupdated_at > cutoff. Equal times stay in-cutoff evidence. Naive values become UTC. - Detail returns
updated_at+live_after_cutoffand still omitspost_body. List payloads stay aggregates-only. No DSN or source SQL. - After
make seed, Demo public post is stamped2026-01-13T09:00:00Z; Demo private post matchescreated_at. Fixture posts setupdated_at = occurred. - Accessible name is
Open live post (updated after cutoff): …only on rewritten titles. Opening a marked title still shows the live body. - TEPP stays behind
tepp_client. Null channels are untouched. Synthetic fixtures only. W3C Time / ISO 8601-1 clocks stay distinct.
Blocking
seeded_dbinsertsEdited own-corp private post(own-corp, private, in-cutoff).test_post_list_includes_public_and_own_corp_but_excludes_other_corpstill exact-sets{"Public post", "Own-corp private post", "Late own-corp private post"}atbackend/tests/test_api.py:612. Same class as #110/#114. Add the edited title to that set.
Residual (rebase, not a product defect)
- Live #74 is
69c035b, not6f79ecb. #148 (39ed6eb) already added the pending-lineage sentence and a kind-specificanalysisRunNextAction. Retention purge on69c035balready took0.87.0and added an ADR 0020 section toCLAUDE.md. Rebase and keep those. Take0.87.1or0.88.0— do not ship a second0.87.0.
Product-gap residuals correctly out of scope
- Cutoff body versioning (ADR 0016 later slice).
- A
source_post.updated_atbump trigger (0001 hasdefault now()only; seed stamps both clocks explicitly). - Showing the write date on the badge (API already returns
updated_at; the mark is the next action). - Snapshot
source_counts3 vs two live in-cutoff titles (pre-existing fixture).
Test gaps (residual)
- No seed-script lock that Demo public is
2026-01-13and Demo private is not. - No HTTP assertion for
updated_at == cutoff(unit test covers it). - Process-unit / thread-group / all-visible scopes share the comparison loop and are not HTTP-tested for the new fields.
Independent reviewer remains needed. This token cannot self-approve #74 or merge.
| "A January post rewritten after the run cutoff.", | ||
| created_at="2026-01-10T12:00:00Z", | ||
| updated_at="2026-01-13T09:00:00Z", | ||
| ) |
There was a problem hiding this comment.
This own-corp private insert is visible on GET /api/posts. test_post_list_includes_public_and_own_corp_but_excludes_other_corp still exact-sets {"Public post", "Own-corp private post", "Late own-corp private post"} at line 612, so the shared seeded_db fixture will fail that test once the live stack is up. Same class as #110/#114. Add Edited own-corp private post to that set. Do not drop this row — it is the buyer proof that an in-cutoff title can still be live_after_cutoff.
| Digest prefixes stay audible; hover a prefix to read the full digest. | ||
| Opening a cutoff title shows the live post -- compare it with the | ||
| cutoff before treating the body as reconstructed evidence (ADR 0016). | ||
| Opening a cutoff title shows the live post. Titles marked updated |
There was a problem hiding this comment.
#74 69c035b already has two sentences this patch must not replace: a pending lineage row says reconstruction has not started yet, and the ADR 0020 retention-purge section above the seed block. Rebase onto that head and keep both, then keep this write-clock sentence. Do not drop the pending-lineage line while adding the mark.
| name = "lineageweave" | ||
| version = "0.86.2" | ||
| version = "0.87.0" | ||
| description = "Reconstructs git-branch-style lineage DAGs from scattered short records using multi-channel score fusion and LLM adjudication." |
There was a problem hiding this comment.
Live #74 69c035b already shipped 0.87.0 for the granted retention purge (ADR 0020). This head cannot keep the same version after rebase. Take 0.87.1 or 0.88.0 in pyproject.toml, lineageweave/__init__.py, frontend/package.json, uv.lock, and the changelog fragment.
There was a problem hiding this comment.
Reviewed exact head b4e6d2b (rebased onto #74 6f79ecb). CodeRabbit GitHub skipped this non-default base; CodeRabbit CLI cannot authenticate in this environment, so this is a full technical review of the committed diff, not a CodeRabbit result.
What holds
The buyer slice is the right one. created_at <= knowledge_cutoff still admits the title; updated_at > knowledge_cutoff only marks a rewrite. Equal clocks stay in-cutoff. The detail payload stays titles plus clocks — no body, DSN, or source SQL. Seed pins Demo public post to 2026-01-13 and Demo private post to the January create clock. Unit, API, and UI tests cover that counter-example.
Do not merge before #74. Do not treat draft #131 as a second landing vehicle.
Required before merge
- Rebase onto current #74
69c035band take 0.87.1. #74 already shipped0.87.0as granted retention purge plus Storybook tokens. This head still claims0.87.0(dated 2026-08-17).git merge-treeagainst69c035bconflicts inARCHITECTURE.md,CHANGELOG.md, and the version files. Keep the retention-purge 0.87.0 notes and add this write-clock slice as 0.87.1. - Keep
source_post.updated_athonest after a body write. The comparison is correct only if the write clock moves when the live row is rewritten. There is still no trigger (or write-path assignment) that bumpsupdated_atonpost_title/post_bodychanges while honoring an explicitupdated_atin the same statement. Seed then does a body-onlyUPDATEafter the pin. A later product edit, or a trigger that always setsnow(), will either hide a rewrite or destroy the Demo public post counter-example. #131 had that trigger; this head dropped it. - Carry the mark through click-through. Opening a marked title still shows the live body with no write-clock vs cutoff line. The list badge is not enough: the next action has to survive the popup. Repeat
updated_atand the cutoff on that opened post, then compare those two clocks before treating the body as reconstructed evidence.
After the rebase
Repeated cutoff badges should use the ADR 0020 tokens already on #74 (frontend/src/styles/tokens.css + Storybook inventory), not a one-off .post-badge opacity. Close #131 as superseded once this head is the only write-clock vehicle.
Frontend lint/test/build and the full suite were still queued on this head at review time. Re-run them on the rebased 0.87.1 commit; do not merge on the 6f79ecb stack.
Sent by Cursor Automation: Fix Issues
| [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning follows | ||
| [Semantic Versioning](https://semver.org/spec/v2.0.0.html). | ||
|
|
||
| ## [0.87.0] - 2026-08-17 |
There was a problem hiding this comment.
Current #74 tip 69c035b already published ## [0.87.0] for granted retention purge and Storybook tokens. Rebase onto that tip and move this write-clock entry to 0.87.1 so both buyer slices stay in the changelog. Merging this 0.87.0 block as-is will conflict and collapse two releases into one version.
| ``created_at <= knowledge_cutoff`` admits the title. ``updated_at`` is | ||
| the live write clock (ADR 0016). Equal times stay in-cutoff evidence. | ||
| """ | ||
| return _as_utc(updated_at) > _as_utc(knowledge_cutoff) |
There was a problem hiding this comment.
updated_at > knowledge_cutoff is the right predicate (equal clocks stay in-cutoff). It only matches a real rewrite if source_post.updated_at moves when post_title / post_body change. Add a write-clock trigger that sets updated_at = now() unless the statement already assigned updated_at, and cover three cases: explicit historical pin stays, a body-only update after cutoff marks the title, a body-only update at the create clock does not.
| "where post_title in ('Demo public post', 'Demo private post') " | ||
| "and created_at > '2026-01-12T12:00:00Z'" | ||
| "update source_post set created_at = '2026-01-10T12:00:00Z', " | ||
| "updated_at = '2026-01-13T09:00:00Z' " |
There was a problem hiding this comment.
This pin is the Demo public post counter-example. The next statement updates post_body without touching updated_at. If you add the write-clock trigger requested on live_write_after_cutoff, either assign updated_at again on that body write or re-pin after every Demo public / Demo private body update so make seed still shows public marked and private unmarked.
| {post.post_title} | ||
| </button> | ||
| {post.live_after_cutoff && ( | ||
| <span className="post-badge">Updated after cutoff</span> |
There was a problem hiding this comment.
The list mark disappears as soon as the operator opens the title. Pass updated_at and live_after_cutoff into that live-post popup and state the two clocks there (“written 2026-01-13, after cutoff 2026-01-12 — compare this body with the run before you treat it as reconstructed evidence”). After the #74 rebase, render this badge with the ADR 0020 tokens already used for repeated chips.
There was a problem hiding this comment.
Reviewed exact head b4e6d2b (rebased onto #74 6f79ecb). CodeRabbit GitHub skipped this non-default base; CodeRabbit CLI cannot authenticate in this environment, so this is a full technical review of the committed diff, not a CodeRabbit result.
What holds
The buyer slice is the right one. created_at <= knowledge_cutoff still admits the title; updated_at > knowledge_cutoff only marks a rewrite. Equal clocks stay in-cutoff. The detail payload stays titles plus clocks — no body, DSN, or source SQL. Seed pins Demo public post to 2026-01-13 and Demo private post to the January create clock. Unit, API, and UI tests cover that counter-example.
Do not merge before #74. Do not treat draft #131 as a second landing vehicle.
Required before merge
- Fix the
seeded_dbpost-list exact set. InsertingEdited own-corp private postmakestest_post_list_includes_public_and_own_corp_but_excludes_other_corpfail: it still asserts exactly{Public post, Own-corp private post, Late own-corp private post}. Add the edited title to that set. - Rebase onto current #74
69c035band take 0.87.1. #74 already shipped0.87.0as granted retention purge plus Storybook tokens. This head still claims0.87.0(dated 2026-08-17).git merge-treeagainst69c035bconflicts inARCHITECTURE.md,CHANGELOG.md, and the version files. Keep the retention-purge 0.87.0 notes and add this write-clock slice as 0.87.1. - Keep
source_post.updated_athonest after a body write. The comparison is correct only if the write clock moves when the live row is rewritten. There is still no trigger (or write-path assignment) that bumpsupdated_atonpost_title/post_bodychanges while honoring an explicitupdated_atin the same statement. Seed then does a body-onlyUPDATEafter the pin. A later product edit, or a trigger that always setsnow(), will either hide a rewrite or destroy the Demo public post counter-example. #131 had that trigger; this head dropped it. - Carry the mark through click-through. Opening a marked title still shows the live body with no write-clock vs cutoff line. The list badge is not enough: the next action has to survive the popup. Repeat
updated_atand the cutoff on that opened post, then compare those two clocks before treating the body as reconstructed evidence.
After the rebase
Repeated cutoff badges should use the ADR 0020 tokens already on #74 (frontend/src/styles/tokens.css + Storybook inventory), not a one-off .post-badge opacity. Close #131 as superseded once this head is the only write-clock vehicle.
Frontend lint/test/build and the full suite were still queued on this head at review time. Re-run them on the rebased 0.87.1 commit; do not merge on the 6f79ecb stack.
Sent by Cursor Automation: Fix Issues
| [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning follows | ||
| [Semantic Versioning](https://semver.org/spec/v2.0.0.html). | ||
|
|
||
| ## [0.87.0] - 2026-08-17 |
There was a problem hiding this comment.
Current #74 tip 69c035b already published ## [0.87.0] for granted retention purge and Storybook tokens. Rebase onto that tip and move this write-clock entry to 0.87.1 so both buyer slices stay in the changelog. Merging this 0.87.0 block as-is will conflict and collapse two releases into one version.
| ``created_at <= knowledge_cutoff`` admits the title. ``updated_at`` is | ||
| the live write clock (ADR 0016). Equal times stay in-cutoff evidence. | ||
| """ | ||
| return _as_utc(updated_at) > _as_utc(knowledge_cutoff) |
There was a problem hiding this comment.
updated_at > knowledge_cutoff is the right predicate (equal clocks stay in-cutoff). It only matches a real rewrite if source_post.updated_at moves when post_title / post_body change. Add a write-clock trigger that sets updated_at = now() unless the statement already assigned updated_at, and cover three cases: explicit historical pin stays, a body-only update after cutoff marks the title, a body-only update at the create clock does not.
| "where post_title in ('Demo public post', 'Demo private post') " | ||
| "and created_at > '2026-01-12T12:00:00Z'" | ||
| "update source_post set created_at = '2026-01-10T12:00:00Z', " | ||
| "updated_at = '2026-01-13T09:00:00Z' " |
There was a problem hiding this comment.
This pin is the Demo public post counter-example. The next statement updates post_body without touching updated_at. If you add the write-clock trigger requested on live_write_after_cutoff, either assign updated_at again on that body write or re-pin after every Demo public / Demo private body update so make seed still shows public marked and private unmarked.
| {post.post_title} | ||
| </button> | ||
| {post.live_after_cutoff && ( | ||
| <span className="post-badge">Updated after cutoff</span> |
There was a problem hiding this comment.
The list mark disappears as soon as the operator opens the title. Pass updated_at and live_after_cutoff into that live-post popup and state the two clocks there (“written 2026-01-13, after cutoff 2026-01-12 — compare this body with the run before you treat it as reconstructed evidence”). After the #74 rebase, render this badge with the ADR 0020 tokens already used for repeated chips.
| created_at="2026-01-20T12:00:00Z", | ||
| ) | ||
| _insert_post( | ||
| "Edited own-corp private post", |
There was a problem hiding this comment.
seeded_db now inserts this own-corp private title, so GET /api/posts will include it. test_post_list_includes_public_and_own_corp_but_excludes_other_corp still exact-sets three titles and will fail on this head. Add Edited own-corp private post to that set (and any other exact-set list that uses seeded_db) before the full suite is treated as green.
There was a problem hiding this comment.
REQUEST_CHANGES on b4e6d2b.
The write-clock slice is the right buyer gap (prefer over draft #131). Admission stays created_at <= knowledge_cutoff; updated_at is a separate comparison; equal clocks stay unmarked; Demo public is the 2026-01-13 counter-example. TEPP stays behind tepp_client. List payloads stay aggregates-only.
Do not merge this head:
- Blocking —
Edited own-corp private postis inserted on the shared API fixture buttest_post_list_includes_public_and_own_corp_but_excludes_other_corpstill exact-sets three titles. Full test suite will fail the same way #110/#114 did. - Blocking — base is stale
6f79ecb. Live #74 is69c035b(retention purge already took0.87.0and added ADR 0020 toCLAUDE.md). Merging this as-is drops the pending-lineage sentence and the retention section. - Blocking —
0.87.0is already shipped on #74. Take0.87.1after rebase.
Landing vehicle is the rebased successor on cursor/bc-d9c9c898-f8dd-4055-a82f-1ef4c0e94184-f040 (v0.87.1, exact-set includes the edited title, seed clocks locked, PostBadge token). Do not merge #150 or #131 in parallel.
Cutoff body versioning stays a later slice. Independent reviewer still needed; this run does not self-approve.
Sent by Cursor Automation: Fix Issues
| "A January post rewritten after the run cutoff.", | ||
| created_at="2026-01-10T12:00:00Z", | ||
| updated_at="2026-01-13T09:00:00Z", | ||
| ) |
There was a problem hiding this comment.
This edited own-corp row is the buyer proof for live_after_cutoff, but test_post_list_includes_public_and_own_corp_but_excludes_other_corp still exact-sets {"Public post", "Own-corp private post", "Late own-corp private post"} at line 612. Keep the row and add the title to that set.
| cutoff before treating the body as reconstructed evidence (ADR 0016). | ||
| Opening a cutoff title shows the live post. Titles marked updated | ||
| after cutoff were rewritten after the run; compare those bodies | ||
| before treating them as reconstructed evidence (ADR 0016). |
There was a problem hiding this comment.
Keep this write-clock sentence, but rebase onto live #74 69c035b first. That head already has the ADR 0020 retention section and the pending-lineage next-action sentence. Merging this file as-is drops both.
| [project] | ||
| name = "lineageweave" | ||
| version = "0.86.2" | ||
| version = "0.87.0" |
There was a problem hiding this comment.
0.87.0 is already taken by #74 retention purge (69c035b). After rebase, ship this slice as 0.87.1 in pyproject.toml, lineageweave/__init__.py, frontend/package.json, and uv.lock.
There was a problem hiding this comment.
Do not merge #150 at b4e6d2b.
This head is dirty against current #74 (69c035b). #74 already shipped v0.87.0 as retention purge and Storybook tokens. Landing this slice as another 0.87.0 would collide and drop the retention entry.
Use #176 (9d57cbe) instead: same write-clock contract on current #74, recorded as v0.88.0. After make seed, open the Demo Corp lineage run — Demo public post is marked Updated after cutoff; Demo private post is not. Opening a marked title still shows the live body.
#162 and #167 still stack on this dirty head. Rebase those onto #176 after #74, or close them in favor of a #176-based successor.
Queued or predecessor-head gates are non-passing. This automation cannot merge.
Sent by Cursor Automation: Fix Issues


Buyer gap
ADR 0016 already hid later-created titles from an analysis-run detail, but every remaining title still carried a generic “the live body may have changed” warning. After
make seed,source_post.updated_atdefaulted to now, so the operator could not tell which January titles were actually rewritten after the run.What the operator sees
Stacked on current #74 (
7f2d4bc). Do not merge before #74.GET /api/analysis-runs/{id}still lists only ABAC-visible titles withcreated_at <= knowledge_cutoff.updated_atandlive_after_cutoff. No post body, DSN, or source SQL.make seed, open Lineage reconstruction · Succeeded · Demo Corp: Demo public post is marked Updated after cutoff (2026-01-13); Demo private post is not.Boundaries
tepp_client. This write does not invent a theta.Tests
tests/test_analysis_run_create.py— write clock>cutoff, equal times stay in-cutoff.backend/tests/test_api.py— edited own-corp title is in the January run; late-created title is not; body is omitted.frontend/src/App.test.tsx— badge and accessible name only on rewritten titles; pending-create mock now returns the created row on the next list fetch.Supersedes conflicting draft #131 (same buyer gap, stale #74 base).