feat: land Demo Corp members under the opened-report next action (v1.1.0) - #203
Conversation
…1.0) After Open period report names the next action, Demo Corp mean θ and member posts land immediately below it, ahead of Other Corp and the week strip.
|
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 |
37a652c
into
feat/role-responsibility-agent-ontology
* feat: R&R's named actor is a PROV-O Agent, not always a person (0.68.0)
Confirmed against real Milestone 2 SAP CRM VOC data: post_summary.py's
R&R extraction forced every named actor into a person slot, but real
business correspondence routinely names an organization acting in its
own name ("당사," "SEWA," "Siemens," "GECO"), not an individual.
- RoleResponsibility.actor_name (renamed from person_name) gains
actor_type_code (prov_person/prov_organization, W3C PROV-O grounded:
Lebo, Sahoo, & McGuinness, 2013) and an LLM-inferred
affiliated_organization_name for person actors -- a bare name
without an employer is hard to place.
- Ontology: :RoleActorPerson rdfs:subClassOf prov:Person,
:RoleActorOrganization rdfs:subClassOf prov:Organization -- genuine
subclasses of the real external PROV-O classes, distinct from the
ontology's existing :Person (a cataloged Keyman with a stable
person_id; an R&R actor is a free-text name with no cataloged
identity).
- migrations/0012_role_responsibility_agent_type.sql renames the
column via RENAME COLUMN (preserves existing rows), not a
drop/recreate.
- Popup R&R list shows a Person/Organization badge and the inferred
affiliation; only a person actor still links to the Keyman panel.
- Also fixes a real deployment gap found via browser E2E testing:
migrations 0005-0011 had accumulated on main without ever being
applied to the long-running demo Postgres volume, surfacing as
CORS-looking failures (missing-table 500s lose their CORS header)
on Evaluate, Reports, Summary, and Chat.
ADR 0006.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
* fix: keep R&R examples synthetic and validate actor_type_code
Drop real-organization names from docs, prompts, and comments. Seed a
synthetic organization actor so the Person/Organization badge is visible
without a live LLM, and reject unknown actor_type_code values.
* feat: capture Keyman job title and avoid same-name merges (v0.69.0)
PersonMention now carries an optional job_title extracted by the LLM
from role phrasing (e.g. "our legal counsel, Sam Okonkwo"), not just
named affiliations. cataloged_person.last_known_job_title persists it,
and _upsert_person treats a conflicting stated title as evidence that a
same-name match is a different real person rather than a re-mention,
so two "Kim Cheolsu"s with different titles get distinct person rows.
Keyman panel renders the title next to the person and per-affiliation
role_title, which existed in the schema but was never surfaced before.
Migration 0013 adds the column additively; 0001_initial_schema.sql
bakes it in for fresh installs, matching this repo's existing pattern.
* fix: seed synthetic Keyman titles so the panel is not empty
After make seed, Ada West / Priya Nair / Jordan Hale carry last_known_job_title
so the new title chip is visible without a live extraction.
* fix: read Keycloak admin password from the environment
Strix flagged the local-dev password literal in seed_demo_data.py after
this branch started editing that file. make seed still injects the
compose default; a direct script run requires KEYCLOAK_ADMIN_PASSWORD.
* feat: R&R actor can be a team, meso-level between person and org (v0.70.0)
Real post text named a company sub-unit ("설계팀"/design team) that
neither ADR 0006's prov_person nor prov_organization fits -- it's part
of a company, not a person and not the company itself. actor_type_code
gains prov_team, grounded in the W3C Organization Ontology's
org:OrganizationalUnit (Reynolds, 2014), a different W3C vocabulary
from PROV-O that exists specifically for this meso-level case.
A team actor requires affiliated_organization_name in the same way a
person actor does -- unlike an organization actor, a team's own name
never answers "which company." Fixed a real bug the new type surfaced:
the R&R badge's label text was a binary Person/Organization ternary
that would have mislabeled a team as "Organization" (the CSS class
name was already generic; the display text was not).
Migration 0014 is purely additive (one lookup row insert), no schema
change -- actor_type_code already stores an arbitrary FK'd code.
* feat: resolve and search-verify abbreviated organization names (v0.71.0)
Real post text names organizations by abbreviation ("한수원" for
"한국수력원자력") that corporate_hierarchy_resolution's character-
similarity matching cannot bridge -- an initialism shares almost no
substring with its expansion, so no similarity threshold recovers it.
New lineageweave/organization_name_resolution.py: an LLM proposes the
full name from context (or declines with UNKNOWN), then the *existing*
relation_verification Searxng client cross-verifies the specific raw/
resolved pairing -- no second web-search integration built, reusing
what this repo already has for a structurally identical problem. Only
a search-corroborated resolution is ever substituted in for
resolve_corporate_entity; an unresolved or unverified name still flows
through unchanged, same never-trust-an-unverified-guess discipline as
every other channel here.
Cached in a new organization_name_resolution table
(migrations/0015), keyed by the raw name so the same abbreviation
across many posts is resolved once, not re-queried every mention.
Grounded in SKOS skos:altLabel/skos:prefLabel (Miles & Bechhofer, 2009).
Wired into backend/app/keyman_ingestion.py's affiliation loop and the
private real-data batch script's paced re-implementation of it -- which
was also found missing role_title persistence entirely (a stale copy
predating that feature), fixed alongside this.
Known, documented gap (ADR 0008): the same request's entity-
relationship classification step still uses the raw, unresolved
organization names -- not fixed here, tracked honestly instead of
silently shipped as if both sides already agreed.
* fix: recover image OCR/caption fields independently, not one strict match (v0.72.0)
_parse_description required a single regex to match TEXT/CAPTION/TAGS
in that exact order in one pass. Reproduced live against real embedded
images from the Milestone 2 batch: real vision responses with the
content right but the formatting only mostly right (bolded labels,
reordered labels, a missing TAGS line) were rejected wholesale,
producing the same "[image: content unavailable]" placeholder as a
genuinely unconfigured vision channel -- discarding real,
already-paid-for content, not a "genuinely could not get it" case.
Each label is now parsed independently by scanning lines for a
TEXT:/CAPTION:/TAGS: prefix (tolerant of markdown emphasis and any
order); only a response with neither TEXT nor CAPTION content raises
ImageDescriptionParseError. Multi-line TEXT (real multi-line OCR
output) is still preserved with real newlines, not flattened.
* feat: R&R team/organization actors get a shared cross-post identity (v0.74.0)
Extraction runs per-post; a team or organization's identity did not
survive across posts the way a Keyman's already did via
cataloged_person -- "설계팀" named in ten posts was ten unrelated
strings, not one entity the KG could link through. Extraction results
must themselves become cross-post lineage clues, not just per-post
artifacts.
New cataloged_team catalog (migrations/0016), identity key (team_name,
affiliated_organization_name) since a bare team name is not by itself
identifying ("설계팀" exists at many real companies) -- reuses the same
resolve_corporate_entity matching Keyman affiliations already use for
the team's parent org, not a second algorithm. An organization actor
resolves against the existing corporate_entity catalog directly, no
new table needed.
knowledge_graph_edges_for_post gains three new edge kinds
(edge_mention_team, edge_team_affiliation, edge_mention_organization)
as distinct object properties, not widened domain/range on the
existing :mentions (which would let RDFS entail every :mentions
subject is both a person and a team). persist_post_summary now
resolves each R&R actor's identity and calls the same
persist_edges_for_post Keyman ingestion already uses -- one function
computes a post's whole edge set regardless of trigger.
A person R&R actor is opportunistically joined to an existing
cataloged_person row by name, never originated by R&R itself --
documented as a real, deliberate gap in ADR 0009 (cataloged_person
needs person_side_code, which R&R's prompt does not currently ask
for), not silently half-done.
* feat: auto-create a real counterparty org into the corporate hierarchy (v0.75.0)
corporate_hierarchy_resolution's similarity matching only ever finds an
ALREADY-cataloged corporate_entity -- it has no path to create one.
Real Milestone 2 data confirmed the actual consequence: 0 of 4,154
person_affiliation rows and 0 of 9,852 R&R organization-actor mentions
ever resolved, because corporate_entity for the real dataset only holds
the employer's own 2-row hierarchy. The standing "통합 고객사 계열
tree AI" requirement (Samsung -> Samsung Electronics Korea -> ...) was
never actually populated for real extraction.
New lineageweave/corporate_hierarchy_inference.py: an LLM proposes a
Group/Company/Plant placement (level + parent name) from the post's
own text, or declines with UNKNOWN. New
backend/app/corporate_entity_ingestion.py's get_or_create_corporate_entity
tries similarity matching first (unchanged), then only creates a real
new row once the proposal is corroborated by the *existing*
relation_verification Searxng client -- no new search integration,
reusing the same reused-verification-client pattern ADR 0008 already
established. Recurses up a bounded (4-level) parent chain so the whole
hierarchy gets real parent_entity_id links, not an orphaned row.
Auto-created corporate_entity_code values are AUTO-<hash>-prefixed --
that column doubles as the real login corp-code Keycloak claim, so an
auto-created counterparty must never collide with that namespace.
Wired into both existing organization-resolution call sites
(keyman_ingestion.py's affiliation loop, post_summary_ingestion.py's
R&R organization-actor loop) rather than a third path, so both routes
to corporate_entity share one creation policy. Found and fixed a
pre-existing gap in backend/tests/test_api.py's seeded_db fixture along
the way: it never seeded the 'plant' corporate_entity_level lookup row.
* chore: stage reviewed PROV-O payload 1/6 [skip ci]
* chore: stage reviewed PROV-O payload 2/6 [skip ci]
* chore: stage reviewed PROV-O payload 3/6 [skip ci]
* chore: stage reviewed PROV-O payload 4/6 [skip ci]
* chore: stage reviewed PROV-O payload 5/6 [skip ci]
* chore: stage reviewed PROV-O payload 6a/7 [skip ci]
* chore: stage reviewed PROV-O payload 6b/7 [skip ci]
* ci: bootstrap complete PROV-O relation support
* ci: normalize generated documentation before PROV-O commit
* ci: separate PROV-O implementation push from workflow installation
* feat: implement every normative PROV-O relation (v0.76.0)
* ci: remove one-shot PROV-O bootstrap workflow
* ci: add exact-head PROV-O standards contract
* ci: repair PROV-O review findings with locked dependencies
* ci: lock PROV-O coverage tooling before review repair
* test: resolve PROV-O review and lock coverage tooling
* ci: remove one-shot PROV-O review repair workflow
* ci: install PROV-O contract dependencies from uv lock
* chore: stage core review hardening script [skip ci]
* chore: stage schema and regression review fixes [skip ci]
* ci: run bounded review-hardening repair
* chore: patch review-support anchors before execution [skip ci]
* ci: repair review-script indentation anchors
* chore: preserve four-space anchors in review support script
* chore: preserve function indentation in review repair output
* ci: preserve generated function indentation before repair
* chore: preserve valid unreferenced PROV reference updates
* ci: use runner-provided rustup for pinned toolchain
* fix: serialize corporate-entity creation against a real observed deadlock (v0.77.0)
A real live Milestone 2 batch run surfaced a genuine
DeadlockDetectedError from concurrent corporate-entity creation: two
concurrent transactions each creating a different new entity, mentioned
in opposite order across two different posts, took row-level locks in
opposite order and deadlocked.
get_or_create_corporate_entity now takes a single named Postgres
advisory transaction lock immediately before the write -- never held
across the slow LLM inference/Searxng verification calls that precede
it -- and re-checks candidates fresh under the lock before inserting.
Every already-cataloged entity still resolves through the unchanged,
lock-free similarity-matching fast path; only the rare creation branch
serializes.
See ADR 0012 (renumbered from 0011 to avoid colliding with the
concurrently-landed PROV-O ADR of the same number).
Co-Authored-By: Claude Sonnet 5 <[email protected]>
* chore: fix generated regression helpers and polymorphic trigger
* fix: harden verified hierarchy and PROV persistence
* ci: remove completed review-hardening workflow
* ci: run exact locked tests against PostgreSQL
* build: install backend from committed uv lock
* docs: de-identify corporate creation lock evidence
* noop
* fix(security): hash-pin Docker uv bootstrap
* fix(security): enforce hash-verified uv bootstrap
* test(docs): reject duplicate and placeholder ADRs
* fix: harden vision parsing and PROV-O contracts
* fix: normalize emphasized vision tags
* docs: align team identity ADR with SQL contract
* docs: align organization resolution ADR with implementation
* fix: preserve emphasized vision values
* ci: repair final PR 74 review blockers
* test(red): define transaction and timezone review contracts
* ci: retry verified PR 74 review repair
* test(red): observe current review regressions
* ci: complete verified PR 74 review repair
* fix: restore ADR 0012 lock and reject XSD +14:01 offsets
Creation writes take the named advisory transaction lock and reload
candidates before insert. Summary replacement commits deletes, mentions,
and edges in one transaction. PostgreSQL lexical xsd:dateTime now rejects
offsets outside ±14:00 so +14:01 fails closed.
* ci: remove completed PR 74 repair workflows
* ci: verify and remove temporary PR 74 repair workflows
* test(red): bound enrichment outside summary transactions
* ci: finish PR 74 transaction-boundary repair
* fix: isolate catalog enrichment from summary writes
* ci: stage PR 74 organization enrichment repair
* ci: run verified PR 74 organization enrichment repair
* ci: remove superseded organization repair scaffolding
* test(red): require source-aware person mention projection
* ci: stage person-projection reconciliation repair
* ci: verify source-aware person and KG projection
* ci: harden person-projection repair transforms
* ci: run hardened person-projection repair
* ci: complete fresh-install and seed projection repair
* ci: verify complete person-projection repair
* ci: isolate PR 74 repair bootstrap failures
* ci: preserve focused projection failure evidence
* test(db): recognize idempotent table declarations
* ci: rerun source-aware projection repair after schema test fix
* fix(data): reconcile source-aware person graph evidence
* docs: record source-aware person projection repair
* feat: show related-person business-side labels (v0.78.0) (#80)
* ci: port related-node side labels onto v0.77
* ci: fix v0.78 port workflow syntax
* ci: use the frontend-pinned pnpm runtime
* fix(ci): accept the released 0.77 changelog date
* fix(ci): update the local project lock without registry resolution
* feat: show related-person business-side labels (v0.78.0)
* ci: verify accessible related-person captions
* ci: harden accessible side-label repair
* ci: make side-label regression insertion structural
* ci: use the verified frontend install contract
* ci: make the accessibility red gate deterministic
* fix(a11y): expose related-person side labels
Screen readers now hear the same business-side caption as the visible chip.
---------
Co-authored-by: opencode-agent[bot] <1549082+opencode-agent[bot]@users.noreply.github.com>
* docs: fold adaptive-orchestration 0.78.0 fragment into changelog
The merge from main brought ADR 0013 and its CHANGELOG.d fragment onto
the protected v0.78.0 head. Record that buyer-visible default in the
compiled changelog without dropping existing 0.78.0 accessibility notes.
Co-authored-by: Seongho Bae <[email protected]>
* test(red): define normalized analysis-run registry
* feat(db): implement normalized analysis-run registry
* feat(db): add fail-closed registry rollback
* chore(db): apply analysis registry on fresh install
* docs(adr): define normalized analysis-run ownership
* docs(research): trace analysis registry standards
* docs(plan): sequence normalized registry delivery
* docs(changelog): record Milestone 2 registry slice
* ci: verify clean normalized analysis registry
* ci: use canonical locked install steps for registry verification
* ci: preserve analysis-run registry failure evidence
* fix(test): roll back aborted registry downgrade transaction
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.
* ci: stage analysis-run registry hardening repair
* ci: verify immutable analysis-run evidence test-first
* fix(db): make analysis-run evidence immutable
* feat: show authorized analysis-run evidence on the home page (v0.79.0) (#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.
* feat: open analysis-run detail from the home list (v0.80.0) (#100)
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.
* feat: show labeled analysis-run status history (v0.81.0) (#102)
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.
* feat: open visible posts from an analysis-run detail (v0.82.0) (#103)
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.
* docs(adr): keep registry ADR 0013 after #74 reused the number
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 <[email protected]>
* docs(changelog): point adaptive-orchestration note at ADR 0015
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 <[email protected]>
* fix: keep Keyman evidence and honor analysis-run cutoff (v0.83.0)
Migration 0016 no longer deletes overlapping Keyman mention_context.
Analysis-run detail lists only posts known at knowledge_cutoff.
Keyman org enrichment finishes before the write transaction.
Replace remaining real organization names with synthetic AGP examples.
Co-authored-by: Seongho Bae <[email protected]>
* fix: fail-closed TEPP seed on the shared Demo Corp snapshot (#118)
* feat: seed a TEPP analysis run through tepp_client (v0.84.0)
Buyer gap: home Analysis runs only showed lineage reconstruction.
make seed now records a Demo Corp TEPP measurement via tepp_client.
The default transport is unavailable, so the row is Failed /
tepp_not_available -- never a fabricated theta. TEPP stays a wire
client, not a local psychometric engine.
* fix: fail-closed TEPP seed on the shared Demo Corp snapshot
#111 still marked a live unused envelope Succeeded, named a different
capture than the registry row, and re-inserted frozen counts. Seed now
reuses the lineage snapshot (ADR 0013), skips count inserts after the
first run, and keeps missing or unused TEPP Failed. The home list tells
the operator to open the run and connect TEPP; detail history keeps
tepp_not_available.
Co-authored-by: Seongho Bae <[email protected]>
---------
Co-authored-by: Seongho Bae <[email protected]>
Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: Seongho Bae <[email protected]>
* fix(ui): show analysis-run digest prefixes on detail (#121)
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 <[email protected]>
Co-authored-by: Seongho Bae <[email protected]>
* fix: keep failed-run next actions kind-specific (#124)
* feat: seed a TEPP analysis run through tepp_client (v0.84.0)
Buyer gap: home Analysis runs only showed lineage reconstruction.
make seed now records a Demo Corp TEPP measurement via tepp_client.
The default transport is unavailable, so the row is Failed /
tepp_not_available -- never a fabricated theta. TEPP stays a wire
client, not a local psychometric engine.
* fix: fail-closed TEPP seed on the shared Demo Corp snapshot
#111 still marked a live unused envelope Succeeded, named a different
capture than the registry row, and re-inserted frozen counts. Seed now
reuses the lineage snapshot (ADR 0013), skips count inserts after the
first run, and keeps missing or unused TEPP Failed. The home list tells
the operator to open the run and connect TEPP; detail history keeps
tepp_not_available.
Co-authored-by: Seongho Bae <[email protected]>
* fix: keep failed-run next actions kind-specific
A failed lineage row must not tell the operator to connect TEPP.
Stacked PRs now run the same GitHub Checks as PRs to main.
Co-authored-by: Seongho Bae <[email protected]>
* docs: keep TEPP next-action copy off failed lineage rows
Co-authored-by: Seongho Bae <[email protected]>
* fix: keep TEPP corpus hint off a succeeded measurement
A calibrated TEPP row must not tell the operator to replace Failed.
Co-authored-by: Seongho Bae <[email protected]>
---------
Co-authored-by: Seongho Bae <[email protected]>
Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: Seongho Bae <[email protected]>
* fix(ui): keep analysis-run digests audible and warn on live posts (v0.84.1) (#127)
* fix(ui): keep analysis-run digests audible and warn on live posts
aria-label on the digest paragraph hid the prefixes from assistive
technology. Move the label to a group, keep prefixes as visible text,
and put the full digest on hover. Tell the operator that a cutoff
title opens the live body so they compare it with the run clock.
Co-authored-by: Seongho Bae <[email protected]>
* docs: mark analysis-run seed pointer as v0.84.1
Co-authored-by: Seongho Bae <[email protected]>
---------
Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: Seongho Bae <[email protected]>
* feat: let operators request a pending analysis run (v0.85.0) (#125)
POST /api/analysis-runs records snapshot, counts, run, scope, and
Pending in one transaction. The home button opens that row so a buyer
can confirm the cutoff corpus. Reconstruction and TEPP stay later
slices — this write never invents a theta.
Rebased onto the live #74 head (includes #118, #121, and #124).
Failed lineage copy stays kind-specific and does not mention TEPP;
only Failed TEPP mentions the measurement service. Seed insert now
asserts Failed / tepp_not_available.
Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: Seongho Bae <[email protected]>
* feat: walk team and organization related nodes (v0.86.0) (#122)
Related-node RWR now loads team and organization mention edges, so a
team-only follow-up is no longer an island. R&R team names become
buttons. Thread-group run lists honor knowledge_cutoff.
ADR 0018 — #125 already used ADR 0017 for POST /api/analysis-runs.
Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: Seongho Bae <[email protected]>
* fix: pin failed-run next actions to registered kinds
Failed period-report rows now tell the operator to rebuild the report. Next-action tests pin reconstruction, measurement, and report copy to the row. A pending TEPP corpus must not claim a calibrated result.
* feat(ui): show embedded post images instead of raw base64 (v0.86.1)
Open a post or evidence panel and see each data-URI picture in document order. The popup no longer dumps the base64 wall. Remote http(s) image URLs stay unloaded. Extract Keyman or Ask still runs OCR on those images.
Rebased onto live #74 head ca9bd82 after #128 squash-merged.
* fix: bind R&R catalog ids without homonym joins (v0.86.2) (#141)
Persist cataloged_team_id and cataloged_corporate_entity_id on post_summary_role (ADR 0019). fetch_persisted_summary reads those columns and does not join corporate_entity by entity_name. Team related matches person/entity 403/404.
Rebased onto live #74 head 7f2d4bc after #140 took v0.86.1.
* fix(ui): pin pending next-action copy to registered kinds (#148)
Pending lineage detail now repeats that reconstruction has not started.
Pending TEPP rows no longer reuse the reconstruction sentence.
Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: Seongho Bae <[email protected]>
* feat: add granted retention purge and Storybook tokens (v0.87.0)
* feat: add granted retention purge and Storybook tokens (v0.87.0)
Operators empty a run-bearing analysis-run registry only after an
unrevoked analysis_run_retention_grant and analysis_run_retention_admin
membership (ADR 0020). PUBLIC cannot execute the definer function.
Repeated citation chips and close buttons use named design tokens and
a Storybook catalog on Node 24.
ADR 0019 stays the R&R catalog-id bind. Do not reuse that number.
Co-authored-by: Seongho Bae <[email protected]>
* test: list a created pending lineage run in the home stub
After POST /api/analysis-runs the list refetch must include the new
Pending row so the buyer-facing "has not started yet" next action is
visible. The previous stub kept only the seed rows.
Co-authored-by: Seongho Bae <[email protected]>
* test: expect pending lineage copy on list and detail
After #148 the next-action phrase is pinned to registered kinds and
shown on both the created list row and the selected detail. Assert
both copies so getByText does not fail on the duplicate.
Co-authored-by: Seongho Bae <[email protected]>
---------
Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: Seongho Bae <[email protected]>
* feat: start a pending lineage reconstruction (v0.88.0)
POST /api/analysis-runs/{id}/start runs ThreadWeave on a frozen Pending lineage cutoff bag and persists run-scoped edges (ADR 0021). Succeeded retries replay the stored digest; Running is 409. TEPP and period-report start stay 422 so this path never invents a theta.
* feat: compare live post write clock with analysis-run cutoff (v0.89.0) (#193)
Analysis-run detail marks in-cutoff titles rewritten after the run.
Demo public post is the edited counter-example; Demo private post still
matches the January cutoff. Bodies stay live.
* feat: warn that cutoff-rewritten titles open the live body (v0.90.0) (#194)
Opening a marked analysis-run title still shows the live post. The
popup now says to compare it with this run instead of inventing a
cutoff snapshot.
* feat: start TEPP through tepp_client; open reconstructed edges (v0.92.0) (#195)
* feat: open reconstructed analysis-run edges as live posts (v0.91.0)
After start, the titled A-100 parent and child are buttons. A marked
child still shows the live-body warning. The popup does not invent a
cutoff snapshot.
* feat: start pending TEPP measurement through tepp_client (v0.92.0)
POST /api/analysis-runs/{id}/start submits AnalysisRunRequest via
tepp_client. A missing or refused transport stays Failed. An accepted
envelope is not persistable yet. Period-report remains 422. No theta
is invented.
* feat: seed the A-100 fork and persist start on a durable outbox (v0.94.0) (#196)
* feat: seed the designed A-100 fork on the Demo Corp lineage run (v0.93.0)
make seed already stamped Succeeded. The home detail now persists
ThreadWeave's parent choices so open-after-seed shows the revised
quote and delivery question. No TEPP theta is invented.
* feat: persist start work on a durable outbox (v0.94.0)
Start commits Running plus one outbox row, wakes Valkey, then
delivers ThreadWeave or tepp_client. A crash no longer loses the
work item. No TEPP theta is invented.
* feat: show outbox delivery and seed the period-report analysis run (v0.96.0) (#197)
* feat: show labeled outbox delivery on analysis-run detail (v0.95.0)
Open the seeded Demo Corp lineage run to see Claimed then Delivered.
Stream entry ids stay off the payload. No TEPP theta is invented.
* feat: seed the Demo Corp period report on the analysis-run registry (v0.96.0)
After make seed, open Period report · Succeeded · Demo Corp to confirm
the cutoff posts. Mean θ stays on the period-report panel. Start stays
422. No TEPP theta is invented.
* feat: open the scored week from a period-report analysis run (v0.97.0) (#198)
* feat: open the scored week from a period-report analysis run (v0.97.0)
After make seed, open Period report · Succeeded · Demo Corp and click
Open period report 2026-W02. Mean θ stays on the report panel. No TEPP
theta is invented.
* fix(ui): focus the opened week and keep failed report rows closed
Open period report 2026-W02 now focuses the report period field.
Failed rows stay without the button. Seed still writes scope_key
2026-W02 and never a theta.
* feat: open the corp grouping with the scored week (v0.98.0) (#199)
* feat: open the corp grouping with the scored week (v0.98.0)
Open period report 2026-W02 from a corporate-entity analysis run also
switches Report grouping to Corporate entity. Mean θ stays on the
report panel. No TEPP theta is invented.
* fix(ui): name the opened Demo Corp grouping
Open period report 2026-W02 now marks Demo Corp current and shows
that label instead of a UUID. The persisted scope grouping key is
the corporate entity, never the week or a theta.
* fix: bind analysis-run visibility with parameterized SQL literals (v0.98.1) (#200)
List and detail queries no longer format a WHERE fragment. The $1 / $2
/ $3 binds are unchanged. Semgrep no longer treats the predicate as
user-concatenated SQL.
* feat: land the comparison strip on the opened Demo Corp row (v0.99.0) (#201)
When the operator is already on 2026-W02, Open period report focuses
the Demo Corp comparison chip instead of the unchanged period field.
* feat: name the next action on the landed Demo Corp report (v1.0.0) (#202)
After Open period report lands on Demo Corp, the panel says to read
its mean θ and member posts. The focused chip uses the visible
Corporate entity caption plus the persisted mean θ.
* feat: land Demo Corp members under the opened-report next action (v1.1.0) (#203)
After Open period report names the next action, Demo Corp mean θ and
member posts land immediately below it, ahead of Other Corp and the
week strip.
* feat: name the next action on the opened Demo Corp member (v1.2.0) (#204)
After Public post opens from the landed Demo Corp report, the panel
says to read Event Lineage, Keyman, and evaluation on that post.
* feat: focus Event Lineage when opening a landed report member (v1.3.0) (#205)
Opening Public post from Demo Corp members now focuses the popup
Event Lineage heading so the next-action copy is reachable. Home
list opens do not steal that focus.
* feat: mark the opened post current in Event Lineage (v1.4.0) (#206)
Opening Public post from Demo Corp members now marks that node
current in the popup Event Lineage DAG so the focused heading has
a you-are-here marker. The home DAG stays unmarked.
* feat: name Keyman and evaluation after the current Event Lineage node (v1.5.0) (#207)
Opening Public post from Demo Corp members now names Keyman and
evaluation after the current Event Lineage node. Home list opens
do not add that copy.
* feat: land Keyman and evaluation under the Event Lineage next action (v1.6.0)
Opening Public post from Demo Corp members now puts Keyman and
evaluation immediately under the Event Lineage next action, ahead
of Affiliate tree. Home list opens keep the earlier order.
* feat: name the first Keyman after landed evaluation (v1.7.0) (#209)
Opening Public post from Demo Corp members now names the first
Keyman after landed evaluation. Home list opens do not add that
copy.
* feat: land first Keyman related nodes under the next action (v1.8.0) (#210)
Opening Public post from Demo Corp members now lands Ada West
related nodes under the first-Keyman next action, ahead of
Affiliate tree. Home list opens still wait for a Keyman click.
* feat: name the first related node after landed Ada West related (v1.9.0)
Opening Public post from Demo Corp members now names the first
related node after landed Ada West related. Home list opens do not
add that copy.
* feat: land first related nodes under the next action (v2.0.0) (#216)
Opening Public post from Demo Corp members now lands Priya Nair
related nodes under the first-related next action, ahead of
Affiliate tree. Home list opens still wait for a related click.
* feat: show cutoff-known post body beside the live rewrite (v2.1.0) (#218)
Open a marked Demo public post from the Demo Corp lineage run and the
January follow-up sits under Body this run knew; the live body names
the later delivery window. GET /api/posts/{id}?as_of= reads
source_post_revision. A missing cover is omitted. Do not invent a
cutoff sentence or a TEPP theta.
* feat: name Ask after Priya Nair related nodes are current (v2.2.0) (#222)
Opening Public post from landed Demo Corp members now names related
nodes for Priya Nair as current and points at Ask about this lineage.
Home list opens do not add that copy. No TEPP theta. No invented cutoff body.
* feat: focus Ask after Priya Nair related nodes are current (v2.3.0) (#223)
Opening Public post from Demo Corp members now focuses the Ask
heading after Priya Nair related nodes are current. Home list
opens do not steal that focus.
* feat: land Ask under the next action (v2.4.0) (#226)
Opening Public post from Demo Corp members now lands Ask about
this lineage under the Ask next action, ahead of Affiliate tree.
Home list opens keep Ask after Keyman.
* feat: name the first Ask after landed chat (v2.5.0)
Opening Public post from Demo Corp members now names the first
seeded Ask after landed chat. Home list opens do not add that copy.
* fix: keep tied organization names unbound (#174)
Classify organization similarity outcomes as unique, miss, or tie. Keep ties unbound before Keyman name rewriting and after the creation-lock reload so live resolution and inference cannot insert a third AUTO catalog row.
Base branch only: feat/role-responsibility-agent-ontology. #74 remains open and unmerged to main.
* feat: land the first Ask answer under the named seed next action (v2.6.0) (#231)
Opening Public post from Demo Corp members now lands the first
seeded Ask answer under the Ask seed next action, ahead of the
input. Home list opens keep that answer after the input.
* feat: name the first cited source after the landed Ask answer (v2.7.0)
Opening Public post from Demo Corp members now names Linked post as
the first cited source after the landed first Ask answer. Home list
opens do not add that copy.
* fix: wait for affiliated corps before lineage create (v2.7.1) (#235)
Request stays disabled until GET /api/me returns affiliated corps so a
multi-affiliation operator cannot POST before the picker appears.
POST /api/analysis-runs records Pending lineage only. TEPP and
period-report kinds 422 before any snapshot write. Do not invent a
theta.
Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: Seongho Bae <[email protected]>
* fix: persist R&R person catalog ids after landed 0019 (v2.7.2) (#236)
Store cataloged_person_id on post_summary_role so a person chip walks
the stored catalog row even when Keyman was not extracted on that post.
Lookup orders by created_at, then person_id. Historical backfill leaves
two same-named mentions unbound (ADR 0027).
Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: Seongho Bae <[email protected]>
* feat: land the first cited evidence under the named citation next action (v2.8.0) (#237)
Opening Public post from Demo Corp members now lands the first
cited evidence under the citation next action, ahead of the
input. Home list opens still wait for a citation click.
* feat: name Event Lineage after landed cited evidence (v2.9.0)
Opening Public post from Demo Corp members now names Event Lineage
after Linked post evidence is current. Home list opens do not add
that copy.
* fix: enable lineage request as soon as affiliated corps load
Use the first affiliated corp as the effective reconstruction target
in the same render that /api/me returns, so Request a lineage
reconstruction is not left disabled waiting for a follow-up state
update when the operator walks more than one corp.
Co-authored-by: Seongho Bae <[email protected]>
* fix(ui): include next-action in analysis-run accessible names (v2.10.1)
Successor to dirty #163. analysisRunAccessibleName includes the next-action sentence for screen readers (WCAG 2.2 SC 4.1.2). Folds into ADR 0014. Version 2.10.1.
Do not merge #74 onto main.
* fix(ui): parse invoice HTML images with an HTML parser (v2.10.2)
Successor to dirty #160. Invoice/post HTML uses a real HTML parser; layout clues stay as offsets; raw base64 and raw HTML do not leak. ADR 0031. Version 2.10.2.
Do not merge #74 onto main.
* fix(ui): drop a stale analysis-run row after its detail 404s (v2.10.3)
Successor to dirty #184. After a listed analysis-run detail 404s, re-read the list so the stale row leaves, and announce the next action with role=alert. Version 2.10.3.
Do not merge #74 onto main.
* fix: empty reconstruction children during granted retention purge (v2.10.4)
Successor to dirty #177. Granted retention purge empties reconstruction children without a superuser DISABLE TRIGGER. Version 2.10.4.
Do not merge #74 onto main.
* feat: customer-group tree and Searxng abbreviation cross-check (v2.11.0)
Customer-group tree (Group/Company/Plant) plus fail-closed Searxng abbreviation cross-check against that tree. Synthetic Demo Corp seed only. ADR 0033, v2.11.0. Do not merge #74 onto main.
* feat: persist Succeeded TEPP time/multilevel results (v2.12.0)
Persist time/multilevel/multi-affiliation TEPP aggregates on the analysis-run and mark Succeeded. Fail-closed for missing transport, accepted-only acks, and theta/IRT/topic envelopes. Synthetic Demo Corp seed only. ADR 0034, v2.12.0. Do not merge #74 onto main.
* fix: TEPP accepted acks are transport evidence, not Succeeded (v2.12.1) (#248)
* fix: treat TEPP accepted acks as transport evidence (v2.12.1)
Do not stamp Succeeded from a published AnalysisRunAccepted
acknowledgement or a LineageWeave-local completed envelope.
Store additive accepted evidence, show Measurement evidence,
and fail closed until TEPP publishes a completed-result contract.
Do not merge #74 onto main.
Co-authored-by: Seongho Bae <[email protected]>
* test: tighten TEPP honesty assertions after first suite run
Use buyer-facing aggregate transport evidence wording, avoid
duplicate-text queries, and keep the public-content denylist off
pre-existing seed password flags.
Co-authored-by: Seongho Bae <[email protected]>
---------
Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: Seongho Bae <[email protected]>
* fix: persist distinct TEPP received and recorded clocks (v2.12.2)
Persist transport-response receipt as received_at and row-write time as recorded_at. Measurement evidence shows two clocks only when those instants differ. Digest recomputation still excludes clocks. Hidden runs stay 404.
* fix: seed Late Demo public post after the analysis-run cutoff (v2.12.3)
Seed synthetic Late Demo public post dated 2026-01-13. After make seed, the January 12 Demo Corp run lists Demo public post and omits Late Demo. Live post list still shows Late Demo. Reuses ADR 0016. No second cutoff. No invented theta.
* fix: exact-match the post-lock duplicate-create re-check (v2.12.4)
get_or_create_corporate_entity's post-lock re-check (ADR 0012) used
the same fuzzy score_corporate_entity threshold (0.6) as real mention
resolution, but its actual purpose is narrower: catching a genuine
concurrent duplicate CREATE of THIS exact entity, per its own comment
("may have just created this exact entity"). A child whose name
contains its own just-created parent's name as a prefix -- exactly
the shape the customer-affiliate-tree hierarchy feature is built for
("Acme" -> "Acme Gwangju Plant") -- scores ~0.7 against that parent
alone under SequenceMatcher, so the child silently resolved to its
own parent's id instead of getting its own catalog row.
Fixed by requiring an exact post-normalization match
(min_similarity=1.0) for this specific re-check only; real fuzzy
mention resolution against the full candidate set (abbreviations,
legal suffixes, sibling disambiguation) is unchanged and still covered
by test_resolves_to_the_correct_sibling_not_a_different_one.
Also fixed test_start_analysis_run_recovers_the_a100_fork: it seeded
snapshot_sha256/configuration_sha256/code_revision_sha with
"t"/"u"/"v"-repeated literals, none valid hex, so its first insert
failed analysis_source_snapshot's own check constraint on every real
run.
Both bugs were caught locally, not by CI: this whole test module
requires a live PostgreSQL/Keycloak/Valkey stack
(pytestmark.skipif(not (postgres and keycloak and valkey))) that CI's
"Full test suite" job does not provide, so neither assertion has ever
actually executed across this branch's history. Confirmed via the
CI run log for the current head commit (465 passed, 106 skipped --
this module's tests are among the skipped).
Full suite green after the fix: 555 passed, 16 skipped. Frontend
build and Python compile also verified clean.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
* fix: min(uuid) has no built-in aggregate in migrations 0019/0025 (v2.12.5)
Both migrations picked "the" value from a `having count(*) = 1` group
via `min(uuid_column)` -- Postgres has no built-in min(uuid) aggregate,
so both failed outright the first time either actually ran against a
real, non-trivial dataset (0019: organization catalog backfill; 0025:
person catalog backfill, same pattern). Fixed to
`min(uuid_column::text)::uuid`, safe given the query's own
`having count(*) = 1` already guarantees exactly one value per group.
Applying the full migration set 0001-0029 against a real, long-lived
43,814-post dataset also surfaced that this database's original
bootstrap had left earlier migrations (0001, 0016) partially applied --
specific tables/indexes/backfills their own later statements defined
were missing even though their initial create-table statements had
run. All 29 migrations are now confirmed genuinely, fully applied end
to end, verified via direct schema comparison against every table/
index any migration defines, not assumption.
Also flags (does not fix, out of scope here) a real, deterministic,
pre-existing, CI-blind test failure in an unrelated feature area
(analysis-run/TEPP lifecycle) -- see CHANGELOG for the full
investigation. Confirmed via git diff this change touches nothing in
that code path.
Full suite: 553 passed (the 2 pre-existing failures above are the only
ones, both already present before this change and unrelated to it).
Co-Authored-By: Claude Sonnet 5 <[email protected]>
---------
Co-authored-by: Claude Sonnet 5 <[email protected]>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: opencode-agent[bot] <1549082+opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: Seongho Bae <[email protected]>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>
Buyer gap
After #202, Open period report 2026-W02 named the next action: read Demo Corp mean θ and member posts, then open a post. The first report row was still Other Corp (empty members). The week strip sat between that sentence and the Demo Corp members.
What changed
Stacked on #74 (
feat/role-responsibility-agent-ontology@1958d70, includes #202). Do not merge before #74.Tests
frontend/src/App.test.tsx— same-week landing lists Demo Corp before Other Corp, puts members under the next action, and opens Public post from that row.cd frontend && pnpm run lint && pnpm run test && pnpm run build— oxlint clean, 66 passed, production build ok.Next action: Keep #74 unmerged until independent review. Do not merge this PR before #74. Leave cursor drafts #142–#191. #192 stays the preferred main-line chip landing.