Skip to content

feat: add normalized analysis-run registry (Milestone 2 slice 1) - #89

Merged
seonghobae merged 21 commits into
feat/role-responsibility-agent-ontologyfrom
feat/analysis-run-registry-v079-clean
Aug 16, 2026
Merged

feat: add normalized analysis-run registry (Milestone 2 slice 1)#89
seonghobae merged 21 commits into
feat/role-responsibility-agent-ontologyfrom
feat/analysis-run-registry-v079-clean

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Buyer impact

Adds the first clean, additive Milestone 2 persistence boundary to the reviewed LineageWeave product. Operators gain a durable derivation root for immutable source captures, aggregate reconciliation, authenticated requests, product scope, reproducibility digests, and legal lifecycle evidence without merging the retained parallel application or exposing private source material.

Refs #79; does not close it.

Exact stack boundary

Normalized registry

Migration 0018_analysis_run_registry.sql adds:

  • analysis_source_snapshot — immutable capture digest, source-contract version, latest evidence-availability time, and capture time;
  • analysis_source_count — one non-negative aggregate per snapshot/count vocabulary;
  • analysis_run — non-null authenticated requester, account-scoped idempotency, run-owned knowledge cutoff, and reproducibility digests;
  • analysis_run_scope — exactly shaped all-visible, corporate-entity, process-unit, or thread-group scope;
  • analysis_run_status_event — append-only state-machine evidence with occurrence and database record time;
  • analysis_run_current_status — derived latest-status view, not a second mutable authority.

All database objects use descriptive two-or-more-word snake_case; enum-like values remain in common_lookup_value; category allowlists prevent an unrelated lookup code from satisfying a run column.

Temporal truth

The snapshot owns maximum_available_time; each run owns knowledge_cutoff. This preserves the functional dependency that one immutable capture can support multiple later analyses. Run creation locks the snapshot and requires:

maximum_available_time <= knowledge_cutoff <= requested_at
captured_at <= requested_at

This aggregate leakage guard complements, rather than replaces, TEPP's finer event/assertion/document/system/availability/cutoff clocks.

Concurrency and immutability

  • Snapshot identity and availability reject updates.
  • Count values reject updates.
  • Count insert/delete and first run creation take the same snapshot-row lock, closing the count-freeze race.
  • The complete count set freezes once the first run references a snapshot.
  • Analysis request identity, actor, cutoff, and digests reject updates.
  • Status appends serialize through the immutable parent run row.

Lifecycle contract

The first status must be pending; ordinals are contiguous; occurrence time is monotonic; and only these transitions are accepted:

pending -> running | cancelled
running -> succeeded | failed | cancelled
terminal -> no successor

Failed events require a bounded machine failure code. Raw exceptions and source/provider payloads are prohibited. Update/delete of status events is rejected.

Authorization and privacy boundary

Every run references a real user_account; idempotency is unique per account. The next repository/API slice must create run, scope, and first status atomically and enforce the existing RBAC/ABAC contract when reading registry data. This PR does not claim an API or UI already exists.

Necessary PII remains in purpose-bound authorized source/product contexts. The registry retains only opaque identifiers, digests, aggregate counts, bounded codes, and clocks. It supports CSAP/SOC 2 evidence readiness without claiming certification.

TDD and verification

The real-PostgreSQL contract was committed before the migration implementation. The one-shot branch verifier and any temporary repair workflow are absent from the final diff versus #74.

Documentation

Merge gates

@coderabbitai

coderabbitai Bot commented Aug 15, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2ff9d916-f7d2-4b22-a64f-21059cbdf3f8

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@seonghobae
seonghobae force-pushed the feat/analysis-run-registry-v079-clean branch from 7ddf20c to ec1ebe5 Compare August 16, 2026 09:58
@seonghobae
seonghobae marked this pull request as ready for review August 16, 2026 09:59
@seonghobae
seonghobae force-pushed the feat/analysis-run-registry-v079-clean branch from ec1ebe5 to 05f00a0 Compare August 16, 2026 10:02
@seonghobae
seonghobae marked this pull request as draft August 16, 2026 10:14
@seonghobae
seonghobae marked this pull request as ready for review August 16, 2026 10:53
seonghobae added a commit that referenced this pull request Aug 16, 2026
#95)

Port the #77 analysis-run evidence surface onto the #89 registry without
a second app or raw source. GET /api/analysis-runs is SQL-scoped; hidden
tenant runs 404. After make seed, Demo Corp shows Lineage reconstruction
as Succeeded with the synthetic document count.
@cursor

cursor Bot commented Aug 16, 2026

Copy link
Copy Markdown

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.

cursor Bot pushed a commit that referenced this pull request Aug 16, 2026
#95)

Port the #77 analysis-run evidence surface onto the #89 registry without
a second app or raw source. GET /api/analysis-runs is SQL-scoped; hidden
tenant runs 404. After make seed, Demo Corp shows Lineage reconstruction
as Succeeded with the synthetic document count.
@cursor
cursor Bot force-pushed the feat/analysis-run-registry-v079-clean branch from 62af5a6 to e58f094 Compare August 16, 2026 14:17
seonghobae and others added 10 commits August 16, 2026 14:42
The fail-closed rollback script starts an explicit transaction. On an
autocommit connection a RAISE left that transaction aborted, so the
empty-registry cleanup could not run.
#95)

Port the #77 analysis-run evidence surface onto the #89 registry without
a second app or raw source. GET /api/analysis-runs is SQL-scoped; hidden
tenant runs 404. After make seed, Demo Corp shows Lineage reconstruction
as Succeeded with the synthetic document count.
Buyer gap: after #95 the home Analysis runs row was inert text.
Clicking the seeded Demo Corp lineage run now loads
GET /api/analysis-runs/{id} and shows cutoff, requested date, and
document count. Hidden runs stay not-visible. Synthetic aggregates
only -- never a DSN or source SQL.
Buyer gap: after #100 the detail showed cutoff and counts but not the
legal lifecycle the registry already stored.

GET /api/analysis-runs/{id} now returns labeled status_history
(Pending → Running → Succeeded with occurrence times). The list stays
latest-status only. Hidden runs still 404 and never leak events.
Failure codes stay machine tokens. Synthetic Demo Corp seed only.
Buyer gap: after #102 the run detail showed history but no way to
open a post. Detail now lists ABAC-visible titles in the run's
scope. Other-corp private posts stay hidden. List payloads stay
aggregates-only. Synthetic titles only.
PR #91 landed an adaptive-orchestration ADR 0013 on the #74 base after
this slice already used 0013 for the normalized analysis-run registry.
Renumber the adaptive record to 0015 so ADR numbers stay unique.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
The #74 changelog fold still called that decision ADR 0013. This stack
keeps the analysis-run registry as ADR 0013, so the adaptive record is
0015.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
@cursor
cursor Bot force-pushed the feat/analysis-run-registry-v079-clean branch from 15e90ca to 955d0b0 Compare August 16, 2026 14:43

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

v0.83 follow-up is on the same tip plus one commit: analysis-run detail must not list posts written after knowledge_cutoff, and it should show revision/config digest prefixes so an operator can confirm the run they approved.

What this PR already does well

  • Migration 0018 keeps snapshot availability and run cutoff on different relations, with 3NF names and append-only lifecycle evidence.
  • Authorized list/detail stay source-redacting: labels and aggregates only; hidden runs 404.
  • Status history is detail-only and uses stored machine failure codes.
  • Synthetic Demo Corp seed only.

Required before claiming temporal truth on the post list

fetch_visible_scope_posts currently returns every ABAC-visible title in scope. Fixture posts use created_at = now() (August 2026) while the seeded run cutoff is 2026-01-12T12:00:00Z, so a later own-corp post would appear inside that January reconstruction. ADR 0013 already requires the cutoff; the read projection has to apply it.

The v0.83.0 slice on cursor/bc-4e088f14-f62b-4ed5-90d0-2167410c4cda-226d adds created_at <= knowledge_cutoff, backdates in-cutoff fixture posts, asserts the late post is absent, and shows digest prefixes. Land that (or equivalent) before treating the post list as as-of evidence.

Merge gates that are still outside this review

  • Do not merge before #74 is on protected main. Local tests.yml only runs on PRs targeting main, so this stacked PR has no Full test suite / Frontend check on the current head.
  • #105 and #107 cover overlapping registry work. Keep one exact-head stack after #74 lands.
  • Qualifying independent approval is still required by the live ruleset.

I cannot merge from this automation. Next action: review the v0.83 cutoff slice, then rebuild this stack onto protected main after #74.

Open in Web View Automation 

Sent by Cursor Automation: fix all

rows = await conn.fetch(
"select post_id, post_title, visibility_code, corporate_entity_id "
"from source_post where corporate_entity_id = $1 "
"order by created_at, post_title",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This scope query has no created_at <= knowledge_cutoff predicate. A post written after the run cutoff still appears in visible_posts, so the detail contradicts ADR 0013's temporal ownership.

Add the cutoff bind to every scope branch (corporate entity, process unit, thread group, all-visible). The v0.83.0 follow-up does that and adds a late own-corp fixture post that must stay absent.

Comment thread frontend/src/App.tsx
))}
</ol>
)}
{selected.visible_posts && selected.visible_posts.length > 0 && (

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The detail lists posts but not the reproducibility digests the API already returns (code_revision_sha, configuration_sha256). An operator cannot confirm this run matches the code they approved.

Show 12-character prefixes here, and keep full digests on the API only. v0.83.0 extracts this panel to AnalysisRunsPanel so the list/detail object can be inventoried for Storybook without growing this file further.

@seonghobae
seonghobae merged commit f27ecfb into feat/role-responsibility-agent-ontology Aug 16, 2026
2 checks passed
seonghobae added a commit that referenced this pull request Aug 16, 2026
The #89 review asked for 12-character code and config prefixes so an
operator can match the approved revision. Full digests stay on the API
only. Do not merge until this review item is checked.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
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.

2 participants