feat: apply analysis-run knowledge cutoff to visible posts (v0.83.0) - #110
feat: apply analysis-run knowledge cutoff to visible posts (v0.83.0)#110seonghobae wants to merge 2 commits into
Conversation
A later own-corp post no longer appears inside a historical run. Detail shows revision and configuration digest prefixes so an operator can confirm the run they approved. AnalysisRunsPanel is extracted for the Storybook inventory. Co-authored-by: Seongho Bae <[email protected]>
Default created_at=now() hid every demo post from the January 12 run. Stamp Demo public/private at 2026-01-10, add Late Demo public post as the after-cutoff counter-example, and import AnalysisRun so tsc -b type-checks the extracted panel.
|
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 |
There was a problem hiding this comment.
The cutoff filter itself is the right fail-closed change. fetch_visible_scope_posts applies created_at <= knowledge_cutoff on every scope, then the same public-or-affiliated check, and I did not find a path that returns a later or unauthorized title on GET /api/analysis-runs/{id}.
This head is not ready to merge. Do the following on feat/analysis-run-cutoff-posts (or take the two repair commits from cursor/bc-aa7451e9-f8e4-4145-8a9b-1e95eb59273b-c133):
- Replace the always-on seed string-contains test with a live
authz_dbcase that inserts before / equal-to / after cutoff posts on corporate-entity, process-unit, thread-group, and all-visible scopes. Keep the seed-script check as a secondary guard. - Update
test_post_list_includes_public_and_own_corp_but_excludes_other_corpsoGET /api/postsincludesLate own-corp private post. That list is not cutoff-scoped; the current exact set of two titles will fail when the live API suite runs. - Label snapshot
source_countsas capture inventory ("in the snapshot"). ADR 0013 stores those counts on the snapshot, not on the run. Aftermake seed, "3 documents" next to two in-cutoff Demo titles is a buyer-visible contradiction. - Skip
analysis_source_countinserts when the Demo snapshot already has rows.BEFORE INSERTfreeze runs beforeON CONFLICT, so a secondmake seedstill raisesanalysis_source_count_frozen_after_run. - Point
_visible_idsat the production thread-group clause. Hiddenall_visibleshould be GET'd, not only listed.
Frontend lint/test/build on the repair: 49 tests, tsc -b production build pass. Always-on test_seed_stamps_demo_posts_relative_to_run_cutoff passes. Live Postgres cases still self-skip without a DSN — same as the rest of this stack.
Do not merge before #74 reaches protected main. Product CI workflows do not run on this base. CodeRabbit skipped because the target is not the default branch; that skip is not a clean review.
Click-through still opens today's post body. ADR 0016 already names that as a later slice — not a merge block for this one.
Sent by Cursor Automation: Fix Issues
| def test_seed_stamps_demo_posts_relative_to_run_cutoff() -> None: | ||
| """make seed must not hide Demo public post behind default created_at=now().""" | ||
| seed = _SEED_SCRIPT.read_text(encoding="utf-8") | ||
| assert "2026-01-12T12:00:00Z" in seed |
There was a problem hiding this comment.
This is the only always-on cutoff test, and it never executes fetch_visible_scope_posts or Postgres. It still passes if the SQL predicate is deleted, as long as scripts/seed_demo_data.py keeps these four strings.
Add an authz_db case that inserts in-cutoff, equal-to-cutoff (2026-01-12T12:00:00Z must appear), and after-cutoff (2026-01-12T12:00:01Z must not) posts, then assert titles for corporate-entity, process-unit, thread-group, and all-visible. Keep this seed-script check as a secondary guard if you want.
| ) | ||
| other_private_post_id = _insert_post("Other-corp private post", other_corp_id, "private") | ||
| _insert_post( | ||
| "Late own-corp private post", |
There was a problem hiding this comment.
seeded_db now has a fourth own-corp private post. GET /api/posts is not cutoff-scoped, so test_post_list_includes_public_and_own_corp_but_excludes_other_corp still asserting {"Public post", "Own-corp private post"} (line 523, outside this hunk) will fail when the live API suite runs. The fixture docstring still says three rows.
Include Late own-corp private post in that exact set, or insert the late post only inside the analysis-run test. Also GET hidden_all_visible_id and expect 404 — list exclusion alone does not prove the detail path.
| <span className="ticket-title">{caption}</span> | ||
| {documentCount && ( | ||
| <span className="post-badge"> | ||
| {documentCount.count_value} {documentCount.count_type_label.toLowerCase()} |
There was a problem hiding this comment.
This badge prints the frozen snapshot count as if it were the cutoff-filtered list. After make seed the operator sees "3 documents" and then two in-cutoff Demo titles (Late Demo is hidden). ADR 0013 stores counts on the capture, not on the run.
Label it as snapshot inventory, e.g. 3 documents in the snapshot, and use the same copy in the detail list (line 104). Do not recount live source_post rows here — that would invent a second authority besides analysis_source_count.
| </ul> | ||
| ) : ( | ||
| <p className="popup-placeholder"> | ||
| No posts were available at this cutoff. Open a later run, or ask an |
There was a problem hiding this comment.
undefined and [] share this empty-state. Today handleOpen always fetches detail, which always sets visible_posts. If a list payload is ever assigned to selected, the operator gets a false "no posts at this cutoff" message.
Render this copy only when visible_posts is an empty array. Leave undefined as no list yet.
|
Superseded by #74 |
TEPP seed already landed on #74 through #118. Replay the remaining #110 counter-example: Late Demo public post (2026-01-13) stays off the January 12 Demo Corp run. No second cutoff filter. No fabricated theta. Co-authored-by: Seongho Bae <[email protected]>


Buyer impact
Open an analysis run and you now see only posts that existed at that run's knowledge cutoff. After
make seed, Demo public post (2026-01-10) still opens from the January 12 reconstruction; Late Demo public post (2026-01-13) does not. A later own-corp post no longer appears inside a historical reconstruction. The detail also shows revision and configuration digest prefixes so you can confirm the run matches the code you approved. If the list is empty, open a later run or ask an administrator to capture a newer snapshot.What changed
GET /api/analysis-runs/{id}appliessource_post.created_at <= knowledge_cutoffon top of the existing ABAC scope filter (ADR 0016).created_at=now()does not empty the January run, and inserts Late Demo public post as the falsifiable counter-example.Revision/Configprefixes fromcode_revision_shaandconfiguration_sha256.AnalysisRunsPanelis extracted fromApp.tsxand inventoried for Storybook. The missingAnalysisRuntype import is included sotsc -btype-checks the panel.Review of #108
#108 shipped the cutoff slice but left two buyer-facing gaps:
created_at=now(), somake seedwould show "No posts were available at this cutoff."AnalysisRunsPanelusedAnalysisRunwithout importing it (verbatimModuleSyntax).This branch replays #108 onto current #74 (
f27ecfb, includes #89/#107 + #103) and applies those fixes. #108 can stay draft.Stack
Stacked on PR #74 (
feat/role-responsibility-agent-ontology). Includes the #89 registry, #95/#100/#102/#103 read surface, plus this v0.83.0 slice. Do not merge before #74 reaches protectedmain.Refs #79.
Verification
cd frontend && pnpm run lint && pnpm run test && pnpm run build— 47 tests, production build passpytest tests/test_analysis_run_authorization.py tests/test_analysis_run_registry_schema.py tests/test_schema.py— 20 passedbackend/tests/test_api.py(self-skips without a live DSN)tepp_client. No AGENTS.md rewrite.