From 88788e24b546b3295b2edf020d133d3bdf594082 Mon Sep 17 00:00:00 2001 From: Bob Date: Wed, 24 Jun 2026 14:45:50 +0100 Subject: [PATCH 01/13] docs: design spec for AI provenance in gene-page User Comments table Fold an AI-assisted (edited/as-is) marker into the "Made by" column as an inline-styled teal pill, with a plain-text split column for clean downloads and sorting, and union the AI run-row source PMID into the existing PubMed column. Gene page only. Co-Authored-By: Claude Opus 4.8 --- ...i-provenance-gene-comments-table-design.md | 230 ++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 docs/superpowers/specs/2026-06-24-ai-provenance-gene-comments-table-design.md diff --git a/docs/superpowers/specs/2026-06-24-ai-provenance-gene-comments-table-design.md b/docs/superpowers/specs/2026-06-24-ai-provenance-gene-comments-table-design.md new file mode 100644 index 000000000..ed2209241 --- /dev/null +++ b/docs/superpowers/specs/2026-06-24-ai-provenance-gene-comments-table-design.md @@ -0,0 +1,230 @@ +# Design: AI-assisted provenance in the gene-page User Comments table + +**Date:** 2026-06-24 +**Repo:** `ApiCommonModel` +**Status:** Approved for implementation planning + +## Context + +VEuPathDB has added a new kind of user comment — an AI-assisted gene-publication +summary. The comment-generation, review, and publish flow is complete: publishing +an AI-assisted comment creates an ordinary `comments` row plus two sidecar rows in +the comment schema: + +- `comment_ai_provenance` (per published comment): `comment_id`, `run_job_id`, + `is_edited` (true iff the published text differs from the AI original), + `created_at`. +- `comment_ai_run` (shared LLM-output cache, keyed by `job_id`): source kind + (`pubmed` | `upload`), `pubmed_id`, `external_url`, `external_title`, + `pdf_content_sha256`, the AI original headline/content, etc. + +See `ApiCommonWebsite/Service/CLAUDE-ai-user-comments.md` for the full back-end +design and `GetCommentAiProvenanceQuery.java` for the canonical join pattern +(`comment_ai_provenance p JOIN comment_ai_run r ON p.run_job_id = r.job_id`). + +This spec covers **one thing only**: showing users which rows in the gene-page +User Comments table were AI-assisted, and whether the human reviewer edited the +AI text or published it as-is. + +## Goal + +In the gene-page **User Comments** table (`CommentTables.GeneComments` → +`UserComments` table in `geneRecord.xml`), each comment row should communicate: + +1. **Whether the comment was AI-assisted** (a `comment_ai_provenance` row exists). +2. **If AI-assisted, whether it was edited or published as-is** (`is_edited`). + +An AI-assisted comment is still published by a real, logged-in user who reviewed +it — so the framing is "made by Dr So-and-so, **AI-assisted**", never "made by AI". + +## Decisions (all approved) + +| # | Decision | Choice | +|---|----------|--------| +| 1 | What to show | AI-assisted yes/no **+** edited-vs-as-is | +| 2 | Placement | Fold into the existing **"Made by"** column (no new column) | +| 3 | Visual treatment | A small **styled teal pill** after the name (matches the FE "Beta" badge) | +| 4 | Pill styling mechanism | **Inline CSS** in the SQL string (self-contained, single repo, matches `snp_context` precedent) | +| 5 | Downloads / sort | Two-column split so downloads are **HTML-free plain text** carrying ` · AI-assisted (edited\|as-is)`, and sort keys off the plain name | +| 6 | Source paper | Fold `comment_ai_run.pubmed_id` into the **existing PubMed column** via a `UNION` in the `refs` subquery | +| 7 | Records/scope | **Gene page only** (`GeneComments`); other comment tables untouched | + +## Technical findings (verified) + +- **Reachability:** `GeneComments` already `LEFT JOIN`s sibling tables in the + comment schema (`CommentFile`, `CommentReference`). `comment_ai_provenance` and + `comment_ai_run` live in that same schema, so they are reachable with the + identical `@REMOTE_COMMENT_SCHEMA@` prefix. +- **HTML rendering:** the record-table renderer renders a cell value as HTML when + it looks like HTML (`RecordTable.jsx`, `MesaUtils.isHtml(val)`) — this is how + the existing `pmids_link` `` renders. So an inline-styled `` pill in a + column value will render. +- **`internal` vs `inReportMaker` are independent scopes** (`FieldScope.java`): + the report-maker scope only excludes `inReportMaker=false` fields (internal + fields still flow into reports); the on-screen scope excludes `internal=true`. + Both flags are settable per `columnAttribute` (`wdkModel.rng:1468-1473`). This + is what makes the two-column split work cleanly. +- **No HTML stripping** in the tabular reporter — a column's value is dumped + verbatim, which is exactly why the *display* (pill) column must be excluded from + reports and a *plain* column provided for download. + +## Changes + +### 1. `Model/lib/wdk/model/records/commentTableQueries.xml` — `GeneComments` query + +**a. Add the provenance joins** (same pattern as the existing `files` / `refs` +joins): + +```sql +LEFT JOIN @REMOTE_COMMENT_SCHEMA@comment_ai_provenance p + ON c.comment_id = p.comment_id +LEFT JOIN @REMOTE_COMMENT_SCHEMA@comment_ai_run r + ON p.run_job_id = r.job_id +``` + +`p.comment_id IS NOT NULL` ⇒ AI-assisted. `p.is_edited` ⇒ edited vs as-is. + +**b. Replace the single `user_name_org` SELECT expression with two columns.** +The current expression is: + +```sql +CONCAT(u.first_name , ' ' , u.last_name , ', ' , u.organization ) as user_name_org +``` + +Becomes a base name expression plus two derived columns: + +```sql +-- plain text: download- and sort-safe; carries a plain provenance suffix +CONCAT( + u.first_name, ' ', u.last_name, ', ', u.organization, + CASE + WHEN p.comment_id IS NULL THEN '' + WHEN p.is_edited THEN ' · AI-assisted (edited)' + ELSE ' · AI-assisted (as-is)' + END +) AS user_name_org, + +-- display: name + inline-styled teal pill (rendered as HTML on screen) +CONCAT( + u.first_name, ' ', u.last_name, ', ', u.organization, + CASE + WHEN p.comment_id IS NULL THEN '' + WHEN p.is_edited THEN + ' ' + || 'AI-assisted · edited' + ELSE + ' ' + || 'AI-assisted · as-is' + END +) AS user_name_org_display +``` + +Notes: +- Postgres string concatenation uses `||`; the existing query already mixes + `CONCAT(...)` and `||` styles — match whichever the surrounding file prefers at + implementation time (the `pmids_link` CASE uses `CONCAT`). +- Both `edited` and `as-is` use the **same** teal (`#0a7c8a`); only the text + differs. (Hex finalisable at implementation; chosen to read as a "Beta"-style + teal pill.) +- Add the new `` declaration to the + `GeneComments` `` column list (alongside the existing + ``). + +**c. Fold the AI source PMID into the existing PubMed column.** Replace the +current `refs` subquery: + +```sql +LEFT JOIN ( + SELECT comment_id, string_agg(source_id,',') as pmids + FROM @REMOTE_COMMENT_SCHEMA@CommentReference + WHERE database_name='pubmed' + GROUP BY comment_id +) refs ON c.comment_id = refs.comment_id +``` + +with a `UNION` that adds the run-row PMID for AI comments: + +```sql +LEFT JOIN ( + SELECT comment_id, string_agg(source_id, ',') AS pmids + FROM ( + SELECT comment_id, source_id + FROM @REMOTE_COMMENT_SCHEMA@CommentReference + WHERE database_name = 'pubmed' + UNION -- UNION (not ALL) dedupes a PMID present in both + SELECT p.comment_id, r.pubmed_id AS source_id + FROM @REMOTE_COMMENT_SCHEMA@comment_ai_provenance p + JOIN @REMOTE_COMMENT_SCHEMA@comment_ai_run r ON p.run_job_id = r.job_id + WHERE r.source_kind = 'pubmed' AND r.pubmed_id IS NOT NULL + ) merged + GROUP BY comment_id +) refs ON c.comment_id = refs.comment_id +``` + +The downstream `pmids_link` CASE (which builds the `` link from `refs.pmids`) +is unchanged and keeps working. Upload-source AI comments have no PMID +(`external_url` instead) and correctly do not appear in the PubMed column. + +### 2. `Model/lib/wdk/model/records/geneRecord.xml` — `UserComments` table + +Currently: + +```xml + +``` + +Becomes two `columnAttribute`s: + +```xml + + + + +``` + +Result: +- **On screen** (`NON_INTERNAL` scope): `user_name_org` is hidden; `user_name_org_display` + renders as "Made by" with the pill. +- **Report maker / download** (`REPORT_MAKER` scope): `user_name_org_display` is + excluded; `user_name_org` is included as "Made by", clean plain text. +- **Sort / search**: operate on the plain `user_name_org`. + +## Coordination / deployment note (not a code change here) + +The `comment_ai_run` and `comment_ai_provenance` tables must be reachable under +`@REMOTE_COMMENT_SCHEMA@` (the website's mapped/FDW view of the comment DB), the +same way `CommentReference` and `CommentFile` already are. Confirm with whoever +provisions the comment-DB replication/mapping that the two new sidecar tables are +exposed there before this query ships. If they are not yet mapped, the joins will +fail at query time. + +## Out of scope + +- Sorting *by AI-assisted status* as a first-class field (the plain + `user_name_org` suffix is incidentally sortable; no dedicated sort field). +- De-duplication warnings. +- `/user-comments/show` page changes (separate follow-up). +- Other comment tables (`CommunityComments`, `GenomeComments`, `PopsetComments`). +- Making the pill themeable from the front-end (rejected in favour of inline CSS; + would require a shared CSS class and web-monorepo coordination). + +## Verification + +1. **Build:** the model builds cleanly (`mvn clean install` per project + `CLAUDE.md` build order: `install/` → `WDK/` → target module). +2. **Human comment (regression):** a gene with an ordinary user comment shows + "Made by" with name+org and **no pill**; PubMed column unchanged. +3. **AI comment, edited:** a published AI comment with `is_edited=true` shows the + teal `AI-assisted · edited` pill after the name; its source PMID appears in the + PubMed column (as a link) even though no `CommentReference` row exists. +4. **AI comment, as-is:** `is_edited=false` shows `AI-assisted · as-is`. +5. **Upload-source AI comment:** shows the pill; PubMed column empty (no PMID). +6. **Download:** add the User Comments table to a report/download → "Made by" + column contains plain text `Name, Org · AI-assisted (edited)` with **no HTML + markup**; no `user_name_org_display` column appears. +7. **PMID dedupe:** an AI comment whose source PMID is also present as a manual + `CommentReference` shows that PMID **once** (UNION dedupe). From 3e6c457aa43f4f2f12444ea60a22e58af674b6b0 Mon Sep 17 00:00:00 2001 From: Bob Date: Wed, 24 Jun 2026 14:51:25 +0100 Subject: [PATCH 02/13] docs: implementation plan for AI provenance in gene-page comments table Two-task plan: extend GeneComments SQL (provenance join, split user_name_org/user_name_org_display columns, PMID union) and split the Made-by columnAttribute in geneRecord.xml. Includes manual verification checklist for a deployed instance. Co-Authored-By: Claude Opus 4.8 --- ...06-24-ai-provenance-gene-comments-table.md | 240 ++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 docs/superpowers/plans/2026-06-24-ai-provenance-gene-comments-table.md diff --git a/docs/superpowers/plans/2026-06-24-ai-provenance-gene-comments-table.md b/docs/superpowers/plans/2026-06-24-ai-provenance-gene-comments-table.md new file mode 100644 index 000000000..9c98b7b7c --- /dev/null +++ b/docs/superpowers/plans/2026-06-24-ai-provenance-gene-comments-table.md @@ -0,0 +1,240 @@ +# AI Provenance in Gene-Page User Comments Table — Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Show, in the gene-page User Comments table, which comments were AI-assisted and whether the reviewer edited the AI text or published it as-is — plus surface the AI source PMID in the existing PubMed column. + +**Architecture:** Pure WDK-model change in one repo (`ApiCommonModel`). Extend the `GeneComments` SQL query to join the two AI sidecar tables, emit a styled-pill "display" copy of the `user_name_org` column alongside a plain-text copy, and `UNION` the AI run-row PMID into the PubMed aggregate. Wire the two copies into `geneRecord.xml` so the on-screen table shows the pill while downloads/sorting use clean text. + +**Tech Stack:** WDK model XML, PostgreSQL SQL (the comment DB), Maven build. + +## Global Constraints + +- **Scope: gene page only.** Modify only `CommentTables.GeneComments` and the `UserComments` table in `geneRecord.xml`. Do **not** touch `CommunityComments`, `GenomeComments`, `PopsetComments`, or their record tables. +- **Single repo.** All edits are in `ApiCommonModel`. No web-monorepo / front-end change (pill styling is inline CSS). +- **Sidecar tables, exact names** (in the comment schema, reached via the `@REMOTE_COMMENT_SCHEMA@` macro): + - `comment_ai_provenance` — columns used: `comment_id`, `run_job_id`, `is_edited`. + - `comment_ai_run` — columns used: `job_id`, `source_kind`, `pubmed_id`. +- **Join keys:** `comment_ai_provenance.comment_id = MappedComment.comment_id`; `comment_ai_provenance.run_job_id = comment_ai_run.job_id`. `comment_ai_provenance` is 1 row per `comment_id` (PK), so the join cannot multiply comment rows. +- **Pill style (inline CSS, verbatim):** `display:inline-block;margin-left:6px;padding:1px 6px;border-radius:8px;background-color:#0a7c8a;color:#fff;font-size:0.85em;font-weight:500;white-space:nowrap;` +- **Pill text:** `AI-assisted · edited` or `AI-assisted · as-is`. **Plain-text suffix** (download column): ` · AI-assisted (edited)` or ` · AI-assisted (as-is)`. +- **Build prerequisite** (per project `CLAUDE.md`): `install/` and `WDK/` must already be built into `~/.m2` before building this module. + +--- + +## File Structure + +| File | Responsibility | Action | +|------|----------------|--------| +| `Model/lib/wdk/model/records/commentTableQueries.xml` | `GeneComments` SQL: joins, split `user_name_org`/`user_name_org_display` columns, PMID union | Modify | +| `Model/lib/wdk/model/records/geneRecord.xml` | `UserComments` table: present the two "Made by" columns | Modify | + +There are no automated unit tests for WDK model SQL/XML in this repo. The per-change gates are **(1) XML well-formedness** (`xmllint --noout`) and **(2) the Maven build**. Full validation is a **manual step on a deployed instance** (and an optional direct-SQL smoke test against the dev comment DB) — see the Manual Verification section at the end. + +--- + +## Task 1: Extend the `GeneComments` SQL query + +**Files:** +- Modify: `Model/lib/wdk/model/records/commentTableQueries.xml` (the `GeneComments` ``, lines ~40–162) + +**Interfaces:** +- Produces (for Task 2): SQL output columns `user_name_org` (plain text incl. provenance suffix) and `user_name_org_display` (name + inline-styled pill HTML). +- Produces: `pmids` aggregate now also contains AI run-row PMIDs. + +All four edits below are in the same `GeneComments` query block. Apply them, then run the single verification at the end of the task. + +- [ ] **Step 1: Add the `user_name_org_display` column declaration** + +In the `` list for `GeneComments` (currently `commentTableQueries.xml:66`), add the new column right after the existing `user_name_org` declaration. + +Find: +```xml + + +``` +Replace with: +```xml + + + +``` + +- [ ] **Step 2: Split the `user_name_org` SELECT expression into plain + display** + +Find the final SELECT item (currently `commentTableQueries.xml:96-97`): +```sql + &&selectReviewed&& + CONCAT(u.first_name , ' ' , u.last_name , ', ' , u.organization ) as user_name_org + FROM +``` +Replace with: +```sql + &&selectReviewed&& + CONCAT(u.first_name , ' ' , u.last_name , ', ' , u.organization , + CASE + WHEN aiprov.comment_id IS NULL THEN '' + WHEN aiprov.is_edited THEN ' · AI-assisted (edited)' + ELSE ' · AI-assisted (as-is)' + END) as user_name_org, + CASE + WHEN aiprov.comment_id IS NULL + THEN CONCAT(u.first_name , ' ' , u.last_name , ', ' , u.organization ) + ELSE CONCAT(u.first_name , ' ' , u.last_name , ', ' , u.organization , + 'AI-assisted · ', + CASE WHEN aiprov.is_edited THEN 'edited' ELSE 'as-is' END, + '') + END as user_name_org_display + FROM +``` +(The ` · ` separator in the plain column is a literal middot UTF-8 character; the file is UTF-8. The display column uses the `·` HTML entity, which the record-table renderer renders as `·`.) + +- [ ] **Step 3: Add the `comment_ai_provenance` LEFT JOIN** + +Find the `gene_counts` LEFT JOIN block (currently ends at `commentTableQueries.xml:119`): +```sql + ) gene_counts ON c.comment_id = gene_counts.comment_id + LEFT JOIN ( + SELECT dr.primary_identifier AS comment_id , ta.gene_source_id +``` +Replace with (insert the new join between `gene_counts` and `integrated_comments`): +```sql + ) gene_counts ON c.comment_id = gene_counts.comment_id + LEFT JOIN @REMOTE_COMMENT_SCHEMA@comment_ai_provenance aiprov + ON c.comment_id = aiprov.comment_id + LEFT JOIN ( + SELECT dr.primary_identifier AS comment_id , ta.gene_source_id +``` +(Only `comment_ai_provenance` is joined here — that is all the `user_name_org` columns need. The run table is joined inside the PMID subquery in the next step.) + +- [ ] **Step 4: Union the AI run-row PMID into the `refs` subquery** + +Find the `refs` subquery (currently `commentTableQueries.xml:108-113`): +```sql + LEFT JOIN ( + SELECT comment_id, string_agg(source_id,',') as pmids + FROM @REMOTE_COMMENT_SCHEMA@CommentReference + WHERE database_name='pubmed' + GROUP BY comment_id + ) refs ON c.comment_id = refs.comment_id +``` +Replace with: +```sql + LEFT JOIN ( + SELECT comment_id, string_agg(source_id,',') as pmids + FROM ( + SELECT comment_id, source_id + FROM @REMOTE_COMMENT_SCHEMA@CommentReference + WHERE database_name='pubmed' + UNION + SELECT cap.comment_id, car.pubmed_id AS source_id + FROM @REMOTE_COMMENT_SCHEMA@comment_ai_provenance cap + JOIN @REMOTE_COMMENT_SCHEMA@comment_ai_run car ON cap.run_job_id = car.job_id + WHERE car.source_kind = 'pubmed' AND car.pubmed_id IS NOT NULL + ) merged + GROUP BY comment_id + ) refs ON c.comment_id = refs.comment_id +``` +(`UNION` (not `UNION ALL`) dedupes a PMID that is present both as a manual `CommentReference` and as the AI source. The downstream `pmids_link` CASE is unchanged.) + +- [ ] **Step 5: Verify XML well-formedness** + +Run: +```bash +cd /home/maccallr/work/ai-wdk/project_home/ApiCommonModel +xmllint --noout Model/lib/wdk/model/records/commentTableQueries.xml && echo WELL_FORMED +``` +Expected: prints `WELL_FORMED` with no parser errors. (Catches a missing quote/paren/tag from the SQL edits.) + +- [ ] **Step 6: Commit** + +```bash +cd /home/maccallr/work/ai-wdk/project_home/ApiCommonModel +git add Model/lib/wdk/model/records/commentTableQueries.xml +git commit -m "feat: AI provenance + source PMID in GeneComments query + +Join comment_ai_provenance for the Made-by pill, emit a plain +user_name_org (downloads/sort) plus a styled user_name_org_display +column, and union the AI run-row PMID into the PubMed aggregate. + +Co-Authored-By: Claude Opus 4.8 " +``` + +--- + +## Task 2: Present the two "Made by" columns in `geneRecord.xml` + +**Files:** +- Modify: `Model/lib/wdk/model/records/geneRecord.xml` (the `UserComments` table, line ~1713) + +**Interfaces:** +- Consumes (from Task 1): SQL columns `user_name_org` and `user_name_org_display`. + +- [ ] **Step 1: Replace the single Made-by columnAttribute with two** + +Find (currently `geneRecord.xml:1713`): +```xml + +``` +Replace with: +```xml + + + + +``` +(`FieldScope` treats `internal` and `inReportMaker` independently: on screen the `NON_INTERNAL` scope hides `user_name_org` and shows `user_name_org_display`; in report maker the `REPORT_MAKER` scope excludes `user_name_org_display` and includes the plain `user_name_org`.) + +- [ ] **Step 2: Verify XML well-formedness** + +Run: +```bash +cd /home/maccallr/work/ai-wdk/project_home/ApiCommonModel +xmllint --noout Model/lib/wdk/model/records/geneRecord.xml && echo WELL_FORMED +``` +Expected: prints `WELL_FORMED`. + +- [ ] **Step 3: Build the model module** + +Run (per project `CLAUDE.md` — assumes `install/` and `WDK/` already built into `~/.m2`): +```bash +cd /home/maccallr/work/ai-wdk/project_home/ApiCommonModel +mvn -q clean install +``` +Expected: `BUILD SUCCESS`. This confirms both modified files assemble into the model artifact. (Build failure here most likely means a typo in a column name or malformed XML.) + +- [ ] **Step 4: Commit** + +```bash +cd /home/maccallr/work/ai-wdk/project_home/ApiCommonModel +git add Model/lib/wdk/model/records/geneRecord.xml +git commit -m "feat: show AI-assisted pill in gene-page User Comments Made-by column + +Split the Made-by attribute into a plain internal column (downloads/sort) +and a display column carrying the inline-styled AI-assisted pill. + +Co-Authored-By: Claude Opus 4.8 " +``` + +--- + +## Manual Verification (deployed instance) + +These cannot be automated in this repo (no DB/model-runtime in the build). Run them on a deployed dev instance whose comment DB has the two sidecar tables exposed under `@REMOTE_COMMENT_SCHEMA@`. They mirror the spec's verification checklist. + +- [ ] **Coordination precheck:** confirm `comment_ai_run` and `comment_ai_provenance` are reachable under the schema that `@REMOTE_COMMENT_SCHEMA@` resolves to (the same place `CommentReference` lives). If not yet mapped, the query errors — escalate before deploying. +- [ ] **Optional direct-SQL smoke test:** run the edited `GeneComments` SQL against the dev comment DB (substitute the real schema for `@REMOTE_COMMENT_SCHEMA@`, a real `org_abbrev`/`source_id`) for a gene known to have (a) a human comment, (b) an edited AI comment, (c) an as-is AI comment. Confirm `user_name_org`, `user_name_org_display`, and `pmids` come back as expected and the row count is unchanged vs the pre-change query (the provenance join must not multiply rows). +- [ ] **Human comment (regression):** gene page shows "Made by" = name+org, **no pill**; PubMed column unchanged. +- [ ] **AI comment, edited:** shows the teal `AI-assisted · edited` pill; its source PMID appears (linked) in the PubMed column even with no `CommentReference` row. +- [ ] **AI comment, as-is:** shows `AI-assisted · as-is`. +- [ ] **Upload-source AI comment:** shows the pill; PubMed column empty (no PMID). +- [ ] **Download:** add the User Comments table to a report → "Made by" column is plain text `Name, Org · AI-assisted (edited)` with **no `` markup**; no separate display column appears. +- [ ] **PMID dedupe:** an AI comment whose source PMID is also a manual `CommentReference` shows that PMID once. + +--- + +## Self-Review + +- **Spec coverage:** join (Task 1 Step 3) ✓; two-column split (Task 1 Step 2, Task 2 Step 1) ✓; inline-CSS pill (Task 1 Step 2, constraint) ✓; clean-download split via `internal`/`inReportMaker` (Task 2 Step 1) ✓; PMID union (Task 1 Step 4) ✓; gene-only scope (Global Constraints) ✓; coordination note + verification (Manual Verification) ✓. +- **Placeholder scan:** none — every step shows exact find/replace content and exact commands. +- **Type/name consistency:** SQL columns `user_name_org` / `user_name_org_display` are produced in Task 1 and consumed by the same names in Task 2; join aliases `aiprov` (top level) and `cap`/`car` (subquery) are self-contained per scope. From 5c0a4a76672050981b6154e4340fc0c0e519bf78 Mon Sep 17 00:00:00 2001 From: Bob Date: Wed, 24 Jun 2026 15:36:41 +0100 Subject: [PATCH 03/13] feat: AI provenance + source PMID in GeneComments query Join comment_ai_provenance for the Made-by pill, emit a plain user_name_org (downloads/sort) plus a styled user_name_org_display column, and union the AI run-row PMID into the PubMed aggregate. Co-Authored-By: Claude Opus 4.8 --- .../wdk/model/records/commentTableQueries.xml | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/Model/lib/wdk/model/records/commentTableQueries.xml b/Model/lib/wdk/model/records/commentTableQueries.xml index 2c578927d..a930b435c 100644 --- a/Model/lib/wdk/model/records/commentTableQueries.xml +++ b/Model/lib/wdk/model/records/commentTableQueries.xml @@ -64,6 +64,7 @@ + @@ -94,7 +95,20 @@ END AS pmids_link, gene_counts.geneCount, &&selectReviewed&& - CONCAT(u.first_name , ' ' , u.last_name , ', ' , u.organization ) as user_name_org + CONCAT(u.first_name , ' ' , u.last_name , ', ' , u.organization , + CASE + WHEN aiprov.comment_id IS NULL THEN '' + WHEN aiprov.is_edited THEN ' · AI-assisted (edited)' + ELSE ' · AI-assisted (as-is)' + END) as user_name_org, + CASE + WHEN aiprov.comment_id IS NULL + THEN CONCAT(u.first_name , ' ' , u.last_name , ', ' , u.organization ) + ELSE CONCAT(u.first_name , ' ' , u.last_name , ', ' , u.organization , + 'AI-assisted · ', + CASE WHEN aiprov.is_edited THEN 'edited' ELSE 'as-is' END, + '') + END as user_name_org_display FROM @REMOTE_COMMENT_SCHEMA@MappedComment c INNER JOIN webready.GeneAttributes_p ga ON c.project_name = ga.project_id AND c.stable_id = ga.source_id @@ -107,8 +121,16 @@ ) files ON c.comment_id = files.comment_id LEFT JOIN ( SELECT comment_id, string_agg(source_id,',') as pmids - FROM @REMOTE_COMMENT_SCHEMA@CommentReference - WHERE database_name='pubmed' + FROM ( + SELECT comment_id, source_id + FROM @REMOTE_COMMENT_SCHEMA@CommentReference + WHERE database_name='pubmed' + UNION + SELECT cap.comment_id, car.pubmed_id AS source_id + FROM @REMOTE_COMMENT_SCHEMA@comment_ai_provenance cap + JOIN @REMOTE_COMMENT_SCHEMA@comment_ai_run car ON cap.run_job_id = car.job_id + WHERE car.source_kind = 'pubmed' AND car.pubmed_id IS NOT NULL + ) merged GROUP BY comment_id ) refs ON c.comment_id = refs.comment_id LEFT JOIN ( @@ -117,6 +139,8 @@ WHERE stable_id IN (SELECT source_id FROM webready.GeneAttributes_p where org_abbrev IN (%%PARTITION_KEYS%%)) GROUP BY comment_id ) gene_counts ON c.comment_id = gene_counts.comment_id + LEFT JOIN @REMOTE_COMMENT_SCHEMA@comment_ai_provenance aiprov + ON c.comment_id = aiprov.comment_id LEFT JOIN ( SELECT dr.primary_identifier AS comment_id , ta.gene_source_id FROM sres.dbref dr From e346068f1c0c5fa628484b31f682974b4d2876ec Mon Sep 17 00:00:00 2001 From: Bob Date: Wed, 24 Jun 2026 15:38:20 +0100 Subject: [PATCH 04/13] feat: show AI-assisted pill in gene-page User Comments Made-by column Split the Made-by attribute into a plain internal column (downloads/sort) and a display column carrying the inline-styled AI-assisted pill. Co-Authored-By: Claude Opus 4.8 --- Model/lib/wdk/model/records/geneRecord.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Model/lib/wdk/model/records/geneRecord.xml b/Model/lib/wdk/model/records/geneRecord.xml index 655887f05..b3ef20bec 100644 --- a/Model/lib/wdk/model/records/geneRecord.xml +++ b/Model/lib/wdk/model/records/geneRecord.xml @@ -1710,7 +1710,10 @@ name" internal="true"/> - + + + + From 59e0e61622a6d1f8b776232a01a2e74dee85ed71 Mon Sep 17 00:00:00 2001 From: Bob Date: Wed, 24 Jun 2026 17:00:16 +0100 Subject: [PATCH 05/13] add title-based tooltips for pills --- Model/lib/wdk/model/records/commentTableQueries.xml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Model/lib/wdk/model/records/commentTableQueries.xml b/Model/lib/wdk/model/records/commentTableQueries.xml index a930b435c..5562d688a 100644 --- a/Model/lib/wdk/model/records/commentTableQueries.xml +++ b/Model/lib/wdk/model/records/commentTableQueries.xml @@ -105,7 +105,13 @@ WHEN aiprov.comment_id IS NULL THEN CONCAT(u.first_name , ' ' , u.last_name , ', ' , u.organization ) ELSE CONCAT(u.first_name , ' ' , u.last_name , ', ' , u.organization , - 'AI-assisted · ', + 'AI-assisted · ', CASE WHEN aiprov.is_edited THEN 'edited' ELSE 'as-is' END, '') END as user_name_org_display From 83df28a1ae28c94309483fe24b10279f0df28cb8 Mon Sep 17 00:00:00 2001 From: Bob Date: Thu, 25 Jun 2026 10:14:36 +0100 Subject: [PATCH 06/13] Better linkage to full comment page --- Model/lib/wdk/model/records/geneRecord.xml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Model/lib/wdk/model/records/geneRecord.xml b/Model/lib/wdk/model/records/geneRecord.xml index b3ef20bec..70ed976ea 100644 --- a/Model/lib/wdk/model/records/geneRecord.xml +++ b/Model/lib/wdk/model/records/geneRecord.xml @@ -1694,7 +1694,20 @@ name" internal="true"/> - + + + + + + $$headline$$ + ]]> + + + + + From 3c6ef3159a89ae98815554e577ca8cc5908885f5 Mon Sep 17 00:00:00 2001 From: Bob Date: Thu, 25 Jun 2026 10:40:40 +0100 Subject: [PATCH 07/13] remove the html from the link and try again --- Model/lib/wdk/model/records/geneRecord.xml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Model/lib/wdk/model/records/geneRecord.xml b/Model/lib/wdk/model/records/geneRecord.xml index 70ed976ea..88cf63f94 100644 --- a/Model/lib/wdk/model/records/geneRecord.xml +++ b/Model/lib/wdk/model/records/geneRecord.xml @@ -1696,14 +1696,12 @@ name" internal="true"/> - + - - $$headline$$ - ]]> - + From df4ea027f9d400875b3ca6540933195a322d58aa Mon Sep 17 00:00:00 2001 From: Bob Date: Thu, 25 Jun 2026 11:07:12 +0100 Subject: [PATCH 08/13] go with right-Guillemet in the end --- Model/lib/wdk/model/records/geneRecord.xml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Model/lib/wdk/model/records/geneRecord.xml b/Model/lib/wdk/model/records/geneRecord.xml index 88cf63f94..1b3dd3fec 100644 --- a/Model/lib/wdk/model/records/geneRecord.xml +++ b/Model/lib/wdk/model/records/geneRecord.xml @@ -1696,12 +1696,13 @@ name" internal="true"/> - + the arrow must be a literal glyph, not an &#xxxx; entity. + --> - + From 9abbc306a6bbb78611bb3d442bc776b8585daf3c Mon Sep 17 00:00:00 2001 From: Bob Date: Thu, 25 Jun 2026 11:19:40 +0100 Subject: [PATCH 09/13] hide comment ID column --- Model/lib/wdk/model/records/geneRecord.xml | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/Model/lib/wdk/model/records/geneRecord.xml b/Model/lib/wdk/model/records/geneRecord.xml index 1b3dd3fec..83afc2f80 100644 --- a/Model/lib/wdk/model/records/geneRecord.xml +++ b/Model/lib/wdk/model/records/geneRecord.xml @@ -1679,18 +1679,10 @@ name" internal="true"/> displayName="User Comments" inReportMaker="true" queryRef="CommentTables.GeneComments"> + - - - - - - - - From 885aa79f1060a7136fd54de9621b8056b0bc3c79 Mon Sep 17 00:00:00 2001 From: Bob Date: Thu, 25 Jun 2026 11:30:26 +0100 Subject: [PATCH 10/13] put AI-assisted pill on a new line --- Model/lib/wdk/model/records/commentTableQueries.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Model/lib/wdk/model/records/commentTableQueries.xml b/Model/lib/wdk/model/records/commentTableQueries.xml index 5562d688a..309c0ad49 100644 --- a/Model/lib/wdk/model/records/commentTableQueries.xml +++ b/Model/lib/wdk/model/records/commentTableQueries.xml @@ -105,13 +105,13 @@ WHEN aiprov.comment_id IS NULL THEN CONCAT(u.first_name , ' ' , u.last_name , ', ' , u.organization ) ELSE CONCAT(u.first_name , ' ' , u.last_name , ', ' , u.organization , - 'AI-assisted · ', + '" style="display:inline-block;margin-top:3px;padding:1px 6px;border-radius:8px;background-color:#0a7c8a;color:#fff;font-size:0.85em;font-weight:500;white-space:nowrap;">AI-assisted · ', CASE WHEN aiprov.is_edited THEN 'edited' ELSE 'as-is' END, '') END as user_name_org_display From 66546ead54f7f161323d4e80bb4d070274ffda09 Mon Sep 17 00:00:00 2001 From: Bob Date: Thu, 25 Jun 2026 11:59:41 +0100 Subject: [PATCH 11/13] add ai_source_kind column for downloads --- Model/lib/wdk/model/records/commentTableQueries.xml | 7 ++++++- Model/lib/wdk/model/records/geneRecord.xml | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Model/lib/wdk/model/records/commentTableQueries.xml b/Model/lib/wdk/model/records/commentTableQueries.xml index 309c0ad49..80e0870fc 100644 --- a/Model/lib/wdk/model/records/commentTableQueries.xml +++ b/Model/lib/wdk/model/records/commentTableQueries.xml @@ -65,6 +65,7 @@ + @@ -114,7 +115,9 @@ '" style="display:inline-block;margin-top:3px;padding:1px 6px;border-radius:8px;background-color:#0a7c8a;color:#fff;font-size:0.85em;font-weight:500;white-space:nowrap;">AI-assisted · ', CASE WHEN aiprov.is_edited THEN 'edited' ELSE 'as-is' END, '') - END as user_name_org_display + END as user_name_org_display, + -- download-only AI provenance source: 'pubmed' | 'upload' | 'N/A' + COALESCE(car2.source_kind, 'N/A') as ai_source_kind FROM @REMOTE_COMMENT_SCHEMA@MappedComment c INNER JOIN webready.GeneAttributes_p ga ON c.project_name = ga.project_id AND c.stable_id = ga.source_id @@ -147,6 +150,8 @@ ) gene_counts ON c.comment_id = gene_counts.comment_id LEFT JOIN @REMOTE_COMMENT_SCHEMA@comment_ai_provenance aiprov ON c.comment_id = aiprov.comment_id + LEFT JOIN @REMOTE_COMMENT_SCHEMA@comment_ai_run car2 + ON aiprov.run_job_id = car2.job_id LEFT JOIN ( SELECT dr.primary_identifier AS comment_id , ta.gene_source_id FROM sres.dbref dr diff --git a/Model/lib/wdk/model/records/geneRecord.xml b/Model/lib/wdk/model/records/geneRecord.xml index 83afc2f80..1b07892ba 100644 --- a/Model/lib/wdk/model/records/geneRecord.xml +++ b/Model/lib/wdk/model/records/geneRecord.xml @@ -1718,6 +1718,8 @@ name" internal="true"/> + + From 3c2037ffe2309218b10b245da951f17f80085275 Mon Sep 17 00:00:00 2001 From: Bob Date: Thu, 25 Jun 2026 12:07:57 +0100 Subject: [PATCH 12/13] modernise the Community Annotations comments table too --- Model/lib/wdk/model/records/geneRecord.xml | 25 ++++++++++++---------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/Model/lib/wdk/model/records/geneRecord.xml b/Model/lib/wdk/model/records/geneRecord.xml index 1b07892ba..87e25ed2e 100644 --- a/Model/lib/wdk/model/records/geneRecord.xml +++ b/Model/lib/wdk/model/records/geneRecord.xml @@ -1732,22 +1732,25 @@ name" internal="true"/> inReportMaker="false" displayName="Community Annotations" queryRef="CommentTables.CommunityComments"> + - - - - + + + + + + + + - - - - From 8fa799ce86c058a7290ef2c209fb2f26fb1e2d44 Mon Sep 17 00:00:00 2001 From: Bob Date: Thu, 25 Jun 2026 15:40:54 +0100 Subject: [PATCH 13/13] feat(comments): union upload-path PMID into GeneComments pmids Co-Authored-By: Claude Opus 4.8 --- Model/lib/wdk/model/records/commentTableQueries.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Model/lib/wdk/model/records/commentTableQueries.xml b/Model/lib/wdk/model/records/commentTableQueries.xml index 80e0870fc..9c15eda7e 100644 --- a/Model/lib/wdk/model/records/commentTableQueries.xml +++ b/Model/lib/wdk/model/records/commentTableQueries.xml @@ -139,6 +139,13 @@ FROM @REMOTE_COMMENT_SCHEMA@comment_ai_provenance cap JOIN @REMOTE_COMMENT_SCHEMA@comment_ai_run car ON cap.run_job_id = car.job_id WHERE car.source_kind = 'pubmed' AND car.pubmed_id IS NOT NULL + UNION + SELECT cap.comment_id, car.external_ref AS source_id + FROM @REMOTE_COMMENT_SCHEMA@comment_ai_provenance cap + JOIN @REMOTE_COMMENT_SCHEMA@comment_ai_run car ON cap.run_job_id = car.job_id + WHERE car.source_kind = 'upload' + AND car.external_ref_kind = 'pubmed' + AND car.external_ref IS NOT NULL ) merged GROUP BY comment_id ) refs ON c.comment_id = refs.comment_id