Role, responsibility, and agent ontology (v2.10.0) - #74
Conversation
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]>
|
Important Review skippedToo many files! This PR contains 220 files, which is 120 over the limit of 100. To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch. Upgrade to a paid plan to raise the limit. This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry. ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (220)
You can disable this status message by setting the 📝 Walkthrough<hidden_range_assignment> 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
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 |
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.
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.
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.
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.
…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.
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.
…atch (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.
…ity-agent-ontology # Conflicts: # CHANGELOG.md # frontend/package.json # lineageweave/__init__.py # pyproject.toml
…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.
Pull request was converted to draft
…y (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.
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.
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]>
seonghobae
left a comment
There was a problem hiding this comment.
UX critique (구매자 화면)
이 PR의 제품 표면이 엔터프라이즈 구매자 콘솔이 아니라 봇 메모장/샌드박스로 읽힌다. CI나 R&R 온톨로지 자체 문제가 아니다.
유지
- Rankings fail-closed:
Rankings · RankWeave not available - 리니지 요청 버튼은 계열사 로드 후 활성화
- TEPP를 점수로 위장하지 않음
- org 뱃지는 현재
#9a3412/#fff3e0(이전#e65100대비율 이슈는 해소된 것으로 보임)
바꾸어야 하는 IA
구매자 화면은 세 장만: 주간 VOC → 사건 lineage → 역할·책임. 감사는 주간 VOC에서 시작하고 다음 결정은 R&R에서 끝난다.
지금 홈은 고객그룹 트리 · analysis run · Rankings · 캘린더 · 기간 리포트 다음에야 DAG가 나온다. 온 이유가 맨 아래다.
같은 포스트인데 리스트에서 열면 요약→평가→Keyman→Event Lineage이고, Event Lineage에서 들어오면(focusEventLineage) 섹션 순서가 바렌다. 공간 기억이 안 생긴다.
제품 크롬이 아닌 것
분석 런 내부, TEPP 영수증/계약 단락, leftover 샌드박스, next-action 튜터(“X is current. Read Y next.”가 랜딩마다 쌓임), 에이전트 로그. 실패 닫힘 빈 상태는 세 화면에 남겨도 된다. 가짜 점수는 안 된다.
제목은 한글, Ask 플레이스홀더·next-action은 영어라 한 화면도 두 언어로 뛰다.
COMMENT only. 구매자 IA가 세 장으로 고정되기 전에는 이 헤드를 제품 UI로 보지 말 것.
Buyer chrome lock (design council)#74 HEAD is the only product slice. Buyer chrome is three screens:
Tokens and Storybook modules attach on this branch only. Do not add:
Fail-closed is a buyer state on those three screens, not a debug panel. Existing |
|
Cycle 2026-08-18T16:10 KST: GitHub writes are live again (comment/close/push). This comment is not APPROVE and is not a merge signal. Exact head remains |
|
Cycle 2026-08-18T20:00 KST: exact head ab77644 still needs independent current-head APPROVE. Owner COMMENT is not APPROVE. Do not push this head from the author token. Auto-merge stays on after independent APPROVE + exact-head required success. |
|
Cycle 2026-08-18T20:00 KST write-retry. Exact head Do not wait on Checks. Strix ModelBehaviorError remains fail-closed flake (0 vulns) — classifier still absent on ContextualWisdomLab/.github. |
…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]>
|
Queue 2026-08-19T03:12 KST. No commit pushed to this head ( |
|
Queue 2026-08-19T06:03 KST. Exact head |
Record current protected main as an explicit parent after #74 was squash-merged independently. Preserve the newer Buyer/Global Ask/runtime tree on this branch, while keeping release metadata monotonic at 2.12.6. Exact-head CI and review evidence must be regenerated on this merge candidate.
Merge leftover post–criterion pairs and fail-closed Rankings from
mainonto this branch as v2.10.0.Exact head:
dde2f3ff64404888473474c3cb52b8bd9b75e400What this revision adds
make seed, leftover pairs sit above the member list; click opens that post. Hidden posts stay omitted.RankWeaveClient(ADR 0030). Unavailable copy is Rankings · RankWeave not available. Never invent a fused score or a theta./api/mereturns, so Request a lineage reconstruction is not left disabled after corps load.Exact-head checks
Do not merge until exact-head required checks are green. Independent current-head approval remains a separate gate.