diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..37ec95a --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,35 @@ +name: Deploy site (staging) + +on: + push: + branches: [main] + paths: ["knowledge/**", "site/**", "tools/prepare_site_content.py", ".github/workflows/deploy.yml"] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: deploy + cancel-in-progress: false + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + - uses: actions/cache@v4 + with: + path: ~/.npm + key: ${{ runner.os }}-npm-${{ hashFiles('site/quartz.config.yaml') }} + - name: Build + run: bash site/build.sh + - name: Deploy to Cloudflare + uses: cloudflare/wrangler-action@v3 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + command: deploy --config site/wrangler.jsonc --env staging diff --git a/.github/workflows/site.yml b/.github/workflows/site.yml deleted file mode 100644 index 5956021..0000000 --- a/.github/workflows/site.yml +++ /dev/null @@ -1,65 +0,0 @@ -name: Deploy site - -on: - push: - branches: [main] - paths: - - "knowledge/**" - - "site/**" - workflow_dispatch: - -env: - # Kept in sync with QUARTZ_SHA in site/build.sh; only used here as a cache key. - QUARTZ_SHA: 97a2d05f80c4c50534959b1d0d41cc4b3895625e - -permissions: - contents: read - pages: write - id-token: write - -# Only one deploy at a time; let an in-flight run finish rather than cancelling it. -concurrency: - group: pages - cancel-in-progress: false - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-node@v4 - with: - node-version: 24 - - - name: Cache npm - uses: actions/cache@v4 - with: - path: ~/.npm - key: ${{ runner.os }}-npm-${{ env.QUARTZ_SHA }} - restore-keys: | - ${{ runner.os }}-npm- - - # Drives the exact same script a contributor runs locally, so CI and - # local builds can't drift apart. See site/build.sh and site/README.md. - - name: Build site - run: bash site/build.sh - - - uses: actions/configure-pages@v5 - - - uses: actions/upload-pages-artifact@v3 - with: - path: public - - deploy: - needs: build - runs-on: ubuntu-latest - permissions: - pages: write - id-token: write - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - steps: - - id: deployment - uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 053dee5..73bca76 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,9 @@ public/ # tracked, despite the blanket `dist/` rule above. !site/okf-meta-plugin/dist/ !site/okf-meta-plugin/dist/** +viz.html +.playwright-cli/ + +# Raw source material reviewed for the bundle (may contain unpublished planning); never committed +sources/ +.wrangler/ diff --git a/CHANGELOG.md b/CHANGELOG.md index eae2643..5387eaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,18 @@ All notable reader-facing changes to this knowledgebase. Format follows [Keep a ## [Unreleased] +### Changed + +- Tightened 112 knowledge pages and their navigation descriptions, reducing repetition while preserving examples and source extracts; a five-part review then restored qualifiers, disclaimers, and quoted source material the tightening had dropped, and reverted twelve pages. +- Diagrams are Excalidraw-rendered SVGs composed for the text column, with click-to-zoom on the site; Mermaid is no longer used. + ### Added +- Source-grounded summaries of 15 project diagram boards, indexed by idea and pillar with links to the source material. +- Reusable OIDM and Anatomic Locations logos for site content and diagrams, with the original style guide and usage notes. + - First full draft of the knowledgebase: 115 documents in OKF 0.2 covering the overview and vision, a 48-term glossary, the semantic foundation (finding models, common data elements, anatomic locations, exam types, terminologies), the data structures (Observation, Exam Finding List, Imaging Problem List, Imaging Persona, FHIR and IHE alignment), the applications, the roadmap and open questions, project history, a repository map, and verbatim reference extracts. - Authoring guide, contributing guide, and migration ledger recording every document migrated from a working repository. - Two validation gates (OKF 0.2 conformance and house rules) run in continuous integration. -- Rendered site built with Quartz and deployed to GitHub Pages, with frontmatter badges showing each document's type, status, provenance, and verification. +- Rendered site built with Quartz and hosted on Cloudflare (dev, staging, and production targets), with frontmatter badges showing each document's type, status, provenance, and verification. - All documents are status draft pending the project lead's verification. diff --git a/DEV_LOG.md b/DEV_LOG.md index 8125d28..0d03b3d 100644 --- a/DEV_LOG.md +++ b/DEV_LOG.md @@ -21,3 +21,40 @@ Engineering narrative for the oidm-knowledge repository: decisions, blockers, an - Phases 2 to 5 complete: six Opus agents wrote the semantic foundation, data structures, applications, and roadmap; each appended source conflicts to a collected file that became `roadmap/open-questions.md` (90 entries plus 21 upstream defects to file as issues). Project lead decisions applied: the taxonomies are the "MGB exam-oriented sub-taxonomies"; the next-generation vocabulary document is published as draft; the use case catalog is published with its committee credit. - Integration: ledger (118 rows) and log merged from agent scratch files; naming made consistent; a dead URL and an exam count corrected; both validators report 115 concepts, 0 errors, 0 warnings; the site rebuilds. Remaining Phase 6 work is the project lead's verification pass, then the first release entry and the follow-up issues (source-repo link-back PRs, upstream defect reports, manuscripts). - Added the project lead's stated goals verbatim to the plan so that documents citing the planning interview have a written source (open question 82). +- Initial local commit made, marked pre-review. Added `Taskfile.yml` (`task check|build|serve|publish|viz`). `task publish` validates, builds Quartz with a bucket-specific config, rewrites internal links to explicit `.html` paths with `tools/flatten_site_links.py` (Quartz has no file-style link option; plain object storage has no clean-URL rewriting), and uploads to the Tigris bucket. Published at https://oidm-public.t3.storage.dev/oidm-knowledge/index.html and verified. Root index now carries a pre-review banner. +- Bucket links, second pass: the first flattening only rewrote hrefs in the HTML, so links built in the browser (explorer sidebar, search results, graph node clicks) still pointed at extensionless URLs and returned 404 on the bucket. `tools/flatten_site_links.py` now also injects a small script into every page that applies the same rule at link creation and click time, and patches the emitted JavaScript so direct `window.location` navigations pass through it. Verified in a real browser against the bucket: sidebar click, search result click, and body links all resolve. +- Diagrams: the project lead rejected Mermaid. Replaced all three Mermaid blocks (architecture, data-structure hierarchy, repository map) with Excalidraw diagrams built by small Python builders in `tools/diagrams/` (shared helpers in `excalib.py`), rendered to SVG through the Excalidraw library in a headless browser (`render_excalidraw.py`, module pinned to 0.18.0 after the unpinned esm.sh build broke), and iterated by viewing each render: architecture took three versions, the repository map four, the hierarchy two. The `.excalidraw` source sits beside each document with its SVG. Diagram iteration was delegated to a Sonnet agent after the first diagram. +- Site: Quartz assumes a host that rewrites clean URLs; the bucket does not. A Starlight spike (file-style output, site-graph plugin for graph and backlinks) is running in the scratchpad; the choice of generator goes to the project lead for review before anything changes. New rule recorded: every tool selection is reviewed with the project lead first. +- Sources: the project lead added seven manuscript and deck files to the bucket folder oidm-knowledge-sources; an agent is extracting and summarizing them into the gitignored `sources/bucket/`. +- Repository review: both validators pass (115 concepts, zero errors or warnings), and the Quartz build succeeds for all 133 Markdown files. All concepts remain unverified drafts. Source inventories now exist for the imported manuscripts/decks and 15 Excalidraw canvases; integration remains outstanding. Recorded publishing workflow gaps, source-watching behavior, documentation discrepancies, and the absence of a configured Git remote in `docs/plans/repository-review.md`. Review only; no publishing or commits. +- Concurrent editing: a Codex session is rewriting bundle documents in this working tree (112 documents, generated.by set to codex/gpt-6, prose tightened, descriptions changed, no warnings remaining after reconciliation). Per the project lead, that run proceeds first; structure and index reconciliation follow once it finishes. Rule for this session: never overwrite a document whose generated.by is another agent's. +- Verification tooling added: `task verify -- ` stamps a human verified entry and status stable; `task review-status` and `task review-list -- ` report progress. The project lead starts verification on the stable areas (glossary, history, references, semantic foundation). +- Remote created at github.com/openimagingdata/oidm-knowledge (public); the deploy workflow is disabled; a local pre-push guard blocks agent pushes of main, so the project lead pushes. +- Editorial pass completed with three sub-agents using pstack `unslop` and `technical-writing`: 18 concepts shortened from 21,186 to 15,732 body words (25.7%). Synchronized index descriptions and retained examples, citations, and draft status. Cross-review restored qualifications lost during shortening. Scope and verification are recorded in `docs/plans/lean-content-pass.md`; no publishing or commits by this session. +- Hosting decided by the project lead: a Cloudflare static site, extensible with Workers. Set up as an assets-only Worker (`site/wrangler.jsonc`, html_handling auto-trailing-slash, which matches Quartz's clean-URL links natively). Quartz stays the generator on maturity grounds after a survey of wiki and knowledge-graph tools found nothing else both mature and maintained; typed-edge graph is a plugin to write later. Retired the object-storage pipeline (link flattener, bucket publish script, GitHub Pages workflow) in favor of `task deploy` and `.github/workflows/deploy.yml` (cloudflare/wrangler-action; needs CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID secrets). First deploy waits on the project lead's `wrangler login`. +- First Cloudflare deploy: https://oidm-knowledge-dev.talkasab.workers.dev, verified in a browser (clean URLs, sidebar, search, SVG diagrams, no console errors). Targets: dev (default), staging, prod as separate Workers via wrangler environments; `SITE_BASE_URL` sets Quartz's baseUrl per target at build time. The push-to-main workflow deploys to staging; production is a deliberate `task deploy:prod`. +- Full editorial review completed after the project lead rejected the initial 18-page cutoff. Three agents and the main editor read the remaining 97 concepts, all 17 indexes, and the historical bundle log; 94 further concepts changed, with three concise glossary references retained. Across both passes, concept bodies total 108,656 → 94,944 words (12.6% reduction at the review snapshot). Cross-review restored technical constraints and checked the element-binding quotation against its pinned source. Coverage and unchanged-page reasons are in `docs/plans/lean-content-coverage.tsv`; results and count methodology are in `docs/plans/lean-content-full-review.md`. Both validators pass with zero errors or warnings, and whitespace checks pass. Concurrent hosting/tooling work was preserved; no commits or publication by this session. + +## 2026-09-22 + +- Restructure planning with the Codex session via `docs/plans/`: Codex wrote `restructure-around-project-ideas.md`; this session wrote `restructure-joint-notes.md` and two idea inventories (`idea-inventory-semantic.md`, 46 ideas; `idea-inventory-structures-and-uses.md`, 41 ideas) from the repositories' design documents, plans, prompts, skills, and ADRs. The project lead withdrew an inventory-derived 41-page list: the structure is the human one (the original brief and the January deck), now four pillars (semantic foundation; data structures; applications and uses; SDKs and sample applications). Ideas mined from repository documents and prompts are the team's own ideas and enter as first-class content; only agent inference is limited to linking prose. `idea-placement.md` places all 87 inventoried ideas under the pillar pages by source kind. +- Read the SIIM 2026 "Reports of the Future" deck (June 2026, public) directly, including its six figures, at the project lead's request. Its Patient Context / Foundation Context framing, three axes, "connective tissue" of relationships and external citations, "resolve, don't reinvent" SDK mechanism, and the ask now sit above the four pillars in the joint notes; a relationships-and-citations page was added to pillar 1. Reading recorded in `sources/bucket/REPORT.md` section 8; source-map rows added to the build plan. No drafting has started; page list awaits Codex's reply and the project lead's review. +- Planning conversation with the Codex session, framed by Codex at the project lead's request, produced a shared understanding recorded in the joint notes: the source eligibility rule, "related representations" wording, the organizing method, and real deletion of redundant generated material. The project lead ruled during it: a CDE and a finding model are the same content in two collections with different review expectations, both moving to the CDE schema rewrite's classes; the OIFM reorganization around that graph is urgent; and the structure is five named pillars (Foundation Context, Data Structures, SDKs, Use Cases, Sample Applications), used by name. The "Observation Type" umbrella the sessions had floated is withdrawn. The joint notes now carry the decisions, the agreed outline with the current pages that collapse into each part, and next steps; the placement table is being re-sectioned under the five names; the build plan gained a 2026-09-22 decisions table. The ACR-RSNA-CDEs session was told the rulings. Still no drafting. + + +- Codex completed three staged pillar drafts in `knowledge/drafts/`: Data Structures, Use Cases, and Sample Applications, totaling 2,704 body words excluding metadata and footnotes. Independent source review corrected coding guarantees, durable-identity claims, provenance review boundaries, and differing status vocabularies. Citations and pinned Git source paths check out; full bundle validation awaits the remaining Claude drafts and index reconciliation. Handoff is recorded in `docs/plans/restructure-codex-drafts.md`; source cross-review and page replacement remain pending. No commit or publication by this session. +- Drafting, Claude side: seven pages staged under `knowledge/drafts/` (introduction, foundation-context, finding-models-and-cdes, anatomic-locations, exam-types, standards, sdks) by four Opus agents, each reviewed by the main session and corrected (inventory IDs removed from prose, agent inferences cut, the deck's own labels used, an internal board cited without its link, American spelling). Three independent source-fidelity reviews of the Codex drafts written to `sources/review/`. Bundle validates at 144 documents, 0 errors, 0 warnings. Committed on `bootstrap`; pull request #1 opened from `bootstrap` into a newly created `main`. + +- Codex completed the source-fidelity cross-review of all seven Claude drafts, with three agents assisting; findings are in `sources/review/drafts-.md`. Claude pages were not edited by this session. Corrected the three Codex drafts and recorded dispositions, including unsupported review claims, in the corresponding response files. Key fixes cover the worked graph example, source-specific status and transport claims, live application links, and team evidence for built demonstrations. Revised bodies total 3,074 words. Strict OKF and bundle checks pass (144 documents, zero errors/warnings), with citation-ID and whitespace checks passing. Updated the drafting plan, joint handoff, and bundle log. Replacement remains separate; no commit or publication by Codex. + +## 2026-09-30 + +- Imported 16 original OIDM and Anatomic Locations logo/mark assets from Tigris into `knowledge/assets/brand/`, plus the 2023 style guide and a source/checksum manifest in `docs/brand/`. Documented logo typography, colors, the guide's conflicting light-blue RGB and hex values, and usage in site content and Excalidraw builders. Site and diagram READMEs link to the notes. The local Quartz build passed and emitted all assets unchanged; both bundle validators, manifest integrity checks, SVG embedding checks, and whitespace checks passed. The asset import leaves theme and diagram application for a separate task. Plan: `docs/plans/2026-09-30-brand-assets.md`, complete. + +## 2026-10-01 + +- Compared current OKF skills and toolchains, including lorsabyan and serradura, and qualified the earlier QMD suggestion. Ran 29 labeled external validator fixtures with baseline-policy warnings excluded: installed/current scaccogatto reported 13/19 problem cases and accepted 10/10 clean cases; lorsabyan reported 19/19 and accepted 10/10. Recorded the shared impossible-date crash, differing check scope, missing backfill agent payload, and unsafe index-prose rewriting. Actual-bundle trials exposed 15 repository-versus-bundle source-path warnings in the alternative validator. Findings and upstream reuse priorities are in `docs/references/okf-tooling-comparison.md`; no installation, bundle changes, commit, or publication. + +- Reviewed OKF tooling origins and current reuse options. All 13 installed skill files match upstream `scaccogatto/okf-skills` commit `d8393f3` byte for byte; custom code is the house checker, verification helper, and publishing integration. Recorded Google's canonical-repository move, available upstream MCP/CI support, QMD and Basic Memory tradeoffs, and metadata compatibility differences in `docs/references/okf-tooling-review.md`. Review plan complete. No tooling changes, commit, or publication. + +- Captured and visually reviewed all 15 unique Excalidraw boards in `links.txt` (17 URL occurrences). Native SVG/PNG exports, source contents, searchable text, and checksum metadata are in gitignored `sources/linked-diagrams/`; 15 source-grounded draft summaries and their index are staged in `docs/references/linked-diagrams/`. Three untouched SVG exports have normalized copies for XML compatibility. Verified coverage, image decoding, SVG parsing, 63 checksums, and local links; OKF conformance has zero errors, with 50 external-directory link warnings whose targets were checked separately. Plan `docs/plans/2026-10-01-linked-diagrams.md` is complete. The proposed layer migration, detailed reference conversion, and figure redraws await the owner's go; no bundle or presentation moves, upload, commit, or publication by this session. diff --git a/README.md b/README.md index 9a010fa..f3acc25 100644 --- a/README.md +++ b/README.md @@ -7,12 +7,13 @@ The content is an [Open Knowledge Format](https://okf.md) 0.2 bundle in [`knowle ## Reading it - Browse on GitHub from [`knowledge/index.md`](knowledge/index.md). -- Rendered site: coming in the first release. +- Source notes: [15 linked diagram summaries](docs/references/linked-diagrams/index.md), with source locators and connections to the five pillars. +- Rendered site: `task build` renders it with Quartz into `public/`; `task deploy` publishes it to Cloudflare (Workers static assets, `site/wrangler.jsonc`); pushes to `main` deploy through `.github/workflows/deploy.yml`. - Agents: read `knowledge/index.md` first, follow links only into what the task needs, and weigh `status`, `verified`, and `stale_after` in each document's frontmatter. ## Contributing -See [CONTRIBUTING.md](CONTRIBUTING.md) and the [authoring guide](knowledge/guides/authoring-guide.md). Two checkers must pass: +See [CONTRIBUTING.md](CONTRIBUTING.md) and the [authoring guide](knowledge/guides/authoring-guide.md). Two checkers must pass; `task check` runs both (or run them directly): ```bash uv run .agents/skills/validate/scripts/okf_validate.py knowledge --strict @@ -24,7 +25,9 @@ uv run tools/check_bundle.py | Path | Purpose | |---|---| | `knowledge/` | The OKF bundle | -| `tools/` | House-rules checker | +| `Taskfile.yml` | `task check`, `task build`, `task serve`, `task deploy`, `task preview`, `task verify`, `task review-status`, `task viz` | +| `site/` | Quartz configuration, badge plugin, build script, Cloudflare Worker config | +| `tools/` | House-rules checker, verification tool, diagram builders, site staging script | | `.agents/skills/` | Installed OKF skills (author, validate, visualize, backfill) | | `CHANGELOG.md` | Reader-facing changes | | `DEV_LOG.md` | Engineering narrative | diff --git a/Taskfile.yml b/Taskfile.yml new file mode 100644 index 0000000..8989e18 --- /dev/null +++ b/Taskfile.yml @@ -0,0 +1,85 @@ +# Task runner for the OIDM knowledgebase. Install: https://taskfile.dev +# +# task list tasks +# task check run both validators (OKF conformance + house rules) +# task build build the Quartz site into public/ +# task serve local dev server with live reload +# task deploy build and deploy to oidm-knowledge-dev; deploy:staging and deploy:prod for the others +# task preview build and serve locally through wrangler +# task viz render the bundle as a single-file interactive graph (viz.html) +version: "3" + +vars: + # Hostnames per target; workers.dev names until custom domains are attached + DEV_URL: '{{.DEV_URL | default "oidm-knowledge-dev.talkasab.workers.dev"}}' + STAGING_URL: '{{.STAGING_URL | default "oidm-knowledge-staging.talkasab.workers.dev"}}' + PROD_URL: '{{.PROD_URL | default "oidm-knowledge.talkasab.workers.dev"}}' + +tasks: + default: + silent: true + cmds: + - task --list + + check: + desc: Validate the bundle (OKF 0.2 conformance, then house rules) + cmds: + - uv run .agents/skills/validate/scripts/okf_validate.py knowledge --strict + - uv run tools/check_bundle.py + + build: + desc: Build the Quartz site into public/ (clean URLs, served by Cloudflare) + cmds: + - bash site/build.sh + + serve: + desc: Serve the site locally with live reload + cmds: + - bash site/build.sh serve + + deploy: + desc: Build and deploy to oidm-knowledge-dev (default target) + deps: [check] + cmds: + - SITE_BASE_URL={{.DEV_URL}} bash site/build.sh + - wrangler deploy --config site/wrangler.jsonc --env dev + + deploy:staging: + desc: Build and deploy to oidm-knowledge-staging + deps: [check] + cmds: + - SITE_BASE_URL={{.STAGING_URL}} bash site/build.sh + - wrangler deploy --config site/wrangler.jsonc --env staging + + deploy:prod: + desc: Build and deploy to oidm-knowledge, the public site + deps: [check] + cmds: + - SITE_BASE_URL={{.PROD_URL}} bash site/build.sh + - wrangler deploy --config site/wrangler.jsonc + + preview: + desc: Build and serve the site locally through Wrangler, exactly as Cloudflare will serve it + cmds: + - bash site/build.sh + - wrangler dev --config site/wrangler.jsonc --env dev + + verify: + desc: "Mark documents verified by the project lead: task verify -- knowledge/glossary/oifm.md [...]" + cmds: + - uv run tools/verify.py {{.CLI_ARGS}} + + review-status: + desc: Show verified / total documents per directory + cmds: + - uv run tools/verify.py --status + + review-list: + desc: "List unverified documents under a directory: task review-list -- knowledge/glossary" + cmds: + - uv run tools/verify.py --list {{.CLI_ARGS}} + + viz: + desc: Render the bundle as one self-contained HTML graph at viz.html + cmds: + - uv run .agents/skills/visualize/scripts/okf_visualize.py knowledge -o viz.html --title "OIDM knowledge" diff --git a/docs/HANDOFF.md b/docs/HANDOFF.md new file mode 100644 index 0000000..b296a52 --- /dev/null +++ b/docs/HANDOFF.md @@ -0,0 +1,60 @@ +# Handoff: everything an agent needs to work on this repository + +Written 2026-10-01 by the Claude session that has worked with the project lead since 2026-09-20. Read this first, then the plans it points to. The project lead is the only person named in this repository; everyone else is an organization. + +## What this is + +A public knowledgebase for the Open Imaging Data Model (OIDM), in four layers (`docs/plans/2026-10-01-sources-and-layers.md`): + +1. **Raw sources**: a private Tigris bucket `oidm-knowledge-sources`, mirrored to gitignored `raw-sources/` (today still `sources/`), with a tracked manifest. Not in the repo. +2. **References**: `knowledge/references/`, one OKF Reference per source with a detailed summary, key quotes where allowed, and figures. Figures from unpublished or internal sources are redrawn with the diagram tooling, never reproduced. +3. **The knowledge bundle**: `knowledge/`, the comprehensive team-facing OKF 0.2 bundle (115 concepts as of 2026-09-21), public only because the repository is. Reorganizing it under the five pillars is Astra's track. +4. **The presentation**: `pages/` (not yet created; the agreed pages are still in `knowledge/drafts/`), the outward pages distilled from the bundle, the only thing the public site builds. Layout in `docs/plans/2026-09-22-layout-plan.md`; status in `docs/plans/restructure-dashboard.md`. + +## The structure of the ideas + +Five named pillars, always used by name and never numbered: **Foundation Context** (the shared, curated clinical knowledge: finding/diagnosis definitions, anatomic locations, exam types, and the relationships among them), **Data Structures** (the patient side: Observation, Exam Finding List, Imaging Problem List, Imaging Persona, and how the patient graph and the foundation graph are woven together), **SDKs**, **Use Cases** (the team's documented possible applications), **Sample Applications** (what was actually built). An Overview page sits above them. + +Rulings that govern content, all from the project lead and recorded verbatim in `docs/plans/restructure-joint-notes.md` ("Decisions of 2026-09-22") and `docs/plans/2026-09-22-layout-plan.md` ("The guidance, verbatim"): + +- A CDE and a finding model are the same kind of content in two collections: Open Imaging Finding Models (inclusive, beta channel, maintained by the OIDM project) and ACR/RSNA Common Data Elements (well-reviewed, release channel, radelement.org). Both are moving onto the next-generation graph schema being developed in the CDE project; reorganizing OIFM around it is an immediate priority. +- OIDM models the whole imaging workflow context across its lifecycle; the current focus is data structures and semantics for imaging results. The Imaging Persona integrates imaging results into one larger graph of the patient's history, underpinned by Foundation Context. +- Nothing is formally specified. Never call any source "the specification" or "canonical". Show each source's version side by side, dated and attributed; never reconcile disagreements. +- Terminology: "finding/diagnosis definitions" for the WHAT axis ("Observation Type" is under consideration, not adopted); "Foundation Context" and "Patient Context"; the two graphs are "woven together" or "interconnected", never "pointers"; "connective tissue" only in the SIIM 2026 deck's sense (relationships and citations between foundation concepts). Measurements name a kind of quantity, not a unit. Use "defines" for node types, not "is a". Use the schema's own relationship names (MAY_MANIFEST_AS, ASSESSED_BY, ...) and its specificity words (pathognomonic, highly suggestive, suggestive). +- Organizations only. The reporting vendor stays generic; the organizations behind the 47 and 31 finding models stay generalized. Manuscripts under review: paraphrase, cite as under review, never quote, never touch reviewer correspondence. Internal boards: schema ideas only, no live links, no people, meetings, or vendor logistics. The project lead's own deck and the ACR-RSNA-CDEs repository figures may be reused. +- Repository documents, plans, prompts, skills, ADRs, and code are team artifacts and first-class sources; carry each source's own status, date, and provenance labels (the CDE decision record's OWNER / CLAUDE DEFAULT). Only an agent's own inference is kept out. +- Read only committed files at a pinned commit in the CDE repository; its working tree holds uncommitted decisions (S53 to S67) and newer graph files that cannot be cited until committed. +- The old 48-term glossary is dropped; a new one grows from the presentation pages as terms earn entries. + +## How work is done + +- **Pages**: the project lead and the Claude session agree the page text line by line in conversation (one page at a time, actual content, not descriptions). The project lead's words go verbatim into the layout plan's "guidance" section so pages can cite them. An **Opus** sub-agent then writes the page from the agreed text (frontmatter, citations verified against pinned sources, validation) and must not reword it. **Astra** (the Codex session in this workspace's second tab) reviews for source fidelity, writing findings to `sources/review/drafts-.md`; the writer applies footnote findings and writes dispositions to `drafts--response.md`; prose questions go back to the project lead. +- **Figures**: design agreed in conversation, built by an Opus sub-agent as an Excalidraw builder in `tools/diagrams/` (helpers in `excalib.py`; icons and licenses in `tools/diagrams/icons/`), rendered and LOOKED AT before reporting; the Claude session looks again; the project lead accepts. Renders for review go in `docs/plans/renders/` (tracked) because `sources/` is gitignored and peruse will not open it. Conventions in `tools/diagrams/README.md`: shared palette by node kind, assessment schemes as purple ovals (never diamonds), solid small arrowheads, schema relationship names on boxed labels, 13px minimum text, no Mermaid, no "pointer". +- **Models**: implementation runs in Opus sub-agents (always pass the model explicitly) or in the codex-impl tabs; never Sonnet for judgment work; never the Fable session itself without explicit clearance. Review every tool or approach choice with the project lead before adopting it. +- **Astra**: find its pane with `herdr pane list` (the codex pane whose cwd is this repo), read it before sending, send with `herdr pane run ""`, and record handoffs in `docs/plans/restructure-joint-notes.md` under "Handoffs". Never ask the project lead to relay. Never commit Astra's uncommitted work unasked; group commits by what belongs together, not by author. +- **Review surface**: the project lead reads files in peruse (`http://agent-dev:7440/p/oidm-knowledge/`); root-absolute links (`/knowledge/...`) resolve there. Keep `docs/plans/restructure-dashboard.md` current whenever a status changes. +- **Git**: branch `bootstrap`, pushed; PR #1 from `bootstrap` into `main` (which the project lead merges). A global pre-push hook refuses any push to `main`; this checkout has `remote.pushDefault=parent`, so push with the remote named: `git push origin bootstrap`. Never commit without the project lead's explicit yes; propose a concise message first. Never delete or overwrite a file you did not create (`links.txt` is the project lead's). +- **Validation**: `task check` runs the OKF 0.2 validator (`.agents/skills/validate/scripts/okf_validate.py knowledge --strict`) and the house checker (`tools/check_bundle.py`: index coverage, link resolution, trust-signal shape, denylist in gitignored `tools/denylist.txt`). Both must be clean before a commit. Index entries use `* [Title](./file.md) - description` with the description identical to the frontmatter; quote YAML descriptions containing colons. + +## The site + +Quartz 5.0.0 (pinned commit in `site/build.sh`) with YAML config in `site/`, local plugins `site/okf-meta-plugin` (frontmatter badges) and `site/okf-lightbox-plugin` (click-to-zoom), staged by `tools/prepare_site_content.py`; hosted as Cloudflare Workers static assets (`site/wrangler.jsonc`), targets dev (`task deploy`, https://oidm-knowledge-dev.talkasab.workers.dev), staging (`task deploy:staging`, also on push to `main` via `.github/workflows/deploy.yml`, needs `CLOUDFLARE_API_TOKEN` and `CLOUDFLARE_ACCOUNT_ID` secrets, not yet set), prod (`task deploy:prod`; production domain knowledge.openimagingdata.org, not yet configured). Credentials are in the environment "to be cleaned up later". The permission classifier has refused `task deploy` from the Claude session once; the project lead can run it. + +Decided 2026-10-01, not yet built: the public site builds from `pages/` only, the Overview as landing page, the explorer ordered by the five pillars; a separate internal Worker builds the bundle from `knowledge/`; dev and staging stamp "DRAFT / Awaiting Review" on every page; production refuses any page without a `verified` entry (`task verify -- ` stamps it). The current deployed site is the 2026-09-21 bundle and does not match the plan. + +## Where the sources are + +- Repositories cloned read-only under `~/`: findingmodel, findingmodels, med-ontology-lookup, ACR-RSNA-CDEs (branch next-gen-2026), RadLex, imaging-problem-list (dev is current), FindingModelForge, CDEStaging, IPL-MVP-ExtractionAndLabeling, anatomiclocations.org, BodyPartIndex.py/.ts, UseCases, FHIRSamples, and the lineage repositories. Pins used so far are recorded in each page's sources. +- `~/exam-types/sources/LoincRsnaRadiologyPlaybook.xlsx`: Playbook entries (LongCommonName column) for exam-type names; a second sheet `core-playbook-dev` may be the project lead's working set. +- `sources/` (gitignored, to become `raw-sources/`): `bucket/` (manuscripts, decks, the AI-evolution essay, extracted text under `bucket/text/`, the reading in `bucket/REPORT.md`), `siim2026/` (the SIIM 2026 deck, its text and images), `excalidraw-diagrams.md` (15 boards with sensitivity flags), `email/2026-09-19-ipl-manuscript-notes.md`, `ipl-example2-study.md`, `review/` (every review and response file), `upstream-issues-draft.md` (22 drafted issues for the source repositories, awaiting the project lead). +- The SIIM 2026 deck (June 2026, public) is the central framing source; the January 2026 status update and the July 2026 webinar are the others; the openimagingdata.org posts are team sources. + +## State on 2026-10-01 + +Agreed, written, reviewed (in `knowledge/drafts/`): `overview.md`, `foundation-context.md`, `finding-models-and-cdes-hub.md`, `next-generation-schema.md`, `relationships.md`. Figures: two-planes (accepted), three-axes v6, mini-network v8, two-collections v1, pillars v8 (castellated B3), nodule neighborhood v3, all awaiting the project lead's accept except two-planes; the pillars stack is not yet embedded in the Overview and the nodule figure is not yet placed (relationships page, and in place of the dated figure on the schema page). The standard-clinical-metadata page text is proposed in conversation and not yet agreed; it should carry the project lead's 2026-09-30 thought that time course and etiology may be properties of the edge to a diagnosis. The remaining pages of the layout plan have reviewed source material in the superseded Tuesday drafts (same directory) but are not written. Astra's brand-asset work (`docs/brand/`, `knowledge/assets/`, `docs/plans/2026-09-30-brand-assets.md`) is in progress and uncommitted. + +Open with the project lead: the figure accepts above; the metadata text; CI secrets; the upstream issue drafts; the CDE decisions S53 to S67 to commit in the CDE repository. + +## Memory for Claude sessions + +Claude sessions in this project directory also load `~/.claude/projects/-home-talkasab-oidm-knowledge/memory/MEMORY.md`, which indexes the same rules as feedback notes. This file is the version other agents can read. diff --git a/docs/brand/README.md b/docs/brand/README.md new file mode 100644 index 0000000..63c07b4 --- /dev/null +++ b/docs/brand/README.md @@ -0,0 +1,60 @@ +# Brand assets + +Original assets retrieved from `t3://oidm-public/logos/` on 2026-09-30. [The manifest](./manifest.json) records each source URI, local path, size, and SHA-256. Files were renamed locally but their contents were preserved. + +## What the guide establishes + +The supplied [2023 style guide](./style-guide-2023.pdf) uses the earlier name **Open Radiology Data Model**. It has two pages covering the logo font and colors. The imported full OIDM logos say **Open Imaging Data Model**. + +| Item | Guide | Implication for the site | +|---|---|---| +| Logo font | Arial Rounded MT Bold, page 1 | Use the supplied artwork to preserve the lettering. This is not a specification for website headings or body text. | +| Light blue | `#49b5ea`, Pantone 298 C, page 2 | A candidate accent color, also present in the OIDM SVGs. | +| Dark blue | `#0033cc`, RGB 0, 51, 204, Pantone 2728 C, page 2 | A candidate link and emphasis color on light backgrounds. Both projects' artwork uses it. | + +**Color discrepancy:** page 2 prints light blue as RGB **4, 149, 234**, which is `#0495ea`, alongside hex **#49b5ea**, which is RGB **73, 181, 234**. The OIDM SVG fills use `#49B5EA`. Use that artwork-backed value for proposed web accents; the original guide remains unchanged. Some paths also use `#0133CC`, a near-match to the dark blue, preserved in the original files. + +The guide gives no website layout, body typography, spacing, minimum logo size, clear-space, or dark-mode rules. It supplies no font files or webfont license. SVG lettering is outlined, so displaying these logos requires no font installation. + +## Assets to use + +All paths below are relative to [`knowledge/assets/brand/`](../../knowledge/assets/brand/). Each filename is available in both `.svg` and `.png`. + +| Project | Full logo variants | Square mark | SVG proportions | +|---|---|---|---| +| OIDM | `oidm/logo-color`, `logo-black`, `logo-white` | `oidm/mark` | Full logo 800 × 197.89; mark 720 × 720 | +| Anatomic Locations | `anatomic-locations/logo-color`, `logo-black`, `logo-white` | `anatomic-locations/mark` | Full logo 538.02 × 179.27; mark 720 × 720 | + +Prefer SVG for the website and diagrams. Transparent PNGs support tools that require raster input: OIDM logos are 2000 × 495, Anatomic Locations logos 2000 × 665, and both marks 720 × 720. The square marks came from the supplied favicon files. Their usefulness at very small sizes should be checked when installing a site favicon. + +The selection omits duplicate print/editing formats, JPGs, pre-sized raster copies, overview illustrations, backgrounds, and the graveyard. The vector originals cover resizing without adding those copies. + +## Suggested application + +These are implementation suggestions, not additional rules from the guide: + +- Use the color full logo for project identification on light backgrounds, the white full logo on dark backgrounds, and black for monochrome output. Preserve proportions and allow space around the artwork. +- Use the square marks beside project names in diagrams. Keep the name visible when the mark alone would be ambiguous. Do not use a project logo as a generic symbol for an anatomy or data-model concept. +- Use dark blue for candidate light-theme links or emphasis. Keep light blue for accents and larger graphic areas. Calculated contrast against white is about 8.95:1 for dark blue and 2.31:1 for light blue, so they are not interchangeable text colors. Check the actual background when applying either. +- Keep the current reading fonts until typography is addressed separately. The existing Quartz theme is in `site/quartz.config.yaml`; importing these assets does not apply a new theme. + +## Use in site content and diagrams + +From a document in `knowledge/drafts/`: + +```markdown +![Open Imaging Data Model](../assets/brand/oidm/logo-color.svg) +``` + +The existing staging and Quartz asset steps copy the files to `public/assets/brand/`, making the example available at `/assets/brand/oidm/logo-color.svg` on the built site. Site header and favicon integration remain separate from importing the files. + +For a diagram builder using `tools/diagrams/excalib.py`: + +```python +image("oidm-logo", x, y, 200, 200 * 197.89 / 800, + "../../knowledge/assets/brand/oidm/logo-color.svg") +image("anatomic-locations-mark", x, y, 48, 48, + "../../knowledge/assets/brand/anatomic-locations/mark.svg") +``` + +Use distinct positions for each element. The helper resolves these paths relative to its own directory and embeds the SVG bytes into the Excalidraw file. Omit the `color` argument to preserve brand colors. Follow the [diagram source-of-truth rule](../../tools/diagrams/README.md#source-of-truth-rule) when adding a logo to an existing graphic. diff --git a/docs/brand/manifest.json b/docs/brand/manifest.json new file mode 100644 index 0000000..b05633b --- /dev/null +++ b/docs/brand/manifest.json @@ -0,0 +1,107 @@ +{ + "retrieved": "2026-09-30", + "files": [ + { + "path": "knowledge/assets/brand/oidm/logo-color.svg", + "source": "t3://oidm-public/logos/Open Imaging Data Model/Open Imaging Data Model logo.svg", + "bytes": 29836, + "sha256": "6872de52cfdda7bafa4778f9f60a3cf2986cea1ed62a45985731cf7663b169c0" + }, + { + "path": "knowledge/assets/brand/oidm/logo-color.png", + "source": "t3://oidm-public/logos/Open Imaging Data Model/Open-Imaging-Data-Model-logo.png", + "bytes": 49644, + "sha256": "3b95bc08f6ceb041e6e097d424fbcdf0b80f323bf5ee353b88c096e5443987b4" + }, + { + "path": "knowledge/assets/brand/oidm/logo-black.svg", + "source": "t3://oidm-public/logos/Open Imaging Data Model/Open Imaging Data Model logo black.svg", + "bytes": 29360, + "sha256": "b27765f299d3f171952f27c068ee0fdb8b1b4bb578624a59b6e36df66d30c712" + }, + { + "path": "knowledge/assets/brand/oidm/logo-black.png", + "source": "t3://oidm-public/logos/Open Imaging Data Model/Open-Imaging-Data-Model-logo-black.png", + "bytes": 42289, + "sha256": "089e8f9d2e0c90a3a4df9bb5e1051441e329dce7f59604c707b7260cc76d8ec4" + }, + { + "path": "knowledge/assets/brand/oidm/logo-white.svg", + "source": "t3://oidm-public/logos/Open Imaging Data Model/Open Imaging Data Model logo white.svg", + "bytes": 29995, + "sha256": "0a99b4ed2091e99dfb5a376b865bf348365fdb7923f96c239c4a877e50d9df63" + }, + { + "path": "knowledge/assets/brand/oidm/logo-white.png", + "source": "t3://oidm-public/logos/Open Imaging Data Model/Open-Imaging-Data-Model-logo-white.png", + "bytes": 48393, + "sha256": "98a4771e17b0ddb0423d066778561d1c406c88320b9bf577735f2ba7fafc8ef8" + }, + { + "path": "knowledge/assets/brand/oidm/mark.svg", + "source": "t3://oidm-public/logos/Open Imaging Data Model/Open Radiology Data Model Project favicon.svg", + "bytes": 11504, + "sha256": "bbea5bf9eb403b7669783b560a32c8c3a43da791c95e24e61e61b21d9a78d183" + }, + { + "path": "knowledge/assets/brand/oidm/mark.png", + "source": "t3://oidm-public/logos/Open Imaging Data Model/Open-Radiology-Data-Model-Project-favicon.png", + "bytes": 18533, + "sha256": "bc7f99373c4e8367d60ad634e0b6c83d9cb16b6a971f711e6d600d318acd7d4a" + }, + { + "path": "knowledge/assets/brand/anatomic-locations/logo-color.svg", + "source": "t3://oidm-public/logos/Anatomic Locations/AnatomicLocations logo.svg", + "bytes": 22668, + "sha256": "c0a83e076d969d616c809354b658df5b463989ed3b3d5985b282a359cfcab759" + }, + { + "path": "knowledge/assets/brand/anatomic-locations/logo-color.png", + "source": "t3://oidm-public/logos/Anatomic Locations/AnatomicLocations-logo.png", + "bytes": 36000, + "sha256": "5e49ad69407de57963b45f0eaf6f229988b1ebed556c450789f7b76e2c429862" + }, + { + "path": "knowledge/assets/brand/anatomic-locations/logo-black.svg", + "source": "t3://oidm-public/logos/Anatomic Locations/AnatomicLocations logo black.svg", + "bytes": 22318, + "sha256": "ca728f7b1c1f8b53bbe08d8efc20aebb6ae0f5e23b4fd96776ec910e63b711cb" + }, + { + "path": "knowledge/assets/brand/anatomic-locations/logo-black.png", + "source": "t3://oidm-public/logos/Anatomic Locations/AnatomicLocations-logo-black.png", + "bytes": 31188, + "sha256": "87908be4a2fbe08d3ff5649db194db9cd78778d1d28b91062b177bbe54ff6108" + }, + { + "path": "knowledge/assets/brand/anatomic-locations/logo-white.svg", + "source": "t3://oidm-public/logos/Anatomic Locations/AnatomicLocations logo white.svg", + "bytes": 22647, + "sha256": "4eb007fee8228e65f62165c1659719242bec8177f53ad81c10fd84731bdf6d3d" + }, + { + "path": "knowledge/assets/brand/anatomic-locations/logo-white.png", + "source": "t3://oidm-public/logos/Anatomic Locations/AnatomicLocations-logo-white.png", + "bytes": 35044, + "sha256": "e1284e1b4f63de7e18b9d1b093210018122de4f7fbd6f00daa89a42f5a55aa20" + }, + { + "path": "knowledge/assets/brand/anatomic-locations/mark.svg", + "source": "t3://oidm-public/logos/Anatomic Locations/AnatomicLocations favicon.svg", + "bytes": 3129, + "sha256": "acd4c6467bf638c07825d902fbc807ebae3a237f095c5dedf4698f336b5833c6" + }, + { + "path": "knowledge/assets/brand/anatomic-locations/mark.png", + "source": "t3://oidm-public/logos/Anatomic Locations/AnatomicLocations-favicon.png", + "bytes": 11523, + "sha256": "444b7ca951c491e79cc0e41a8fdd7795dcadaa0c973b85b51f2af98b4f224524" + }, + { + "path": "docs/brand/style-guide-2023.pdf", + "source": "t3://oidm-public/logos/Open Radiology Data Model Project style Guide.pdf", + "bytes": 69726, + "sha256": "f0d08539d4a5f1a78bda59a7bc7bb6237571a594a20b2c91fb8cd670c6e9b37f" + } + ] +} diff --git a/docs/brand/style-guide-2023.pdf b/docs/brand/style-guide-2023.pdf new file mode 100644 index 0000000..bf957e6 Binary files /dev/null and b/docs/brand/style-guide-2023.pdf differ diff --git a/docs/plans/2026-09-22-layout-plan.md b/docs/plans/2026-09-22-layout-plan.md new file mode 100644 index 0000000..4459830 --- /dev/null +++ b/docs/plans/2026-09-22-layout-plan.md @@ -0,0 +1,282 @@ +# Layout plan: the knowledgebase as the project lead described it + +Status: Proposed, 2026-09-22. Written by Claude for the project lead and the Codex session (Astra) to check. No content changes until it is agreed. Supersedes the "Agreed outline" page list in `restructure-joint-notes.md` and the ten-anchor shape of `knowledge/drafts/`. + +## The guidance, verbatim + +Project lead, 2026-09-27 to 2026-09-29, on the Finding Models and Common Data Elements hub page: + +> I think what we want to say is that the finding/diagnosis definition is an unified anchor for the CONCEPT of a finding/diagnosis in a form that can be used to attach associated context: name, synonyms, definition, attributes, etc. OIFM are AN inclusive collection, intended for rapid prototyping... ACR/RSNA Common Data Elements (always include the organizations) are the well-reviewed... published through radelement.org. Forget about talking about the current schema's sets and elements--waste of bits. + +> "Finding Models and Common Data Elements" / "Definitions of findings and diagnoses anchor these concepts in a form that associated content can..." + +> "...maintained by the OIDM project..." / "The OIFM repository is intended for rapid, community-based prototyping and iteration based on an open-source model." / "...with changes proposed by anyone." / Take out "uneven" / "in the project lead's words" is RIGHT OUT. I think the thing to emphasize is that they will have the same schema and describe the same ideas. Major difference is that OIFMs is much more "beta"/rapid additions and updates and CDEs is much more "release"/reviewed and stable. + +> I think we should also emphasize that we will maintain cross-links: when something migrates to CDEs, it will continue to be maintained in the OIFM repo but have a reference to its CDE identity. "Both CDEs and OIFMs are document-oriented today, and moving..." + +The agreed hub text (2026-09-29) is the one the Opus agent writes verbatim into `knowledge/drafts/finding-models-and-cdes-hub.md`. + +Project lead, 2026-09-30, on figures: "Let's make the AssessmentSchemes ovals rather than diamonds--those have a flowchart implication that doesn't obtain here." Recorded as a convention in tools/diagrams/README.md. + +Project lead, 2026-09-30, four prose decisions on the relationships page: (1) change the associated-findings example to a pair the graph records as OCCURS_WITH; (2) the renal abscess clause becomes "...may have sequela beyond the course of the acute pyelonephritis episode."; (3) "whether or not one causes the other"; (4) use the schema's specificity words: pathognomonic, highly suggestive, suggestive ("they're cooler"). + +Project lead, 2026-09-30, on the pulmonary nodule neighborhood figure (illustrative; reflects updates the project lead, as the CDE project's clinical expert, intends for the CDE graph): rename "attenuation" to "composition" and "pulmonary margin" to "margin"; drop "lesion count"; "ground glass nodule" for "non-solid pulmonary nodule"; add the Grouping "pulmonary parenchymal abnormality"; add the diagnoses "pulmonary neoplasm" and "pulmonary granuloma" (subtype of the grouping); add "Fleischner criteria" as an assessment scheme; add subspecialty; show SEEN_ON CT, XR, and MR; no values; no time course or etiology for now: "I'm starting to think that may need to be a property of the edge connecting it to a diagnosis. Actually, that's the same for etiology." + +Project lead, 2026-09-30, on the relationships page: + +> Emphasizing that they're "strictly apart" makes it seem like THAT'S the issue. / Let's just call this subsection "Findings <-> Diagnoses: Manifestation and Causation" / "Pyelonephritis APPEARS AS striated nephrogram..." "when the pyelonephritis resolves, the striation goes with it..." / Next subsection called "Deriving the Differential" / "The schema distinguishes manifestation and causation to enable inference:..." / We should ALSO include the idea of associated findings here, and the properties of the edges themselves that get at how commonly findings/diagnoses are associated in the specified way / Don't include the "HPO and Orphanet" reference / "a pulmonary nodule definition specifies how a pulmonary nodule WILL BE DESCRIBED. The assessment is a separate assertion, defined by the AssessmentScheme definition, which allows for evaluation of the nodule according to the defined criteria." / "...by an ASSESSED_BY edge" + +Project lead, 2026-09-30, on the next-generation schema page: + +> "Both Open Imaging FInding Models and RSNA/ACR Common Data Elements are moving..." / Show a link to the ACR/RSNA CDE schema repository, on the next-gen-2026 branch. / "...as a graph of interconnected concepts rather than a set of documents." / "Applications will be able to use either or both collections at once via a common SDK based on the new schema." / "FindingClass" defines the properties of the items described in imaging reports. A "Diagnosis" is a separate, closely-related node type, distinguished by a different set of possible relationships. Groupings are broad classes of findings/diagnoses such as "renal abnormality", usually intended to be used in the negative. / For most of these node class definitions, we want to use "defines" rather than "is a" (this is a very tricky but important semantic distinction) / "AssessmentScheme" definitions layout the systems such as Lung-RADS via which a constellation of other findings is evaluated. / "The anatomic scope property of each other node indicates the locations and/or structures in which they may be localized (e.g., "lung parenchyma" for a pulmonary nodule). / "Edges integrate the notes into a rich fabric of interrelated concepts, enabling reliable, reproducible inference." / "Edges bind FindingClass and Diagnosis definitions to their anatomic scope and to the DataElements and Measurements used to specify their attributes. The edges themselves may contain properties that provide additional detail about the relationships between nodes." / Concept nodes as a note below the list, introducing the paragraph that also talks about anatomic scope. / Use the actual table of relationship types as examples. / "Evolution of CDEs and Finding Models: Both CDEs and existing Open Imaging Finding Models will have to migrate from their current JSON document-based organization to a new graph-oriented format, likely using RDF/OWL as an underlying storage format. More ergonomic data structures will also be developed for use in SDKs and via an API." + +Project lead, 2026-09-30, on the SDKs (for the pillars figure and the SDKs index): "I think we should also say that the SDKs help AUTHOR and MAINTAIN the underlying foundation context." + +Project lead, 2026-09-29, on Measurements (for the three-axes figure and the next-generation schema page): + +> Measurements don't have EXPLICIT units, they indicate what KIND of thing they are: length (with appropriate length units, which could be mm, cm, whatever), CT density (HU), or count (unitless), ratio (unitless), velocity (m/s, cm/s), volume (cc, mL, mm^3..., L) + +Project lead, 2026-09-24, on the Overview page: + +> OIDM is NOT just for modeling imaging results, it is for modeling the ENTIRE imaging workflow context throughout its lifecycle. It's meant to enable a common platform across the medical imaging ecosystem that enables tools that will assist radiologists, technologists, ordering providers, and back-office staff. RIGHT NOW, we happen to be focused on data structures and semantics for representing imaging results, whether from current exams or prior, and from AIs, radiologists, technologists, or modalities themselves, and for integrating those results across time. We will ALSO model the broader patient context and enable linking between imaging results and patients' OTHER diagnoses, procedures, and issues. + +> The imaging persona doesn't place the rest of the patient context "alongside"--it integrates them into a single, larger graph, underpinned by the Foundation Context. Basically, the imaging results can be integrated into the larger fabric of the patient's history. + +> Let's call it "finding/diagnosis definitions" since they're used so interchangably. It really might be that "ObservationType" is the better catch-all term. + +> "Pointers" is a... well, pointless inclusion. The idea is that the patient graph is deeply interconnected with the Foundation Context graph, attaching baseline clinical knowledge to the contingent patient facts. [...] every finding, diagnosis, location, and exam type. + +Source added by the project lead on 2026-09-24: `~/exam-types/sources/LoincRsnaRadiologyPlaybook.xlsx` (44,178 Playbook part rows with LOINC numbers, part types, RadLex IDs and preferred names; a second sheet `core-playbook-dev`, 995 rows) for the exam-types page and diagrams. The ACR-RSNA-CDEs next-gen graph (`docs/next-gen-schema/graph/*.jsonl`, `alpha/graph/definition-graph.json`, `diagrams/*.svg`) supplies real nodes and typed edges for the Foundation Context figures. + +Wording rules from these: "finding/diagnosis definitions" is the term for the WHAT axis for now ("Observation Type" is under consideration as the catch-all, not adopted); the connection between the graphs is described as interconnection that attaches knowledge to facts, never as pointers; the Imaging Persona integrates imaging results into one larger graph of the patient's history. + +Project lead, 2026-09-23, correcting the first version of this plan: + +> I think in the foundation context page, we need the document on finding models to be something that encompasses both OIFMs (and that repo) but also the RSNA/ACR Common Data Elements and the relationshpi between the two. We should ALSO think about how to present the work on the next-generation schema (which will be for BOTH CDEs and OIFMs--I think applications will be able to use both at once). + +Project lead, 2026-09-22: + +> There should be a big overview page, layout out a HIGH-LEVEL justification of the project, talking about what the CORE PIECES of it ARE (not the DETAILS, just basics about what they ARE). These are the first three pillars: foundation context, data structures, SDK. +> Then the next couple of things: start with some basics of USE CASES. We can have a LIST oriented view of cases, only SOME of which have a more fleshed out page. +> We can also have a list of our sample/demo applications, some of which are RELATED to the use cases. +> There should be a directory on the foundation context, with some documents on the key ideas related to FindingModels/CDEs and the definitions that go into them. There should be a page on the OIFM repository (with a node to its relationship to the CDE project). Tehre should be a page on AnatomicLocations, referencing existing work but also pointing to the fact that we're migrating to incorporate with RadLex. We can also describe the ExamType content to come. + +And, on the shape: no page budget; the number of pages follows from the ideas. "Repository pages" are not a pattern: the one page on the OIFM repository exists because that repository *is* the inclusive collection of finding models. + +## The pattern + +- The **overview** justifies the project at a high level and says what the core pieces are, in basics: Foundation Context, Data Structures, SDKs. Then the basics of Use Cases, and the list of Sample Applications. +- Each pillar is a **directory**. Its `index.md` says what the pillar is, in basics, and lists its documents. +- Inside a directory: a **document per key idea**. Existing work (code, sample data, manuscripts, decks) is cited from inside the idea documents as existing work, dated. Where nothing exists yet, the document says so and describes what is to come. +- **Use Cases** is list-oriented: an index listing every documented case with a line each; only some cases have a fleshed-out page. +- **Sample Applications** is a list of built demos, some with a page, linked to related use cases where the sources document the relationship. +- Everything keeps OKF frontmatter, draft status, dated sources, and side-by-side representations where sources differ. Idea documents link to their neighbors so the graph view is meaningful. + +## The layout + +``` +knowledge/ + index.md THE OVERVIEW: justification; what the core pieces are; + basics of use cases; the list of sample applications; + structure before transport; nothing formally defined; the ask + foundation-context/ + index.md what Foundation Context is; the three axes over existing standards + finding-models-and-cdes.md THE HUB: what a finding model and a CDE are (one kind of + content in two collections); the OIFM collection and the + ACR/RSNA collection in basics; the relationship between the + two (the ruling of 2026-09-22, the workbench, coverage + measurement, the staging path); links to the three + documents below and to the next-generation schema + oifm-content.md what the inclusive collection holds and where it is going: + the provenance streams and counts, the MGB exam-oriented + sub-taxonomies as the immediate direction, the Gamuts-derived + models being superseded, conversion direction, proposals + back to the library (Sem-B2, B7, B8, B9) + definition-formats.md the definitions that go into them today: the OIFM JSON + document (attributes, index codes, the lean published model + versus the full metadata), the RadElement set and element + format, and how one corresponds to the other (Sem-A1, C1, + C2, C3) + identifiers.md the OIFM identifier scheme with its organization segment, + RDES and RDE identifiers, index codes as the join (Sem-B1) + next-generation-schema.md THE SHARED SCHEMA TO COME, for both collections: the + next-gen-schema work in the CDE project as the common graph + (FindingClass, Diagnosis, Grouping, DataElement, Measurement, + bindings, anatomic scope, values as nodes), pinned and dated; + that applications are expected to use both collections at + once through it; the urgent OIFM document-to-graph + reorganization; what is decided, proposed, and open, with + the record's provenance labels + relationships.md the relationship family and the derived differential; + components and associated findings; assessment schemes; + role tagging of elements (proposal); part of the shared + schema, linked from it + standard-clinical-metadata.md what the graph carries for a finding beyond its elements: + three dated statements side by side; linked from the schema + authoring-and-review.md the principles: what counts as a finding, splitting, negatives, + synonyms, naming, stubs, triage, three review tiers, + prompts as fragments, human review as authority + anatomic-locations.md the index: containment, part-of, laterality, synthetic terms, + curation rules; existing work (the 2022 set, the current + package, the manuscript under review); the migration into RadLex + exam-types.md content to come: the stated goals in both dated phrasings, + the Playbook, the anatomy edges, the one written design + standards.md RadLex, SNOMED CT, FMA, LOINC and the Playbook: which axis + layers over which; external citations + data-structures/ + index.md what the structures are, in basics; the Observation as the + unit; that there are two graphs + observation.md what an Observation carries; presence, change, confidence; + pertinent negatives and normality; source text; location + assignment; pointers into Foundation Context + two-graphs.md the patient graph and the definition graph and how they + connect: standing potential versus this radiologist's + assertion; the calculus and pyelonephritis worked examples; + the CDE report graph and the IPL representations as related + representations, dated + exam-finding-list.md all findings of one exam; faithful translation; IHE IDR + imaging-problem-list.md organized by finding; entry identity; succession; derived + status and the three vocabularies; entity resolution; + provenance and corrections; recommendations + imaging-persona.md concept only, as the deck and the site state it + structures-versus-transport.md the 2026-09-19 framing; FHIR and DICOM as expressions; + the documented, unimplemented mappings + sdks/ + index.md what an SDK is here (the project lead's definition); + resolve, don't reinvent; the two consumer families + findingmodel-sdk.md format objects, index, retrieval modes, MCP server, + authoring support; its relationship to the content + repository and the CDE project + anatomic-locations-sdk.md lookup, hierarchy walks, laterality, search; the + BodyPartIndex lineage + terminology-lookup.md the lookup tool across RadLex, SNOMED CT, FMA, LOINC, UMLS + imaging-problem-list-sdk.md proposed: issue #1's system of data models for Observation, + Exam Finding List, and Imaging Problem List + (the reporting SDK, named only, stays in the index with a + link to reporting assistance) + use-cases/ + index.md THE LIST: every documented case, one line each, grouped + by purpose, with its source; links to fleshed-out pages + reporting-assistance.md the context object model and plugin container; the 2024 + demonstrations; vendor-driven framing + imaging-history.md the six application families; the life-cycle uses + outcome-tracking.md follow-up completion, radiology-pathology correlation + breast-imaging.md one entity across assessments; the MQSA audit + sample-applications/ + index.md THE LIST: every built demo, one line each, with its link, + what it demonstrates, and the use case it relates to + finding-model-forge.md authoring and review application + imaging-problem-list-viewers.md viewer 1 and viewer 2 with anatomy + report-extraction-platform.md extraction, coding, persistence, review; its evaluation + and PHI-local stance + rendering-search-and-exchange.md the 2023 rendering, 2024 ontology-search, and exchange + demonstrations + glossary/ removed at the replace step; rebuilt from the new pages as terms earn entries +``` + +Pages not listed above are not planned. More idea documents appear wherever a source carries a distinct idea; no cap. + +## Mapping from what exists + +From the ten reviewed drafts in `knowledge/drafts/`: + +| Draft | Becomes | +|---|---| +| `introduction.md` | `knowledge/index.md`, extended with the basics of use cases and the list of sample applications | +| `foundation-context.md` | `foundation-context/index.md` | +| `finding-models-and-cdes.md` | split eight ways: `finding-models-and-cdes.md` (the hub), `oifm-content.md`, `definition-formats.md`, `identifiers.md`, `next-generation-schema.md`, `relationships.md`, `standard-clinical-metadata.md`, `authoring-and-review.md` | +| `anatomic-locations.md`, `exam-types.md`, `standards.md` | move as they are | +| `data-structures.md` (Codex) | split: `data-structures/index.md` plus `observation.md`, `two-graphs.md`, `exam-finding-list.md`, `imaging-problem-list.md`, `imaging-persona.md`, `structures-versus-transport.md` | +| `sdks.md` | split: `sdks/index.md` plus the four SDK pages | +| `use-cases.md` (Codex) | `use-cases/index.md` as the list, plus the four fleshed-out pages | +| `sample-applications.md` (Codex) | `sample-applications/index.md` as the list, plus the four pages | + +From the placement table (`idea-placement.md`), every placed idea lands in one of the documents above; the split restores material the drafts cut to meet the withdrawn word caps, from the sources. Ideas per document are listed in the placement table's sections; the split agents work from it. + +From the current bundle: the old directories (`overview`, `semantic-foundation`, `data-structures`, `applications`, `roadmap`, `history`, `repositories`, `references`) are removed after a unique-content check against the new documents. `glossary` is kept pending the project lead's decision on its size. `guides` and `plans` stay as maintenance records off the reading path. + +## Open points for the project lead + +Decided 2026-09-29: the reporting vendor in the 2024 update stays generic for now; the organizations behind the 47 and 31 finding models stay generalized; figures from the SIIM 2026 deck and the ACR-RSNA-CDEs repository may be used ("They're all mine"). Glossary, decided 2026-09-29: the existing 48-term glossary is dropped ("PACKED with obsolete stuff"); a new glossary is built out from the real pages as they are written, one entry only when a page needs a term defined across topics. Removal happens at the replace step, since the old pages still link into it. + + +1. Glossary: keep all 49 terms, cut to cross-topic terms, or drop in favor of the idea documents' own definitions. +2. The three naming choices already raised: the reporting vendor in the 2024 update; the two organizations behind the 47 and 31 finding models; the uncommitted CDE decisions S53 to S67. +3. Whether `two-graphs.md` is its own document (as planned here) or lives inside `observation.md`. + +## Open points for Astra + +1. Does the split of your three drafts above match what you would do? Name any document you would merge, split further, or rename. +2. Any placed idea that has no home in this layout? +3. The order of work once the project lead says go: split Foundation Context and Data Structures first (the two graphs), then SDKs, then the two lists. + +## Execution, once agreed + +1. First, correct the placement table (Use-A5, B5, B9, A20 per the review dispositions) and record each idea's destination document in it. Then split agents (Sonnet, one per directory) produce the documents from the corrected drafts, the review dispositions, the placement table, and the sources; recover distinct sourced ideas and necessary qualifications, not repetition or rejected claims; scope every absence claim to the sources reviewed; write frontmatter, sources, and neighbor links. +2. One Opus fidelity check per directory, then one review across directories for repeated explanations, terminology, links, and source status. +3. Overview written last, from the directory indexes. +4. Replace the old pages by an explicit file mapping (the `data-structures` directory is both an old and a new destination); unique-content check first; update root index, log, diagrams, and site navigation; validate; deploy to dev for the project lead's verification pass. + +## Astra review + +2026-09-22. Review of this proposal against the owner's guidance, `idea-placement.md`, and the corrected drafts and review dispositions. The directory pattern and list-oriented applications sections fit the guidance. I propose the adjustments below before we ask the owner to decide. No content changes are authorized by this review. + +### 1. Split of the three Codex drafts + +- Keep `two-graphs.md` separate. It explains relationships between patient assertions, relationships between definitions, and the references connecting them. That warrants a document readers can reach from either pillar. The overview introduces the connection briefly. Observation describes the instance and links to this explanation. The calculus and pyelonephritis examples belong here, with their different scopes preserved. +- Keep the proposed Observation, Exam Finding List, Imaging Problem List, Imaging Persona, and transport documents. I would not split the IPL further at this point. Identity, matching, history, and derived status need to be explained together. A short, sourced Imaging Persona document is sufficient for the concept's present state. +- Rename `imaging-problem-list-uses.md` to `imaging-history.md`. The proposed contents include the broader imaging life cycle as well as IPL applications. Keep the other three use-case pages. Give each distinct documented case one list entry, combining repeated occurrences across sources and linking to detail where useful. The manuscript and webinar groupings remain attributed on the detail page. +- Keep the Forge, viewers, and extraction-platform pages. Rename `interoperability-demonstrations.md` to `rendering-search-and-exchange.md` if it houses all three demonstrated capabilities. The 2024 ontology-search demo demonstrates retrieval, so an interoperability heading would misdescribe it. List the catalog, command-line applications, and earlier extraction experiment without requiring separate pages. + +### 2. Coverage and explicit homes + +I found no placed idea that requires another directory. The layout has suitable homes, but the following assignments need to be explicit before splitting: + +| Idea | Home | +|---|---| +| Use-A17, report sections beyond Findings and the board's open structure questions | `exam-finding-list.md` | +| Use-A26, evidence fidelity and the named extraction failures | `exam-finding-list.md`; implementation and evaluation link from `report-extraction-platform.md` | +| Use-A7, observation provenance and review | `observation.md`; IPL corrections and merge/split operations remain in `imaging-problem-list.md` | +| Use-A13, unresolved anatomy reconciliation; Use-A14 and A22, permanence, ranking, and repeated reporting | `imaging-problem-list.md` | +| Sem-C6 and C7, the package's documentation authority and compatible database releases | The finding-model SDK document, scoped to that package | +| Sem-B8 and B9, content conversion direction and proposals back to the library | `oifm-repository.md` | +| Deck examples of rules and generative assistance, plus the ACR priorities | Individual entries in the Use Cases list, with detail only where the sources supply it | + +The placement table needs correction before agents use it as drafting instructions. Its Use-A5 says status is "never stored", although the reviewed viewer implementation stores derived status. Use-B5 conflates the webinar families, manuscript grouping, and planned breast example. Use-B9 treats the board workflow as demonstrated. Use-A20 calls the extraction platform a precursor without source support. These were resolved in the draft reviews. Keep the IDs as coverage checks and carry forward those corrections. + +### 3. Order of work + +I agree with Foundation Context and Data Structures first, SDKs next, and the two lists after them. Before splitting, record the agreed destinations and boundaries in the placement table and read the review dispositions alongside the corrected drafts. Write the overview last, as proposed. + +After the directory reviews, add one review across directories for repeated explanations, terminology, links, and source status. Then check unique content before removing old pages, reconnect navigation and diagrams, update the logs and plan, validate, and build the dev site. The directory called `data-structures` is both an old and a new destination, so replacement must use an explicit file mapping rather than a blanket directory deletion. + +### Other changes I propose + +1. Merge the proposed `finding-models-and-cdes.md` collection explanation into `oifm-repository.md`. Put the definition of a finding model and the intended shared graph in `finding-definitions.md`. The collection page can then explain inclusiveness, review expectations, content direction, and its CDE relationship once. The Foundation Context index links both. This preserves the owner's requested OIFM page without giving the two-collection explanation two homes. +2. Change Sample Applications from "each linked to the use case" to "link to related use cases where documented". The owner said some are related. Every entry can identify the idea it demonstrates without inventing a use-case relationship. The overview can carry application names and links; descriptions and status belong in the Sample Applications list. +3. Organize SDK pages around developer capabilities. Package names can identify existing implementations. Rename `imaging-problem-list-sdk.md` to `structured-data-models.md`, since the cited proposal covers Observation, EFL, and IPL. A separate reporting SDK page is useful only if it explains a distinct developer-facing idea beyond the proposal's name and status; otherwise retain those in the SDK index and link to reporting assistance. +4. Replace "restore cut material" with "recover distinct sourced ideas and necessary qualifications". Removing the word cap does not justify restoring repetition, repository inventories, or claims rejected during review. Add a document when its idea merits a separate explanation. Keep source detail behind citations where it does not help explain that idea. +5. Scope absence claims. "No artifact" and "unimplemented mappings" must identify the reviewed sources or prototype. The reviews established built reporting and FHIR demonstrations alongside proposed SDKs and IPL mappings. Preserve the current drafts' distinction during the split. Describe RadLex migration as direction with its dated state, and keep the urgent OIFM document-to-graph reorganization visible. + +I agree with the overall shape subject to resolving these boundaries. The owner retains the glossary and terminology decisions. My recommendation on the owner's third open point is the separate two-graphs document described above. + +2026-09-22: The layout is agreed on Astra's side, including the clarifications in Claude's reply, pending the owner's decisions and go-ahead. + +## Claude reply to the Astra review + +2026-09-22. Agreed and applied to the layout above: + +- `two-graphs.md` stays its own document, reachable from both pillars; Observation links to it. Imaging Problem List is not split further; Imaging Persona is one short document. +- `imaging-problem-list-uses.md` becomes `imaging-history.md`; `interoperability-demonstrations.md` becomes `rendering-search-and-exchange.md`; the catalog, the CLIs, and the early extraction experiment are list entries without pages. +- The separate `finding-models-and-cdes.md` is dropped. `oifm-repository.md` opens with the ruling and carries the two collections, content direction, and the CDE relationship once; `finding-definitions.md` carries what a definition is and the common graph as the destination. Sem-B8 and B9 go to the repository page. +- Sample Applications link to related use cases only where documented; the overview carries names and links, the list carries descriptions and status. +- SDK pages stay one per SDK as the project lead named them (finding models, anatomic locations, terminology lookup, the proposed Imaging Problem List SDK), organized inside around developer capabilities. The page keeps the name `imaging-problem-list-sdk.md` because that is the project lead's term; its body says the proposal covers Observation, Exam Finding List, and Imaging Problem List. The reporting SDK is a line in the SDK index linking to reporting assistance, not a page. +- "Restore cut material" is replaced by "recover distinct sourced ideas and necessary qualifications". Absence claims are scoped to the reviewed sources; built demonstrations stay distinguished from proposals; RadLex migration is direction with its dated state; the OIFM document-to-graph reorganization stays visible. +- The explicit-homes table is adopted; those destinations go into the placement table before splitting, together with the four corrections (Use-A5, B5, B9, A20). + +2026-09-23, project lead's correction applied: `oifm-repository.md` and `finding-definitions.md` are replaced by one encompassing `finding-models-and-cdes.md` (OIFMs and their repository, the ACR/RSNA CDEs, and the relationship between the two) and a separate `next-generation-schema.md` presenting the shared schema for both collections, which applications are expected to use together. Sem-B8 and B9 go to the encompassing document. + +2026-09-23, later: the project lead agreed that the encompassing document is a hub with three children: `oifm-content.md`, `definition-formats.md`, `identifiers.md`. Sem-B8 and B9 go to `oifm-content.md`. +- Order of work and the cross-directory review as you propose; replacement by explicit file mapping. + +Nothing outstanding between us on the layout. Remaining decisions are the project lead's: the glossary, the three naming choices, and the go. diff --git a/docs/plans/2026-09-30-brand-assets.md b/docs/plans/2026-09-30-brand-assets.md new file mode 100644 index 0000000..093b028 --- /dev/null +++ b/docs/plans/2026-09-30-brand-assets.md @@ -0,0 +1,20 @@ +# Brand assets from Tigris + +Status: complete, 2026-09-30. + +Bring the useful OIDM and Anatomic Locations brand assets from `t3://oidm-public/logos/` into the repository and record what the supplied style guide supports for website presentation. + +1. Read the style guide and inspect the logo variants alongside the site's asset pipeline. +2. Import a small selection of original SVG and PNG assets, plus the guide, with source paths and checksums. +3. Document colors, typography, variant selection, and use in site content and diagrams. Distinguish supplied rules from suggested applications. +4. Check file integrity and site asset handling. Update the site and diagram documentation, changelog, and development log, then mark this plan complete. + +The work prepares assets and guidance. Applying a new site theme or changing the existing diagrams is a separate task. + +## Result + +- Imported 16 unmodified SVG and transparent PNG assets into `knowledge/assets/brand/`, plus the original two-page guide in `docs/brand/`. +- Recorded source URIs and checksums in `docs/brand/manifest.json`. The guide's light-blue RGB and hex values disagree; the SVG artwork supports the hex value `#49b5ea`. +- Wrote `docs/brand/README.md` with source-backed guidance, separate application suggestions, and site/diagram usage examples. Updated the site and diagram READMEs, changelog, and development log. +- Local Quartz build passed. All 16 built assets match the imported bytes, all 17 source-file checksums match the manifest, and all eight SVGs embed unchanged through `excalib.image()`. +- Strict OKF validation and the house bundle checker passed with zero errors or warnings. `git diff --check` passed. No theme changes, diagram changes, deployment, or commit were made for this task. diff --git a/docs/plans/2026-10-01-linked-diagrams.md b/docs/plans/2026-10-01-linked-diagrams.md new file mode 100644 index 0000000..4285ce3 --- /dev/null +++ b/docs/plans/2026-10-01-linked-diagrams.md @@ -0,0 +1,22 @@ +# Linked diagram references + +Status: complete, 2026-10-01. Capture and summary task only; layer migration awaits the project lead's approval. + +Capture every unique URL in `links.txt` as a visual source and a concise, reusable reference to the project's ideas. + +1. Identify unique links and retrieve each original diagram, preferably as SVG and PNG. Save captures and provenance under `sources/linked-diagrams/`. +2. Inspect each diagram, using readable detail views for large boards. Check earlier transcriptions against the retrieved source. +3. Write one source-grounded Markdown summary per diagram under `docs/references/linked-diagrams/`, with an index, source URL, local artifact paths, and connections to the agreed pillars. Preserve historical wording and proposal status. +4. Verify link coverage and artifacts, review summaries for unsupported interpretations, update this plan and the development log, and mark completion. + +Repeated URLs share one capture and summary. Source boards are historical evidence; they do not override the owner's current terminology or decisions. + +## Results + +- Captured all 15 unique boards from 17 URL occurrences as native SVG and PNG exports. Preserved source contents, searchable text, timestamps, and checksums under `sources/linked-diagrams/`. +- Visually reviewed every board and wrote 15 draft Reference summaries, with an [index](../references/linked-diagrams/index.md), source locators, pillar connections, and links to related working pages. +- Preserved three XML-invalid native SVGs unchanged and provided normalized `usable.svg` copies alongside them. +- Verified URL coverage, PNG decoding, selected SVG XML, 63 artifact checksums, and every local summary link. OKF conformance reports zero errors; its 50 warnings concern links outside the standalone reference directory, whose targets were separately verified on disk. +- Updated README, DEV_LOG, and CHANGELOG for discoverability and handoff. + +The [sources and layers plan](./2026-10-01-sources-and-layers.md) arrived during capture. These short summaries remain staged in `docs/references/linked-diagrams/` until that plan is approved; conversion into its detailed reference template and figure redraws belong to that work. No bundle or presentation files were moved, and no bucket upload or site publication was performed. diff --git a/docs/plans/2026-10-01-okf-tooling-comparison.md b/docs/plans/2026-10-01-okf-tooling-comparison.md new file mode 100644 index 0000000..5029609 --- /dev/null +++ b/docs/plans/2026-10-01-okf-tooling-comparison.md @@ -0,0 +1,13 @@ +# OKF tooling comparison + +Status: complete. + +1. Record this follow-up plan. +2. Compare available OKF skills and tools using current primary sources, version coverage, maintenance, and repository fit. +3. Inspect upstream functionality missing from this installation and separate useful additions from duplication. +4. Compare search options against the repository's content, provenance requirements, and client access needs. Distinguish documented capabilities from tested results. +5. Save findings, update the development log, and mark this plan complete. Update reader-facing documentation only if behavior changes. + +Scope: research and recommendations. Keep OKF. No installation, migration, commit, or publication. + +Results: [tooling comparison](../references/okf-tooling-comparison.md). Compared current primary documentation for direct OKF skills/toolchains and adjacent search tools. Ran both installed and current scaccogatto validators and lorsabyan's validator against 29 external fixture bundles with baseline-warning adjustment; documented scope differences and a reproducible impossible-date crash. Ran the alternative validator and index generator in read-only modes against the actual bundle; recorded path-contract warnings and prose-preservation limits. Recommended selective upstream reuse and task-based search evaluation. No search performance claims or tool selection without a benchmark. Origins review and development log updated; no reader-facing behavior changed, so no changelog entry. diff --git a/docs/plans/2026-10-01-okf-tooling-review.md b/docs/plans/2026-10-01-okf-tooling-review.md new file mode 100644 index 0000000..b569f57 --- /dev/null +++ b/docs/plans/2026-10-01-okf-tooling-review.md @@ -0,0 +1,13 @@ +# OKF tooling review + +Status: complete. Scope: investigate and recommend; no tooling replacement. + +1. Record this plan before the investigation. +2. Trace the format and installed skills to their sources; inspect local changes and project-specific tooling. +3. Check current upstream tools and adjacent alternatives against the repository's needs. +4. Save findings with source links, recommend what to reuse, and mark the review complete. +5. Review relevant documentation and update the development log. Add a changelog entry only if reader-facing behavior changes. + +Preserve unrelated workspace changes. Do not commit or publish. + +Results are in [the tooling review](../references/okf-tooling-review.md). All 13 installed skill files match the September installation-era upstream revision. Checked current upstream documentation and compared newer files. Identified local policy and publishing integrations, upstream source relocation, retrieval alternatives, and compatibility issues for a future update. Documentation review complete; development log updated. No reader-facing behavior changed, so the changelog is unchanged. diff --git a/docs/plans/2026-10-01-sources-and-layers.md b/docs/plans/2026-10-01-sources-and-layers.md new file mode 100644 index 0000000..32dd54c --- /dev/null +++ b/docs/plans/2026-10-01-sources-and-layers.md @@ -0,0 +1,70 @@ +# Sources, bundle, and presentation: the three layers + +Status: Agreed in principle 2026-10-01 (the four open points answered); execution not yet started. Written by Claude from the project lead's description. Companion: `docs/HANDOFF.md` holds everything else an agent needs. + +## The project lead's description, verbatim + +> I'd like to have a literal knowledge bundle of OKF files which are mostly for internal team use. They're in a public repo, and anyone can look at them and see what they see, but they're not what we'd present. We'd ALSO like to have a series of interconnected pages that ARE intended as the outward presentation of these ideas, where the knowledge for them is a distillation of the broader knowledgebase to make it more accessible to outsiders. + +> I would ALSO like to maintain something like source material. I will create a non-public bucket on tigris for raw source material (presentations, manuscripts, emails, etc.). I (or people I give appropriate credentials to) can access that bucket to fill out a raw-sources directory, but this is NOT in the repo. We will generate DETAILED distilled summaries with key quotes and ESPECIALLY extracted graphics into a references directory. We can cite these in our knowledge bundle as needed, and if required go back and dig into the raw source. + +> I would promote "paraphrase and describe figures" to "generate new versions of the figures capturing key points". + +## The layers + +| Layer | Where | In the repo? | Audience | Content | +|---|---|---|---|---| +| Raw sources | private Tigris bucket, mirrored to `raw-sources/` | no (gitignored); a manifest is | credentialed team | presentations, manuscripts, emails, boards, spreadsheets, as supplied | +| References | `knowledge/references/` | yes | team | one OKF Reference per raw source: detailed distilled summary, key quotes where allowed, figures (extracted or redrawn), pointer to the raw file | +| Knowledge bundle | `knowledge/` | yes | team (public by virtue of the repo) | comprehensive OKF concepts mined from every source, citing references; reorganized under the five pillars over time | +| Presentation | `pages/` | yes | outsiders | the interconnected pages agreed with the project lead, each a distillation citing bundle pages; what the site builds | + +Each layer cites the one below it. Nothing on the site links into the raw layer. + +## Raw sources + +- The bucket is `oidm-knowledge-sources` on Tigris, private; credentials are the project lead's to grant and are never recorded in the repo. +- `raw-sources/` is gitignored. A `raw-sources/MANIFEST.json` (tracked) lists each file: bucket path, size, SHA-256, date added, a one-line description, and a sensitivity class (`public`, `restricted-until-published`, `internal`). +- A task `task sources:pull` mirrors the bucket into the directory with the t3 tool; `task sources:check` verifies the manifest against the directory. +- The current `sources/` directory becomes `raw-sources/` once the bucket exists; its extracted text and the bucket report move with it. Nothing in it is deleted. + +## References + +One document per raw source, type `Reference`, from a fixed template: + +- frontmatter: title; the raw file's manifest id and checksum; producing organization; date; status of the source (public talk, manuscript under review, internal board, email note); sensitivity class; who extracted it and when. +- body: what the source is and why it matters; a detailed distilled summary, section by section; key quotes, each with its location; the source's figures, one subsection each, with the figure file beside the reference; the claims other documents are likely to cite, each with its location; open questions the source raises. +- figures: for `public` sources, extracted as supplied (with the extraction method recorded); for `restricted-until-published` and `internal` sources, redrawn with the diagram tooling as a new figure capturing the key point, the builder recording which source figure it distills. The original stays in the raw layer. +- rules: organizations only, never an individual; reviewer correspondence never summarized or quoted; for a manuscript under review, no quotes until published; vendor names generalized where the project lead has said so. + +## Knowledge bundle + +Unchanged in role: the comprehensive, team-facing OKF bundle. Changes from this plan: + +- Concepts cite references by id instead of gitignored paths or bucket URLs. +- The bundle's own reorganization under the five named pillars (Foundation Context, Data Structures, SDKs, Use Cases, Sample Applications) is a separate track, mostly Astra and agent work, since its readers are the team. Nothing is deleted for being too detailed; the glossary stays dropped per the 2026-09-29 decision. + +## Presentation + +- The pages agreed with the project lead move from `knowledge/drafts/` to `pages/`, in the directory layout of `docs/plans/2026-09-22-layout-plan.md`, with the Overview at the root. +- The public site builds from `pages/` only. A separate internal site builds from `knowledge/` (the bundle) as its own Cloudflare static Worker, for the team. +- Release gating, decided 2026-10-01: no presentation page reaches the production site until the project lead has reviewed it (`verified` set by `task verify`). Pre-review pages go only to staging, and EVERYTHING deployed to staging carries a visible "DRAFT / Awaiting Review" label on every page. The production build fails if any page lacks a `verified` entry. +- Presentation pages keep frontmatter (status, provenance, sources) and cite bundle pages; the same validators run on both directories. + +## Steps, once agreed + +1. Manifest and sync task; move `sources/` to `raw-sources/`; gitignore update. +2. Reference template; convert the eight sources already summarized (the two SIIM decks, the January deck, the three manuscripts, the reporting-schema deck, the AI-evolution essay) and the board transcription into references; redraw figures for restricted sources. +3. Re-point bundle citations at the references. +4. Create `pages/`, move the agreed drafts, point the public site build at it, reorder the explorer to the five pillars, make the Overview the landing page. +4a. Site gating: a build-time switch that stamps "DRAFT / Awaiting Review" on every page for dev and staging builds, and a production build that refuses any page without a `verified` entry. Reviewed with the project lead before implementing (tool and approach choices are always reviewed first). +4b. Internal site: a third Worker (`oidm-knowledge-internal`) building the bundle from `knowledge/` with the same banner rule; access control to be decided with the project lead (Cloudflare Access is the obvious candidate; review first). +4c. Deploy the presentation to dev, then staging, for the project lead's verification pass. +5. Dashboard and layout plan updated; DEV_LOG and CHANGELOG entries. + +## Decisions, 2026-10-01 + +- Presentation directory: `pages/`. +- The bundle gets an internal site build on a Cloudflare static Worker. +- Nothing pre-review on production; staging only, every page labeled "DRAFT / Awaiting Review". +- Bucket: `oidm-knowledge-sources` (private). diff --git a/docs/plans/idea-inventory-semantic.md b/docs/plans/idea-inventory-semantic.md new file mode 100644 index 0000000..7bb9eb0 --- /dev/null +++ b/docs/plans/idea-inventory-semantic.md @@ -0,0 +1,1970 @@ +# Idea inventory: the semantic ideas + +Step 1 of [restructure-around-project-ideas.md](restructure-around-project-ideas.md), Claude side. +Area: finding models and their relationship to ACR/RSNA common data elements; anatomic locations +and their relationship to RadLex; exam types; the terminologies underneath. + +This is a working inventory, not a draft of any page. It records distinct ideas the team has +expressed or demonstrated, with pinned evidence. It does not reconcile disagreements and does not +supply motivation the sources do not state. + +## How to read an entry + +**Status** is one of *stated goal*, *working proposal*, or *implemented example*. One idea can carry +several. + +**Implemented** says what the code or content actually does about the idea, in the idea's own terms, +with a pointer. It does not reproduce install steps, usage documentation, or schemas. + +**Evidence** names the specific document, prompt, skill, or data file and what it says. Prompts are +primary sources: they are where the team's operational definitions are written down and enforced. +Pointers take the form `path @ branch commit`. Manuscripts under peer review are paraphrased, never +quoted, and are not treated as accepted fact; their reviewer correspondence was not read. People are +not named; organizations and roles are. + +## Commit pins + +| Repository | Branch | Commit | +|---|---|---| +| `findingmodel` | `main` | `75afd39` | +| `findingmodel` | `dev` | `504a42a` | +| `findingmodel` | `feature/metadata-cleanup` | `1942b06` | +| `findingmodels` | `main` | `4475ac1` | +| `findingmodels` | `taxonomy-export-2026-08-15` | `a30c3c9` | +| `findingmodels` | `content/chestcts` | `0472a46` | +| `findingmodels` | `findingmodels-metadata` | `dcc6c4c` | +| `ACR-RSNA-CDEs` | `next-gen-2026` | `44836c1` | +| `CDEStaging` | `main` | `b814a10` | +| `anatomiclocations.org` | `main` | `1f39fa4` | +| `anatomiclocations.org` | `content_work` | `35624d7` | +| `BodyPartIndex.py` | `main` | `388ae0a` | +| `BodyPartIndex.ts` | `main` | `dec578e` | +| `RadLex` | `main` | `13a5abe` | +| `RadLex` | `experiment/kg-radlex-parsing` | `5162a65` | +| `med-ontology-lookup` | `main` | `a1fd3ae` | +| `med-ontology-lookup` | `issue-3-typed-provider-failures` | `9cc3eec` | +| `med-ontology-lookup` | `docs/reviewed-proposal-backlog` | `f059792` | + +Non-repository sources: the Anatomic Locations Index manuscript under review at JDIM +(`sources/bucket/text/jdim-02183.md`, manuscript body pages 3 to 17 only); the SIIM Enterprise +Imaging webinar of 15 July 2026 (`sources/bucket/text/ipl-webinar-deck.md`); the Next Gen Object +Oriented Reporting Schema deck of 15 September 2026 (`sources/bucket/REPORT.md` §6); fifteen +Excalidraw boards (`sources/excalidraw-diagrams.md`); the project lead's goals recorded in +`knowledge/plans/2026-09-20-knowledgebase-build-plan.md`. + +--- + +# A. What a finding model is + +## A1. Finding model + +**Idea.** A finding model is "a structured, machine-readable definition of an observation a +radiologist would name in a report." The library of models is framed not as a label set but as the +knowledge base that lets downstream systems turn unstructured report text into structured +observation objects, each tagged with the finding type and its attribute values. Two guiding +principles are stated together: a finding is a noun phrase and everything else is an attribute; and +findings exist in time, because a report is a snapshot while the findings it describes persist +across exams. + +**Status.** Implemented example, with the rationale stated. + +**Implemented.** Two model classes with the same docstring express the authoring lifecycle: a base +model carrying name, description, synonyms, tags and attributes with no identifiers, and a full +model adding the finding identifier, per-attribute identifiers, per-value codes, index codes, +anatomic locations and contributors. An abstract protocol names the surface both share. +`packages/findingmodel/src/findingmodel/finding_model.py @ main 75afd39`; +`packages/findingmodel/src/findingmodel/abstract_finding_model.py @ main 75afd39`. + +**Evidence.** +- The `core_concept.md` prompt fragment, "What a finding model is" and "Two guiding principles" — + the definition, the noun-phrase principle, and the findings-exist-in-time argument that justifies + a change-from-prior attribute on every model. + `prompts/fragments/core_concept.md @ taxonomy-export-2026-08-15 a30c3c9` +- The "Finding Models: Overview" authoring document, "Why Finding Models Exist" — the report to + observation to downstream pipeline, and the claim that the definitions carry meaning rather than + names. `notes/oifm-overview.md @ next-gen-2026 44836c1` (a verbatim copy of the upstream + `prompts/overview.md`). +- The "Finding Model Schema" document, "Main Finding Model Object" — required identifier, name, + description and attributes; optional synonyms, tags, contributors and index codes. + `schema/finding_model_schema.md @ taxonomy-export-2026-08-15 a30c3c9` +- The "OIFM Repo" Excalidraw board, handwritten explainer panel — the team's own plain-language + framing: "Writing the dictionary to translate from radiologist language to computer-speak and + back." `sources/excalidraw-diagrams.md` + +**Related.** A2, A3, A5, A6, A9, B1. + +**Disagreements.** Naming differs across the allied work: *finding model / attribute / value* in the +finding model documents, *FindingClass / DataElement / Value* in the next-generation vocabulary, +*Finding / Attribute* in an earlier committee-facing deck. The rename decision and the table of who +said what are recorded in "Next-Generation CDE Schema: Current Understanding" §6 +(`docs/next-gen-schema/00-current-understanding.md @ next-gen-2026 44836c1`). + +**Undetermined.** Whether one vocabulary absorbs the other. Issue F of that same document states the +open alternatives and does not choose. + +--- + +## A2. What counts as a finding + +**Idea.** The boundary is drawn by a test: would a radiologist write "there is [X]" or "no [X]" as a +standalone statement? Findings include pathology, physiologic observations, devices and hardware, +postsurgical states, anatomic variants, image-quality observations, and diagnoses. What is excluded +is enumerated just as carefully: a state of a finding ("stable cardiac silhouette"), a qualified +version of another finding ("large pleural effusion"), normal anatomy, radiographic signs and +interpretation techniques ("silhouette sign", "double density sign", "air-fluid level"), and exam +metadata, history or recommendations. A generic descriptor can become a finding when anatomic +context makes it reportable on its own: "air-fluid level" is not a finding, "air-fluid levels in +bowel" is. + +**Status.** Stated as doctrine in prompts; enforced as a review checklist item, not by code. + +**Implemented.** The quality-review checklist opens with the noun-phrase and level-of-abstraction +checks, and the review skill runs that checklist against one file at a time. +`prompts/fragments/quality_checklist.md @ taxonomy-export-2026-08-15 a30c3c9`; +`.claude/skills/finding-review/SKILL.md @ taxonomy-export-2026-08-15 a30c3c9`. + +**Evidence.** +- The `core_concept.md` fragment, "What counts as a finding" and "What is NOT a finding" — the six + inclusion categories and the five exclusion categories, with the air-fluid-level boundary case. + `prompts/fragments/core_concept.md @ taxonomy-export-2026-08-15 a30c3c9` +- The "Finding Models: Overview" document, "The 'Would a radiologist report it?' Test" — the same + test with worked yes and no cases. `notes/oifm-overview.md @ next-gen-2026 44836c1` +- The "Open Imaging Finding Models" Excalidraw board, box "Finding Model Rules" — an earlier draft + of the same guidance, adding two rules the current fragments do not state in those words: avoid + "associated findings" where a related finding is clinically distinct, and consider splitting + clearly distinguishable sub-types into separate models. `sources/excalidraw-diagrams.md` + +**Related.** A1, A3, A4, A5, B7. + +**Disagreements.** The board's sub-type rule (split solid from part-solid pulmonary nodule) sits +against the next-generation vocabulary's stated presumption to lean toward the general class with +location carried separately, which "What the Vocabulary Must Express" §2.4 calls "the +highest-frequency modelling decision in the corpus" and records as unresolved. +`docs/next-gen-schema/01-what-the-vocabulary-must-express.md @ next-gen-2026 44836c1` + +**Undetermined.** Whether the board rules were superseded deliberately. The board is undated in the +transcription. + +--- + +## A3. Specificity, splitting, and the right level of abstraction + +**Idea.** Three related questions are answered by one document: is this one finding or several; is +this subtype a value on the parent or its own model; is this name at the right level. Compound names +joining two entities split when one part can be present while the other is absent. A subtype becomes +its own model when it is a fundamentally distinct observation rather than the same observation with +a qualifier, with a practical signal offered: you would need different attributes to describe it. +"Tension pneumothorax" is not "pneumothorax, type: tension" because it has its own signs and its own +management implications. A descriptor plus entity earns its own model when the combined phrase +carries meaning beyond the sum of its parts: "calcified nodule" implies a benign fully calcified +lesion while "nodule with calcifications" implies one that may still warrant follow-up. Findings at +several levels may coexist when radiologists report at both. + +**Status.** Stated as authoring doctrine; applied by judgment. + +**Implemented.** The review sub-agent returns extraction candidates naming the exact attributes that +should become their own model, and those candidates are recorded rather than auto-applied. +`.claude/skills/finding-review/SKILL.md @ taxonomy-export-2026-08-15 a30c3c9`, steps 4 and 5. + +**Evidence.** +- The `scope_and_specificity.md` fragment — the compound-splitting test, the subtype decision + question, the descriptor-plus-entity test, and the too-broad / too-narrow / right-level worked + lists. `prompts/fragments/scope_and_specificity.md @ taxonomy-export-2026-08-15 a30c3c9` +- The "Finding Models: Overview" document, "Specificity and Scope" — the same material in the + upstream authoring guidance. `notes/oifm-overview.md @ next-gen-2026 44836c1` + +**Related.** A2, A4, A7, B7. + +**Disagreements.** None within the finding model documents. + +--- + +## A4. Negative assertion as a first-class finding + +**Idea.** "No fracture" and "the upper abdomen is unremarkable" are active observations of absence, +so the library deliberately carries broad scoped findings such as "chest wall fracture" and "upper +abdominal abnormality" purely so that absence can be asserted against something. The scope of such a +finding is set by what is assessable on an exam: "fracture" is too broad because it spans the whole +body, "chest wall fracture" is right for a chest radiograph, "upper abdominal abnormality" is right +for a chest CT because the upper abdomen is in the field of view. + +**Status.** Stated as an authoring rule; implemented in every model's first attribute; reappears as +a structural requirement in the next-generation vocabulary. + +**Implemented.** Every model carries `presence` as its first attribute with the four values absent, +present, indeterminate and unknown, and the creation script emits it unconditionally. Any source +offering only yes/no or bare present/absent is upgraded to the full four-value set. +`prompts/fragments/presence_and_change.md @ taxonomy-export-2026-08-15 a30c3c9`; +`packages/findingmodel/src/findingmodel/create_stub.py @ main 75afd39`. + +**Evidence.** +- The `scope_and_specificity.md` fragment, "Findings must cover negative assertions" and "Scoped + broad findings (for 'no X' assertions)" — the rule and the two worked names. + `prompts/fragments/scope_and_specificity.md @ taxonomy-export-2026-08-15 a30c3c9` +- "What the Vocabulary Must Express" §1 — why a finding class must be a term rather than a set of + actual lesions, so that an observation carrying `presence: absent` is not pointing at a nodule + that does not exist; and §5, where `grouping` is dropped as a classification value and returns as + a narrow node type for negative-only nodes such as "renal abnormality". + `docs/next-gen-schema/01-what-the-vocabulary-must-express.md @ next-gen-2026 44836c1` +- The SIIM webinar worked Exam Finding List — a pertinent negative, "no filling defect to suggest + pulmonary embolism," coded as present/absent rather than omitted. + `sources/bucket/text/ipl-webinar-deck.md` + +**Related.** A2, A5, B5, C1. + +**Disagreements.** Whether negation propagates down the finding hierarchy is open. "Current +Understanding" Issue A records the motivating case and states the three conditions it depends on, +including a closed-world assumption that the radiologist actually assessed everything beneath the +class. `docs/next-gen-schema/00-current-understanding.md @ next-gen-2026 44836c1` + +--- + +## A5. Description and diagnosis both count + +**Idea.** Radiologists both describe what they see and name what they conclude, and the team models +what radiologists actually say rather than what a cleaner ontology would prefer. The authoring +guidance is explicit that diagnostic terms are first-class findings and instructs authors not to +question whether a diagnosis "should" be one. + +**Status.** Stated as an authoring rule; implemented as data in two different ways. + +**Implemented.** In the exam-oriented sub-taxonomies the distinction is a column, `finding_type`, +separating an observation from a diagnosis on every row; the CT head list types 261 rows observation +and 222 diagnosis, the CT chest/abdomen/pelvis list 1,371 and 448. +`lists/README.md @ taxonomy-export-2026-08-15 a30c3c9`. In the metadata work it becomes a model-level +enumeration, `entity_type`, whose assignment prompt draws the line: diagnosis for named diseases, +disorders, injuries, complications, syndromes and disease entities; finding for broad observations, +descriptive lesions, morphology, enhancement patterns, effusions and umbrella abnormality labels. +`packages/findingmodel-ai/src/findingmodel_ai/metadata/prompts/entity_type.md @ feature/metadata-cleanup 1942b06`. + +**Evidence.** +- The `core_concept.md` fragment, "What counts as a finding" — diagnoses listed with the + instruction "Do not question whether a diagnosis 'should' be a finding." + `prompts/fragments/core_concept.md @ taxonomy-export-2026-08-15 a30c3c9` +- The `entity_type.md` assignment prompt — the operational rule set, including that source tags are + weak context and must not alone determine the type, and that negative findings, artifacts, + assessments and recommendations must not be converted into diseases merely because they imply + clinical consequences. + `packages/findingmodel-ai/src/findingmodel_ai/metadata/prompts/entity_type.md @ feature/metadata-cleanup 1942b06` +- "What the Vocabulary Must Express" §1 and §5 — the finding and diagnosis definitions taken over + from the finding model guidance unchanged, with the observation that the classification is of the + term as used, not of the bodily state. + `docs/next-gen-schema/01-what-the-vocabulary-must-express.md @ next-gen-2026 44836c1` + +**Related.** A1, A9, B5. + +**Disagreements.** Three positions coexist. The finding model corpus keeps finding and diagnosis as +values of one field on one kind of object. The next-generation vocabulary makes Diagnosis a separate +node type while keeping one taxonomy that crosses the labels, with the "X without Y" test as the +subsumption criterion ("empyema without effusion" is not a sentence, so empyema is a subtype of +pleural effusion across the label boundary). An external reviewer's alpha implementation declares +the two disjoint in OWL, with probes that expect a finding which is also a diagnosis to be +unsatisfiable. The comparison document records this as decision area ST03, to be worked through +rather than settled. `docs/next-gen-schema/07-relationship-family.md` §2 and +`docs/next-gen-schema/12-alpha-structural-comparison.md` §3 @ `next-gen-2026 44836c1`. Separately, +the profile of the exam-oriented sub-taxonomies notes that no diagnosis is ever placed under an +observation in those files, which the unrestricted taxonomy would change, and marks it "worth +raising with the author". `notes/hood-taxonomies-profile-2026-09-01.md @ next-gen-2026 44836c1` + +--- + +## A6. Presence and change from prior + +**Idea.** Every finding model carries two standard attributes first and in order: presence, then +change from prior. Change from prior is not a single vocabulary but a minimum set (unchanged, +stable, new, resolved) plus at least one clinically appropriate direction-of-change pair, and the +instruction is to include every descriptor a radiologist might reach for rather than the single best +one, because "over-inclusion is cheap; under-inclusion causes missed matches." A pleural effusion can +be described as larger, increased, or worsened, so all three pairs go in. Categories that cannot +change that way get the minimum set only: devices and hardware, congenital variants, postsurgical +states, and technique observations. Individual pairs are dropped where they make no sense even when +others apply, so a fracture can be new, resolved or unchanged but does not get larger. + +**Status.** Implemented example, with the rationale stated. + +**Implemented.** The creation script emits the minimum set by default and takes direction pairs as an +explicit opt-in flag per model or per batch entry; it also strips the awkward leading article from +the generated attribute description. The quality-review step then confirms the pair choice, and a +separate script modifies pairs after the fact. +`prompts/fragments/presence_and_change.md @ taxonomy-export-2026-08-15 a30c3c9`, "What the create +script does, and what review must catch". + +**Evidence.** +- The `presence_and_change.md` fragment — the two required attributes and their order, the four + presence values, the three direction pairs with the finding categories each suits, the exclusion + categories, and a grammar section governing the attribute description (plural verbs for plural + nouns, article agreement, no article for mass nouns). + `prompts/fragments/presence_and_change.md @ taxonomy-export-2026-08-15 a30c3c9` +- The `core_concept.md` fragment, "Findings exist in time" — the temporal justification for + requiring change from prior on every model. + `prompts/fragments/core_concept.md @ taxonomy-export-2026-08-15 a30c3c9` +- The "Open Imaging Finding Models: Pipeline and Repo" flowchart on the "OIFM Repo" board — the + same two attributes, plus optional location and size, as the defining shape of a stub. + `sources/excalidraw-diagrams.md` + +**Related.** A1, A4, A8, A12. + +**Disagreements.** The upstream-proposals document records that the library's own stub creator +emitted all eight change-from-prior values unconditionally and generated an awkward description, that +12 of 14 models in a head-CT test batch had their pairs winnowed by review, and that every one had +the article flagged; it proposes inverting the default. This is a recorded defect in the library, not +a dispute about the rule. `docs/plans/findingmodel-upstream-proposals.md @ taxonomy-export-2026-08-15 a30c3c9`, item B1. + +--- + +## A7. Synonyms as the matching surface + +**Idea.** Synonyms are how unstructured report text reaches a model, so the instruction is to be +aggressive about collecting them: formal and informal forms, acronyms, eponyms, brand names, +spelling variants, plurals, and common report phrasings such as "air under the diaphragm" for +pneumoperitoneum. The strictness rule is the counterweight: every synonym must mean the exact same +thing at the same level of specificity, because "a bad synonym doesn't just fail to match — it +matches the *wrong thing*." Subtypes are never synonyms. A taxonomy of traps is given: sign versus +disease (Kerley B lines are not interstitial pulmonary edema), consequence versus cause, different +pathophysiology (ventricular hypertrophy is not enlargement), different procedure (kyphoplasty is +not vertebroplasty), device subtype, and wrong anatomic scope. + +**Status.** Implemented example (the rule is enforced procedurally at authoring time). + +**Implemented.** Two checks run before a synonym is added. A collision check searches the corpus and +branches three ways: the term already sits on a model meaning the same thing, which signals a +possible duplicate model and is flagged rather than merged; the term sits on a model meaning +something different, in which case it is added to neither and the ambiguity is flagged; or it is not +found, and is safe. A pre-emptive cross-body-region check then asks whether the term is canonical for +a different finding elsewhere even if the corpus does not yet contain that model, with follicular +cyst, cavernous hemangioma, adenoma, carcinoid and nodule named as traps. +`prompts/fragments/synonym_rules.md @ taxonomy-export-2026-08-15 a30c3c9`. + +**Evidence.** +- The `synonym_rules.md` fragment — the aggressiveness instruction, the same-meaning-same-specificity + test, the nine-row trap taxonomy, the collision procedure, and the cross-body-region check. + `prompts/fragments/synonym_rules.md @ taxonomy-export-2026-08-15 a30c3c9` +- The `naming.md` fragment, "When to keep the unscoped short form as a synonym" — the rule that + generic imaging descriptors such as hypoattenuation, enhancement, calcification, lucency and + sclerosis fail the test because context does not reliably disambiguate them at the language-model + layer. `prompts/fragments/naming.md @ taxonomy-export-2026-08-15 a30c3c9` + +**Related.** A1, A8, E2. + +**Disagreements.** None recorded. + +--- + +## A8. Naming conventions + +**Idea.** Names are lowercase with spaces, acronyms expanded with the acronym kept as a synonym, +eponyms minimized, brand names replaced by the generic term. A name must be self-describing enough +that someone scanning thousands of models can tell what each is about, which means an anatomic +anchor: "pulmonary linear opacity" not "linear opacity". The anchor must be real anatomy rather than +a generic tissue-type modifier, because "parenchymal", "cortical", "stromal" and "medullary" are +ambiguous across organs. Names carry no parenthetical qualifiers, no population qualifiers, no "with" +clauses embedding an associated finding, and no comma lists; slashes are handled by type, splitting +genuinely different findings, converting locations or severities into an attribute, and demoting +truly interchangeable terms to synonyms. + +**Status.** Implemented for models the project authored; not yet true of imported content. + +**Implemented.** A deterministic linter checks underscores, lowercase, self-synonyms and the rest, +labelling each hit an error (definitely wrong, auto-fixable), a warning (needs human confirmation), +or a review item (needs language-model judgment). Filenames are derived mechanically from the name, +and the rule that a name producing consecutive underscores must be simplified is a naming rule +justified by that derivation. +`prompts/fragments/mechanical_lint.md` and `prompts/fragments/naming.md @ taxonomy-export-2026-08-15 a30c3c9`. + +**Evidence.** +- The `naming.md` fragment — casing, canonical forms with worked substitutions, the self-describing + rule with the tissue-modifier trap, the conciseness rules, and the slash typology. + `prompts/fragments/naming.md @ taxonomy-export-2026-08-15 a30c3c9` +- The "Definition Cleanup Plan" — nine mechanical defect classes traceable to imported content, + including title case on common-data-element and institutional models, "with" clauses, and + population qualifiers such as "cerebellar mass in a child", each with worked examples. + `docs/plans/definition_cleanup.md @ taxonomy-export-2026-08-15 a30c3c9` + +**Related.** A7, A11, B12. + +**Disagreements.** None on the rules. The cleanup plan's own corpus counts disagree with the +identifier registry shipped in the same tree, because the plan was written at an earlier commit. + +--- + +## A9. Assessment schemes modeled apart from what they assess + +**Idea.** A scoring system is a valid finding model but a different model from the observation it +scores. A pulmonary nodule model captures what the nodule looks like; a Lung-RADS model captures the +risk category assigned to it. The stated reason is that different radiologists can describe the same +nodule identically and assign different categories, so systems need to reason about the two +independently. Measurement groupings are also valid findings, where "the 'finding' is the act of +performing a structured quantitative assessment, and the attributes are the measurements within it." + +**Status.** Stated as an authoring rule; implemented as a metadata value; extended into a node type +in the next-generation vocabulary. + +**Implemented.** `assessment` is a value of the entity-type enumeration, and its assignment prompt +defines it as a score, grading scale, classification, reporting category, or grouped +measurement-and-interpretation package, distinct from `measurement`, which is one quantitative +metric. +`packages/findingmodel-ai/src/findingmodel_ai/metadata/prompts/entity_type.md @ feature/metadata-cleanup 1942b06`. + +**Evidence.** +- The `scope_and_specificity.md` fragment, "Scoring systems and structured assessments are valid + findings" — the rule with its stated reason, and the measurement-grouping paragraph. + `prompts/fragments/scope_and_specificity.md @ taxonomy-export-2026-08-15 a30c3c9` +- The "Definition Cleanup Plan", reclassification section — pushback from the data side, flagging + imported entries such as "Alpha Angle Measurement" as quantification tools rather than + observations, which is why they lack presence. + `docs/plans/definition_cleanup.md @ taxonomy-export-2026-08-15 a30c3c9` +- "The Finding and Diagnosis Relationship Family" §1 — `ASSESSED_BY` from a finding or diagnosis to + an assessment, with `INTERPRETED_FROM` as its finer twin naming the specific inputs a scheme is + computed from. `docs/next-gen-schema/07-relationship-family.md @ next-gen-2026 44836c1` + +**Related.** A5, B6, B8. + +**Disagreements.** None recorded. + +--- + +## A10. Associated findings versus components + +**Idea.** Two different kinds of related thing get two different treatments, distinguished by an +independence test. An associated finding is separate and independent with its own lifecycle — +pneumonia and pleural effusion each occur alone — and is modelled as one multichoice attribute on +the index model, presence-level only, whose values name real finding models. A component is an +intrinsic part of the finding itself — the solid component of a mixed pulmonary nodule — and is +extracted into its own model; the parent may record only its presence or its count, never its size, +density or morphology, because those belong to the component's own model. Three signals mean +something needs extraction: prefixed attributes such as "solid component size", groups of attributes +all describing the same sub-entity, and characterization beyond presence of something other than the +index finding. + +**Status.** Stated as an authoring rule and enforced as a lint check on one branch; contradicted by +another branch. + +**Implemented.** The deterministic linter checks the associated-findings shape, flagging attributes +scattered as separate "presence of X" entries rather than consolidated into one multichoice +attribute. Extraction candidates surface in the review sub-agent's output field rather than being +applied automatically. +`prompts/fragments/mechanical_lint.md` and `prompts/fragments/associated_vs_component.md @ taxonomy-export-2026-08-15 a30c3c9`. + +**Evidence.** +- The `associated_vs_component.md` fragment — both independence tests, the one-attribute rule with + its worked shape, the parent-may-record-count rule, and the three extraction signals. + `prompts/fragments/associated_vs_component.md @ taxonomy-export-2026-08-15 a30c3c9` +- The "Open Imaging Finding Models" board, "Finding Model Rules" — the earlier and stricter form of + the same instinct: avoid associated findings, give a clinically distinct related finding its own + model. `sources/excalidraw-diagrams.md` + +**Related.** A2, A3, B8. + +**Disagreements.** Direct and unresolved. The chest CT content branch's project specification +forbids an associated-findings attribute outright and requires separate findings instead, the +opposite of the main rule. Its own output does neither cleanly: a converted model carries exactly the +scattered per-finding presence attributes the main linter treats as a defect. +`PROJECT_SPECIFICATION.md` parts 4 and 9, and `defs/from_cdestaging_ct_chest/aberrant_subclavian_artery.fm.json`, +both `@ content/chestcts 0472a46`. + +--- + +# B. How the content is made + +## B1. Identifiers that carry provenance + +**Idea.** A finding model identifier has the form `OIFM_{ORG}_{six digits}`, an attribute +`OIFMA_{ORG}_{six digits}`, and a choice value a code derived from its attribute's identifier. The +three-or-four-letter middle segment is the contributing organization, so provenance is legible from +the identifier itself and different institutions can mint without a central allocator. + +**Status.** Implemented example. + +**Implemented.** Identifier allocation queries the published index for identifiers already used by +that organization code, then draws random six-digit candidates with collision retry; promoting a base +model to full mints the model identifier and any missing attribute identifiers. Choice-value codes +are generated mechanically from the parent attribute's identifier. A validator enforces global +uniqueness of both identifier kinds and additionally detects case-folded name conflicts, normalized +slug conflicts, and an attribute identifier owned by a different model — duplicate detection at the +identifier level, not the semantic level. +`packages/findingmodel/src/findingmodel/index.py` and +`packages/findingmodel/src/findingmodel/index_validation.py @ feature/metadata-cleanup 1942b06`; +`packages/findingmodel/src/findingmodel/finding_model.py @ main 75afd39`. + +**Evidence.** +- The "Finding Model Structured Metadata Fields" reference, identity fields — the pattern and the + statement that the prefix is the contributing organization code, with a worked identifier. + `notes/oifm-metadata-fields.md @ next-gen-2026 44836c1` +- The repository's own `CLAUDE.md` — the identifier patterns, the rule that generated artifacts are + never hand-edited, and the validator workflow that regenerates them. + `CLAUDE.md @ taxonomy-export-2026-08-15 a30c3c9` +- The "OIFM Repo" board, notes "Identifier format" and "Prelim OIFM ID" — the earlier form + `OIFM_CRTR_123456`, the source-organization list, and a serial scheme of days since 2025-01-01 + plus random digits. `sources/excalidraw-diagrams.md` + +**Related.** A1, B2, C3. + +**Disagreements.** The next-generation vocabulary mints from a single fresh namespace with no +organization segment, and "Current Understanding" Issue E records as open "whether the ID space is +partitioned for distributed minting", naming the finding model organization segment as the existing +mechanism for exactly that. +`docs/next-gen-schema/00-current-understanding.md @ next-gen-2026 44836c1` + +--- + +## B2. Corpus as a merge of uneven provenance streams + +**Idea.** The corpus is not one authoring effort but several merged. Counted from the identifier +registry, 2,382 finding models come from five sources: 1,933 derived from the Radiology Gamuts +Ontology, 256 authored by the project, 115 from ACR/RSNA common data elements, 47 from an +institutional contributor, and 31 from a vendor. Each stream carries its own defects, and the cleanup +plan traces nine mechanical defect classes to specific streams. + +**Status.** Implemented example (the corpus); stated cleanup plan, still marked draft. + +**Implemented.** Conflicting imports are quarantined rather than deleted: eighteen files sit in a +`conflicts/` tree under subdirectories named for the collision they represent, held out of the live +corpus. `conflicts/ @ taxonomy-export-2026-08-15 a30c3c9`. + +**Evidence.** +- The identifier registry — the per-organization counts above. + `ids.json @ taxonomy-export-2026-08-15 a30c3c9` +- The "Definition Cleanup Plan" — the nine defect classes with per-class counts and worked examples, + and the observation that some Gamuts-derived entries are differential-diagnosis patterns rather + than findings at all. `docs/plans/definition_cleanup.md @ taxonomy-export-2026-08-15 a30c3c9` + +**Related.** A8, B3, B12. + +**Disagreements.** The cleanup plan's counts (2,379 models) differ from the registry shipped beside +it (2,382), because the plan was written at an earlier commit. The webinar states 2,458 as of July +2026. These are freshness differences, not conflicting claims. + +--- + +## B3. Stub creation and iterative improvement + +**Idea.** Most of a finding model can be produced mechanically. A list of finding names is drawn +from three sources — an existing ontology, subject-matter experts, and a model reading real report +text — and every name becomes a stub carrying presence and change from prior, plus location and size +where the finding has them. Stubs get identifiers immediately so they can be used at once, and are +then improved through four named iteration modes: experts propose changes and a model edits the JSON +for them; a model proposes improvements from reference material it may find itself; sites download a +kit, combine their own report text with published models, and submit pull requests; and outside +groups review models and endorse them. + +**Status.** Implemented example for stub creation and two iteration modes; working proposal for the +site kit and the endorsement mode. + +**Implemented.** Stub creation emits a base model with exactly the two canned attributes. A separate +optional step drafts a richer description with citations and prints it for review without touching +the model file; a fix script writes an approved description and synonym list back in. The enrichment +fragment restricts this to single-finding work and tells batch flows to skip it as too slow. +`packages/findingmodel/src/findingmodel/create_stub.py @ main 75afd39`; +`prompts/fragments/enrichment.md @ taxonomy-export-2026-08-15 a30c3c9`. + +**Evidence.** +- The "Open Imaging Finding Models: Pipeline and Repo" flowchart on the "OIFM Repo" board — the + three sources, the stub fields, and the four iteration modes with their descriptions; the + "Community Connect 2024-11-07" note on the same board gives the same approach as a method for + creating data models at scale. `sources/excalidraw-diagrams.md` +- The `enrichment.md` fragment — when to use the description-drafting step and when not to. + `prompts/fragments/enrichment.md @ taxonomy-export-2026-08-15 a30c3c9` + +**Related.** A6, B4, B5, B12. + +**Undetermined.** Whether the downloadable site kit or the endorsement mode were ever built. No +artifact was found for either. + +--- + +## B4. Triage before create + +**Idea.** Nothing is authored before the corpus has been searched properly. Two or three +complementary search targets are generated per candidate, run, and the pooled results judged for +exact semantic match by the agent itself, which reports one of three outcomes: an exact match, no +match after reasonable search, or true ambiguity. The instruction "Do not forward raw result lists to +the user" makes the judgment the agent's job rather than the reader's. + +**Status.** Implemented example. + +**Implemented.** The search-and-triage fragment lists six specificity traps that the judgment must +avoid. On the chest CT content branch the triage becomes a persisted artifact: each source record +gets its search targets, a decision, the matched identifier, and the full candidate list with the +query that surfaced each, committed alongside the converted models. +`prompts/fragments/search_and_triage.md @ taxonomy-export-2026-08-15 a30c3c9`; +`reviews/triage_cdestaging_chunk_1.json @ content/chestcts 0472a46`. + +**Evidence.** +- The `search_and_triage.md` fragment — the procedure, the three outcomes, and the traps. + `prompts/fragments/search_and_triage.md @ taxonomy-export-2026-08-15 a30c3c9` +- The `finding-author` skill, step 1 — the same procedure as the first step of interactive + authoring, with the no-raw-lists instruction restated. + `.claude/skills/finding-author/SKILL.md @ taxonomy-export-2026-08-15 a30c3c9` + +**Related.** A7, B3, B5, B6. + +--- + +## B5. Review in three tiers, with context isolation + +**Idea.** Review is layered, and each layer does only what it is good at. A deterministic linter +runs pure pattern checks and labels each hit an error, a warning, or a review item. A language-model +quality review then applies a checklist that the linter deliberately does not attempt, and is given +one file path and nothing else. A human sign-off through a terminal interface is mandatory for batch +and review flows. The context rule is stated as a requirement rather than a preference: "Cross-finding +context isolation is mandatory: each finding is drafted and reviewed by a fresh sub-agent with no +exposure to its neighbors." + +**Status.** Implemented example. + +**Implemented.** The review skill refuses to run against a dirty working tree so that its edits can +be diffed cleanly, with a conversational override and no command-line flag for it. Fan-out runs in +parallel groups of five, each sub-agent receiving a single file path with the instruction "No +neighbors, no batch context, no prior conversation." Concrete suggested fixes are applied; +extraction candidates and warnings are recorded into a review file rather than applied. +`.claude/skills/finding-review/SKILL.md @ taxonomy-export-2026-08-15 a30c3c9`, steps 1 through 5; +`.claude/skills/finding-batch/SKILL.md @ taxonomy-export-2026-08-15 a30c3c9`. + +**Evidence.** +- The `mechanical_lint.md` fragment — the deterministic checks and the three severity levels with + their meanings. `prompts/fragments/mechanical_lint.md @ taxonomy-export-2026-08-15 a30c3c9` +- The `quality_checklist.md` fragment — the checklist, the required output shape, and an explicit + section naming what it intentionally does not flag. + `prompts/fragments/quality_checklist.md @ taxonomy-export-2026-08-15 a30c3c9` +- The `finding-batch` skill — the isolation requirement stated as mandatory, the accepted input + shapes, and the cross-row duplicate check surfaced to the user before drafting. + `.claude/skills/finding-batch/SKILL.md @ taxonomy-export-2026-08-15 a30c3c9` + +**Related.** B4, B6, C6. + +--- + +## B6. Prompts as loadable fragments, sized against measured degradation + +**Idea.** The authoring rules live in small fragment documents that a skill loads at the step where +they apply, and the skill files are "pure orchestration". The reason is written down and measured +rather than asserted: instruction-following degrades as the number of simultaneous instructions +rises, material in the middle of a long prompt gets less attention than material at either end, and +extraneous but semantically similar context measurably harms structured output. The team's own +diagnosis of its earlier prompts is that a review agent with about forty checklist items plus a +thirty-rule conventions document was "deep in degradation territory", and that appending conventions +after the task instructions pushed the agent's own task rules into the lost middle. + +**Status.** Implemented example, with the research written up as the justification. + +**Implemented.** Fifteen fragments sit under a prompts directory with a defaults file, and each +skill names the fragment to load at each step rather than inlining the rules. The `finding-author` +skill loads orientation once per session, then names a different fragment at search, at synonym +editing, at drafting, at creation, and at lint. +`prompts/fragments/ @ taxonomy-export-2026-08-15 a30c3c9`; +`.claude/skills/finding-author/SKILL.md @ taxonomy-export-2026-08-15 a30c3c9`. + +**Evidence.** +- "Prompt Length and Instruction Complexity: Research and Recommendations" — the question as the + team posed it (about 19 KB of shared documents inlined into every agent call, roughly 25,000 + characters of instructions per call), the five research findings, and the analysis of the team's + own three agent prompts against them. + `docs/plans/prompt_length_research.md @ taxonomy-export-2026-08-15 a30c3c9` +- The three skill files — each states "All rules, CLI cheatsheets, and procedures live in + `prompts/fragments/`. This file is pure orchestration." + `.claude/skills/{finding-author,finding-batch,finding-review}/SKILL.md @ taxonomy-export-2026-08-15 a30c3c9` + +**Related.** B5, C6. + +**Disagreements.** None recorded. The related rule on the metadata side is stricter still: when an +evaluation miss exposes a general rule, add it to the field-standards document and cover it with an +evaluation rather than pasting the missed case into the prompt, and never copy active evaluation +fixtures into prompt text. +`docs/metadata/enrichment/prompt-guidance.md @ feature/metadata-cleanup 1942b06` + +--- + +## B7. Exam-oriented finding sub-taxonomies + +**Idea.** Content direction is now six per-exam-context finding hierarchies — chest radiograph, +musculoskeletal radiograph, head CT, chest/abdomen/pelvis CT, mammography, spine MRI — 3,789 rows in +total. Each file is one hierarchy in which a row names its parent by name, "Parents are generic, +children add specificity". An anatomic category sits beside the hierarchy as an independent grouping +rather than part of it. The project lead stated on 2026-09-21 that this branch is "the immediate +direction for all of the content, probably replacing a lot of the Gamuts-based models", and asked +that the taxonomies be called the MGB exam-oriented sub-taxonomies. + +**Status.** Stated goal (the direction); implemented example (the six files). + +**Implemented.** The taxonomy doubles as a coverage ledger. An identifier is filled only where a row +matched a model that already exists, by exact name, and "Nothing was minted here"; 1,028 of 3,789 +rows matched, so the files measure as data how much of each exam type the corpus covers, very +unevenly — 305 of 403 for chest radiographs against 5 of 198 for mammography. "Blank rows are the +ones needing triage." A writeback loop fills that column, runs only after full review and human +sign-off, and is idempotent. +`lists/README.md @ taxonomy-export-2026-08-15 a30c3c9`; +`prompts/fragments/csv_writeback.md @ taxonomy-export-2026-08-15 a30c3c9`. + +**Evidence.** +- The taxonomy README — the six files with row and identifier counts, the column meanings, the + parent semantics, the nothing-was-minted rule, and the warning that an identifier can appear on + two rows where earlier writebacks mapped two findings onto one model. + `lists/README.md @ taxonomy-export-2026-08-15 a30c3c9` +- "Profile of the Hood Finding Taxonomies" — the measured shape: 411 of 414 untyped rows are parents + of other rows; 73 parents in the CT list have both observation and diagnosis children; a recurring + three-part naming pattern of abnormality, anatomic variant and postsurgical change per region; + eight rows sharing an identifier with another row. + `notes/hood-taxonomies-profile-2026-09-01.md @ next-gen-2026 44836c1` +- The project lead's recorded content direction. + `knowledge/plans/2026-09-20-knowledgebase-build-plan.md` + +**Related.** A5, B2, B12, D1. + +**Disagreements.** The profile records that a morphology axis derived from a name-suffix census was +proposed and rejected on 2026-09-02, on the grounds that the suffixes describe how names are formed +rather than categories radiologists reason about. It also records the duplicate identifiers as unmade +synonym-or-subtype decisions. + +**Undetermined.** Whether the hierarchy is meant to enter the schema. No branch read carries a +parent, hierarchy or taxonomy field on a finding model; the parent relation exists only in the CSV +files. What `finding_cluster` means is declared in the README but never explained, and is populated +in one file only. + +--- + +## B8. Convert and merge, with a fixed direction + +**Idea.** Converting an outside definition set into finding models is a merge with a fixed direction: +incoming definitions merge into the existing corpus, never the reverse. A specificity guard prevents +matching an incoming specific term to a general existing model, so "tunneled catheter" must not match +"detectable hardware". Merge decisions are typed rather than ad hoc: enhanced, identical, subset, +needs review, and no similarities, each with its own action. + +**Status.** Implemented example on a content branch, six of twenty-one planned chunks converted. + +**Implemented.** A special case discards an incoming two-value presence attribute when the existing +model already carries the standard four values. The per-chunk flow is fixed — triage, convert, lint, +quality review, apply fixes, review file, human handoff, apply feedback — and the branch's own +instruction file says "User triggers one chunk at a time — never auto-run all 21 chunks." +`PROJECT_SPECIFICATION.md` parts 6 and 7, and `CLAUDE.md`, both `@ content/chestcts 0472a46`. + +**Evidence.** +- The chest CT project specification — the direction rule, the specificity guard with its worked + case, and the five merge-decision types. `PROJECT_SPECIFICATION.md @ content/chestcts 0472a46` +- The batch progress document and the conversion skill — the chunked workflow in practice. + `docs/cdestaging_ct_chest_batch_progress.md` and + `.claude/skills/finding-cdestaging-batch/SKILL.md @ content/chestcts 0472a46` + +**Related.** A10, B4, B12. + +**Undetermined.** How extracted sub-findings link back to their parents is named as an open design +problem on that branch: they are "identified and logged but not written to disk". No mechanism exists +on any branch read. + +--- + +## B9. Content repository proposes changes upstream to the library + +**Idea.** The content effort is treated as a source of requirements for the tooling, not only a +consumer of it. A document analyses what should move upstream into the library based on patterns +built while authoring, sizes each entry to become one issue, and states its evidence base as a +fourteen-model test batch plus a review pass plus three sessions of fragment refinement. + +**Status.** Implemented example (the proposals document and one filed issue); working proposals (the +rest). + +**Implemented.** The content repository carries a reference implementation of each proposal as a +local script, and the document points at it — direction-pair selection and article stripping are done +client-side in the content repo's creation script pending the library change. +`docs/plans/findingmodel-upstream-proposals.md @ taxonomy-export-2026-08-15 a30c3c9`, item B1. + +**Evidence.** +- The upstream-proposals document — section A bugs (a release version-contract mismatch reproduced + against published package versions) and section B library enhancements, each with a problem + statement, an evidence count from the test batch, and a proposed interface. + `docs/plans/findingmodel-upstream-proposals.md @ taxonomy-export-2026-08-15 a30c3c9` + +**Related.** A6, B6. + +--- + +# C. Foundation context and metadata + +## C1. Lean published models versus the full metadata schema + +**Idea.** The published finding model is deliberately lean — identifier, name, description, synonyms, +tags, attributes, index codes. A forward schema adds eight structured fields the team calls +foundation context: body regions, subspecialties, etiologies, entity type, applicable modalities, +expected time course, age profile, sex specificity. Four of these are presented in the team's own +webinar as what lets an agent judge whether a finding *should still be there* on a new exam: where it +is anatomically, what type of finding it is, how long it lasts, and whether it is transient or +permanent. The worked justification is that an aneurysm should be expected on every future exam and +tracked for growth, a resolved pulmonary embolism treated as gone, and an ovarian cyst known to clear +and recur with the cycle so that every cyst is not linked into one thread. + +**Status.** Stated goal ("Definition formats, needs overhaul for increased metadata"); implemented +example on the work edge; explicitly labelled in the July 2026 webinar as "the forward, AI-populated +schema, not yet carried by the published definitions". + +**Implemented.** All eight fields are typed Pydantic fields on both model classes on the development +and metadata branches, and absent from the released branch. The schema absorbs legacy vocabularies +rather than migrating data: normalizing validators map old title-cased regions, a legacy "ALL" value, +a coarse `traumatic` etiology, two film-modality codes, and a free-text "pediatric" age label onto +current values, with unknown values falling through to an ordinary enumeration error. Only entity +type is required; the rest may be null. +`packages/findingmodel/src/findingmodel/types/models.py` and `types/metadata.py @ feature/metadata-cleanup 1942b06`; +contrast `packages/findingmodel/src/findingmodel/finding_model.py @ main 75afd39`. + +**Evidence.** +- "Canonical Structured Metadata and Enrichment Rewrite", "Canonical Model Shape" — the eight fields, + the full value lists, and the stated goal of making metadata "canonical `FindingModel` state rather + than disposable enrichment output", with the recorded reason that two earlier pathways both + produced sidecar output instead. + `docs/canonical-structured-metadata-and-enrichment-rewrite.md @ feature/metadata-cleanup 1942b06` +- "Finding Model Structured Metadata Fields" — the field-by-field reference with each enumeration and + its meanings. `notes/oifm-metadata-fields.md @ next-gen-2026 44836c1` +- The webinar's "Lean vs full" and "Foundation card" slides — the framing, the four dimensions with + their justification, and the etiology taxonomy on screen with a subdural hematoma carrying both a + traumatic and a vascular code. `sources/bucket/text/ipl-webinar-deck.md`, slides 28 to 30 +- The project lead's stated goals. `knowledge/plans/2026-09-20-knowledgebase-build-plan.md` + +**Related.** A5, C2, C3, C4, D2. + +**Disagreements.** The entity-type value sets differ. The finding model enumeration keeps `grouping` +and `recommendation`; "What the Vocabulary Must Express" §5 drops both, on the grounds that a +recommendation has no subject in the patient and that grouping is a structural role rather than a +kind of finding, then reinstates Grouping as a node type. That document also removes `measurement` as +a classification in favour of a separate definition type. +`docs/next-gen-schema/01-what-the-vocabulary-must-express.md @ next-gen-2026 44836c1`. The subspecialty +and etiology enumerations also differ between the development and metadata branches: one code was +removed as "not an official RSNA specialty content code", another renamed, two added, and two new +parent etiology codes introduced, so data valid on one branch will not validate on the other. +`docs/metadata/subspecialties.md` and `CHANGELOG.md @ feature/metadata-cleanup 1942b06`. + +**Undetermined.** Whether the eight fields will land on the released branch. The branch's readiness +assessment is recorded as not yet passing and nothing has been merged. + +--- + +## C2. Each metadata field is defined by what it excludes + +**Idea.** The metadata fields are specified less by what they mean than by the near-miss they must +not admit. Subspecialty is which radiology service would *read and report* the finding, not which +service *orders* the study, and the policy document lists what was deliberately kept out: modality +codes, education, policy, informatics, physics and research tracks, and radiation oncology, each with +a reason. Expected time course is how long a finding stays *visible on imaging*, "not the clinical +duration of the underlying disease". Sex specificity is about anatomy, not prevalence. Applicable +modalities covers only modalities routinely used to demonstrate, evaluate, quantify or follow the +finding, not theoretical detection or incidental visibility. Etiologies name the common process types +the finding implies, "not a differential diagnosis". Age profile separates what a finding *can occur +in* from what it is *more common in*. + +**Status.** Working proposal (the policy); implemented example (the enumerations and the prompts that +apply them). + +**Implemented.** The assignment prompts encode the exclusions as operational rules with defaults that +differ per field. The etiology and time-course prompt states that "The two fields have opposite +defaults. **Etiology defaults to null** — assign only with direct support from the finding name or +description. **Time course defaults to a committed value**", and orders the work: decide etiology +first, then use it when choosing time course. It forbids inferring cause from anatomy, modality, +appearance, age context or generic clinical association, and caps output at about three codes. +`packages/findingmodel-ai/src/findingmodel_ai/metadata/prompts/etiology_tempo.md @ feature/metadata-cleanup 1942b06`. + +**Evidence.** +- The `etiology_tempo.md` assignment prompt — the goal statement, the opposite-defaults rule, the + allowed code lists, and the specific negative rules (a nonspecific descriptive finding gets no + benign/malignant differential; metabolic activity does not by itself imply neoplasm; calcified + lymph nodes do not inherit lymphadenopathy's etiologies). + `packages/findingmodel-ai/src/findingmodel_ai/metadata/prompts/etiology_tempo.md @ feature/metadata-cleanup 1942b06` +- The subspecialty policy document — the kept and not-kept tables with a reason per exclusion, and a + tie-breaker between two overlapping codes. + `docs/metadata/subspecialties.md @ feature/metadata-cleanup 1942b06` +- The field-standards document — about fifteen decision standards for modality applicability + including three named negative rules, and the specific etiology adjudications. + `docs/metadata/fields.md @ feature/metadata-cleanup 1942b06` +- The project vocabulary document — an "avoid" line under each domain term, for example ordering + specialty under subspecialty and clinical disease duration under time course. + `CONTEXT.md @ feature/metadata-cleanup 1942b06` + +**Related.** C1, C3, C4. + +**Disagreements.** None recorded. + +--- + +## C3. Index codes must be exact + +**Idea.** A code stored on a finding model must be an exact match or a clinically substitutable +near-equivalent for the whole model concept. Broader, narrower, related, complication-specific, +severity-specific and temporally qualified codes do not belong there unless the model itself is +defined at that narrower level; they belong in a separate review artifact where they can be +categorized. The code object stays a plain system, code and display triple, and relationship +semantics do not live on it — if the project later needs them, it should add a typed wrapper rather +than overload the existing object. + +**Status.** Working proposal as policy; implemented as prompt rules and evaluation scoring, not as +schema enforcement. + +**Implemented.** The ontology assignment prompt operationalizes the rule in both directions: reject a +candidate that *adds* unsupported detail (material, device subtype, location, named vessel, pattern, +disease context, benign or malignant status, histology, grade, stage) and reject one that *drops* a +meaningful modelled qualifier (patient group, pregnancy, timing, acuity, chronicity, severity, +location, modality, laterality, focality, pattern, composition). It adds that an unqualified tumour +includes benign and malignant forms, that a measurement or score used to evaluate a disease is not +the disease, and that non-canonical concepts should be preserved as review evidence with a +relationship and a rejection reason. +`packages/findingmodel-ai/src/findingmodel_ai/metadata/prompts/ontology_decision.md @ feature/metadata-cleanup 1942b06`. + +**Evidence.** +- The `ontology_decision.md` assignment prompt — the rules above, and the instruction to return no + canonical candidate when none is good enough. + `packages/findingmodel-ai/src/findingmodel_ai/metadata/prompts/ontology_decision.md @ feature/metadata-cleanup 1942b06` +- "Canonical Structured Metadata and Enrichment Rewrite", index-code semantics — the policy with the + do-not-overload instruction. + `docs/canonical-structured-metadata-and-enrichment-rewrite.md @ feature/metadata-cleanup 1942b06` +- "Index code target fixture integration" — the measured consequence: adding missing source-code + targets alone would have lifted index-code scoring only from about 0.674 to about 0.736, so + coverage was necessary but not sufficient, and the four miss buckets are coverage, retrieval, + matching and abstention. + `docs/plans/index-code-target-fixture-integration-2026-06-23.md @ feature/metadata-cleanup 1942b06` + +**Related.** C2, C5, E1, E2. + +**Disagreements.** "Current Understanding" Issue J keeps open the option this rule closes: "index +codes as open system URIs, distinguishing exact-match from broader/narrower". +`docs/next-gen-schema/00-current-understanding.md @ next-gen-2026 44836c1` + +**Undetermined.** Nothing enforces the rule at runtime. It is policy carried by prompts, review and +evaluation. + +--- + +## C4. Focused assignment agents, advisory audit, and null as an answer + +**Idea.** Metadata is assigned by seven narrow agents rather than one broad classifier — entity type, +etiology and tempo, patient applicability, subspecialty domain, modality applicability, ontology +decision, anatomy decision — each with a lean prompt and a typed decision output, assembled by one +orchestrator that never decides a field value itself. The recorded reason is that focused agents +allow concise prompts, per-field evaluation, and targeted tuning of weak fields; the recorded cost is +more agents, more orchestration, and more model calls per finding. Candidate discovery is a separate +role: search agents propose, assignment agents dispose. A final pass audits rather than enforces, and +the repository insists on calling it an auditor because "validators enforce structure; the auditor is +advisory". Null is a legitimate answer with four enumerated meanings, and scoring penalizes +unsupported additions more heavily than omissions. + +**Status.** Working proposal recorded as an architecture decision; implemented on the work edge. + +**Implemented.** Agents run in three parallel batches with etiology and tempo gated on entity type. +Candidate lists are capped and candidate identifiers use a system-and-code form the output validator +checks, retrying on invented identifiers. The auditor emits severity-tagged flags only, combining +deterministic checks (missing evidence, display mismatch against a cached preferred term, +anatomy-versus-sex conflicts) with an optional second-opinion pass. An ontology evidence cache +accumulates across runs and is explicitly "evidence only, never authority" when stale. +`docs/adr/0002-split-agent-assignment-architecture.md`, +`docs/metadata/enrichment/enrichment-agent-architecture.md`, and +`packages/findingmodel-ai/src/findingmodel_ai/metadata/ontology_cache.py @ feature/metadata-cleanup 1942b06`. + +**Evidence.** +- The split-agent architecture decision record — the seven agents named, the decision, and its + stated consequences. `docs/adr/0002-split-agent-assignment-architecture.md @ feature/metadata-cleanup 1942b06` +- The enrichment agent architecture document — the agent, prompt, output and evaluation table, and + the search-proposes/assignment-disposes boundary. + `docs/metadata/enrichment/enrichment-agent-architecture.md @ feature/metadata-cleanup 1942b06` +- The metadata README and evaluation document — "Unsupported additions are usually more harmful than + omissions", the four meanings of null, conservative-abstention credit, and the separation of gates + from quality scores. `docs/metadata/README.md` and `docs/metadata/enrichment/evaluation.md @ feature/metadata-cleanup 1942b06` +- The `anatomy_decision.md` assignment prompt — "Select the smallest candidate set that covers the + modelled anatomic scope", the instruction that candidate support levels are evidence and not + commands, and the rule to select no anatomic candidate at all rather than use a narrower child or + landmark as a proxy. + `packages/findingmodel-ai/src/findingmodel_ai/metadata/prompts/anatomy_decision.md @ feature/metadata-cleanup 1942b06` + +**Related.** C1, C2, C3, C5, E1. + +**Disagreements.** The rewrite document records that two earlier enrichment pathways are to be removed +with no compatibility shims. That is a recorded reversal within the repository, not an open dispute. + +--- + +## C5. Human review is the only authority + +**Idea.** Generated metadata does not reach the corpus on its own. Review actions are approved, +skipped or feedback, and only approved records may be written back. Sub-agent triage may organize a +queue but is not authority, and generated source diffs are not gold. Feedback has four named routes — +human promotion, conversion into a general rule plus an evaluation, a source-model authoring fix, or +deferral — none of which write source directly. + +**Status.** Stated as policy; implemented as gates and fixtures. + +**Implemented.** Writeback runs through a command that verifies review-package and reviewed-payload +hashes, records before and after hashes, validates each model before writing, and refuses any record +not in the approved-output fixture; a refusal check against a feedback record returned a refusal, "the +intended authority boundary". A commit-time gate blocks source writeback unless about thirteen named +conditions hold, on the principle that "Source commits must be derived from the source-apply +manifest, not from `git diff`". A second gate blocks deleting the legacy code path until the new one +passes a real end-to-end run, with mocked unit tests explicitly not counting. Unapproved diffs are +quarantined rather than discarded. +`docs/metadata/enrichment/human-review-and-writeback.md @ feature/metadata-cleanup 1942b06`. + +**Evidence.** +- The human review and writeback document — the three review actions, the feedback routing, the two + gates, and the reconciliation of 180 review events over 150 unique records into a 78-definition + source baseline. `docs/metadata/enrichment/human-review-and-writeback.md @ feature/metadata-cleanup 1942b06` +- The metadata enrichment plan history — the decisions stated as such: human review is authoritative; + generated source diffs are not gold; feedback records must be dispositioned before another corpus + batch. `docs/plans/metadata-enrichment-plan-history-2026-05-24.md @ findingmodels-metadata dcc6c4c` + +**Related.** B5, C4, C7. + +--- + +## C6. Documents record judgment; the schema is the specification + +**Idea.** The metadata documents hold decisions and policy — field standards, subspecialty policy, +review gates, release strategy — while field types, patterns, the code object's shape and +normalization behaviour live in code and are read from code. The stated cause is that +hand-maintained structural documents drift, and that a prior consolidation lost and duplicated +exactly that kind of detail. + +**Status.** Stated as an architecture decision. + +**Implemented.** Enumeration value tables may appear in the field-standards document but are to be +generated or checked against the enumerations rather than hand-authored. The decision record's own +consequence section instructs a future reader who finds no field types in that document to look at +the models rather than re-add them. +`docs/adr/0001-lean-metadata-docs-schema-is-spec.md @ feature/metadata-cleanup 1942b06`. + +**Evidence.** +- The lean-metadata-docs architecture decision record — the decision, its cause, and its two + consequences. `docs/adr/0001-lean-metadata-docs-schema-is-spec.md @ feature/metadata-cleanup 1942b06` +- The project vocabulary document — system vocabulary separated from domain vocabulary, each term + with an "avoid" line, plus a flagged-ambiguities section resolving prior collisions such as + "tagging" against the tags field and "finding" meaning both the container and a classification + value. `CONTEXT.md @ feature/metadata-cleanup 1942b06` + +**Related.** B6, C2. + +--- + +## C7. Two databases from one source commit + +**Idea.** Publish two database artifacts built from the same enriched source: one in the legacy shape +readable by the currently published runtime, and one carrying the structured-metadata columns, the +enriched JSON, and a provenance table recording schema name and version, source commit, build +timestamp, package versions and embedding model. The stated reason is that existing consumers keep +working unchanged while metadata-aware consumers get the new data, rather than forcing a breaking +single-database migration. + +**Status.** Stated as an architecture decision; partly implemented. + +**Implemented.** A manifest key controls when the metadata-aware database becomes the default, and a +package-release gate moves the data-repository scripts off a local wheelhouse onto released package +pins before publication. +`docs/adr/0003-dual-db-pre-post-metadata-release.md` and +`docs/metadata/enrichment/database-artifacts-and-package-pinning.md @ feature/metadata-cleanup 1942b06`. + +**Evidence.** +- The dual-database architecture decision record — the decision, its reason, and its three + consequences. `docs/adr/0003-dual-db-pre-post-metadata-release.md @ feature/metadata-cleanup 1942b06` +- "Schema Versioning (Future Work)" — the related and deferred idea, that a package version requires + exactly one schema version and backward compatibility comes from the manifest keeping old-schema + databases available, with schema version (structure) separated from content version (freshness). + `tasks/schema-versioning-future.md @ main 75afd39` + +**Related.** C5, E1. + +--- + +## C8. Three retrieval modes over the corpus + +**Idea.** The registry answers three different questions with three different mechanisms rather than +overloading one. Query-driven search combines full-text and vector retrieval with metadata filters +pushed into the query before ranking. Browse is filter-only with pagination, and explicitly replaces +an earlier overload where an empty search string carried tag filters. Related-model lookup is +deterministic with no language model, scoring metadata overlap with configurable weights. + +**Status.** Implemented example on the development and metadata branches; absent from the released +branch. + +**Implemented.** Related-model scoring weights anatomic location highest, then index code, then +entity type, then body region, etiology and subspecialty, then modality, age, sex and time course, +with a minimum score below which nothing is returned; the weights are recorded as "provisional and +must be tuned against a gold case set before release". Filters are OR within a facet and AND across +facets, while tags keep all-of semantics. A pre-authoring overlap check runs five phases — an exact +name and synonym fast path, model-assisted planning that emits alternate search terms and metadata +hypotheses, multi-pass candidate gathering, model-assisted selection with a rejection taxonomy, and +assembly — where deterministic code gathers and merges and the model only makes the edit-versus-create +judgment, with an unfiltered text path always preserved so a wrong facet guess cannot collapse +recall. The registry is also exposed to agents as a tool server. +`packages/findingmodel/src/findingmodel/index.py`, +`packages/findingmodel-ai/src/findingmodel_ai/search/similar.py`, and +`packages/findingmodel/src/findingmodel/mcp_server.py @ feature/metadata-cleanup 1942b06`. + +**Evidence.** +- "Canonical Structured Metadata and Enrichment Rewrite", retrieval section — the three modes, the + filter semantics, the weight table, and the provisional-weights caveat. + `docs/canonical-structured-metadata-and-enrichment-rewrite.md @ feature/metadata-cleanup 1942b06` +- The similar-models planning prompt — "Prefer MORE GENERAL terms" and "NEVER more specific than the + finding itself", the rule that keeps recall wide during candidate gathering. + `packages/findingmodel-ai/src/findingmodel_ai/search/similar.py @ feature/metadata-cleanup 1942b06` + +**Related.** B4, C1, E2. + +--- + +# D. Anatomic locations + +## D1. Spatial containment as a single-parent tree to the whole body + +**Idea.** Every anatomic structure gets exactly one containing parent, defined as the smallest +anatomic entity that fully encloses it, so every entry has one unambiguous chain of enclosing regions +to a single root, the whole body. A structure spanning several subregions takes the smallest region +containing the whole of it, so the pancreatic duct is contained by the pancreas rather than by any +one of its parts. The purpose stated is deterministic, auditable traversal: software that extracts "3 +mm cyst in the pancreatic tail" has no representation of the pancreas, the retroperitoneum and the +abdomen to consult, and this supplies one. + +**Status.** Implemented example. + +**Implemented.** The shipped index data is a strict rooted tree with a single self-referencing root +and no multi-parent entries. The libraries walk it: ancestors terminate at the hard-coded whole-body +identifier, and a containment predicate answers whether one structure lies inside another. The +current package exposes the same traversal from a command line, printing the chain from whole body +down to a named structure with its children. +`body_part_index/body_part.py @ BodyPartIndex.py main 388ae0a`; +`docs/anatomic-locations.md @ findingmodel feature/metadata-cleanup 1942b06`. + +**Evidence.** +- The Anatomic Locations Index manuscript under review at JDIM, Methods "Hierarchy construction" and + Results "Hierarchy structure" — the single-parent rule, the smallest-fully-containing-region rule + with the pancreatic duct case, verification that every chain reaches the root, a longest chain of + seven hops, and a depth distribution consistent with whole body to major region to subregion to + structure. `sources/bucket/text/jdim-02183.md` +- The project site's homepage — "a directed, rooted tree hierarchy, starting from the whole body and + ramifying through body regions", with the curated set described as "Complete-ish" and + "Non-degenerate: no uncertainty as to which node represents a structure". + `docs/index.markdown @ anatomiclocations.org main 1f39fa4` +- "Current Understanding" §2.6 — independent verification against the data file on 2026-07-28: + strict rooted tree, single root, every node exactly one containing parent, no multi-parent entries + anywhere. `docs/next-gen-schema/00-current-understanding.md @ next-gen-2026 44836c1` +- The anatomic locations research task — the traversal chosen for the current database is an + adjacency list with recursive queries and an explicit depth limit "to prevent infinite loops in case + of data errors", judged optimal for a read-only hierarchy of this size. + `tasks/anatomic-locations-graph-research.md @ findingmodel main 75afd39` + +**Related.** D2, D3, D5, D6, F1. + +**Disagreements.** The manuscript records the cost of the single-parent rule as a limitation: a +structure spanning sibling subregions is assigned to their common parent, so the pancreatic duct's +course through the individual subdivisions is not represented. It also records that the hierarchy +uses deliberately coarse regional grouping. The next-generation gap log notes that the data places +the lung inside the pleural space, "an anatomic oddity that affects containment traversal". + +**Undetermined.** Three node counts coexist across sources — 2,890 in the published file, 2,891 in +the manuscript, 2,926 in the current package data — because they were read from different releases. +That is freshness, not disagreement. + +--- + +## D2. Containment and part-of are different relations + +**Idea.** Where a structure physically sits and what functional structure it belongs to are two +different questions, and conflating them breaks spatial reasoning. The abdominal aorta is contained +by the retroperitoneum but is part of the aorta; the aortic arch is contained by the mediastinum but +is part of the aorta; the appendix is contained by the pelvis but is part of the colon. The +single-parent constraint applies only to containment; a structure may have zero, one or more +functional part-of associations. Anything walking the hierarchy must declare which relation it means, +because for the upper lobe of the right lung containment yields right lung, thorax, whole body while +part-of yields right lung and stops. + +**Status.** Implemented example. + +**Implemented.** The two relations are separate fields, one required and one optional, and the +authoring guidance tells a curator which to use: containment for "X is inside Y" (the hilum is inside +the lung), part-of for "X is a component of Y" (the stomach is part of the gastrointestinal tract). +The older TypeScript library mirrors the containment traversal for the functional hierarchy with its +own ancestor, child and predicate functions; the Python library exposes only a single part-of hop. +`.claude/skills/manage-anatomic-locations/reference/json-schema.md @ findingmodel main 75afd39`; +`README.md @ BodyPartIndex.ts main dec578e`; `body_part_index/body_part.py @ BodyPartIndex.py main 388ae0a`. + +**Evidence.** +- The anatomic locations field reference, "containedByRef vs partOfRef" — the spatial-versus- + mereological distinction with worked cases and the note that many entries have both. + `.claude/skills/manage-anatomic-locations/reference/json-schema.md @ findingmodel main 75afd39` +- The project site's code page — the same two hierarchies named and illustrated, kidney in the + retroperitoneum against adnexa as part of a system. + `docs/code.markdown @ anatomiclocations.org main 1f39fa4` +- The Anatomic Locations Index manuscript, Methods "Hierarchy construction" and Results "Index + composition" — the distinction with the abdominal aorta case, and 991 functional links each tying a + structure to a system. `sources/bucket/text/jdim-02183.md` +- "Current Understanding" §2.6 — a three-row worked table and the statement that the two traversals + answer different questions. `docs/next-gen-schema/00-current-understanding.md @ next-gen-2026 44836c1` + +**Related.** D1, D6, F1. + +**Disagreements.** Which hierarchy a given check walks is an open item that "must be stated each +time". `docs/next-gen-schema/11-anatomy-axis.md @ next-gen-2026 44836c1` + +--- + +## D3. Laterality as explicit triads + +**Idea.** Left, right and unsided variants of a bilateral structure are three distinct entries joined +by explicit links, rather than one entry plus a modifier. The stated reason is an implementation +convenience: the links permit direct deterministic navigation among corresponding forms without +reconstructing or searching for a post-coordinated expression at runtime. The consequence drawn in +the next-generation vocabulary is that laterality is carried by the location, so there will be no +laterality data elements. + +**Status.** Implemented example; working proposal for the consequence. + +**Implemented.** The curation rule is a three-entry pattern: an unsided entry carrying links to both +sided variants, and each sided entry carrying a link to its counterpart and back to the unsided form, +with the sided entry's container pointing at the sided version of its container where one exists. The +libraries navigate this in both directions from either end. Where a lateralized code does not exist +in an external terminology, the guidance is to use the unsided code for all three entries and say so +in the change description. +`.claude/skills/manage-anatomic-locations/reference/laterality-conventions.md @ findingmodel main 75afd39`; +`README.md @ BodyPartIndex.py main 388ae0a`. + +**Evidence.** +- The laterality conventions reference — the compound identifier pattern using two modifier + identifiers, the three-entry pattern with a worked example, and the container rule. + `.claude/skills/manage-anatomic-locations/reference/laterality-conventions.md @ findingmodel main 75afd39` +- The Anatomic Locations Index manuscript, Methods "Cross-referencing and technical implementation" — + complete triads for all 795 bilateral structures with the implementation-convenience reason stated. + `sources/bucket/text/jdim-02183.md` +- "Current Understanding" §2.6 — "Laterality is carried by the location, not by a DataElement. + Accordingly there will be no laterality DataElements", superseding an earlier committee draft + element list. `docs/next-gen-schema/00-current-understanding.md @ next-gen-2026 44836c1` + +**Related.** D1, D4, F1. + +**Disagreements.** An external reviewer's alpha implementation offers a laterality data element +including a bilateral value, against the sided-location approach; recorded as decision area ST08. +`docs/next-gen-schema/12-alpha-structural-comparison.md @ next-gen-2026 44836c1` + +--- + +## D4. Synthetic post-coordinated terms + +**Idea.** Where a clinically routine localization concept has no pre-coordinated term — almost always +because laterality or enumeration is missing — an identifier is minted by joining existing RadLex +identifiers with an underscore, so the composition is transparent and machine-readable. Three +patterns account for all of them: laterality only, enumeration only, and enumeration plus laterality. + +**Status.** Implemented example. + +**Implemented.** The identifier pattern in the published schema admits arbitrarily many joined +identifiers, and 1,010 of 2,890 shipped entries carry a composite identifier. +`data/body_parts_schema.json` and `data/body_parts.json @ anatomiclocations.org main 1f39fa4`. + +**Evidence.** +- The Anatomic Locations Index manuscript, Methods "Synthetic term generation" — the three patterns + with worked identifiers and counts, and the Discussion caveat that the count should not be read as + evidence that established ontologies lack mechanisms for adding concepts, because these gaps are + specific to one lexicon and do not generalise. `sources/bucket/text/jdim-02183.md` +- The laterality conventions reference — the modifier identifiers and the compound form as a curation + rule rather than a description. + `.claude/skills/manage-anatomic-locations/reference/laterality-conventions.md @ findingmodel main 75afd39` +- "The Anatomy Axis, Current State" §1 — the compound identifiers named as "the exception the RadLex + track will remove by minting real ids". + `docs/next-gen-schema/11-anatomy-axis.md @ next-gen-2026 44836c1` + +**Related.** D1, D3, D6. + +**Disagreements.** The manuscript records the cost as a limitation: systems built on the underlying +lexicon will not recognize compound identifiers without an added mapping layer. + +--- + +## D5. Measuring what existing ontologies actually populate + +**Idea.** Rather than asserting qualitatively that existing ontologies are unsuitable, measure how +completely each one populates the containment or part-whole relation it declares, each against its +own anatomy term set so that no resource is penalized for covering more or less anatomy. The reported +result is that in none of the three can software start at a structure and follow the declared +relations up to a whole-body class. The stated interpretation is not that the resources are defective +but that none was built to answer what encloses the structures radiologists name. + +**Status.** Implemented example (a reproducible measurement); under review, not published. + +**Implemented.** The measurement is specified to be recomputable: each count derives from a named +relation and a stated term set, with per-resource derivations given in supplementary methods, and a +best-case re-measurement pools every declared relation plus subproperty and inverse forms and repeats +the analysis. `sources/bucket/text/jdim-02183.md`, Methods. + +**Evidence.** +- The Anatomic Locations Index manuscript, Methods "Measuring containment in existing resources" and + Results — the method, the pooled best case, and the finding that nearly half of one resource's + anatomy concepts have more than one taxonomic parent so that following it branches rather than + yielding a single chain. `sources/bucket/text/jdim-02183.md` +- The project site's homepage, Introduction — the earlier qualitative version of the same argument: + lack of desired terms, too many unnecessary or degenerate terms, limited anatomic organization. + `docs/index.markdown @ anatomiclocations.org main 1f39fa4` + +**Related.** D1, D6, F2. + +**Disagreements.** The webinar compresses the result into a ratio, "11.5× the containment coverage of +RadLex", which appears in no other source in that form. +`sources/bucket/text/ipl-webinar-deck.md`, slide 31 + +**Undetermined.** The manuscript states plainly that the study does not measure downstream utility: +no benchmark, user study or deployment demonstrates that the hierarchy improves retrieval, tagging, +labeling or correlation. It asks to be read as a descriptive resource paper. + +--- + +## D6. An overlay on RadLex, not a competitor + +**Idea.** The curated set began outside RadLex because RadLex lacked the coverage and structure +imaging needed, but was keyed to RadLex identifiers throughout, and its relationship is now stated as +an overlay: RadLex concepts and predicates sit underneath, and the file adds identifiers RadLex lacks, +its own containment and part-of hierarchies, and laterality. It is described as the basis of the +RadLex anatomy axis going forward because the RadLex anatomy track is editing it, with aiming at the +published release compared to editing a three-year-old version of a document others have been +editing. A location's identifier is its RadLex identifier, and a RadLex code is never shown beside a +location because the location code *is* the RadLex code. + +**Status.** Stated goal ("this will be blended in with RadLex"); working proposal recorded as agreed +on 2026-09-13; incorporation in progress. + +**Implemented.** The current package data is pointed to at a pinned commit rather than copied. The +gap between what the file has and what it lacks is tracked as a running list of specific node +requests fed upstream — lung parenchyma, perirenal space and its sided forms, pericardial space, +subarachnoid space, and real identifiers for the compound sided variants. +`docs/next-gen-schema/11-anatomy-axis.md` and `docs/next-gen-schema/04-anatomy-gaps.md @ next-gen-2026 44836c1`. + +**Evidence.** +- "The Anatomy Axis, Current State" §1 and §4 — the overlay statement dated 13 September 2026, the + three-year-old-document argument, and a dated record of what was agreed on three occasions. + `docs/next-gen-schema/11-anatomy-axis.md @ next-gen-2026 44836c1` +- "Current Understanding" §2.6 — "It is now a subproject of RadLex and is imminently becoming an + identified collection within RadLex itself", with the synthetic nodes expected to receive real + identifiers. `docs/next-gen-schema/00-current-understanding.md @ next-gen-2026 44836c1` +- The Anatomic Locations Index manuscript, Discussion, future work — incorporation by the RSNA RadLex + Committee described as underway, covering the terms themselves, with the note that a prospective + process for revising and periodically reviewing the hierarchy still needs to be defined. + `sources/bucket/text/jdim-02183.md` + +**Related.** D4, D5, D7, F2. + +**Disagreements.** An external reviewer's alpha extracts a RadLex subset with local wrappers where the +agreed substrate is the pinned overlay; recorded as decision area ST06. +`docs/next-gen-schema/12-alpha-structural-comparison.md @ next-gen-2026 44836c1` + +--- + +## D7. The missing is-a and structure-type layer + +**Idea.** The curated set has containment and part-of but no taxonomic relation and no structure-type +nodes, so a statement like "this finding applies to tendons" cannot be made. This is recorded as the +major shortcoming and the first thing to resolve. RadLex can supply a first layer without inventing +anything, because every plain-identifier location has a taxonomic chain in the published ontology, +yielding several hundred locations under each of muscle, artery, vein, tendon and bone. Two cautions +accompany it: the ontology's own release note warns that some taxonomic categorizations were +converted from part-of and may be wrong, and the deep formal chain is not the clinically useful +layer. + +**Status.** Working proposal (a derived, pinned overlay handed to the anatomy track); stated goal +(two scope families to develop). + +**Implemented.** The second-generation record model on an unmerged content branch already carries +taxonomic identifiers alongside new relations for vascular structure — branch-of and flows-to — on +several hundred records, so the shape has been tried as data even though it was never merged. +`updates/ @ anatomiclocations.org content_work 35624d7`. + +**Evidence.** +- "The Anatomy Axis, Current State" §2, §3 and §5 — the has-and-lacks table, the derived + structure-type counts with both cautions, and the two scope families (tissue types and structure + types) with their connections to the location hierarchy explicitly still open. + `docs/next-gen-schema/11-anatomy-axis.md @ next-gen-2026 44836c1` +- The anatomy gap log — the running node-request list and the coverage figures behind it. + `docs/next-gen-schema/04-anatomy-gaps.md @ next-gen-2026 44836c1` + +**Related.** D6, F1, F2. + +**Disagreements.** The anatomy axis document separates the project lead's two scope families from +"exploratory ideas from the assistant, not adopted". + +**Undetermined.** Whether the second-generation per-file record model was adopted, rejected, or +superseded. Its field vocabulary differs from the published schema on nearly every field and its +naming is internally inconsistent; there is no design note. Several of its fields do reappear in the +current package's field reference, including a region field and an ACR Common identifier, which the +reference documents but does not explain the provenance of. + +--- + +## D8. Curation rules that make the codes usable + +**Idea.** The value of the index is less the terms than the discipline of the mappings, and the +curation rules are written down. External anatomy coding uses one member of a three-concept family: +the "Structure of ..." concept always, never the "Entire ..." or "... part" forms, because the +structure concept is what the terminology intends for finding sites and procedure sites. Definitions +prefer authoritative sources in a stated order. Synonyms are the clinical shorthand radiologists +actually use. + +**Status.** Implemented example (a curation rule applied by a skill with validation scripts). + +**Implemented.** The management skill ships a lookup script, a sampling script and a validation +script beside the field reference, so a curator adding entries checks candidate codes and validates +the result rather than hand-editing. +`.claude/skills/manage-anatomic-locations/scripts/ @ findingmodel main 75afd39`. + +**Evidence.** +- The anatomic locations field reference, "SNOMED Coding Guidance — The SEP Triad" — the three + concept types with an always/never/never instruction and the reason; and the fallback rule when a + lateralized code does not exist. + `.claude/skills/manage-anatomic-locations/reference/json-schema.md @ findingmodel main 75afd39` +- The same reference, text fields — the region value list and the ranked preference for definition + sources. + +**Related.** D3, D6, F2. + +--- + +## D9. A reference layer, not a labeling algorithm + +**Idea.** The index is a reference and normalization layer, not an automatic labeling system. +Identifiers may be applied at exam or series level to describe anatomy covered, or at report or +finding level to represent where an observation is. Labels may be generated by rules, language +processing or AI and then normalized, but whatever route generates a label, a person or a downstream +check confirms the assigned structure before anything relies on it. Containment then supplies the +broader context without further annotation. The team is explicit that localization is only one +dimension: knowing where a finding is does not establish what kind of process it is, how long it has +been present, whether it is transient, or whether it is the same lesion recorded elsewhere. + +**Status.** Stated goal; implemented example of the roll-up. + +**Implemented.** Every finding is anchored to a specific location code and the containment hierarchy +rolls it up to a top-level body region, so a patient is presented as an anatomy dashboard organized +by where findings are rather than by which report they came from. The demonstrated viewer shows the +gap honestly, with a banner admitting two findings have no specific anatomic location. +`sources/bucket/text/ipl-webinar-deck.md`, slides 31 and 33. + +**Evidence.** +- The Anatomic Locations Index manuscript, Discussion — the reference-layer statement, the + confirm-before-relying rule, the roll-up example, and the explicit one-dimension limit. + `sources/bucket/text/jdim-02183.md` +- The anatomic location assignment rules — the three-step precedence ladder used by the extraction + platform: explicit anatomy in the text, then the finding's own target organ, then the exam-scoped + coarse region, with laterality following the same shape. + `knowledge/data-structures/anatomic-location-assignment-rules.md` + +**Related.** C1, D1, E2. + +**Disagreements.** None recorded. The webinar's four foundation-context dimensions are the team's own +answer to the one-dimension limit the manuscript states. + +--- + +# E. Exam types + +## E1. Preferred high-level exam entries over the Playbook + +**Idea.** Exam types should be a thin wrapper over an existing governed knowledge graph — the +LOINC/RSNA Radiology Playbook together with RadLex — rather than a new vocabulary. What the wrapper +adds is a set of *preferred* high-level entries at the granularity clinicians and systems use, such +as CT Chest, MRI Brain and X-ray Knee, marked as preferred among the many codes describing variants +of the same study. The idea is four years old in nearly the same words. + +**Status.** Stated goal only, restated across four years and three documents. No artifact exists. + +**Implemented.** Nothing models exams, studies, procedures or protocols in the finding model +repositories; there is no exam-type entity and no exam-to-finding relationship. Exam identity does +real work in the extraction platform only as a bare code in an exam header and as the bottom rung of +the anatomy precedence ladder. +`knowledge/semantic-foundation/exam-types/existing-building-blocks.md`. + +**Evidence.** +- The project lead's stated goals — "Needs wrapper tooling around the knowledge graph represented by + RadLex LOINC playbook" and "Need to define the PREFERRED high-level entries". + `knowledge/plans/2026-09-20-knowledgebase-build-plan.md` +- The project site's roadmap — a companion for exam types based on Playbook exam definitions, listed + under content tasks and unchanged since January 2023. + `docs/index.markdown @ anatomiclocations.org main 1f39fa4` +- The "Common Anatomic Locations" board, "Active Issues" box — exam type definitions of the most + common exams based on LOINC with common identifiers, listed as an active issue beside the anatomy + work. `sources/excalidraw-diagrams.md` +- "Product direction: an agent-ready medical terminology graph gateway" — the only written design: a + radiology domain profile in which "orderables live in the LOINC/RSNA Radiology Playbook, while + findings, anatomy, and report language live in RadLex", with Playbook-weighted ranking, legacy + identifier detection, and taught crosswalk correspondences. Recommended direction, not built. + `docs/product-roadmap.md @ med-ontology-lookup main a1fd3ae` +- The chest CT coverage roadmap — an earlier, cruder form of the same coupling: a per-exam finding + table with frequency, priority, a RadElement set link where one exists, and a RadLex identifier + column. `definitions/upmedic/roadmap.md @ CDEStaging main b814a10` + +**Related.** B7, D9, E2, F1. + +**Undetermined.** Nothing found states why the exam-type library was never built while the anatomic +location library was. + +--- + +## E2. Exam-to-anatomy inclusion edges and the imaging region + +**Idea.** What makes an exam type more than a code list is typed edges to the anatomy it covers, +distinguishing anatomy that is *always* included, which may be expressed as a hierarchy rather than a +flat list, anatomy that is *usually* included for edge cases, and anatomy that is *possibly* included +and would have to be checked. The 2024 board states the same requirement as defining an imaging +region: a CT chest region contains the chest but also what a radiology exam of the chest would +include, such as the lower neck, the upper abdomen and the shoulders. The 2023 roadmap puts it as +exam definitions specifying all *included* body parts. + +**Status.** Stated goal only. No artifact. + +**Implemented.** Nothing. The nearest running behaviour is the finding-scope rule applied by +judgment: a finding model's scope should match what is assessable on a given exam type, which is why +"chest wall fracture" and "upper abdominal abnormality" exist as models. Nothing checks a model's +scope against a coded exam type, because there is nothing to check against. +`prompts/fragments/scope_and_specificity.md @ findingmodels taxonomy-export-2026-08-15 a30c3c9`. + +**Evidence.** +- The project lead's stated goals — the three edge kinds named, with the hierarchy note on "always + included". `knowledge/plans/2026-09-20-knowledgebase-build-plan.md` +- The "Common Anatomic Locations" board, "Exam Types" box — the imaging-region definition with the + lower-neck, upper-abdomen and shoulders example. `sources/excalidraw-diagrams.md` +- The Anatomic Locations Index manuscript, Discussion — the same capability named from the other + side, as something the index does not supply: relating a finding's location to what an exam covers + would additionally require a model of scan-protocol coverage. The use case it would serve, + identifying relevant prior studies covering overlapping anatomy even when acquired for different + purposes, is stated in the same section. `sources/bucket/text/jdim-02183.md` + +**Related.** A4, D1, D9, E1. + +**Undetermined.** Whether "always / usually / possibly" means three edge types, one edge with a +strength property, or something else. The goal statement does not say. The strength-bearing guidance +model in F1 is a different mechanism for a different purpose. + +--- + +# F. The next-generation vocabulary and the terminologies + +## F1. Anatomic scope, not location + +**Idea.** The vocabulary owes each finding class a statement of which anatomic locations are +congruent with it, and calling that field "location" is wrong because the statement ranges over three +different kinds of thing and only two are spatial: a named structure checked by identity or descent, +a region checked by containment, and a *structure type* such as arteries or tendons checked +taxonomically, "not spatial at all" — tendons are scattered across the body and share no common +container. Guidance is not a location: a clavicle fracture class records the clavicle while an actual +fracture is at the left clavicle. Guidance also varies in strength, from definitional through very +weak to not anatomic at all, so it records its strength. A companion idea removes the need for a +finding class in a whole category of reporting: a location can bind directly to data elements and +measurements, so describing normal anatomy — bile duct calibre, ovarian volume, endometrial thickness +— needs no finding class at all, and a binding on the unsided organ is satisfied by an observation on +a sided one without copying the edge. + +**Status.** Working proposal, with several parts recorded as owner decisions and explicitly not +jointly settled. + +**Implemented.** Scope resolution works today by plain traversal against the anatomy data for two of +the three kinds; the third waits on the missing taxonomic relation (D7). Worked location and element +examples are committed as data. +`docs/next-gen-schema/examples/common-bile-duct.location.json @ next-gen-2026 44836c1`. + +**Evidence.** +- "What the Vocabulary Must Express" §2 — the three kinds with how each is checked, the + guidance-is-not-a-location distinction, and §2.1's list of places that are not structures + (potential spaces, cavities, zones, interfaces, positions relative to a landmark) with the warning + that a vocabulary unable to express them will see authors invent ungrounded value sets again. + `docs/next-gen-schema/01-what-the-vocabulary-must-express.md @ next-gen-2026 44836c1` +- The same document §2.3 — the strength table from definitional (pulmonary nodule in lung) through + very weak (metastasis) to not anatomic (free air, "air where air should not be"). +- The same document §3 and §3.1 — the breadth argument that finding classes must cover more than + abnormalities, and the direct-binding decision for normal structures with what it buys and what it + requires. + +**Related.** D1, D2, D7, F3. + +**Disagreements.** Recorded as decision areas ST07 and ST08 against an external reviewer's alpha, +where scope kinds and the laterality treatment differ across code paths. Whether guidance records +which kind it is, and how binding it is, remain open as Issue H. +`docs/next-gen-schema/12-alpha-structural-comparison.md` and +`docs/next-gen-schema/00-current-understanding.md @ next-gen-2026 44836c1` + +--- + +## F2. Terminology roles, and search recall as the gate + +**Idea.** Each terminology has a stated role. RadLex is the foundation for findings, anatomy and +report language, chosen for coverage at the granularity radiologists report, governance with a +defined pathway for contributing terms back, and stable identifiers. SNOMED CT is the cross-reference +for enterprise coding, and is what DICOM's anatomic region sequence and FHIR's body-site value sets +already bind to, so the index sits above the coding scheme rather than competing with it and adoption +proceeds through existing bindings. LOINC and the Playbook own orderables. A connected idea concerns +search quality: a lookup that fails silently is worse than one that fails loudly, because an agent +then concludes the concept is missing and proposes a duplicate. The stated target is "recall good +enough that a MISS is real evidence of an ontology gap rather than evidence of unlucky phrasing." + +**Status.** Implemented example (the cross-references, the search rework, the lookup gateway); stated +goal (the interoperability-through-existing-bindings argument). + +**Implemented.** Search keeps exact label and synonym tiers as the *confidence* signal and adds +full-text relevance ranking as the *recall* layer, emitting a categorical match type rather than a +score because scores are not comparable across queries, with a per-query relative cutoff. A tokenizer +override was required because the default deletes every digit at index and query time, which matters +for vertebral levels, assessment categories, sequence weightings and isotopes. A measured evaluation +compared three arms and concluded that the exact tier earns its place on confidence rather than +ranking, so "the original metric was the flawed part, not the design". The terminology gateway +queries each ontology separately and interleaves results so the largest source cannot hide the +others, resolves a term, code or concept identifier by auto-detecting its shape, and uses medical +shorthand rather than raw type codes in its filters. +`docs/plans/hybrid-fts-search.md @ RadLex experiment/kg-radlex-parsing 5162a65`; +`README.md` and `src/med_ontology_lookup/ @ med-ontology-lookup issue-3-typed-provider-failures 9cc3eec`. + +**Evidence.** +- "Hybrid FTS search" — the false-gap failure mode named as the worst one the project has, the + alphabetical-ranking example, the design, the tokenizer finding with its measured share of affected + labels, and the evaluation with its own correction. + `docs/plans/hybrid-fts-search.md @ RadLex experiment/kg-radlex-parsing 5162a65` +- The Anatomic Locations Index manuscript, Methods "Term selection" and Discussion — why RadLex was + chosen as the foundation, the recommendation of SNOMED CT for enterprise coding and the distinction + between filling a coding role and populating containment, and the DICOM and FHIR binding argument. + `sources/bucket/text/jdim-02183.md` +- "RadLex baseline" — direct verification against the published ontology, including that its external + references run through one untyped string property dominated by one source and that SNOMED mapping + is effectively absent, contradicting a committee assumption. + `docs/next-gen-schema/05-radlex-baseline.md @ next-gen-2026 44836c1` +- "Product direction: an agent-ready medical terminology graph gateway" — the stated boundary that + this is a gateway and not a terminology source, the explicit non-goals, and the insistence that a + shared concept identifier "is evidence of connection, not proof of exact equivalence". + `docs/product-roadmap.md @ med-ontology-lookup main a1fd3ae` +- The project review and proposal — typed provider failures with a reproduced authentication failure + silently converted into an empty result, and the requirement that a collection result distinguish + complete, partial, failed and capped outcomes because "A plain list cannot communicate whether it + is complete". `docs/project-review-and-proposal.md @ med-ontology-lookup docs/reviewed-proposal-backlog f059792` + +**Related.** C3, D5, D6, E1. + +**Disagreements.** The manuscript treats SNOMED CT as the enterprise coding target to cross-reference; +the next-generation vocabulary treats RadLex as the thing to stay close to and treats the SNOMED +mapping gap inside RadLex as a problem to work around. + +--- + +## F3. Contributing terms back, and the two-phase proposal loop + +**Idea.** Gaps found while using a terminology are fed back to it rather than patched locally. An +agent reads a report, searches the graph, confirms each hit, redirects obsolete concepts to their +replacements, and decides whether each term is genuinely present — "a loose keyword overlap is not +enough, and a broader or related concept does not count as a match". For each unmatched term it then +proposes a new concept with the closest existing parent, a precise term, a rationale for why this is +a genuine gap and why that parent is the closest fit, and optional typed relationships, under the +rule "Only include a relationship if you found a real existing RID for the other end of it; do not +guess a RID." + +**Status.** Implemented example (the mechanism); the corresponding curation gate exists separately. + +**Implemented.** Proposals are validated against the graph before being appended: unknown +identifiers, unused relation types and blank names or rationales are rejected, and the whole batch +fails together because the output file is append-only and a candidate pointing at an invented +identifier cannot be reviewed. On the ontology side, every push runs a reasoner consistency check and +report checks, catching inconsistent logic and accidental duplicate or merged terms before they land. +`.claude/skills/radlex-concepts/SKILL.md @ RadLex experiment/kg-radlex-parsing 5162a65`; +`docs/TESTING.md @ RadLex main 13a5abe`. + +**Evidence.** +- The extract-concepts and suggest-concepts skill documents — the two phases with their acceptance + rules and the no-guessed-identifier constraint. + `.pi/skills/extract-radlex-concepts.md` and `.pi/skills/suggest-new-concepts.md @ RadLex experiment/kg-radlex-parsing 5162a65` +- The ontology testing document — the continuous-integration checks and what they are meant to catch. + `docs/TESTING.md @ RadLex main 13a5abe` +- The Anatomic Locations Index manuscript, Methods "Term selection" — a defined pathway for + contributing terms back named as one of three reasons the lexicon was chosen as the foundation. + `sources/bucket/text/jdim-02183.md` + +**Related.** D6, D7, F2. + +**Undetermined.** Whether any proposed concepts were actually submitted. The candidate output file is +excluded from version control and absent; the repositories describe the proposal mechanism and the +curation gate but nothing connects the two. + +--- + +## F4. The finding model relationship registry + +**Idea.** The finding model source schema draft proposes that a model store only the relationship +assertions authored on it, with authors never maintaining both sides of an inverse pair, and tooling +deriving inverse and symmetric views from a checked-in registry in which each relationship type +declares whether it is inverse-backed, symmetric, or one-way. The same draft separates a *source* +model, which may refer to a canonical shared attribute file instead of redefining presence and change +from prior inline, from a *hydrated* model in which those references are expanded, with runtime +operating on the hydrated form. Governance moves to per-model history sidecars recording who or what +acted. + +**Status.** Working proposal only. + +**Implemented.** Nothing. The relationship registry exists only in the draft; the live corpus +implements no relationship mechanism at all. The one relationship-shaped construct that does exist in +the corpus is the associated-findings attribute (A10), which references other models by name rather +than by identifier. + +**Evidence.** +- "FindingModel Source Schema v2 Draft" — the source-versus-hydrated distinction, canonical attribute + reuse with the two permitted overrides, the relationship-authorship rule, the registry semantics + with three worked pairs, and the corpus layout placing models, attributes and registries side by + side. `notes/oifm-schema-v2-draft.md @ next-gen-2026 44836c1` +- "The Finding and Diagnosis Relationship Family" §6 — the correction recording that this registry + exists only in the draft and that the live repository implements nothing, verified against the + repository on 2026-09-01, which makes the finding model work "a potential consumer of this family + rather than prior art to reconcile with". + `docs/next-gen-schema/07-relationship-family.md @ next-gen-2026 44836c1` + +**Related.** A10, B1, F5. + +**Disagreements.** The two designs differ on shared attributes. The draft allows a model to reference +a canonical attribute; the graph design makes a shared element one node with one identity, and +"Current Understanding" §5.1 names the file-based copy-on-reference choice as the reason bringing +models over is "a review step, not a bulk import". + +**Undetermined.** Whether this draft is live. It is dated April 2026 and nothing in the finding model +repositories implements it. + +--- + +## F5. The relationship family and the derived differential + +**Idea.** Seven relationship pairs plus a catch-all connect finding classes and diagnoses, with +manifestation and causation kept strictly apart: a striated nephrogram *is* pyelonephritis appearing +on imaging, while a renal abscess is a distinct second entity pyelonephritis produced. The test +offered is whether a clinician would say the source "got better" or that "a complication resolved". +Manifestation edges carry two optional independent properties, a typicality scale adopted verbatim +from an existing phenotype-frequency standard with its percentage anchors, and a three-value +specificity scale omitted entirely when uninformative because an absent property means no judgment +was recorded. The differential is not an edge type at all but a derived view: the diagnoses reachable +over the manifestation inverse, filtered by context and ranked. A missing edge between habitually +confused diagnoses means a finding class is missing, not that a workaround edge is needed. A report +edge and a class edge are different assertions, which forces a vocabulary relationship to have +identity of its own so a report edge can cite the potential it expresses. + +**Status.** Working proposal, explicitly tentative and non-comprehensive; implemented at prototype +scale. + +**Implemented.** The worked pyelonephritis and pleural effusion families exist as committed graph +data and as generated diagrams, and the September 2026 deck renders one report's six observations +against their class definitions, showing report-plane edges as a separate family from class edges. +`docs/next-gen-schema/graph/pyelonephritis.jsonl` and `docs/next-gen-schema/examples/ @ next-gen-2026 44836c1`; +`sources/bucket/REPORT.md` §6. + +**Evidence.** +- "The Finding and Diagnosis Relationship Family" §1 to §6 — the family table with domains and + ranges, the manifestation-versus-causation test, the two property scales with their sources and the + reason one takes a numeric escape hatch and the other does not, the derived-differential argument + with its precedent, and the prior-art anchor table. + `docs/next-gen-schema/07-relationship-family.md @ next-gen-2026 44836c1` +- "Current Understanding" §1.3 — the two-level argument and the identity consequence. + `docs/next-gen-schema/00-current-understanding.md @ next-gen-2026 44836c1` +- "The Mat and the Tree" §2.3 — the display specification's card frame, whose bottom row carries + exactly the foundation-context axes of C1: modality, region, subspecialty, sex, age, course, + etiology. `docs/next-gen-schema/09-mat-and-tree.md @ next-gen-2026 44836c1` + +**Related.** A9, C1, F1, F4. + +**Disagreements.** Recorded within the document: the negative typicality value "sits oddly" on an edge +named for manifestation and the alternative of a separate negative edge type is flagged; whether the +causal pair also takes typicality is left open. A separate two-sided fork is recorded as undecided: +an external reviewer's engineering memo recommends a condition on the edge where an existing element +value controls a relationship's applicability, reserving subtyping for independently meaningful class +identity, while the project lead's counter-proposal is subtype classes. The memo carries its own +warning that reading only it gives a one-sided picture. +`notes/conditional-relationships-memo.md @ next-gen-2026 44836c1` + +--- + +## F6. Measurement, method, and interpretation are three things + +**Idea.** "Peak systolic velocity is 350 cm/s" and "this represents hemodynamically significant +stenosis" are two assertions with different truth conditions, different provenance, and different +failure modes. The stated reason for keeping them apart is durability: thresholds move while +measurands and methods do not, so storing the interpretation makes the data wrong and unrecoverable +when criteria are revised, while storing the value plus a separate interpretive assertion citing the +criteria it applied lets the interpretation be re-derived and the change audited. Three corollaries +follow: confidence belongs to the interpretation, because one does not *possibly* measure 350 cm/s; +measurements must stand alone, because radiologists frequently report them with no interpretation at +all; and measurement becomes a definition type distinct from a data element, with method optional +and by default unspecified, so an absent method must not be filled with an assumed default. + +**Status.** Working proposal, recorded as an owner decision within the branch. + +**Implemented.** Measurement definitions exist as committed example data with their quantity, units +and range, separate from the categorical element definitions. +`docs/next-gen-schema/examples/size-mean-diameter.element.json @ next-gen-2026 44836c1`. + +**Evidence.** +- "What the Vocabulary Must Express" §4 — the two-assertion argument, the + thresholds-move-measurands-do-not principle with a twenty-five-year illustration from a standard + measurement atlas, the three corollaries, and the decision separating measurement from data + element with method optional. + `docs/next-gen-schema/01-what-the-vocabulary-must-express.md @ next-gen-2026 44836c1` +- The same document §4.2 — the note that this principle is already written down in narrower form in + the finding model guidance, which separates a nodule model from its risk-category model because + different radiologists assign different categories. + +**Related.** A9, F1, F5. + +**Disagreements.** Recorded as decision area ST09 against an external reviewer's alpha: the two +implementations have separate node families but "common binding behavior and interpretation links +need agreement". `docs/next-gen-schema/12-alpha-structural-comparison.md @ next-gen-2026 44836c1` + +--- + +## F7. Finding models as the CDE workbench + +**Idea.** Finding models are not a lightweight copy of common data elements; they are the fast, +ungoverned proving ground ahead of them. The January 2026 status deck names this "OIFM: the CDE +workbench" — rapid innovation ahead of adoption, programmatic knowledge for tools and model context, +and exploratory metadata "that can graduate to standards". The allied side states the other half: the +finding model effort "has independently built much of this and is roughly one iteration ahead", and +its models can be treated as drafts for finding classes, brought over for review rather than authored +from scratch. The project lead's own statement is shorter: the common-data-element work "should +dovetail with the OIFM work". + +**Status.** Stated goal in both directions; implemented example running in the opposite direction. + +**Implemented.** 115 of 2,382 models carry the common-data-element organization code, contributed with +an organization record naming the ACR/RSNA project and an index code in the RadElement system pointing +back at the set they came from. That index code is the join that lets a finding-model pipeline emit +common-data-element-labeled output. The chest CT content branch vendors 145 raw set definitions and a +converter beside them. +`ids.json @ findingmodels taxonomy-export-2026-08-15 a30c3c9`; +`cdes/definitions/` and `scripts/cde_to_finding_model.py @ content/chestcts 0472a46`. + +**Evidence.** +- The January 2026 status deck extract — the workbench framing and the "workbench effect" in the + executive summary. `knowledge/references/status-update-2026-01.md` +- "Current Understanding" §5.1 — a seven-row table of what the finding model work already answers + (decoupling, source versus hydrated form, quantity kinds, a relationship registry, governance + sidecars, metadata vocabularies, modelling guidance) and the caveat about bringing models over. + `docs/next-gen-schema/00-current-understanding.md @ next-gen-2026 44836c1` +- The staging repository's self-description and extraction-process note — "a staging area for + definitions of radiology common data elements in JSON format ... prior to their entering the review + pipeline", and a worked conversion of report language into what it calls mini-observations. + `README.md` and `docs/report_extraction_process.md @ CDEStaging main b814a10` + +**Related.** B2, B8, C3, F8. + +**Disagreements.** How the crossover works is explicitly open: a shared identity space and canonical +element registry, or a crosswalk maintained as a first-class deliverable. "Current Understanding" +Issue F states both and chooses neither. The practical asymmetry is recorded elsewhere: the IHE draft +prefers a common-data-element set code in the slot a finding model would occupy, and a model that has +not graduated has no set identifier to put there. + +--- + +## F8. Measuring coverage by running real reports against the vocabulary + +**Idea.** The gaps in a finding vocabulary are found by taking real report text and recording what it +says that the definitions cannot carry. Three gap classes are catalogued separately, each as a plain +list. *Composite negative statements* are sentences asserting absence across several structures at +once, often bundled with a technique limitation, which no single finding-plus-presence pair +represents. *Uncovered findings* are things reports say for which no definition exists at all. +*Missing attributes* are findings whose definition exists but which the report characterized along an +axis the definition does not carry, each entry linking to the specific definition file that fell +short. + +**Status.** Implemented example (the catalogues exist as data); the method is described but not +automated. + +**Implemented.** The extraction process document works one real pulmonary angiogram report into a +list of mini-observations, each a finding with a presence value and its attributes, and states the +two follow-up tasks that produced the catalogues: align finding, attribute and value names with the +definitions, and collect blanket negative statements into a separate file to catalogue and examine. +`docs/report_extraction_process.md @ CDEStaging main b814a10`. + +**Evidence.** +- The composite negative statements catalogue — real sentences grouped by body region, including + cases that bundle an absence with a technique caveat about contrast limiting sensitivity. + `report_representation/negative_statements.md @ CDEStaging main b814a10` +- The uncovered findings catalogue — findings with their reported attributes and no definition behind + them. `report_representation/uncovered_findings.md @ CDEStaging main b814a10` +- The missing attributes catalogue — each entry naming the finding, the attribute the report used, + and a link to the definition file lacking it. + `report_representation/missing_attributes.md @ CDEStaging main b814a10` +- The chest CT coverage roadmap — the same coverage question asked prospectively instead, as a + frequency-and-priority table per exam with a RadElement set link where one exists. + `definitions/upmedic/roadmap.md @ CDEStaging main b814a10` + +**Related.** A4, B7, F7. + +**Disagreements.** None recorded. + +**Undetermined.** Whether the three catalogues were ever acted on. They are dated 2024 to 2025 and no +document records a disposition. + +--- + +# What could not be determined + +1. **Whether the finding model format and the next-generation vocabulary converge on one artifact.** + Both sides state the relationship as a direction. Issue F of "Current Understanding" records the + mechanism as open and nothing decides it. +2. **What the project lead means by "interesting relationship/graph work coming from CDEs" for the + finding model format.** The relationship family (F5) and the draft registry (F4) are the candidate + artifacts; no document connects them to that goal statement. +3. **Whether the finding model relationship registry draft is live.** Dated April 2026, implemented + nowhere, and corrected in the relationship-family document as draft-only. +4. **Whether the exam-oriented sub-taxonomy hierarchy is meant to enter the schema**, and what + `finding_cluster` means. Declared in the taxonomy README, never explained, populated in one file. +5. **How the sub-taxonomy anatomic category relates to the metadata body-region enumeration.** The + categories are finer and not obviously mappable; no crosswalk exists on any branch read. +6. **Whether the eight structured metadata fields will land on the released branch.** Implemented on + a branch, readiness recorded as not passing, nothing merged, and the branch carries breaking + enumeration and validation changes not stated as agreed. +7. **How extracted sub-findings link to their parents.** Named as an open design problem on the chest + CT branch; no mechanism anywhere. +8. **Whether the second-generation per-file anatomy record model was adopted, rejected, or + superseded.** Hundreds of data files on an unmerged branch, inconsistent field names, no design + note, though several of its fields reappear in the current package's field reference. +9. **What the ACR Common identifier on anatomic location records is** — code system, issuing + authority, relation to RadLex identifiers. It appears as a bare numeric string in the field + reference and on the unmerged branch, and the name change from Body Part Index to Anatomic + Locations Index is nowhere explained. +10. **Why the exam type library was never built.** Four statements of the goal across four years; no + document explains the gap. How "always / usually / possibly" would be represented is equally + unstated. +11. **Whether proposed RadLex concepts were ever submitted**, and whether the three report-derived gap + catalogues were ever acted on. +12. **Whether the RSNA/ACR committee has seen or assented to any decision after June 2026.** The + decision record's provenance is the project lead and an assistant throughout; the last recorded + committee event is a meeting on 12 June 2026. + +--- + +# Proposed idea pages for this area + +Each page is one explanatory home; the ideas it houses are listed by inventory identifier. + +| Page | One line | Houses | +|---|---|---| +| `finding-model` | What a finding model is, what it contains, and the identifiers that carry its provenance. | A1, B1 | +| `what-counts-as-a-finding` | The boundary rules, the specificity rules, negative assertions, and the deliberate blending of description and diagnosis. | A2, A3, A4, A5 | +| `finding-model-conventions` | The operational rules the team enforces: presence and change from prior, synonyms as a matching surface, naming, associated findings versus components. | A6, A7, A8, A10 | +| `assessment-and-measurement` | Why a score is modelled apart from what it scores, and why a measured value is a separate assertion from its interpretation. | A9, F6 | +| `authoring-finding-models` | How content is actually produced: stubs and iteration modes, triage before create, three-tier review with context isolation, and why the prompts are fragments. | B3, B4, B5, B6 | +| `finding-model-content` | The corpus as merged provenance streams, the exam-oriented sub-taxonomies as direction and coverage ledger, convert-and-merge, and the upstream proposal loop. | B2, B7, B8, B9 | +| `foundation-context` | The eight metadata fields, each defined by what it excludes, and the exactness rule for index codes. | C1, C2, C3 | +| `assigning-metadata` | Focused agents, advisory audit, null as an answer, human review as the only authority, and how the artifacts are published. | C4, C5, C6, C7 | +| `finding-model-retrieval` | The three retrieval modes and the overlap check that runs before anything is authored. | C8 | +| `anatomic-location-index` | Containment as a single-parent tree, part-of kept separate, laterality triads, synthetic terms, and the curation rules that make the codes usable. | D1, D2, D3, D4, D8 | +| `why-anatomic-locations` | What was measured about existing ontologies, and what the index is and is not for. | D5, D9 | +| `anatomic-locations-and-radlex` | The overlay relationship, the missing taxonomic layer, and contributing terms back. | D6, D7, F3 | +| `anatomic-scope` | How a finding class says where it belongs, and how normal structures are described without one. | F1 | +| `exam-type` | Preferred entries over the Playbook and the inclusion edges to anatomy. | E1, E2 | +| `next-generation-vocabulary` | The redesign of the common-data-element vocabulary and the relationship family, including the draft finding model registry it corrects. | F4, F5 | +| `finding-models-and-cdes` | The workbench relationship in both directions, and how coverage is measured against real reports. | F7, F8 | +| `terminologies` | The role each vocabulary plays and why search recall is the gate. | F2 | + +Seventeen pages. `assessment-and-measurement` is small and may fold into `what-counts-as-a-finding` +if the measurement-versus-interpretation material from the next-generation work is thin once drafted. +Whether `next-generation-vocabulary` stays one page or splits by node types and relationships is a +drafting decision, not an inventory one. + +# Existing bundle pages holding unique team-authored material + +Each is the only durable copy in this repository of something the team wrote. They must be rehomed +before their current pages are removed. + +| Page | Unique material | Proposed home | +|---|---|---| +| `references/oifm-overview-extract.md` | The full upstream finding model guidance, quoted by four other pages. The prompt fragments now supersede it as the live source, but this is the only copy of the consolidated form. | Keep as a supporting reference linked from `what-counts-as-a-finding`. | +| `references/oifm-metadata-fields-extract.md` | The field-by-field metadata reference from a gist that is in no repository. | Keep as a supporting reference linked from `foundation-context`. | +| `references/cde-schema-differences.md` | The analysis of where the CDE set schema and the RadElement API diverge. | Keep as a supporting reference linked from `finding-models-and-cdes`. | +| `references/finding-model-schema.md` | The schema in prose. | Fold the load-bearing parts into `finding-model`; the code is the specification, per the team's own decision record. | +| `references/anatomic-location-json-schema.md` | The record shape in prose. | Fold into `anatomic-location-index`, keeping only what prose says better than the field reference. | +| `semantic-foundation/anatomic-locations/laterality-conventions.md` | Migrated laterality conventions. | Fold into `anatomic-location-index`. | +| `data-structures/anatomic-location-assignment-rules.md` | The three-step precedence ladder and the exam-to-region fallback table. | Belongs to the structures and applications area; flagged because `why-anatomic-locations` and `exam-type` both cite it. | +| `semantic-foundation/exam-types/existing-building-blocks.md` | The LOINC code census in the sample data, the Playbook provenance count in the ontology file, the viewer display table, the template corpus. | Reduce heavily; keep the few facts `exam-type` needs and drop the inventory. | +| `roadmap/open-questions.md` | Team questions mixed with agent-found documentation defects. | Split: team questions move beside the idea they belong to; defects go to `sources/upstream-issues-draft.md`. | +| `roadmap/anatomic-locations-and-radlex.md`, `roadmap/exam-types.md`, `roadmap/finding-model-format-evolution.md`, `roadmap/finding-model-content-direction.md` | Stated directions, already sourced. | Fold each into its idea page's direction section. No separate roadmap area for this material. | diff --git a/docs/plans/idea-inventory-structures-and-uses.md b/docs/plans/idea-inventory-structures-and-uses.md new file mode 100644 index 0000000..6fdd091 --- /dev/null +++ b/docs/plans/idea-inventory-structures-and-uses.md @@ -0,0 +1,926 @@ +# Idea inventory: observations, imaging history, applications, and OIDM's purpose + +Status: Working inventory for step 1 of `restructure-around-project-ideas.md`. Not a published page. No idea pages written. + +Scope: 41 distinct ideas (A1-A26 structures, B1-B11 applications, C1-C4 purpose). Area covered: observations and imaging history (Observation, Exam Finding List, Imaging Problem List, Imaging Persona, status and trajectory, succession and linking, provenance and review, application-layer structures versus transport expressions, extraction and coding of findings from reports); the applications and uses the team wants to demonstrate; OIDM's stated purpose and the relationship among its parts. + +## How to read this + +Each idea carries a **statement** in the team's own terms, a **status** (stated goal / working proposal / implemented example; several entries where an idea exists at more than one status), **evidence** as precise pointers, **related ideas**, **unresolved** alternatives with attribution, and **undetermined** where the sources do not settle a question. + +Evidence conventions and short names used throughout: + +| Short name | What it is | Pin | +|---|---|---| +| IPL repo `main` | `openimagingdata/imaging-problem-list`, branch `main` | `06f64a7` (2025-11-18) | +| IPL repo `dev` | same repo, `origin/dev` | `36fa30c` (2026-07-22) | +| JDIM IPL manuscript | "The Imaging Problem List: A Standards-Based Framework for Longitudinal Tracking of Imaging Findings", JDIM-D-26-02980 **R1, under review** | `sources/bucket/JDIM-D-26-02980_R1.pdf`; clean manuscript pp.3-32; printed page numbers cited below | +| JACR IPL manuscript | "Follow-Up Chest CT Reporting Is Mostly Re-Documentation…", **prepared for submission**, blinded | `sources/bucket/text/jacr-ipl-manuscript.md`; supplement `…/jacr-ipl-supplement.md` | +| SIIM webinar | "The Imaging Problem List as an Accelerator for Radiology AI Applications", SIIM Enterprise Imaging Webinar, delivered 2026-07-15, **public** | `sources/bucket/text/ipl-webinar-deck.md`, cited by slide number | +| January 2026 deck | "OIDM 2026 Status Update: Realizing Object-Oriented Imaging Results" | `sources/gamma-2026-status-update.md` | +| Email notes | Project lead's notes on the revised IPL manuscript, 2026-09-19 | `sources/email/2026-09-19-ipl-manuscript-notes.md` | +| Board *n* | Excalidraw board *n* as transcribed | `sources/excalidraw-diagrams.md` | +| example2 study | File-by-file code read of the dev-branch sample data and viewers, 2026-09-21 | `sources/ipl-example2-study.md` | +| Site post | openimagingdata.org Ghost post, dated | live site | + +Other pins: `IPL-MVP-ExtractionAndLabeling` `main` `b06948f` (2025-10-20), branch `origin/Persistent_FHIR_Resources` `5ea6720`; `OpenImagingDataModel.py` `main` `455e5b6` (2024-11-13); `FHIRSamples` `main` `9ae2fa9` (2024-03-13); `UseCases` `main` `71a90d2` (2024-02-26); `CDETemplateDemo` `master` `e09f255` (2023-06-15); `FindingModelForge` `main` `f55dc85` (2025-08-20), `origin/dev` `15d9ebc` (2026-01-02). + +Board sensitivity. Boards 1, 2, 6, 7, 10, 11 and 15 carry named individuals, meeting attendee lists, or vendor-collaboration histories per the sensitivity section of `sources/excalidraw-diagrams.md`. Only schema and data-model ideas are drawn from them here, with organizations named and people, dates tied to people, and meeting histories omitted. Boards 4, 8, 12, 13 and 14 are flagged low or moderate sensitivity with no named individuals. Board 8 is the one flagged as exhibit-ready and public-facing. Response-to-reviewer correspondence in both JDIM PDFs was identified and not read for content, and is cited nowhere. + +## Prompts as primary sources + +The prompts the team wrote carry its operational definitions: what counts as a finding, how presence, negation, hedging, laterality and location are decided, and what a valid extraction is. They are cited here as documents in their own right, by file and constant name, not as "the repository". All are on IPL repo `dev` `36fa30c` unless stated. + +| Document or prompt | What it governs | +|---|---| +| `src/finding_extractor/extractor/prompt.py` | The extraction system prompt, assembled from named blocks: `ROLE_BLOCK`, `CORE_INSTRUCTIONS_BLOCK`, `DEDUPLICATION_BLOCK`, `PRESENCE_BLOCK`, `ATTRIBUTES_BLOCK`, `LOCATION_BLOCK`, `NON_FINDING_BLOCK`, `OUTPUT_FORMAT_BLOCK`; plus `CHUNK_ROLE_BLOCK` and `CHUNK_RULES_BLOCK` for the chunk sub-agent | +| `src/finding_extractor/coding/prompt.py` | Four coding prompts: `FINDING_TERM_SYSTEM`, `LOCATION_TERM_SYSTEM`, `FINDING_CODE_SELECTOR_SYSTEM`, `LOCATION_CODE_SELECTOR_SYSTEM`, each with numbered rules | +| `prompts/validator_prompt_example.md` | The chunk reviewer's system prompt, user-prompt template, and structured response shape | +| `docs/coding-agent-prompts.md` ("Coding Agent Prompts — Draft v2") | The same four coding prompts with a "Design Notes" section explaining why there are four and what each unresolved reason signals | +| `docs/coding-agent-design.md` | The coding pipeline's phases, rationale and tuned parameters | +| `docs/report-sections.md` | The canonical report-section vocabulary, alias table, and detection rules | +| `docs/extraction-internals.md` | Sectioning and chunking behavior, the chunk contract, the reviewer contract | +| `docs/anatomic-location-assignment-rules.md` | The location precedence ladder, laterality, bilateral and specificity rules | +| `docs/technical-imaging-findings.md` | The catalog of modality-specific technical terms and the rule against reinterpreting them | +| `initial-extraction-plan.md` | The original model design and the post-extraction validation design | +| `docs/plans/extractor-evals-redesign.md`, `extraction-reviewer-ux.md`, `extraction-reviewer-workflows.md` | Evaluation honesty, the reviewer instrument, gold adjudication | +| `config.py` in `IPL-MVP-ExtractionAndLabeling` `main` `b06948f` | `EXTRACTION_SYSTEM_PROMPT`, the two-field ancestor of the current model | + +Code behavior is reported as what the software does, in the idea's terms, with a pointer. Installation and usage documentation is not reproduced. + +--- + +# Part A. Observations and imaging history + +## A1. Observation as the atomic unit of an imaging result + +**Statement.** One Observation records one finding asserted on one exam: *what* (a coded finding type), *where* (an anatomic location), and *attributes* (presence indicators, change from prior, measurements, lesion characteristics). The January 2026 deck calls it "the atomic unit" with a "universal structure across systems." + +**Status.** Stated goal (deck); implemented example (every EFL entry in the sample data); working proposal (the typed class model on Board 4). + +**Evidence.** +- January 2026 deck, "Observation object (atomic unit)": "What + Where + Attributes: finding tag + anatomic location + lesion characteristics. Presence indicators, change from prior, measurements. Universal structure across systems." — the deck's own definition of the unit. +- IPL repo `dev` `36fa30c`, `CLAUDE.md` "Domain Model": each EFL finding "has an OIFM code, description, and attributes (presence/absence, change from prior)" plus an optional `anatomicLocation` of `{locationId, locationDisplay}`. — the shape as the repo states it. +- example2 study §1.2: across all 276 EFL entries in `sample_data/example2`, the keys actually used are exactly `observationId`, `findingCode`, `findingDescription`, `attributes[]`, optional `anatomicLocation`, optional `reportText`; every `attributes[]` array has exactly one member and it is always `presence`. — what the implemented example actually carries, as against what the model allows. +- Board 4 ("OIDM Object Model"), class-diagram cluster: `Observation` with `id`, `code` (CDE Set ID), `body_site`, `tracking_id`, `components[]`; `Observation Value` with `code` (CDE Element ID) and `value`. — a typed class proposal including a tracking identifier. +- `OpenImagingDataModel.py` `main` `455e5b6`, `openimagingdatamodel/observation/observation.py`: `Observation` with `id`, `identifier`, `code`, `status`, `subject`, `bodySite`, `derivedFrom`, `component` as a discriminated union of codeable-concept / string / integer / boolean variants; the class docstring states "The Observation class is the model for FHIR Observation objects", and a code comment records a deliberate divergence, that "the FHIR spec has all fields optional, but we require system and code". — the 2024 reference implementation's shape. +- Site post "Findings, CDEs, and Observations", 2023-06-24: "Each `Observation` is labeled with a ACR/RSNA Common Data Element (CDE) Set ID to indicate what kind of finding it is, and the value for each attribute of the finding is labeled with a CDE Element ID." — the definition of "CDE-labeled". +- `IPL-MVP-ExtractionAndLabeling` `main` `b06948f`, `src/schemas.py`: the ancestor `Finding` model is two fields, `name` ("Lowercase finding name") and `present` (bool). `config.py` `EXTRACTION_SYSTEM_PROMPT` asks for "all radiologic findings mentioned" as `{"name", "present"}` pairs, listing pathological findings, anatomical variations, incidental findings and "Negative findings (explicitly stated as absent)". — the minimal starting point the current model grew from. + +**What the code implements.** `src/finding_extractor/models.py` on IPL repo `dev` `36fa30c` defines the current extraction-side Observation as `Finding` with `finding_name`, `presence`, `location` (a separate `FindingLocation` of `body_region`, `specific_anatomy`, `laterality`), `attributes` (a list of open key/value `FindingAttribute`), `report_text` and `source_section`. `initial-extraction-plan.md` records why location is its own structure rather than an attribute: it is "**separate from other attributes** because location is often implied by the exam type rather than stated explicitly." The same plan records the decision to leave the attribute key open: constraining it "would reject valid but uncommon attributes." + +**Related.** A2, A4, A12, A21, A25, C2. + +**Unresolved.** The deck names measurements and lesion characteristics as attributes; example2 populates only presence. Whether the gap is a data-collection artifact or a model position is not stated in any source read. + +**Undetermined.** No committed JSON Schema or Pydantic model for Observation exists in any repository read; `$schema` URLs in the sample files resolve to nothing (example2 study §1.2, IPL repo `main` `CLAUDE.md` "Schema Reference"). + +## A2. Two-level architecture: Exam Finding List, then Imaging Problem List + +**Statement.** Findings are represented at two levels. The Exam Finding List (EFL) is the list of findings declared present or absent on one examination. The Imaging Problem List (IPL) is the patient-level aggregation of EFL observations across examinations into longitudinal entries. The JDIM manuscript states the reason: "A radiologist observes one examination at a time, but their judgments (is this new, is this the same finding) span examinations, so we designed the IPL as a two-level data model." + +**Status.** Working proposal (manuscript, webinar, deck); implemented example (repo, sample data, viewers). + +**Evidence.** +- JDIM IPL manuscript, Methods, "Structure of the Imaging Problem List", printed p.6: the two-level rationale quoted above, and "The first level is the Exam Finding List (EFL): the observations recorded on a single imaging examination." +- JDIM IPL manuscript, printed p.7: "The second level is the IPL itself: a patient-level aggregation of EFL observations across examinations into longitudinal finding entries." +- IPL repo `main` `06f64a7`, `README.md`: EFL is "In the context of an imaging exam, a list of the findings declared as present/absent on that exam"; IPL is "In the context of a patient, the list of findings that have been described as present/absent in exams of the patient." — the repository's own two-level statement, unchanged on `dev`. +- January 2026 deck, strategic pillar 2: "atomic Observation -> Exam Finding List -> IPL -> 'Imaging Persona'." — a four-level hierarchy, of which two levels are built. +- SIIM webinar slide 17 ("Two-level model") and slide 16 (pipeline: "reports → structured extraction → per-exam EFLs → temporal aggregation → the IPL → five downstream application families"). +- IPL repo `dev` `36fa30c`, `scripts/generate_ipl_from_efls.py`: deterministic aggregation of all `*_efl.json` in a directory into one IPL, no model calls (example2 study §3.3). + +**Related.** A1, A3, A5, C2. + +**Unresolved.** The deck's hierarchy has four levels; the manuscript and repository define two. Imaging Persona (A16) is named only in the deck and the boards. + +## A3. The faithful-translation constraint on the Exam Finding List + +**Statement.** The EFL is a near one-to-one translation of what the radiologist asserted on one examination, with no comparison across examinations and no extrapolation beyond the report text. The webinar states the consequence: "nothing invented enters the foundation," which is what lets every derived layer be trusted without re-verification against the source text. The JACR manuscript states the same requirement for its extraction tool: "Our tool was built to transcribe, not interpret." + +**Status.** Working proposal (manuscript, webinar); implemented example with a measured failure mode (JACR extraction tool); implemented example (verbatim-quote validation in the extraction platform). + +**Evidence.** +- JDIM IPL manuscript, printed p.6: "The EFL is intended to be a near one-to-one translation of what the radiologist asserted on one examination, with no comparison across examinations and no extrapolation beyond the report text." +- SIIM webinar slide 17 speaker notes: "That is the source of trust: nothing invented enters the foundation… Put inference in the foundation and you contaminate everything above it." +- SIIM webinar slide 18 speaker notes: "nothing on the right exceeds the sentence it came from: no comparison across exams, no inference." +- JACR IPL manuscript, Discussion: "The record's fundamental building block, the extracted finding, has to stay true to what the board-certified radiologist said… inferring what the radiologist probably meant would introduce unpredictability into the extractions." +- JACR IPL manuscript, Results, "Extraction and matching validity": for at least 3.6% of findings (111 of 3,056) the tool supplied an assertion the radiologist did not write, recording lymph node enlargement for a neutrally stated measurement. The Discussion calls this out: "The label was technically correct, but the tool should still not have supplied the inference." — a measured violation of the constraint by the team's own tool, reported against itself. +- The extraction system prompt states the rule three times. `CORE_INSTRUCTIONS_BLOCK` item 5: "**When quoting report text, BE EXACT** — verbatim excerpts only, never paraphrase". `OUTPUT_FORMAT_BLOCK` closes with "Remember: QUOTE MUST BE VERBATIM. Do not paraphrase or summarize the report text." `CHUNK_RULES_BLOCK` item 6 requires the quote be "a substring copied from the TARGET CHUNK that supports the finding." +- `CHUNK_ROLE_BLOCK` sets an evidence boundary for the chunk sub-agent: "Work only on the TARGET CHUNK text. Adjacent context is advisory only and must not be used as extraction evidence." `prompts/validator_prompt_example.md` repeats it for the reviewer: "Evidence boundary: only REPORT_CHUNK is evidence; surrounding context is advisory." +- `initial-extraction-plan.md`, "Post-Extraction Validation", names the verbatim check as "the most common extraction failure mode", and its addendum promotes it from a post-hoc report to an enforcement point: an `@agent.output_validator` that raises `ModelRetry` so a paraphrase triggers a retry rather than a warning. The rationale is recorded as "the single biggest extraction-quality win." +- `docs/report-sections.md` records a design point that protects the rule: the auto-detected section hint "is placed **before** the report delimiters, so verbatim validation against the original text is unaffected." +- example2 study §1.2: every EFL observation carries `reportText`, a verbatim quote from the report Markdown. + +**What the code implements.** Verbatim quoting is enforced at run time, not merely requested: IPL repo `dev` `36fa30c` `CLAUDE.md` records "Validated both as a PydanticAI output validator and post-hoc," and the reviewer's failure taxonomy has a `hallucination` category for "clinically meaningful content unsupported by the chunk text" (A26). `initial-extraction-plan.md` also specifies a coverage check that compares the union of every `report_text` and `non_finding_text.text` against the full report "to surface any text the agent skipped entirely," so the extraction accounts for the whole report rather than only the parts it recognized. + +**Related.** A5, A8, A10, A23, A26, B2, B4. + +## A4. Entry identity is the finding code plus the anatomic site + +**Statement.** One IPL entry is one finding in one patient, identified principally by finding code plus anatomic site. A diagnosis or category the radiologist assigns, such as a LI-RADS category, is an attribute recorded on the observation rather than a separate identity, so a lesion whose category is revised stays one entry and the revision becomes part of its trajectory. + +**Status.** Working proposal (manuscript); implemented example (the dev-branch grouping key). + +**Evidence.** +- JDIM IPL manuscript, printed p.8: "Each IPL entry is one finding in one patient. Its identity rests principally on two fields, the finding code and the anatomic site… A diagnosis or category, such as LI-RADS LR-3, is the radiologist's interpretation, recorded on the observation, so a hepatic lesion whose LI-RADS category the radiologist revises on subsequent imaging stays one entry and the revision becomes part of its trajectory." +- IPL repo `dev` `36fa30c`, `CLAUDE.md`: the IPL "Groups observations by finding type **and** anatomic location (`locationId`) across exams… consumers key on the IPL finding `id`, not `finding_type_code`." +- IPL repo `dev` `36fa30c`, `scripts/generate_ipl_from_efls.py`, in-code comment: "A finding code at two distinct anatomic locations… becomes two separate IPL entries" (example2 study §3.3). +- example2 study §1.3: 123 IPL entries over 276 observations; every observation folded into an entry shares that entry's `{locationId, locationDisplay}` exactly, which follows mechanically from the grouping key. +- JDIM IPL manuscript, printed p.6: "A finer gradation the radiologist states, such as a BI-RADS assessment category, is recorded as an attribute of the observation." + +**Related.** A2, A10, A12, A13. + +**Unresolved.** Entry identity in the worked exemplar was still moving between sources. See A5's entity-count difference. + +## A5. Status is derived from the observation history, never stored — and three vocabularies disagree + +**Statement.** An entry's status is computed from its observation history by fixed rules and recomputed whenever the history changes, so no model judgment is stored as clinical fact and an application can tell what a radiologist stated from what the system computed. Trajectory is likewise a read of the history rather than a stored field. Three sources name three different status vocabularies. + +**Status.** Working proposal (manuscript, webinar); implemented example (both viewers compute status; the second stores a precomputed copy). + +**Evidence.** +- JDIM IPL manuscript, printed p.8: "The IPL entry status has one of four values programmatically derived from the observation history, recomputed whenever that history changes." Active = most recent observation present and new or changed; Stable = present and unchanged; Resolved = an earlier observation present and the most recent absent; Excluded = explicitly reported absent at some point and never observed present, "a tracked pertinent negative, such as 'no pneumothorax'" (printed p.9). +- JDIM IPL manuscript, printed p.9: "A reader or an application reads an entry's trajectory from its observation history… **The entry has no trajectory element of its own.**" +- JDIM IPL manuscript, printed p.11: "What the IPL then displays, from an entry's status to its trajectory, is computed by fixed rules from the linked observations, so no model judgment is stored as clinical fact." +- SIIM webinar slide 21 speaker notes: status is derived at read time with two top-level values mirroring "the clinical problem list's active/resolved model", and **within Active** a trajectory of "appearing, progressing, regressing, fluctuating", "the finer read from the measurements." +- IPL repo `main` `06f64a7`, `CLAUDE.md` "Temporal Status Tracking": three states — Present, Resolved, Not Present/Ruled Out — with filters All / Currently Present / Resolved / Ever Present / Ruled Out. +- IPL repo `dev` `36fa30c`, `CLAUDE.md`: "Tracks temporal status: currently present, resolved, never-present/ruled-out" — three states named. +- IPL repo `dev` `36fa30c`, `docs/plans/viewer-v2-anatomy-dashboard.md`, "Status Semantics": four values — `current`, `always`, `resolved`, `never_present`. +- example2 study §2.1 and §3.4: viewer v1's `computeFindingStatus` and `build_viewer_v2_data.py`'s `compute_status` implement the identical four-branch algorithm; v1 labels the fourth branch `never`, viewer_v2 labels it `never_present`; viewer_v2 also adds `unknown` for an entry with no observations. Viewer_v2 **stores** the result in `viewerMetadata.statusByFindingId` in its generated bundle rather than computing it in the browser. +- example2 study §1.3: the canonical `sample_data/example2/MRN0000001_ipl.json` has **no `status` field at all**. + +**Related.** A2, A4, A7, B1. + +**Unresolved — four attributed positions on status.** + +| Source | Vocabulary | +|---|---| +| JDIM IPL manuscript (under review) | Active, Stable, Resolved, Excluded; no trajectory element | +| SIIM webinar, 2026-07-15 (public) | Active, Resolved; trajectory within Active: appearing, progressing, regressing, fluctuating | +| IPL repo `main` and `dev` `CLAUDE.md` prose | Present/current, Resolved, Never-present/ruled out (three) | +| IPL repo `dev` viewer_v2 plan and both viewers' code | current, always, resolved, never_present (plus `unknown` in code) | + +**Unresolved — the exemplar entity count.** The same synthetic patient (64-year-old, cirrhosis, 15 exams, 4 modalities, 2017-2024) yields 223 observations in 41 entries in the JDIM manuscript abstract and 225 observations in 43 entries in the SIIM webinar (slide 24). `sources/bucket/REPORT.md` §7 attributes the difference to the webinar version splitting acute from healed rib fractures and acute L4 compression fracture from chronic L4 compression deformity into separate rows, where the manuscript keeps each as one entry with an internal acute-to-healed trajectory. This is an unresolved entity-identity rule, not a counting error. + +**Undetermined.** Whether the deliberate storage of status in viewer_v2's generated bundle is a considered exception to "never stored" or a build-pipeline convenience is not stated in the viewer plan. + +## A6. The succession link + +**Statement.** One entry tracks one physical entity across its whole course. When a resolved finding leaves a different entity behind, the new entity gets its own entry and is connected to the resolved one by a succession link rather than mutating the original. The manuscript's example is a pneumonia and the residual scarring it leaves. + +**Status.** Working proposal only. + +**Evidence.** +- JDIM IPL manuscript, printed p.8: "The entry's succession link connects a resolved entry, such as a pneumonia, to the entry for the distinct finding it left behind, such as the residual scarring." +- JDIM IPL manuscript, printed p.9: "One entry tracks one physical entity in the patient across its whole course, including observations that report it absent. The scarring a pneumonia leaves behind is a different entity from the pneumonia, so it gets its own entry but is associated with the resolved pneumonia by a succession link." +- SIIM webinar slide 22 speaker notes: "the pneumonia Resolves, and its scarring enters as its own distinct entry rather than mutating the original." +- `sources/bucket/REPORT.md` §4: Figure 2 of the manuscript shows a dashed succession-link arrow from resolved pneumonia to its scarring sequela on the patient timeline. +- example2 study §1.4: "There is no succession/supersede/merge field anywhere connecting these two entries" — the implemented sample data has no succession link. + +**Related.** A5, A7, A13. + +**Undetermined.** Whether the acute-to-healed fracture case belongs to succession or to within-entry time course. The manuscript treats evolution as "the stated time course within one entry" (printed p.11); the webinar exemplar splits it into two entries (A5, entity-count difference). + +## A7. Per-observation provenance and review status, and corrections as provenance operations + +**Statement.** Each observation records where it came from, whether a radiologist has reviewed it, any change a radiologist made to what a model produced, and the original report text. For a model source, provenance records the model's identity and version, its inputs, its output, and any confidence it provides. Review status is "unreviewed" or "affirmed"; a later affirmation or rejection supersedes an earlier one with both retained. Merging entries, splitting an entry, and marking an observation in error are logged as provenance operations, not statuses. + +**Status.** Working proposal (manuscript, webinar); a lineage precedent that overloads a different field; not implemented in the sample data. + +**Evidence.** +- JDIM IPL manuscript, printed p.10: "Provenance records, for each observation, where it came from, whether a radiologist has reviewed it, any change a radiologist made to what a model produced, and the original report text… The review status is 'unreviewed' or 'affirmed'… A later affirmation or rejection supersedes an earlier one, with both retained in provenance. Observations within one entry may differ in source and review status, so each has its own provenance." +- JDIM IPL manuscript, printed p.9: "When two entries are discovered to be one finding, when one entry is determined to be two separate entities, or when an observation was entered in error, the record is corrected by merging, splitting, or marking the observation, and each correction is logged in provenance. Merging, splitting, and marking are provenance operations, not statuses." +- SIIM webinar slide 46 speaker notes: "every machine-generated observation is marked unreviewed until a radiologist affirms it; LLM is an enumerated provenance source, so this is not a bolt-on." +- IPL repo `main` `06f64a7`, `README.md`: the EFL specification asks that "each Observation should include some kind of provenance marker." No field is named. +- `FHIRSamples` `main` `9ae2fa9`: the same lung-screening finding appears twice, once as an AI observation with FHIR `status` `preliminary` and once as the radiologist's with `status` `final`, the resources otherwise identical — the only implemented precedent, and it overloads the FHIR `status` field rather than carrying a provenance structure. +- example2 study §2.2: "No clinical confidence, hedge, review-status, or provenance field exists anywhere in either viewer's data model or rendering code." +- IPL repo `dev` `36fa30c`, `README.md` "Extraction Persistence": the platform stores each extraction run with its report link, timestamp, model, reasoning setting and full JSON payload, and represents reviewer edits as correction objects (`add_finding`, `update_finding`, `comment`) — provenance implemented for the *extraction pipeline*, not for the IPL data structure. + +**Related.** A3, A8, B2, B4. + +## A8. Entity resolution is the open problem; graduated-confidence linking is the proposal + +**Statement.** Matching observations across examinations is the unsolved step. Simple matching on finding code plus site suffices when a finding is the only one of its type at its location. For harder cases the team proposes graduated-confidence linking: a radiologist's explicit comparison to a specific prior makes a high-confidence link; code plus location plus temporal plausibility makes a medium-confidence link; spatial proximity alone makes a low-confidence link; below any threshold the observations stay separate entries. Both manuscripts state that a false split costs redundancy while a false merge corrupts a trajectory. + +**Status.** Working proposal (linking model); implemented example (code-plus-site matching only); measured limitation (JACR). + +**Evidence.** +- JDIM IPL manuscript, printed p.11: "The simplest linking logic is matching on code and site… This suffices when a finding is the only one of its type at its location: one aortic aneurysm, one instance of hepatic steatosis, one set of coronary artery calcifications. **The exemplar in Results uses this matching alone.**" +- JDIM IPL manuscript, printed p.12: the three confidence levels, verbatim as summarized above, and "When confidence is insufficient at any level, the observations would be kept as separate IPL entries." +- SIIM webinar slide 13: "report → extraction · solved → findings → same entity? · open → one tracked entity", with slide 23 speaker notes: "never a merge on weak evidence. A false split costs a little redundancy; a false merge corrupts a trajectory. Be honest that the current prototype links on finding code alone; matching is the open frontier." +- JACR IPL manuscript, Results: 181 of 2,232 findings (8.1%) "could not be matched to a single earlier finding", mostly where a patient had several findings of one type in one location; these receive no grade but stay in the denominator, making the reported burden a lower bound. "Deciding whether two descriptions name one finding or two is entity resolution." +- JACR IPL manuscript, Take Home Points: "The remaining implementation work is entity resolution, deciding when two descriptions on different CTs name the same finding." +- JACR IPL manuscript, Table 2: four ordered matching rules (Name, Site, Match, Ambiguity) plus a fifth for grading, each with its stated error direction; "Every matching rule fails toward keeping findings separate, because wrongly merging two findings manufactures a re-documentation." +- JDIM IPL manuscript, printed p.19: "The IPL is an application-layer data model over the CDE-labeled FHIR Observations… DICOM Structured Reports are a natural source of EFL observations, and the DICOM tracking identifier marks observations as referring to one finding without defining how they are matched, collected, or used." + +**Related.** A4, A9, A13, A19. + +**Unresolved.** The JACR rules and the JDIM graduated-confidence model are two different formulations of the same step, developed for different purposes (a locked measurement instrument versus a proposed linking model), and no source reconciles them. + +## A9. One finding may be described by several observations in one report, and by different codes across reports + +**Statement.** The same finding is often described more than once in a single report, in the findings section and again in the impression, and the EFL records one observation per finding per examination while preserving each sentence that contributed to it. Across reports, observations of one finding may use different but related codes: more or less specific terms, a diagnosis substituted for a finding or the reverse, or the entity's own evolution such as acute rib fractures becoming healed rib fractures. + +**Status.** Working proposal (manuscript); measured difficulty (JACR); explicit direction from the project lead. + +**Evidence.** +- Email notes, point 1: "The same finding is often described by more than one observation in a single report (findings section and impression). Found in the JACR chest CT work; aggregating observations into one or several findings was hard for the LLM. To be included in the manuscript." +- Email notes, point 2: "Observations of one finding across reports may use different but related codes: more or less specific terms; a diagnosis substituted for a finding or vice versa; the entity's evolution over time (acute rib fractures becoming healed rib fractures). **The manuscript should make clear how the IPL structure accounts for finding versus diagnosis.**" +- JDIM IPL manuscript, printed p.6: "A report may describe one finding twice, in the findings section and again in the impression. The EFL records one observation per finding per examination and preserves each sentence that contributed to it, so reconciling repeated descriptions within a report is part of producing the EFL." +- JDIM IPL manuscript, printed p.11: "The terms may be broader or narrower (a hepatic lesion on one report, a hepatic cyst on the next), substitute a diagnosis for the finding it rests on (pneumonia for consolidation), or follow the finding's evolution (an acute fracture, then a healed one). Evolution is the stated time course within one entry. Matching the other two would draw on the relationships among codes that a finding vocabulary defines, so that codes related at the vocabulary level can be matched at the patient level." +- JACR IPL manuscript, Methods, "Rules for aggregating findings across CTs": the worked emphysema case — "one patient's emphysema was called 'centrilobular paraseptal emphysema', then 'emphysematous change', then 'emphysema', then 'centrilobular emphysema'." +- example2 study §1.4: `ipl-finding-102` "pancreatic lesion" folds two separate EFL observations from the same 2021-08-26 exam (`pancreatic_lesion_0` and `pancreatic_mass_0`) into one entry — the implemented case of two observations of one finding in one report. +- SIIM webinar slide 42: the breast case, where at biopsy "the entity transitions from mass-as-observation to fibroadenoma-as-diagnosis" while remaining one entity across five exams. +- JACR supplement, S2, gives the study's operational definition: "An observation is what the radiologist sees on the image… A diagnosis is what the radiologist concludes those observations represent, and it is not itself visible"; the diagnosis attaches to the observation it interprets and carries the radiologist's stated confidence, so one abnormality is not counted twice. + +**What the code implements.** The extraction prompt's `DEDUPLICATION_BLOCK` is the working resolution of the one-finding-many-observations problem inside a single report. It makes the body text primary ("The Findings (or Comment/Body) section contains the detailed descriptions. Extract all findings from there first"), extracts from the impression only what the body does not already carry ("**Impression: extract UNIQUE items only** — If the Impression/Conclusion contains a diagnosis or finding that has NO corresponding description in the body text, extract it as a finding… Do NOT re-extract findings already covered by a body-text finding"), records where each finding came from in a `source_section` field valued `findings`, `impression`, `both` or null, and settles conflicts in favor of the body: "**Body text is authoritative** — When a finding appears in both sections, use the body text for details… The body section has the specifics; the impression is a summary." A separate rule handles repetition within one section: "**One entry per distinct finding instance** — If the same finding is described in multiple paragraphs within the body text, extract it once using the most detailed description." `CHUNK_RULES_BLOCK` item 7 handles the opposite case, where one sentence names a general finding and then instances of it: extract "both the general finding and each specific instance, and apply this for both present and absent statements." + +**Related.** A4, A8, A11, A23, A24, A26, and the finding-model vocabulary relationships covered by the semantic inventory. + +**Unresolved — finding versus diagnosis.** Four positions are on record, none reconciled: +- JDIM IPL manuscript (printed p.8): a diagnosis is an attribute of the observation, not a separate identity. +- The project lead, 2026-09-19 (email notes, point 2): the structure's account of finding versus diagnosis is not yet clear enough and should be made explicit in the manuscript. +- IHE Imaging Diagnostic Report Phase II public-comment draft, as extracted on `RSNA/ACR-RSNA-CDEs` `next-gen-2026` (`knowledge/data-structures/ihe-idr-alignment.md` and its cited extract): positive clinical findings are FHIR `Condition`, negatives are `Observation`. +- The working default recorded in that same extract: "every assertion in a radiology report, diagnoses included, is encoded as an `Observation`", because "'consistent with pneumonia' is a radiologist's assertion, not an established clinical condition." +- The next-generation CDE vocabulary's worked example deck tags each observation FINDING / DIAGNOSIS / GROUPING and links them with report-plane edges `SUPPORTS` and `ASSOCIATED_WITH` (`sources/bucket/text/next-gen-reporting-schema.md`; `sources/bucket/REPORT.md` §6) — a fifth treatment, from the allied CDE workstream. + +## A10. Presence is binary; confidence and hedging are a separate axis + +**Statement.** Presence is present or absent. Confidence is definite or hedged, recording whether the radiologist committed plainly or professed uncertainty. The hedge is recorded on whichever assertion the radiologist softened, the finding's presence or one of its attributes, and the exact wording is preserved. The webinar states the design reason: a top-level "indeterminate" fuses which way the radiologist leaned with how firmly they said it. + +**Status.** Working proposal (manuscript, webinar); a contrary implemented example. + +**Evidence.** +- JDIM IPL manuscript, printed p.6: "Presence is present or absent, and confidence is definite or hedged, recording whether the radiologist committed plainly or professed uncertainty." +- JDIM IPL manuscript, printed p.7: "A hedge is recorded on whichever assertion the radiologist softened, whether the finding's presence ('possible pneumonia') or attribute ('likely acute'), and the preserved report text retains the exact words." +- SIIM webinar slide 19 speaker notes: "Rule 4 in particular: binary presence plus per-axis confidence is more faithful and more elegant than a top-level 'indeterminate', which fused which way the radiologist leaned with how firmly." +- SIIM webinar slide 20 speaker notes: "'Possible' hedges the presence axis: presence stays binary, the hedge is recorded per-axis; the stated chronicity (acute) is recorded as stated, never inferred." +- example2 study §1.2 and §1.4: the implemented sample data uses a **three-value** presence vocabulary — `present` (113), `absent` (160), `indeterminate` (3) — with no separate confidence field; "Indeterminate is a real third presence state… distinct from present/absent, and it participates in status computation exactly like `absent` does." +- JACR IPL manuscript, Outcomes: hedged findings are reported separately from the primary outcome (42 of 57 hedged chronic findings re-documented with no change, versus 951 of 1,229 unhedged). + +**What the code implements.** The extraction prompt's `PRESENCE_BLOCK` defines a **four-value** presence vocabulary and, unusually, states the test for applying it. The values: "**present**: The finding is explicitly stated as present"; "**absent**: The finding is explicitly stated as absent (e.g., 'no ascites', 'normal hilar contours', 'unremarkable')"; "**indeterminate**: Cannot be determined from the report"; "**possible**: Hedged/uncertain language ('raising the possibility of', 'suggestive of', 'cannot exclude')". The test separates a hedged *observation* from a hedged *interpretation*: "When the imaging observation itself is definitively seen but the interpretive label uses hedging, the finding is **present** — e.g., 'decreased attenuation suggestive of fatty infiltration' → hepatic steatosis is **present** (the decreased attenuation IS observed)… When the finding/diagnosis itself is uncertain, use **possible**… Key test: Is the imaging observation definitively seen, or is the diagnosis itself uncertain?" This is the finding-versus-diagnosis distinction of A9 operating as a presence rule. `initial-extraction-plan.md` fixes the same four values as a `Literal` on the model so an out-of-vocabulary value fails validation. + +**Related.** A3, A5, A9, A23. + +**Unresolved — three positions on presence, not two.** + +| Source | Presence vocabulary | +|---|---| +| JDIM IPL manuscript, printed p.6, and SIIM webinar slide 19 | Binary present/absent, with confidence definite/hedged as a separate per-axis value; an explicit argument against a fused top-level "indeterminate" | +| Extraction prompt `PRESENCE_BLOCK`, and `initial-extraction-plan.md` | Four values: present, absent, indeterminate, possible — where "possible" is hedging and "indeterminate" is "cannot be determined from the report" | +| example2 sample data (example2 study §1.2) | Three values in use: present, absent, indeterminate; no `possible` and no separate confidence field | + +The extractor's split of "possible" from "indeterminate" keeps hedging distinct from unassessability, which is closer to the manuscript's intent than the sample data is, but it still puts both on the presence axis rather than a second one. No source states which vocabulary is meant to win. + +## A11. Pertinent negatives are first-class entries + +**Statement.** A finding the radiologist explicitly reports absent is recorded as an observation with presence absent, not omitted, and an entry that has only ever been reported absent is a tracked pertinent negative. A finding the report does not mention has no observation on that EFL at all, and adds nothing to its entry's status. + +**Status.** Working proposal (manuscript, webinar); implemented example (the sample data is majority-absent). + +**Evidence.** +- SIIM webinar slide 18 speaker notes: "Walk the pertinent negative first: 'no filling defect' is captured as pulmonary embolism, absent; negatives are first-class entries, not omissions." +- JDIM IPL manuscript, printed p.9: "'Excluded' means at some point the radiologist explicitly reported the finding absent and no other observation recorded it present (a tracked pertinent negative, such as 'no pneumothorax')." +- JDIM IPL manuscript, printed p.7: "A finding the report does not mention has no observation on that EFL." And printed p.9: "A report that does not mention a finding adds no observation to its entry, so the entry's status is unchanged." +- example2 study §1.2: of 276 observations in the sample data, 160 are `absent` — the majority. +- JDIM IPL manuscript, printed p.16: cross-subspecialty value depends on it — "that history, including what radiologists excluded on earlier examinations, is available without manual retrieval and could spare repeat examinations." +- SIIM webinar slide 20 speaker notes: on an absent row, "the stated temporal word marks the negation scope: 'no NEW consolidation' is not the same assertion as 'no consolidation.'" +- Board 1 (internal; schema content only), "Exam Finding List" table: rows for negative findings carry a count of 0 and are starred, with the report text highlighted in two colors for positives and explicit negatives. +- JACR IPL manuscript, Methods: by contrast the JACR study **excluded** statements of normality and analyzed positively reported findings only. + +**What the code implements.** Negation is a first-class extraction target, not a filter. The extraction prompt's `CORE_INSTRUCTIONS_BLOCK` item 2 requires extracting "ALL findings — including present, absent, possible, and indeterminate findings". The coding prompts keep negation out of the concept: `FINDING_TERM_SYSTEM` rule 5 says "If a finding is a normal-variant or absent finding (e.g., 'no ascites'), generate terms for the finding itself (e.g., 'ascites', 'peritoneal fluid'), not for the negation", and `FINDING_CODE_SELECTOR_SYSTEM` rule 6 states flatly "The finding's `presence` does NOT affect code selection." The anatomic-location work applies the same separation: `docs/plans/anatomic-location-efl-ipl.md` records that "**Absent findings still get anatomy** — presence doesn't gate location ('No hydronephrosis' → kidney, 'adrenal glands are unremarkable' → adrenal)." + +**Related.** A5, A3, A10, A23, A25. + +**Unresolved.** The JDIM/webinar model makes explicit negatives first-class; the JACR measurement excludes normal statements. The two have different purposes and no source reconciles the scope difference. + +## A12. Every finding carries a standardized anatomic location, assigned by explicit rules + +**Statement.** Each observation is anchored to a single anatomic location identifier from the RadLex-derived Anatomic Locations index, and a written precedence ladder decides which location: explicit anatomy in the report text or section context wins; otherwise the finding's own target organ at its own anatomic-noun granularity; otherwise the exam-scoped coarse region. Laterality follows explicit text, then a sided exam, then generic, and is resolved against the whole report section rather than the finding's isolated quote. + +**Status.** Working proposal (the written rules); implemented example (the enrichment pass and the coding pipeline). + +**Evidence.** +- IPL repo `dev` `36fa30c`, `docs/anatomic-location-assignment-rules.md`: the three-step precedence ladder, the laterality source priority, the bilateral-finding rules (separable positives split into left and right; an inseparable diffuse process stays generic and unsided; a contiguous midline finding stays one unsided finding; a generic absent finding on a paired organ never takes a side), and the specificity rule that "the target's granularity matches the finding's anatomic noun, capped by the report — never finer." Includes the worked left-shoulder section-laterality example and the explicit warning that "reviewing or coding from the isolated `reportText` silently drops section laterality." +- IPL repo `dev` `36fa30c`, `docs/plans/anatomic-location-efl-ipl.md`, status header: COMPLETE 2026-06-10; "EFLs in `sample_data/example2` enriched with `anatomicLocation`… (260/275 localized)"; the locked decision that the indicator is "RID id + display name only… a single location per observation." +- example2 study §3.2: `enrich_efl_anatomy.py` runs each finding through the *production* coding pipeline `finding_extractor.coding.runtime.run_coding` rather than a sample-data heuristic, and writes a per-decision review CSV including unresolved cases. +- January 2026 deck, "Anatomic Locations": "Anatomy baked into OIFM definitions and Observation objects." +- SIIM webinar slide 31 speaker notes: "Every finding is anchored to a specific RadLex Anatomic Locations code, and the containment hierarchy rolls it up to a top-level body region." + +**What the code implements.** The two location prompts encode the rules the assignment document states in prose. `LOCATION_TERM_SYSTEM` rule 2 keeps the anatomy separate from the finding: "Name the ANATOMIC STRUCTURE, not the finding. For a finding in the 'right lower lobe', the terms should be 'right lower lobe', 'lower lobe of right lung' — NOT 'right lower lobe opacity'." Rule 3 supplies the fallback when the report says nothing: "If location is null, infer from the exam info (body_part, modality) and report context." Rule 7 encodes a structural fact about the index that the anatomy work established: "When laterality is 'bilateral' OR the anatomy is inherently bilateral (e.g., 'lung bases', 'kidneys', 'adrenal glands'), generate SEPARATE terms for each side. The index stores lateralized entries individually — there is no entry for 'kidneys', only 'left kidney' and 'right kidney'." Rule 8 asks for a parent term one level up alongside the specific one, which is what makes a near-miss recoverable. `LOCATION_CODE_SELECTOR_SYSTEM` presents each candidate with its region, laterality, containment parent and part-of parent, so both hierarchies are visible at the moment of choice, and rule 4 states "LATERALITY MATTERS. Never select the wrong side." + +The extraction prompt fixes a nine-value `body_region` vocabulary — chest, abdomen, pelvis, head, neck, spine, upper extremity, lower extremity, breast (`LOCATION_BLOCK`) — as a coarse axis beneath the free-text `specific_anatomy` that the coding step later resolves to an identifier. `ATTRIBUTES_BLOCK` keeps the axes from collapsing: "Do NOT use 'location' as an attribute key — location belongs in FindingLocation fields." + +**Related.** A4, A13, A25, B1, and the anatomic-locations ideas in the semantic inventory. + +**Unresolved — one location per observation, or several.** `docs/plans/anatomic-location-efl-ipl.md` records the locked decision as "a single location per observation", and instructs the enrichment pass that "If `run_coding` returns multiple `location_codes` for an observation, take the first/primary coded one to honor the single-location decision." But `LOCATION_CODE_SELECTOR_SYSTEM` rule 2 says "MULTIPLE LOCATIONS are allowed when a finding genuinely spans more than one distinct structure. Do NOT select redundant ancestor/descendant pairs," and `docs/coding-agent-prompts.md` Design Notes confirm the coding bundle carries `location_codes` as a list. The coding tool models a finding that spans structures; the Exam Finding List does not carry one. + +**Undetermined.** The rules document says these "were agreed for the `sample_data/example2` correction pass and are the intended spec for tuning the automated location-coding step later"; whether they have been applied beyond example2 is not stated. + +## A13. Anatomic-compatibility reconciliation is unresolved, and the sample data shows the cost + +**Statement.** Because grouping keys on the exact location identifier, the same finding coded generically on one exam and specifically on another produces two unconnected entries. Deciding whether a generic-versus-specific pair for one finding code names the same problem is the anatomic-compatibility reconciliation step, and it has not been started. + +**Status.** Stated open problem (the rules document names it and defers it); demonstrated failure in the implemented example. + +**Evidence.** +- IPL repo `dev` `36fa30c`, `docs/anatomic-location-assignment-rules.md`, known-limitation section, quoted in `knowledge/roadmap/ipl-data-model-system.md`: "Parent/child or generic-vs-specific pairs for the *same finding code across exams* (e.g. 'lung' vs 'lower lobe of right lung'; 'kidney' vs 'left kidney') still produce separate IPL groups. Deciding whether such observations are the same problem or distinct is the **anatomic-compatibility reconciliation** step." +- IPL repo `dev` `36fa30c`, `docs/plans/anatomic-location-efl-ipl.md`: "**Follow-on:** Step 3b anatomic-compatibility reconciliation and the fresh anatomy-aware viewer remain future phases." +- example2 study §1.4, two live instances: renal cystic disease `OIFM_GMTS_016635` splits into `ipl-finding-046` at generic kidney `RID205` (one ultrasound observation whose text never states a side) and `ipl-finding-047` at left kidney `RID29663` (three CT observations), where the report text is visibly tracking one lesion's size across all four; and hepatic lesion `OIFM_OIDM_160831` splits into `ipl-finding-089` (segment 6, one observation) and `ipl-finding-090` (generic liver, four observations) including a 2023-01-18 sentence that explicitly refers back to the segment-6 lesion and still lands in the other group. "There is no succession/supersede/merge field anywhere connecting these two entries." + +**Related.** A4, A6, A8, A12. + +## A14. Permanent findings, and the need to rank entries before display + +**Statement.** Some findings a patient is expected to have on every subsequent examination indefinitely — degenerative change, calcification, healed injury, congenital variant, biologically inert lesion, postsurgical change, implanted device, irreversible process, structural remodeling. Whether a finding is permanent is a declared attribute of the finding type, not something inferred from observing a series. Because most of an accumulated record goes unmentioned at any one examination, an IPL has to rank its entries before displaying them, and permanence is one measured signal for that ranking. + +**Status.** Implemented example (a locked study taxonomy attribute with measured results); stated design implication. + +**Evidence.** +- JACR IPL manuscript, Methods: "Permanent findings are those a patient is expected to have on every subsequent CT indefinitely, such as a healed rib fracture or postsurgical change, which distinguishes them from chronic findings followed for change such as an enlarging aortic aneurysm. **The label comes from the finding itself, not from observing the series.**" +- `sources/bucket/REPORT.md` §2 lists the nine declared permanent categories from the manuscript's taxonomy. +- JACR IPL manuscript, Table 3: 607 of 993 findings re-documented with no change were permanent (61.1%); 69 of 103 findings that dropped out of documentation and returned were permanent (67.0%); 371 of 765 new-to-series findings were permanent findings documented for the first time (48.5%). +- JACR IPL manuscript, Discussion: "Compiled from a patient's entire imaging history, most of the record goes unmentioned at any one examination. An IPL would therefore have to rank its entries before displaying them, and whether a finding is permanent is one measured signal for that ranking." +- JACR IPL manuscript, Table 3, IPL coverage at the fourth CT: the fourth report re-documented 19.1% (308 of 1,615) of the entries in an IPL built from the first three CTs; permanent entries were re-documented at 34.1%, nearly twice that rate. + +**Related.** A15, B5, A22. + +## A15. Foundation context: four per-finding dimensions that tell an agent what to expect + +**Statement.** Four additional dimensions carried on a finding's definition — where it is anatomically, what type of finding it is (a hierarchical, multi-valued etiology taxonomy), how long it lasts, and whether it is transient or permanent — are what let an agent judge whether a finding should still be present on a new examination. The webinar states these belong to a forward schema and are not carried by the published definitions. + +**Status.** Stated direction (webinar), attributed to a forward schema rather than the committed corpus. + +**Evidence.** +- SIIM webinar slide 28 speaker notes: "the committed, published finding model is lean: 2,458 definitions with id, name, description, synonyms, tags, attributes, and index codes. None of the four foundation-context dimensions are first-class fields there. FindingModelFull is the forward schema that adds them… these fields are the forward, AI-populated schema, not yet carried by the published definitions." Slide text names `body_regions · anatomic_locations`, `entity_type · etiologies`, `expected_time_course`, `subspecialties · applicable_modalities`, `sex_specificity · age_profile`. +- SIIM webinar slide 29 speaker notes: "this tells an agent whether a finding should still be there. Expect the AAA on every future exam and track its growth; treat a resolved PE as gone; know the ovarian cyst clears and recurs with the cycle so you don't link every cyst into one thread." +- SIIM webinar slide 30: the etiology taxonomy, hierarchical and multi-valued, listed verbatim — `inflammatory`, `inflammatory:infectious`, `neoplastic:{benign,malignant,metastatic,potential}`, `traumatic:{acute,sequela}`, `vascular:{ischemic,hemorrhagic,thrombotic,aneurysmal}`, `iatrogenic:{post-operative,post-radiation,device,medication-related}`, `degenerative`, `metabolic`, `congenital`, `developmental`, `autoimmune`, `toxic`, `mechanical`, `idiopathic`, `normal-variant`; "a subdural hematoma is both traumatic:acute and vascular:hemorrhagic." +- example2 study §3.5 and §2.2: `viewer/data/enriched_findings.json` (97 entries) already carries `body_regions[]`, `modalities[]`, `subspecialties[]`, `etiologies[]` as `"category:subtype"` strings and `anatomic_location{id,text}`, and viewer_v2's "Definition data" panel renders them — a partial implemented instance of the forward schema, for 97 of the finding codes used. + +**Related.** A8, A14, B1, and the finding-model metadata ideas in the semantic inventory. + +**Undetermined.** This inventory did not read the `findingmodel` repository; the relationship between `FindingModelFull` and the metadata-cleanup work belongs to the semantic inventory. + +## A16. Imaging Persona and the reporting data context object model + +**Statement.** Beyond the patient's imaging findings sits the surrounding clinical context. The January 2026 deck names it Imaging Persona with four categories: clinical context (orders, indications), medical baseline (problem list, allergies, laboratory results), specialized history (oncology, treatments), and surgical history (operative records, pathology, implants). Two boards give the same idea a fuller, differently named shape as an object model spanning Patient, Order, ImagingStudy, CurrentReportText, PriorReports, TrackedObservations, EHR Data, and Observations. + +**Status.** Stated goal (deck); working proposal (boards); no schema, sample, or code. + +**Evidence.** +- January 2026 deck, "Imaging Persona (big picture)": the four categories verbatim. +- January 2026 deck, strategic pillar 2: Persona is the fourth level of the hierarchy after the IPL. +- Board 4 ("OIDM Object Model", low sensitivity), central mind map: branches Patient (identifiers, DOB, sex/gender, referrer), Order (indications, order questions and responses, timestamps, imaging studies), PriorReports (report text, observations), TrackedObservations (observation types, observations), EHR Data (lab values, pathology reports, problems/diagnoses, allergies, operative notes, clinical notes), ImagingStudy(s) (identifier, resource information, DICOM metadata, timestamps), CurrentReportText (status, authors, "Text (DOM)", timestamps), Observations (identifier, observation type as a CDE Set ID, tracking ID, body part, components). Hand annotations map Patient/Order and EHR Data to FHIR, ImagingStudyType to the LOINC/RadLex Playbook, and BodyPart to Anatomic Locations. +- Board 9 ("OIDM Big Picture"), "Reporting Data Context Object Model" frame: nine fields — patient demographics, order information, EHR information (problem lists, labs, vitals, operative notes, pathology), current report, prior radiology reports, longitudinal findings, AI-generated data, DICOM-SR data, NLP-extracted data. The board states this frame is a duplicate of Board 4's mind map. +- Board 14 ("ACR OIDM", low sensitivity), Reference Implementations component list names "Tracked Observations" as a first-class component alongside Anatomic Locations, Exam Types, CDE Sets/Elements, Observations, Imaging Exams, Imaging Reports and EMR Items. +- Site post "Data Model: Structure and Function", 2024-01-25: the model organizes observations, current report text, imaging studies, patient, order, prior studies, tracked observations, and EHR data. +- Board 1 (internal; schema content only): proposes representing non-imaging clinical data in the same structure — "Implants; Operations — e.g., appendectomy, if there's a record of it can add it to the IPL under the same semantic identifier that would be used when a radiologist describes post-appendectomy findings in an abdomen CT report." + +**Related.** A1, A17, B8, C2. + +**Unresolved.** Three names for overlapping things: "Imaging Persona" (deck), "OIDM Data Context Model" / "OIDM Object Model" (Boards 4 and 9), "Reporting Data Context Object Model" (Board 9). No source states whether these are the same structure. + +**Undetermined.** Storage versus query-time assembly, ownership of each context category, encoding, and maintenance are unspecified in every source read. + +## A17. Report sections beyond Findings are unmodeled + +**Statement.** The finding/Observation pattern covers the Findings section. Impression, diagnoses and differential diagnoses, recommendations, communication, comparison, technique, clinical history and indication, and limitations are enumerated as sections that also need representation, with the open question of whether impression-level statements are Observations too or a distinct structure that links back to finding Observations. + +**Status.** Stated open questions, recorded on a board; nothing built. + +**Evidence.** +- Board 6 ("Structured Report Representation", internal; schema content only), note "2025-03-06 Report Structures to Represent": the eight sections listed verbatim, with "Findings (already covered)". +- Board 6, "Impression" box: the impression is "usually a numbered/bulleted list, often ordered by priority/severity", "can reference findings by number or implicitly", "may state a diagnosis or differential rather than restating a finding directly", and "can group multiple findings under one summary statement." +- Board 6, note "2025-04-09": "Should Impression items be OIDM Observations too, or a different structure entirely (linking back to Finding Observations)? Need a way to represent 'grouped' findings with a common cause/diagnosis. Causative relationships between findings?" +- Board 9, "Report Representation" work thread: "Have good FHIR structure for simple findings — working on more complex situations: Complex/associated findings, Diagnoses based on findings, Differential diagnoses, Recommendations." + +**What the code implements.** A canonical section vocabulary exists and is used, even though only two sections yield findings. `docs/report-sections.md` gives seven canonical names with their aliases: `findings` (aliases comment, body), `impression` (conclusion), `technique`, `indication` (clinical information), `clinical_history` (history), `comparison`, and `recommendation` (clinical correlation). Detection is "best-effort, deterministic" regex over header patterns in priority order, using "a **whitelist approach** to avoid matching subsection headers like `**Liver:**` or `**Lungs:**`" — so body-system subheads inside the findings section are deliberately not mistaken for report sections. The detected structure is persisted with the report and backfilled lazily for reports stored before the feature existed. + +`docs/extraction-internals.md` records the consequence: "extraction proceeds only on `findings` and `impression` sections", with an inference step for reports that have no findings header ("infers an implicit findings block immediately before first impression when plausible"). Everything else in the report is not discarded but classified: the extraction prompt's `NON_FINDING_BLOCK` assigns each remaining span one of seven categories — metadata, technique, indication, comparison, clinical_history, impression, other — and `initial-extraction-plan.md` states the purpose: "This lets us account for every piece of text in the report — findings go into `ExtractedFinding.report_text`, everything else goes here." So the sections Board 6 lists as unrepresented are, in the implementation, recognized and labeled but not yet turned into structure. + +**Related.** A9, A18, A26, C2. + +## A18. Recommendation structure, and a live-versus-closed axis on IPL entries + +**Statement.** A follow-up recommendation is a structure of its own: the exam (possibly with protocol, with anatomy important), a timeframe, the finding or target with optional conditionality, and a citation such as Fleischner, the ACR incidental-findings papers, or a *-RADS system. When a recommended finding is an IPL entry the recommendation attaches to that entry and the radiologist closes it when a later examination shows resolution. One board proposes the IPL itself as the display surface, with entries that are "live" versus "inactive/not being acted on/closed." + +**Status.** Working proposal (board, manuscript); stated goal (deck's ACR priorities); nothing built. + +**Evidence.** +- Board 12 ("Outcome Tracking Schema", no named individuals), "Recommendation Structure" box: "Exam (possibly w/protocol) — Anatomy important here; Facilitate 'one-click to close' (1C2C); Timeframe; Finding/target (± Conditionality, options); Citation (e.g., Fleischner, ACR IFs, *-RADS, etc.)." +- Board 12, "Recognizing Follow-up Exams": "Facilitated orders could have a flag on them indicating they're a response to a recommendation. A given recommendation definition could have the idea of which kinds of exams would be appropriate for closing it." +- Board 12, "Imaging Problem List" box (starred): "Captures findings. Can have the idea of things that are 'live' versus those that are inactive/not being acted on/closed." +- JDIM IPL manuscript, printed p.15: "When a finding recommended for follow-up is an IPL entry, the recommendation is attached to that entry, and the radiologist can close it when a later examination shows resolution. While the finding persists, its observation history is the dated list of examinations a radiologist checks against an external surveillance protocol, such as the Fleischner Society intervals." +- JDIM IPL manuscript, printed p.16: "Because both the recommendation and its closure are in the IPL record, a department could measure follow-up completion from the record instead of by chart abstraction or keyword search." +- January 2026 deck, ACR priorities: recommendation tracking named first. + +**Related.** A5, A14, B5, B7. + +**Unresolved.** Whether "live versus closed" is a second status axis on an entry or a property of an attached recommendation. Board 12 puts it on the entry; the JDIM manuscript attaches the recommendation to the entry and keeps status derived from observations alone. + +## A19. A finding as a persistent tracked entity with a durable identifier + +**Statement.** Rather than recomputing groups, each finding becomes a tracked entity with an identifier that persists, so a later report of the same lesion adds a dated value to the existing resource instead of creating a new one. The lineage design note states it plainly: "Each finding becomes a **tracked entity** with a FHIR ID that persists." + +**Status.** Working proposal on an unmerged branch of a superseded prototype; the same idea appears as a `tracking_id` field on the object-model board and as a multi-vendor exchange requirement on a demo board; the current implementation approximates it by grouping instead. + +**Evidence.** +- `IPL-MVP-ExtractionAndLabeling`, branch `origin/Persistent_FHIR_Resources` `5ea6720`, file `FHIR_Example_Structure` (no extension): a three-step process — extract and map to OIDM codes; for each finding ask "Does this finding already exist in our FHIR database?" and either link and add a new observation value or create a new Observation with a unique ID; then query and visualize. Worked timeline: one liver lesion at 1.6 cm (2022-05-10), 2.1 cm (2022-11-15), 2.8 cm (2024-10-15), each with a `status` of `new` or `growing`. Example queries: "Show me the timeline for liver lesion." +- Board 4, class diagram: `Observation` carries `tracking_id` as a field. +- Board 15 ("Pulm Nodule Demo Project", internal; schema content only), Complete Workflow step 4: "Ideally, prior known nodules is actually a series of Observation objects, all with a common tracking ID." Step 5 asks: "Who adds the tracking ID to the Observation, and how does this get communicated." +- JDIM IPL manuscript, printed p.8: "The entry's tracking identifier links its observations across reports"; printed p.19: the DICOM tracking identifier "marks observations as referring to one finding without defining how they are matched, collected, or used." +- Site post "Data Model: Structure and Function", 2024-01-25: "**Tracked Observations**: An index of the association of the same radiology finding (e.g., a tumor or a fracture)" — the idea in prose, two years before the design note. +- `FHIRSamples` `main` `9ae2fa9`, `example1OIDMradiologist.json`: the finding Observation's `focus[]` carries a body structure and an imaging selection that share the **same** DICOM structured-report `tracking-uid` identifier, with the selection giving study, series and instance identifiers plus an image region. The same-lesion identity mechanism here is a DICOM tracking UID tied to a place on an image. + +**What the code implements.** The `FHIR_Example_Structure` note's store is not FHIR and does not claim to be. It is a patient-keyed local JSON document whose keys are invented strings such as `fhir-obs-liver-lesion-001`, each holding the finding name, a SNOMED code, a first-detected date, and an observation list of `{report_date, size_mm, status}` with `status` values `new`, `persistent` and `growing`. Identity across reports is decided by matching the finding name together with the location text, framed in the note as the question "Have we seen a hepatic lesion in segment 8 before?" The note proposes two supporting services, an "OIDM MCP" for mapping a phrase to a standard code and a "FHIR Resource Manager" that it labels "not a real server, just local database." + +**Related.** A4, A8, A21, B9. + +**Unresolved — two unconnected designs for the same problem.** `FHIRSamples` identifies one lesion across observations with a DICOM tracking UID anchored to an image region; the `FHIR_Example_Structure` note identifies it with an invented string key in a local store, matched on name plus location text. Neither references the other, and the JDIM manuscript's "tracking identifier" (printed p.8) names the function without picking a mechanism. Who owns and assigns the identifier is an open question on Board 15 and is answered nowhere read. + +**Unresolved — three coding targets in one family.** The IPL repository codes findings with OIFM identifiers; the `FHIR_Example_Structure` note codes them with SNOMED; `FHIRSamples` and `OpenImagingDataModel.py` code them with RadElement `RDES`/`RDE` identifiers. The RadElement system URI is itself inconsistent across the lineage samples, appearing as `https://radelement.org` and `https://www.radelement.org`, with two misspelled variants in `CDETemplateDemo` `e09f255`. These are lineage artifacts rather than positions, but any statement that the structures carry "a finding code" has to say which. + +## A20. A formal system of data models with generated schemas + +**Statement.** The structures should exist as annotated Pydantic models from which JSON Schemas are generated, with camelCase aliases on export and snake_case attributes internally, covering Observation (with an Extracted Observation subtype raised as a question), Exam Finding List, and Imaging Problem List. + +**Status.** Stated goal, unclaimed by any plan. + +**Evidence.** +- `openimagingdata/imaging-problem-list` issue #1, "Create System of Data Models", opened by the project lead, still open with no comments and no assignee as of this reading: "Needs models for: Observation — Extracted Observation sub-type?; Exam Finding List; Imaging Problem List. Pydantic. Extensive annotation to generate JSON schemas. camelCase aliases in export, snake_case object attributes." +- Project lead's stated goals, `knowledge/plans/2026-09-20-knowledgebase-build-plan.md`, Imaging Problem List: "Define appropriate data structures for representing both observations in radiology reports and their relationships"; "Create standard data structure formats, etc. for working with these." +- IPL repo `dev` `36fa30c`, `docs/plans/anatomic-location-efl-ipl.md`, grounding facts: "There is **no Pydantic model or committed JSON schema** for the EFL format, so adding a field is purely additive." +- example2 study §1.2: the `$schema` value in the EFL files points at `https://github.com/openimagingdata/imaging-problem-list/schema/exam-problem-list-schema.json`, which IPL repo `main` `CLAUDE.md` states "doesn't exist yet." + +**Related.** A1, A2, A21. + +## A21. Application-layer data structures, distinct from transport expressions + +**Statement.** OIDM defines a system of data structures for representing imaging exam result information, intended to be used inside applications to both read and create result data. These are not a transport definition: not FHIR, not DICOM. They may eventually need FHIR expressions to travel, and should be designed to allow that, but that is separate from the definition of the structures applications manipulate. Agreeing the structures is what makes it easier to agree what must be conveyed between systems, and the structures guide the design of the FHIR profiles that inter-process communication will require. + +**Status.** Explicit direction from the project lead (2026-09-19) and a decision of record (2026-09-21); already partly expressed in the manuscript under review; contradicted by the current repository documentation. + +**Evidence.** +- Email notes, point 3: "'Application layer data model' is imprecise. Better: 'a system of defined data structures for representing imaging exam result information', 'intended to be used within applications to both read and create result data'." +- Email notes, point 4: "The structures are NOT a transport definition (not FHIR, not DICOM). They may eventually need FHIR expressions to travel over FHIRcast, and should be designed to allow that, but that is completely separate from the definition of the structures applications manipulate." +- Email notes, point 5: "Agreed structures make it easier to agree on what must be conveyed between systems… The structures GUIDE the design of the FHIR profiles and related artifacts that will need agreement for inter-process communication. This is the motivation for the IPL." +- `knowledge/plans/2026-09-20-knowledgebase-build-plan.md`, "Decisions added 2026-09-21", row "Data structures versus transport": records this as the project's position and directs that the data-structure documents be reframed. +- JDIM IPL manuscript, printed p.7: "The IPL is an application-layer data model: the data structures that applications read and write to represent a patient's imaging findings, **defined independently of any transport protocol**. When systems exchange the record, those structures can be expressed in FHIR, and each element of the model can be carried by a FHIR Release 5 resource (Table 1)… Storage representation, location, versioning, and exchange with reporting, archive, and electronic health record systems are implementation choices. An implementation may store the record in relational, document, or graph form." +- JDIM IPL manuscript, printed p.18: "Shared data structures come first. When systems hold the same structures, what must pass between them to convey a patient's findings is easier to agree on, and the structures guide the FHIR profiles that exchange will require. We offer this model as a starting point for an open, community-developed standard." +- January 2026 deck, call to action: "structure-first (then FHIR etc.)." +- Site post "Data Model: Structure and Function", 2024-01-25: OIDM is "a superstructure on top of these FHIR definitions to both organize them and enable more straightforward programmatic access to the data"; "the relationship between OIDM and FHIR might be that between the browser's DOM and HTML." + +**Related.** C1, C2, C3, A22. + +**Unresolved — the term itself.** The manuscript under review uses "application-layer data model" in its abstract, its Methods (printed p.7), its Discussion (printed p.19) and its Limitations (printed p.19). The project lead on 2026-09-19 calls that phrase imprecise and proposes replacing it. The manuscript's own gloss already says "defined independently of any transport protocol", so the disagreement is over the label, not obviously over the content. + +**Unresolved — the FHIR mapping itself.** Two mappings are on record for the IPL: + +| Source | IPL FHIR expression | +|---|---| +| IPL repo `main` `06f64a7` and `dev` `36fa30c`, README and `CLAUDE.md` | "**Report** containing a list of **Condition** objects (labeled with the finding identifier), where each Condition object also contains a list of **Observation** objects" | +| JDIM IPL manuscript, Table 1 (image page 88 of the PDF), as summarized in `sources/bucket/REPORT.md` §4 | EFL observation → `Observation` (CDE-labeled); examination report → `DiagnosticReport`; anatomic site → `BodyStructure`; IPL entry → `List` (or a custom profile); succession link → a `Reference` between Lists or an extension; status → none, derived only; review status → `Provenance` | + +"Report" is not a FHIR resource name. Neither mapping is implemented: IPL repo `dev` `36fa30c` has no FHIR resource classes and no code that emits FHIR (`knowledge/data-structures/fhir-mapping.md`, "What is actually implemented"). + +**Unresolved — components versus hasMember.** OIDM's attribute encoding uses `Observation.component` throughout (IPL repo `main` README; `FHIRSamples` `9ae2fa9`; `OpenImagingDataModel.py` `455e5b6`). The IHE Imaging Diagnostic Report Phase II public-comment draft states `Observation.component` "is not used" and routes elements through `hasMember` instead, while the January 2026 deck names IDR as the EFL's target ("Connects to IHE Imaging Diagnostic Report (IDR) FHIR representation"). Recorded in `knowledge/data-structures/ihe-idr-alignment.md` from the extract on `RSNA/ACR-RSNA-CDEs` `next-gen-2026`; unresolved. + +## A22. The re-documentation burden: measured evidence for the Imaging Problem List + +**Statement.** A two-site study of 200 serial chest CTs measured how much of a follow-up report re-documents findings an earlier report in the same series already described, and what depth of memory an IPL would need to supply it. + +**Status.** Implemented study with results (prepared for submission). + +**Evidence.** All from the JACR IPL manuscript, Results and Table 3; 50 patients, four consecutive chest CTs each, two academic sites, report text only, extraction validated against radiologist review. + +| Measure | Result | +|---|---| +| Findings on follow-up CTs that were chronic | 57.6% (1,286/2,232), 95% CI 54.5-60.8 | +| Chronic findings asserted without hedging, re-documented with no change (primary outcome) | 77.4% (951/1,229), 95% CI 73.3-81.4 | +| Of content re-documented with no change, share permanent | 61.1% (607/993) | +| Follow-up findings an IPL built from the whole series would account for | 44.5% (993/2,232) | +| Follow-up findings the most recent report alone would account for | 26.7%, at most 31.1% | +| Findings tracked on two or more CTs that dropped out and returned | 18.9% (103/545), two-thirds permanent | +| Fourth-CT findings an IPL built from the first three already lists | 49.6% (308/621) | +| IPL entries the fourth report re-documented | 19.1% (308/1,615) | +| Extraction confirmed against the source report | 98.3% (1,153/1,173) | + +Additional evidence: the taxonomy "is built on the Open Imaging Data Model finding vocabulary" and sites were "mapped against the Anatomic Locations index, a RadLex-derived anatomic reference" (Methods), so the study is also a use of the semantic foundation. The supplement (`sources/bucket/text/jacr-ipl-supplement.md`) states the taxonomy is "built on the Open Imaging Data Model chest CT finding taxonomy, with the codes this study added" and that the rule set, taxonomy and analysis code "will be made available in a public repository at publication." + +**Related.** A8, A14, B5. + +**Undetermined.** Both manuscripts are unpublished. The JACR one carries no manuscript number or cover letter, so its submission status is not confirmed by the file itself. + +## A23. Normality is recorded as an absent abnormality + +**Statement.** A report sentence saying a structure is normal is not empty of findings. It is translated into the corresponding abnormality, marked absent. "Clear lungs" becomes a pulmonary parenchymal or airspace abnormality, absent; "normal cardiac silhouette" becomes cardiomegaly, absent. A statement covering a whole region at once is a blanket negative, and it must be scoped to an abnormality the sentence actually excludes rather than to an unrelated or over-specific one. + +**Status.** Implemented example, encoded in three prompts and given a named failure mode. + +**Evidence.** +- Extraction prompt `CORE_INSTRUCTIONS_BLOCK` item 4, "**Normal findings are absent abnormalities**", with three worked mappings: "'clear lungs' → 'pulmonary airspace abnormality', absent"; "'normal cardiac silhouette' → 'cardiomegaly', absent"; "'normal lung volumes' → 'pulmonary volume abnormality', absent". +- `CHUNK_RULES_BLOCK` item 3: "If a structure is described as normal, encode the corresponding abnormal finding as absent. For example, 'clear lungs' implies an absent pulmonary parenchymal abnormality finding." +- `PRESENCE_BLOCK` treats normality wording as a plain absent assertion: absent means "explicitly stated as absent (e.g., 'no ascites', 'normal hilar contours', 'unremarkable')". +- `prompts/validator_prompt_example.md`, user-prompt template: "Explicit negatives should be represented as clinically meaningful absent findings; blanket negatives should map to appropriately scoped absent findings (e.g., 'clear lungs' -> {'finding_name': 'pulmonary parenchymal abnormality', 'presence': 'absent'}), not unrelated or over-specific absent findings." The reviewer's problem taxonomy includes `incorrect_blanket_negative` as one of seven named failure types. +- `FHIRSamples` `main` `9ae2fa9`, `chest_ct_report/findings.md`: the hand extraction records "Consolidation / Absent", "Pleural effusion / Absent", "Pneumothorax / Absent" and star-marks "Pericardium / Normal: No effusion, no thickening, no calcs" as a model apparently missing — the same idea reached by hand in 2024, and the same vocabulary gap. +- `IPL-MVP-ExtractionAndLabeling` `main` `b06948f`, `config.py` `EXTRACTION_SYSTEM_PROMPT`, already asks for "Negative findings (explicitly stated as absent)". + +**Related.** A11, A9, A24, A26. + +**Unresolved.** The idea has a vocabulary cost that no source resolves: it requires a coded abnormality to exist for every structure a radiologist can call normal, at the right scope. The `FHIRSamples` hand extraction star-marks exactly such gaps, and the `definition_mismatch` and `no_candidate_match` rejection reasons in the coding prompts (A24) are designed to surface them, but nothing states who fills them. + +## A24. Coding aims at convergence, so generalizing is allowed and specializing is not + +**Statement.** The point of assigning a code is that descriptions referring to the same clinical concept end up with the same label, whether they appear in one report, across one patient's reports, or across patients. That goal makes the two directions of error asymmetric. A slightly more general code is acceptable and often preferred, because it groups equivalents. A more specific code is never acceptable, because the report did not assert that specificity and using it fragments what should be one group. When nothing fits, the finding is left uncoded with a reason, rather than forced. + +**Status.** Implemented example, stated as the explicit purpose inside the coding prompts. + +**Evidence.** +- `FINDING_TERM_SYSTEM`, opening: "The goal of this process is to assign a common standardized label to all descriptions that refer to the same clinical concept — whether they appear in the same report, across reports for one patient, or across different patients. This means terms should target the general concept, not report-specific details. Being too specific defeats the purpose of grouping equivalent findings together." +- `FINDING_TERM_SYSTEM` rules 2 and 3: "Prefer slightly MORE GENERAL terms over more specific ones… for '3 mm nonobstructing left renal calculus', good search terms would be 'renal calculus', 'urinary tract calculus', 'kidney stone' — NOT 'nonobstructing renal calculus' or '3 mm kidney stone'"; "NEVER propose terms that are MORE SPECIFIC than the extracted finding name. Specificity beyond what the report states risks matching the wrong concept." +- `FINDING_CODE_SELECTOR_SYSTEM` rules 2 and 3 apply the same asymmetry at selection: "A SLIGHTLY MORE GENERAL candidate is acceptable and often preferred… 'urinary tract calculus' is a good match for 'renal calculus' — it groups all urinary stones under one label, and the specific location is captured separately"; "A MORE SPECIFIC candidate is NOT acceptable. 'Staghorn calculus' is NOT a valid match for 'renal calculus' — the report does not assert that level of specificity, and using it would fragment what should be a single group." +- `FINDING_CODE_SELECTOR_SYSTEM` rule 5, refusing to force a match: "If NO candidate is a reasonable match, return null for oifm_id. Do not force a match. An unresolved finding is better than a wrong code." The rejection must be classified as `too_specific`, `too_broad`, `wrong_concept`, or `definition_mismatch`, the last defined as "the candidate's NAME looks like a match, but its description, synonyms, or tags reveal a more specific or different concept than the name suggests." +- `LOCATION_CODE_SELECTOR_SYSTEM`, "Unresolved Reasons", makes the same distinction for anatomy: `no_candidate_match` ("you know where the finding is located, but none of the candidates adequately represent that structure") versus `location_unknown` ("you cannot determine where the finding is located even after considering the report context and exam type"). +- `docs/coding-agent-prompts.md`, Design Notes, states what the reasons are for: `no_candidate_match` "flags index gap"; `definition_mismatch` "flags ontology entries needing cleanup". The refusal is a feedback channel into the vocabulary, not only a null. +- `FINDING_TERM_SYSTEM` rules 6 and 7 bound the generalizing: do not generalize to "pure meta-categories like 'finding', 'disease', or 'pathology'… The broadest acceptable term should still name a recognizable clinical concept. Prefer 'abnormality' when generalizing an observation"; and "For FOCAL findings, 'lesion' is the standard generalizing term — a lesion is a focal abnormality. Do not use 'lesion' for diffuse processes." +- `prompts/validator_prompt_example.md` guards the same boundary from the extraction side, with `over_specific_finding_name` among its problem types and the instruction that names "should not be more specific than the chunk supports." +- `docs/coding-agent-design.md` records that a deterministic fast path runs first: an exact or synonym hit in the finding index or the anatomic location index resolves without any model call, so the model is consulted only for what the index did not already settle. + +**Related.** A3, A8, A9, A23, A25, and the finding-model index in the semantic inventory. + +**Unresolved — technical language.** The two coding prompts pull opposite ways on modality-specific wording. `FINDING_TERM_SYSTEM` rule 8: findings in technical language "should be searched using the technical observation term itself — do not reinterpret as a specific diagnosis or pathological process." `FINDING_CODE_SELECTOR_SYSTEM` rule 8: "When the finding is described in modality-specific technical language (e.g., 'hypodense lesion', 'T2 hyperintense focus'), match based on the underlying clinical concept, not the imaging technique." `docs/technical-imaging-findings.md` sides with the first, warning that "Marrow signal abnormality' should be searched as exactly that — it is the observation. Do NOT reinterpret as 'bone marrow edema' or 'marrow infiltration', which are specific diagnoses that may or may not be the cause." Whether the selector is meant to strip only the modality wrapper or to resolve to a diagnosis is not stated. + +## A25. Finding type, anatomic site, and presence are independent axes + +**Statement.** What a finding is, where it is, and whether it is present are coded separately and do not condition each other. The type code answers what, the location code answers where, and presence rides on neither. + +**Status.** Implemented example, stated as rules in the coding prompts and realized in the pipeline's shape. + +**Evidence.** +- `FINDING_CODE_SELECTOR_SYSTEM` rule 7: "Match based on WHAT the finding is, not WHERE it is. Anatomic location is coded separately." Rule 6: "The finding's `presence` does NOT affect code selection." +- `LOCATION_CODE_SELECTOR_SYSTEM` rule 1 mirrors it from the other side: select the candidates "that best represent WHERE the finding is located". +- `docs/coding-agent-design.md`: the pipeline runs finding-code selection and location-code selection as "**parallel LLM calls** within the same concurrency semaphore", each with its own term generator, and `docs/coding-agent-prompts.md` Design Notes record that "A finding can resolve via fast-path on one axis but not the other," so the two axes are tracked independently per finding. +- The extraction prompt keeps the axes apart in the data too: `ATTRIBUTES_BLOCK` forbids "location" as an attribute key, and `initial-extraction-plan.md` makes `FindingLocation` a separate structure rather than one more attribute. +- `docs/plans/anatomic-location-efl-ipl.md`: "presence doesn't gate location" — an absent finding still receives anatomy. +- JDIM IPL manuscript, printed p.8: entry identity rests on the finding code and the anatomic site together, which is only well defined if the two are coded independently (A4). + +**Related.** A1, A4, A12, A24. + +## A26. A named taxonomy of extraction failures, checked by an independent reviewer + +**Statement.** Translating prose into structure has specific, nameable ways of going wrong, and the system checks for them with a second model that reviews each chunk against its source text and can send that chunk back for re-extraction. The failures are enumerated: content asserted that the text does not support, a finding in the text with no structure representing it, the wrong presence, a name more specific than the text supports, a mishandled blanket negative, and wrong or wrongly scoped location. + +**Status.** Implemented example. + +**Evidence.** +- `prompts/validator_prompt_example.md`, system prompt, lists the "issue patterns that justify re-extraction" verbatim: "extraction structure contains clinically meaningful content unsupported by the chunk text (hallucination)"; "some report text describing a finding is not represented by any extraction data structure (missed finding)"; "a structure describes a finding as being present when it is not, or absent when it is possible (wrong presence)"; "finding name is more specific than described in the chunk text (too specific finding name)"; "incorrect representation of a blanket negative (incorrect blanket negative)"; "wrong or too-specific or general location information (incorrect location)". The structured response uses the type vocabulary `hallucination`, `missed_finding`, `wrong_presence`, `over_specific_finding_name`, `incorrect_blanket_negative`, `incorrect_location`, `other`. +- The same file bounds the reviewer's remit: "Do not request re-extraction for formatting/style differences alone", and the user template tells it "do not perform a fresh extraction" — it judges, it does not replace. +- The reviewer's decision object is one per chunk: `report_chunk_id`, `should_reextract`, `problems[]` each with a finding index, a problem type and a detail, and a `rationale`. +- `docs/extraction-internals.md`, "Reviewer Contract", records an independence requirement in configuration: the reviewer model is "optional override; **must differ from extraction model**". Reviewer feedback "is threaded to retry chunks and appended to the chunk extraction prompt", and "Review timeout is non-fatal — pipeline continues without re-extraction." +- `docs/extraction-internals.md`, chunking: sentence spans are computed first; short sections pass through whole; an impression with list structure is chunked deterministically by grouped list items; otherwise semantic grouping with a sentence-group fallback; a default cap of three sentences per chunk. Each chunk is handed to the sub-agent with preceding and following half-chunk context marked advisory. + +**What the code implements.** IPL repo `dev` `36fa30c` runs extraction and review as a per-chunk pipeline with bounded concurrency, so a chunk can be reviewed while other chunks are still being extracted, then merges and deduplicates across chunks before optional whole-output validation (`docs/extraction-internals.md`, "End-to-End Pipeline" and "Stage Status Sequence"). The named stages are preflight, sectionize, extract_exam_info, extract_sections, review, merge_dedupe, validate_output, persist, then completed, completed_with_warnings or failed — and `completed_with_warnings` is a distinct terminal state, so an extraction that raised concerns is neither silently accepted nor thrown away. + +**Related.** A3, A23, B2, B4. + +--- + +# Part B. Applications and uses + +## B1. The Imaging Problem List viewer, and anatomy as presentation only + +**Statement.** Two viewers exist. The first navigates IPL → EFL → report with status and body-region filters. The second is an anatomy-first dashboard: an abstract body-map schematic with burden shown as fill intensity, laterality shown spatially in radiological orientation, and drill-down from region to organ cluster to exact location to finding to observation. Its governing rule is that the viewer trusts the IPL: "Each IPL `finding.id` is the canonical clinical problem row. Anatomy grouping is presentation-only and must never merge or split IPL findings." + +**Status.** Implemented example (both deployed); working proposal (the redesign plan's later slices). + +**Evidence.** +- IPL repo `main` `06f64a7`, `CLAUDE.md` "IPL Viewer Application": three-level navigation, temporal status tracking, status and body-region filtering, multi-patient support, dark-mode-first "designed for radiologists". +- IPL repo `dev` `36fa30c`, `docs/plans/viewer-v2-anatomy-dashboard.md`: the trust rule quoted above; the status semantics; the anatomy precedence ladder (IPL location first, then index metadata, then cluster config, containment ancestors only as a fallback, `unlocalized` otherwise); the four laterality buckets `left`, `right`, `midline_nonlateral`, `generic_unspecified` with "Generic/unspecified findings must not be folded into left/right counts"; the body-schematic redesign with its explicit record of why the first stacked-card layout failed; and "Anatomy clustering is deterministic presentation metadata. It is not clinical reconciliation." +- Same plan, finding-detail requirement: the detail must separate **instance data** (actual location, status, observations, dates, report evidence) from **definition data** (description, synonyms, typical anatomy, modalities, subspecialties, etiologies, ontology codes) from **anatomy data** (RID, region, cluster, laterality, containment path). +- example2 study §2.2: the implemented `MetadataSections` panels match that three-way separation; drill-down state is mirrored into the URL query string so any view is a shareable link; evidence highlighting is strict Unicode-normalized exact substring matching with an index map back to the unmodified report text, and a miss surfaces as a warning "rather than silently failing or approximating." +- example2 study §2.2: the generated bundle's `manifest.json` carries exactly 7 build-time warnings — 2 `missing_anatomy`, 4 `evidence_not_exact`, 1 `missing_definition` — surfaced in the UI. These are QA signals about the bundle, not clinical confidence. +- SIIM webinar slides 26 and 33: both prototypes driven live by attendees; slide 33 speaker notes name "the honest edge, the banner admitting two findings have no specific anatomy location." +- January 2026 deck: demo at `https://imaging-problem-list.pages.dev`. + +**Related.** A5, A12, A13, B5. + +**Unresolved.** The two viewers diverge on same-exam duplicate observations: viewer v1 merges them into one row per `report_id`, viewer_v2 lists each separately (example2 study §2.2). Neither behavior is stated as the intended one. + +**Undetermined.** `viewer/data/` is not example2: it holds a pre-anatomy 98-entry bundle for the same patient, no script on `dev` writes to it, and 0 of 288 finding entries there carry `anatomicLocation` (example2 study §2.1). Whether the deployed v1 is meant to be retired is not stated. + +## B2. The report extraction, coding, persistence and review platform + +**Statement.** The dev branch is a working platform that takes report text to coded findings and keeps the human in the loop: chunked multi-provider LLM extraction with verbatim-quote validation, a separate coding step, SQLite persistence with reports deduplicated by content hash and every extraction run stored with its model and settings, reviewer corrections as first-class objects, asynchronous job processing, an API, a batch CLI, and a reviewer UI. + +**Status.** Implemented example. + +**Evidence.** +- IPL repo `dev` `36fa30c`, `README.md`: providers OpenAI, Anthropic, Google, OpenRouter, Ollama, vLLM; the persistence section (SHA-256 report dedupe; each extraction run stored with report link, timestamp, model, reasoning setting, full JSON payload; corrections as `add_finding`, `update_finding`, `comment`); the Taskfile command surface; the batch extraction CLI. +- IPL repo `dev` `36fa30c`, `CLAUDE.md` "Architecture Notes": chunked extraction with bounded concurrency and a reviewer sub-agent that "can flag issues and trigger targeted re-extraction of specific chunks"; verbatim quote validation; "Post-extraction coding pipeline: After extraction, a separate coding agent maps findings to standardized OIFM codes. This is a distinct step from extraction"; TaskIQ workers over a Redis broker; API returns 202 plus a job ID. +- IPL repo `dev` `36fa30c`, `docs/human-review-workflow.md`: the gold-extraction workflow — batch-generate one candidate extraction per report, human reviewers overread and correct, corrected files become the gold set. +- SIIM webinar slide 16 speaker notes: "the extractor shown is one implementation of many. Many groups will build their own harness; what they share is the data model it targets." — an explicit statement that the platform is not the contribution. + +**Related.** A3, A7, B3, B4, C1. + +## B3. Coding is an independent job, decoupled from extraction + +**Statement.** Assigning OIFM finding codes and anatomic location codes is a separate job from extraction. Extraction output persists without codes; coding is triggered separately and can be re-run with different models or settings. It runs as a five-phase pipeline over the flat merged finding list: fast-path index lookup, parallel LLM term generation for findings and locations, batched index search, parallel per-finding LLM selection, and assembly, with each phase degrading non-fatally. + +**Status.** Implemented example with a written design rationale. + +**Evidence.** +- IPL repo `dev` `36fa30c`, `docs/coding-agent-design.md`: "Coding assigns OIFM finding codes and anatomic location codes to extracted findings. It is an **independent job** — fully decoupled from extraction." The five phases; the non-fatal per-phase design ("One finding's failure does not block other findings"); four separate prompts; tuned parameters `SEARCH_LIMIT = 6`, `MAX_CANDIDATES = 12`, `MAX_CONCURRENCY = 8`, each with a stated prototype-testing justification; and "Dropping full report text from term generation prompts produced identical results with 22% fewer input tokens." +- IPL repo `dev` `36fa30c`, `docs/plans/anatomic-location-efl-ipl.md`: the location-coding prompt rule that "If location is null, infer from the exam info and report context", and that "presence does not affect coding" — absent findings still get anatomy. +- example2 study §3.2: the sample-data enrichment pass reuses the production coding runtime rather than a one-off heuristic, and works around its name-based grouping by spreading repeated finding names across slots so each observation is coded from its own report text. + +**Related.** A12, B2, and the finding-model index ideas in the semantic inventory. + +## B4. Honesty-first evaluation of extraction + +**Statement.** An extractor evaluation that scores throughput and raw yield cannot distinguish a real recall gain from fabrication. The redesign makes the primary matcher quote-first, scores attribute *values* rather than only keys, freezes run configurations, keeps per-case artifacts, and uses adjudicated gold files rather than reviewed extractor output as the source of truth. + +**Status.** Stated direction with a recorded descope decision; version one scoped, not yet reported as implemented. + +**Evidence.** +- IPL repo `dev` `36fa30c`, `docs/plans/extractor-evals-redesign.md`, descope note dated 2026-07-07: "recent model-selection rounds (e.g. 2026-05-14, which made gemma4 the local default on '67s avg + 30% more findings') score throughput and raw yield, and cannot distinguish recall gains from fabrication." The plan was "deliberately **descoped rather than discarded**" after 3.5 months with zero implementation, because "The full plan's ceremony… is what made it unstartable." +- Same document, "Current Problems To Fix": the smoke dataset is in-sample because it is built from few-shot prompt examples; "Current gold is too close to reviewed extractor output in the extractor's own schema"; "Attribute scoring only checks keys, not values"; matching applies presence/location/attribute bonuses before those same fields are scored, "which can hide semantic errors." +- Same document, Core Decisions: "Source of truth is adjudicated gold in `*.gold.v1.json` files, not raw `*.extracted.json` output"; gate and benchmark sets "must both be held out from prompt examples." + +**What the code implements.** The instrument for producing that gold is a deliberately primitive one. `docs/plans/extraction-reviewer-ux.md` describes `extraction_reviewer/` as "the standalone, single-file HTML review tool — no server, no install, no network at run time," and `docs/plans/extraction-reviewer-workflows.md` records that its vanilla-JavaScript, no-CDN build is "a **sanctioned exception**" to the project's own frontend convention because "the offline `file://` zero-install requirement justifies it" — the tool has to run on a reviewer's machine wherever the reports are. A reviewer walks findings one at a time with keyboard verdicts of approve, flag or unsure, logs findings the extractor missed by highlighting the supporting text in the full report, and exports one review file per extraction. A later round added structured flag targets so a reviewer names which field is wrong rather than only writing a comment: finding name, presence, anatomic site, laterality, size, severity, extent, temporal status, hedged language, and lumps-multiple. + +The workflows plan states the intended path from review to gold: a converter applies a review file to its source extraction, passing approved findings through, surfacing flagged ones for correction, and turning missed findings into stubs to fill in, with the result finalized by an adjudicator and ingested by the evaluation harness. That chain, "the reviewer→converter→import-gold pipeline," is named "the documented source-of-truth path for gold." + +**Related.** A3, A26, B2. + +**Undetermined.** The gold file schema is open: the workflows plan records that the evaluation plan "names `*.gold.v1.json` but doesn't fix the schema; proposal is 'extraction schema + adjudication provenance fields.'" + +## B5. Six downstream application families for the Imaging Problem List + +**Statement.** The same record supports report pre-population, incidental-finding surveillance, chronic-disease monitoring, cross-subspecialty awareness, quality surveillance and research cohorts, and a breast-imaging case. + +**Status.** Stated design implications awaiting evaluation (manuscript's own words); the webinar presents them as a roadmap. + +**Evidence.** +- JDIM IPL manuscript abstract: "Pre-populated chronic findings, follow-up tracking, cross-subspecialty awareness, and a substrate for artificial intelligence (AI) reasoning are **design implications awaiting evaluation**." +- JDIM IPL manuscript, printed p.15, "Report Efficiency": "A reporting system built on the IPL could pre-populate confirmed chronic findings for the radiologist's review, so that dictation, or an artificial intelligence (AI) draft, focuses on what is new or changed." +- JDIM IPL manuscript, printed p.15, "Follow-Up Tracking and Safety": "Of lung nodules recommended for follow-up imaging, 40-60% do not receive it on time, and some of those lost to follow-up progress to advanced-stage cancer." +- JDIM IPL manuscript, printed p.16: cross-subspecialty awareness (the adrenal nodule seen on a chest CT five years earlier), and "The IPL and the clinical problem list are complementary: one tracks what imaging observes over time, the other what clinicians diagnose and manage." +- JDIM IPL manuscript, printed p.14-15: "identification for research, quality assurance, and education. The applications that follow are examples of what the model could enable." +- SIIM webinar slides 36-41: the six families named and given one slide each — report pre-population (slide 37: draft opens with each finding flagged pre-filled or new, "Interpretation, not inventory"), incidental-finding surveillance (slide 38: "report content, not exam code, decides completion… same exam code, opposite outcomes"), chronic-disease monitoring (slide 39: "True growth rate: frequent f/u masks it"), cross-subspecialty awareness (slide 40, with per-organ rules and "4.1% of recs avoidable with all priors"), quality surveillance and research cohorts (slide 41). +- SIIM webinar slide 35 speaker notes: ">1.5 M new incidental lung nodules/yr (Gould 2015)… 40-60% of recommended follow-up never happens." +- January 2026 deck, "IPL across imaging life cycle": planning (MRI safety, mobility, pre-authorization); intra-exam (rules-based protocoling); interpretation (findings-oriented PACS views, real-time quality control); post-interpretation (passive screening, research, outcomes). +- Board 1 (internal; content only), "Imaging Problem List" overview box: "MRI safety checks; Protocoling; Interpretation process — Draft report generation, PACS integration, Point-of-care report quality checks; Coding/billing; Drive EMR-side care pathways (CDS hooks); Data mining; Differential displays of reports: specialists, patients; Population health monitoring." + +**Related.** A14, A18, B6, B7, B8, B11. + +## B6. Breast imaging: one entity across assessments, and an automated MQSA audit + +**Statement.** A breast mass tracked as one IPL entity across five examinations and eighteen months, its BI-RADS assessment moving 0 → 3 → 4A → biopsy → 2, with the marker clip becoming a durable re-identification anchor. Two applications are proposed on that record: presenting the IPL to the radiologist while reading, and an automated outcomes audit built from the BI-RADS assessment and any pathologic cancer diagnosis within one year — the data the federally required Mammography Quality Standards Act audit is built from. + +**Status.** Stated as planned work, not results, by the source itself. + +**Evidence.** +- SIIM webinar slide 42, "Breast IPL": the five-exam sequence with dates and assessments verbatim; "At biopsy the entity transitions from mass-as-observation to fibroadenoma-as-diagnosis, and the marker clip becomes a durable re-identification anchor on every future exam. **Present as planned work, not results;** the monitoring agent is later scope." +- SIIM webinar slide 43 speaker notes: the display-at-interpretation application with its design path ("focus groups with breast radiologists, then iterative usability testing toward a pilot"); and the audit — "for every screening exam the IPL already holds the BI-RADS assessment and any pathologic cancer diagnosis within one year: exactly the data the federally required MQSA audit is built from. Today that audit mixes semi-automated and manual steps, and many facilities audit only mammography; an IPL-derived audit runs continuously across mammography, ultrasound, and MRI. **Present as planned work: design, not results.**" + +**Related.** A4, A9, B5, B7. + +## B7. Outcome tracking, follow-up completion, and radiology-pathology correlation + +**Statement.** A design for closing the loop between what a radiologist reported and what later happened to the patient: what a "future clinical event" record needs, patient factors kept deliberately separate from EHR data, an escalating cascade from per-case feedback up to population statistics, notification and worklist actions, and concrete use cases including diagnostic-yield auditing of the *-RADS systems, feedback to ordering providers, and interventional-radiology outcomes. A companion board works the imaging-to-biopsy-to-pathology link and proposes a shared tracking identifier across imaging Observation, procedure note and pathology report. + +**Status.** Working proposal on internal boards, grounded in a published quality-measure article; one named demo project in a governance board; nothing built. + +**Evidence.** +- Board 12 ("Outcome Tracking Schema", no named individuals, moderate sensitivity as unpublished design): the "Future Clinical Event" event types (imaging, pathology, operations and procedures, endoscopy/arthroscopy, diagnoses and problem-list items, lab tests, death, registry data, disposition, therapeutic) and result information; the patient-factor box annotated "Keep patient factors separate (from EHR and other sources)" covering demographics, risk factors, medical conditions, socio-economic factors, connectedness with the healthcare system and technology, and allostatic load; the six-step "use cases cascading" from identifying outcome data up to "Track pathways: incidental detection → follow-up study → biopsy/surveillance → treatment → morbidity → survival"; the Actions box (notify leadership/supervisor, notify radiologist immediately or by periodic digest, notify provider or patient of follow-up that has not occurred, create a registry, put on a work queue or dashboard). +- Board 12, "Specific Use Case examples": recommendation completion tracking; "auditing of diagnostic yield of malignancy-related RADS (BI-RADS, PI-RADS, TI-RADS, LI-RADS, Lung-RADS)"; trainee draft-to-final significant-change notification; continuous AI monitoring at aggregate and provider level; ordering-provider feedback on diagnostic yield; IR outcomes. +- Board 12 cites Kadom et al., "Novel Quality Measure Set: Closing the Completion Loop on Radiology Follow-up Recommendations for Noncritical Actionable Incidental Findings", *J Am Coll Radiol* 2022;19:881-890 — a real external source not referenced anywhere in the current bundle. +- Board 7 ("Radiologist Outcome Feedback", internal; schema content only): use cases for outcome tracking (personal performance review, training and education, quality improvement and peer review, research); interface options (passive, active query, aggregate dashboards); the "Path Result ↔ Biopsy Procedure" note — "Could use a shared tracking ID across imaging Observation → procedure note → pathology report." +- Board 14 ("ACR OIDM", low sensitivity), Demo Projects: "Outcome tracking demo" named alongside the templating and pulmonary-nodule demos. +- Board 1 (internal; content only): the cross-source integration idea — assembling an ED visit, a CT finding, an operative note, a pathology finding and a subsequent CT sequela under one concept such as "appendicitis", described as "Multiple channels that feed into a master, integrated knowledge base." + +**Related.** A18, A19, B5, B11. + +## B8. The reporting assistance framework: a context object model plus a plugin container + +**Statement.** A reporting tool hosts plugins in a container. The container supplies an OIDM-defined data context object and accepts a fixed set of commands from the plugins, re-running every plugin whenever the context changes. Two sources give the command list at different depths. + +**Status.** Stated goal (deck's applications pillar, named "Open Imaging Reporting SDK"); working proposal (the 2023 site post and the board slide); one working rendering precedent; no container implementation. + +**Evidence.** +- January 2026 deck, strategic pillar 3: "Applications: Open Imaging Reporting SDK (vendor-driven innovation); demo apps: IPL Browser, early draft-generation tools." +- Site post "OIDM-Based Next-gen Reporting Assistance Framework", 2023-07-16: plugins written in a language such as JavaScript; the container supplies current findings, prior reports and the exams being reported; plugins issue four kinds of command (insert generated text, request information from the radiologist, alert the radiologist to a problem, send data to an external system); the container re-runs every plugin whenever context changes. +- Board 9 ("OIDM Big Picture"), "Reporting Assistance Framework" frame (described in the transcription as a polished, presentation-quality slide, not hand-drawn): **nine** commands — insert text into report; add/change data in data context; prompt radiologist for data; get EMR data elements; alert radiologist to quality issues; show radiologist images/findings; activate communication tools; package/send data to EMR/registries; request inference on images — against the **nine-field** Reporting Data Context Object Model listed in A16. +- Board 9, "SDK Development" work thread: "Multi-vendor shared work to define the structure of 'apps'; Need defined data structures, program interfaces; Incorporate other defined information; Model is web browser DOM." +- Board 9, "Next-Generation Assisted Reporting Use Cases" mind map (also present on Board 13): branches AI Tool Integration, Quality Checks (coding/MIPS checks; language and structure checks including left/right errors, sex-phenotype errors, anatomy-based errors, report length versus norms, findings-versus-diagnosis placement, undesirable phrases such as "cannot exclude"; "Is asked question answered?"), Specialized Reporting Applications, External Applications, Smart References, Facilitate/Automate Workflows, Report Generation, Longitudinal Reporting, Radiologist Situational Awareness. +- `CDETemplateDemo` `master` `e09f255`: a working web service that flattens a CDE-labeled FHIR Observation into template data keyed by component display name, derives boolean flags including presence and absence, and renders a Mustache text template; sample observations and templates are added as files under `mapper_ui/public/`. The one working precedent for a plugin that inserts generated text, and it uses no language model. +- openimagingdata.org About page, last modified 2023-06-21: programming interfaces promised in TypeScript/JavaScript, Python and C#. `knowledge/applications/reporting-sdk.md` records that the first two became lineage repositories and no C# library was written. + +**What the code implements.** `CDETemplateDemo` `master` `e09f255` is the working slice of the "insert generated text" command, and its presence handling is the interesting part. `mapper-logic/src/mappers/jsonToObservation.ts` validates an incoming Observation and flattens its components into a lookup keyed three ways — by element code, by lowercased display name, and by capitalized display name — and `obsToMustache.ts` additionally sets each value string as a boolean flag so a template can branch on it. The commit named "Better presence handling (w/samples)" added a special case: when the component is presence, it sets `presence_present` and `presence_absent` booleans, and the sample template wraps the descriptive sentence in one and adds "There is no pneumothorax." under the other. So one coded Observation and one template render either an affirmative sentence or its negation, which is the rendering counterpart of A11 and A23. + +**Related.** A11, A16, A17, A23, B5, C2. + +**Unresolved.** The 2023 post names four commands; Board 9's slide names nine. No source states which supersedes the other. The post's own wording is that assistance "would take the form of standard commands generated by the scripts back to the reporting environment, which could then insert generated text into the existing report, ask the radiologist for additional information, alert the radiologist to a particular problem, or send data to an external system", with plugins authored "in a standard programming language, like JavaScript", and the container re-running them because "As the report context changes (more AI data comes in, the radiologist updates the report manually), the reporting tool would re-run each script with the updated data context so it could take appropriate actions." + +**Unresolved — no global presence element.** The presence element identifier is per CDE set: `RDE1717` for pulmonary nodule in `FHIRSamples` `9ae2fa9`, `RDE421` for pneumothorax in `CDETemplateDemo` `e09f255`. Any tool that wants to find "the presence element" of an arbitrary set must therefore do what Board 15's "CDE Role Standard Tagging" proposes (B9), and nothing yet does. + +**Undetermined.** The project lead confirmed the SDK is concept only; no repository, package, issue or branch for it was found (`knowledge/applications/reporting-sdk.md`, "Status first"). + +## B9. A multi-vendor interoperability demonstration exchanging CDE-labeled FHIR Observations + +**Statement.** A named demonstration project — pulmonary nodules — in which an EHR vendor, reporting vendors, AI vendors and PACS vendors exchange pulmonary-nodule findings encoded as CDE-labeled FHIR Observations over FHIRcast, with a seven-step workflow from AI-generated nodule description through radiologist acceptance, report incorporation, retrieval of prior known nodules, association, and return of both text and Observation objects to the EHR. + +**Status.** Working proposal on an internal board; named as a demo project in the governance board; no implementation found. + +**Evidence.** +- Board 15 ("Pulm Nodule Demo Project", internal; schema and workflow content only, vendor-partnership framing omitted). Title: "RSNA/ACR AI In Practice Demo Project: Pulmonary Nodules!" Subtitle: "Exchange of radiology findings encoded as CDE-labeled FHIR Observations." Four vendor-role categories are given (EHR, reporting, AI, PACS), each with named example companies; the organizations are recorded in the source and are not reproduced as partnership claims here. +- Board 15, "Basic Principles": "Everywhere, we send data structured as FHIR Observations (including ontology codes). Exchanging everything as FHIRcast." +- Board 15, Complete Workflow, steps 1-7 as transcribed, including step 4's shared tracking ID (see A19) and step 5's open questions about who associates new nodules with prior ones and who adds the tracking ID. +- Board 15, "Smart Annotations": a PACS viewer infers which CDE Set a radiologist is characterizing from the annotation tool used and the anatomy under it, elicits the remaining elements the Set defines, and sends a FHIR Observation with the Set ID and components tagged with element IDs over FHIRcast. +- Board 15, "CDE 'Role' Standard Tagging": use standard SNOMED/RadLex tags on element definitions to mark an element's role or purpose (presence, location, size with its several measures, volumes, segmentation data, modality-specific measures such as radiodensity, echogenicity and MR signal, contrast behavior), so that a viewer needing "the volume element" can find the element carrying SNOMED 118565006 rather than hardcoding element IDs per Set. +- Board 14 ("ACR OIDM"), Demo Projects: "Pulmonary nodule demo (RSNA IAIP project)" and "Templating project (SIIM Hackathon)". +- Board 1 (internal; schema content only): the parallel exchange sketch in which a reporting vendor sends a structured finding list with the report result, an EHR vendor maintains the patient's imaging findings repository and exposes an imaging-problem-list view at interpretation time over FHIRcast, and the reporting vendor reads it back to display history, generate report text and check reports; with the open question of which FHIR resource the EHR should send back ("borrow/adapt FHIR structures for real problem lists? Condition resource?"). + +**Related.** A19, A21, B8, C3. + +**Unresolved.** Board 1 records the IPL maintenance question as genuinely open: EMR-maintained versus dynamically generated by an Assembler service versus cached; "how do we make sure the IPL is dynamically generated, updated/not stored, and cached." + +## B10. Local-only operation for protected health information + +**Statement.** The extraction platform supports local and on-premises model providers so that protected health information need not leave the institution, with a local-only mode that has been hardened and whose remaining work is shelved behind explicit reopen triggers. + +**Status.** Implemented example plus a stated-direction backlog. + +**Evidence.** +- IPL repo `dev` `36fa30c`, `README.md`: Ollama ("local models, no API key needed") and vLLM ("OpenAI-compatible deployments") as first-class providers, with `.env.ollama.example` and `.env.vllm.example` at the repository root. +- IPL repo `dev` `36fa30c`, `docs/archive/local-only-mode.md`, `docs/archive/local-only-mode-hardening.md` (archived, i.e. completed) and `docs/plans/local-only-future-tightening.md` (active). +- `knowledge/roadmap/ipl-data-model-system.md`, "Local-only operation": "Protected health information stays on local models, with remaining hardening items shelved behind explicit reopen triggers." +- JACR IPL manuscript, Methods: "The same code and the same language model ran at both sites on each institution's approved deployment" — the practical constraint the local-model work serves. + +**Related.** B2, B4. + +## B11. The use case catalog and the six value categories + +**Statement.** A catalog of application ideas, each tagged with one or more of six value categories taken from the RSNA Reporting Informatics Committee's use-case work: reporting efficiency, care team communication, operations/quality/safety, research, public health, education. The catalog was to grow into per-case files with defined metadata; it never did. + +**Status.** Implemented example (the catalog exists and is complete as far as it goes); stated but abandoned process. + +**Evidence.** +- `UseCases` `main` `71a90d2`, `Index.md` and `README.md`: the entries and the six value categories, reorganized without additions in `knowledge/history/use-cases.md`. Last commit 2024-02-26; four of the seven headings (Protocoling System, AI Pipeline, PACS Viewing, Data Exploration) are placeholders with no entries. Entries contributed by the RSNA Reporting Informatics Committee are marked as such in the source. +- Board 13 ("OIDM Use Case Brainstorming", no named individuals): the same Value Categories table, confirmed matching; the process questions ("What information should be captured as part of a use case? Do we want a text or data-based format (JSON)?"; "Create a GitHub repository for these?"); the planned artifacts (a README base document with metadata and submission guidelines, an Index.md, per-category directories); the six category axes (workflow/list oriented, AI pipeline oriented, reporting oriented, image-viewer oriented, data exploration/outcome oriented, multi-category); and a circled "Medico-legal Issues" note attached to the "Multiview Reporting" cluster (radiologist view, PCP view, specialty-oriented views, patient view). +- January 2026 deck, next steps: "use-case pipeline -> CDE group" — the catalog's intended downstream consumer. + +**Related.** B5, B7, C3. + +--- + +# Part C. OIDM's purpose and the relationship among its parts + +## C1. OIDM's stated purpose + +**Statement.** The project's own statements of purpose, in order of date: the site describes it as "defining unified data structures to integrate new functionality into imaging informatics platforms"; the January 2026 deck calls the goal "standardizing the DNA of imaging IT" and titles itself "Realizing Object-Oriented Imaging Results"; the project lead's 2026-09-19 formulation is "a system of defined data structures for representing imaging exam result information", "intended to be used within applications to both read and create result data". + +**Status.** Stated goal, expressed at three dates with shifting emphasis. + +**Evidence.** +- openimagingdata.org project site tagline (cited in `knowledge/overview/what-is-oidm.md`): "defining unified data structures to integrate new functionality into imaging informatics platforms." +- January 2026 deck, title and subtitle. +- Email notes, points 3 and 4 (see A21). +- Board 9 ("OIDM Big Picture"), "Where (i.e., Vision)" statement: "Tools throughout imaging informatics should form an *integrated, open platform*, allowing all to add and inter-connect new functionality leading to more efficient, higher quality patient care." +- Board 14 header: "Project that defines methods and tools that create IT platforms within the imaging ecosystem." +- JDIM IPL manuscript abstract: "Radiologists need a longitudinal record of findings to interpret efficiently and to integrate intelligent tools, and we found no radiology data standard that defines one." +- `sources/bucket/text/ai-evolution-radiology.md` (in-progress working draft, no venue; **paraphrase only, several sentences are objectively incomplete mid-edit**): argues that the limiting factor in radiology AI is not model capability but the absence of a shared, relational "foundation context" specifying findings, diagnoses, anatomy and their relations, comparable to what DICOM and PACS did for images, and that radiologists must author and steward that representation. Per `sources/bucket/REPORT.md` §1, the draft was last saved 2026-08-14 with 219 tracked insertions and 190 deletions. + +**Related.** A21, C2, C3. + +## C2. The relationship among the parts: three layers, and the DOM analogy + +**Statement.** The work organizes into a semantic foundation (finding models and CDEs, anatomic locations, exam types, terminologies), a set of data structures built on it (Observation, Exam Finding List, Imaging Problem List, Imaging Persona), and applications that read and write those structures. Each layer depends on the one below through shared identifiers. The relationship to FHIR is described by analogy: "the relationship between OIDM and FHIR might be that between the browser's DOM and HTML." + +**Status.** Stated organization (deck, site); working proposal at the class level (Board 4); the organizing principle of the current bundle. + +**Evidence.** +- January 2026 deck, strategic pillars: "1. Semantic foundation: OIFM -> CDEs; Anatomic Location definitions. 2. Data structures: atomic Observation -> Exam Finding List -> IPL -> 'Imaging Persona'. 3. Applications: Open Imaging Reporting SDK; demo apps." +- Site post "Data Model: Structure and Function", 2024-01-25, read live: the model's parts are named one by one — "**Observations:** These are the individual radiology findings that the radiologists is describing in their current report"; "**Current Report Text:** The actual text of the current report, ideal represented as hypertext with tags"; "**Imaging Stud(y|ies)**"; "**Patient**"; "**Order**"; "**Prior Imaging Studies**: Representations of the patient's imaging history, including both report text"; "**Tracked Observations**: An index of the association of the same radiology finding (e.g., a tumor or a fracture)"; "**EHR Data**". On FHIR: "The data model is intended to make extensive use of FHIR definitions in its structuring, but will likely reflect a superstructure", and "An analogy for the relationship between OIDM and FHIR might be that between the browser's DOM and HTML." This is the earliest first-hand statement of the parts list that Board 4 later draws, and it names Tracked Observations as an index of the association of one finding across exams, which is the A19 idea in prose. +- Board 9, "SDK Development" work thread: "Model is web browser DOM" — the same analogy, independently. +- Board 4, hand annotations: FHIR maps to the Patient/Order and EHR Data branches; the LOINC/RadLex Playbook to ImagingStudyType; Anatomic Locations to BodyPart — an explicit statement of which external vocabulary supplies which part. +- Board 9, "OIDM Work Threads" frame, six workstreams: Data Model Toolchain; Anatomic Locations/Exam Types; Data Model Content; SDK Development; Report Representation; Utility Library. The Data Model Content box (highlighted) states the content strategy: "Significant challenge is too few data element definitions; New concept—'stub' data elements: presence, change attributes only; Will allow rapid expansion of database; Iterate to improve models in open crowd-sourced model; ACR/RSNA review as needed; Transform to ACR/RSNA CDEs." +- Board 1 (internal; content only), "Ingredients": "Standard codes for findings (CDEs!) — Don't need complete data models — 'CDE stubs' suffice." +- January 2026 deck, "OIFM: the CDE workbench": finding models as a "Rapid innovation / proving ground before ACR/RSNA CDE adoption", supplying "ground-level info for tool access + LLM context engineering" and "exploratory metadata… that can graduate to standards." +- JDIM IPL manuscript, printed p.19: "The CDEs, the OIDM finding models, and the terminologies they map to (RadLex and SNOMED CT) provide a vocabulary of findings and anatomic sites, not a patient's history." — the clearest statement of the boundary between the semantic foundation and the data structures. +- JDIM IPL manuscript, printed p.6: the EFL finding code "comes from the Open Imaging Data Model (OIDM) finding vocabulary, an open lexicon in the lineage of the RSNA/ACR CDEs." + +**Related.** A2, A21, C1, C3; the CDE-workbench relationship belongs primarily to the semantic inventory. + +**Unresolved.** The deck's layer-2 hierarchy has four levels; only two are built (A2, A16). + +## C3. Structure first, standards after; and how agreement is supposed to happen + +**Statement.** Define the data structures first, then express them in FHIR and other standards. Convening is proposed as the mechanism: an ACR-OIDM Structured Imaging Results Working Group co-hosted with the ACR, bringing expert and vendor participants into an "academic-vendor big tent", feeding a use-case pipeline to the CDE group and standardizing the result. The ACR Data Science Institute's role is sketched separately as sponsoring, logistics, volunteer opportunities and demo projects. + +**Status.** Proposal recorded in the deck and on a board; nothing in any repository records the working group as convened. + +**Evidence.** +- January 2026 deck, call to action: "ACR-OIDM Structured Imaging Results Working Group; structure-first (then FHIR etc.); vendor-driven." ACR priorities named: recommendation tracking, AI validation (correlating AI against radiologist Observations), quality metrics, *-RADS support. Next steps: "host/moderate academic-vendor big tent; use-case pipeline -> CDE group; standardize the result." +- Board 14 ("ACR OIDM", low sensitivity): the ACR Data Science Institute's four branches — Sponsoring (identity, project participation, spread message, show usage with ACR); Logistics (meeting coordination, project management, space at events); Volunteer Opportunities (governance, use cases and future demos, CDE definition and review, CDE indexing, anatomic locations, exam-types-to-anatomy, reference implementations, demo projects, website and documentation, white papers, standard-making via IHE); Demo Projects; Reference Implementations (work with or within existing open-source efforts; grant or paid support; the component list in A16). +- JDIM IPL manuscript, printed p.18: "Vendors are beginning to build longitudinal tracking features with, to our knowledge, no published data model to guide them. Shared data structures come first… We offer this model as a starting point for an open, community-developed standard." +- JDIM IPL manuscript, printed p.17: "The drafters of the Integrating the Healthcare Enterprise (IHE) Imaging Diagnostic Report (IDR) profile included a prior finding catalog use case, conceptualized as an imaging problem list for the reading radiologist, based on earlier presentations of the model described here… The IHE supplement leaves the catalog's information model out of scope, deferred to subsequent work on the model presented here." +- SIIM webinar slide 32 speaker notes: "the adoption path is already forming: the IHE Imaging Diagnostic Report profile names a prior finding catalog as an imaging problem list. This rides existing standards rather than inventing new ones." +- JDIM IPL manuscript, printed p.18, "Adoption": "Pre-populated chronic findings are a natural entry point for IPL adoption… **Affirming must save the radiologist time immediately, because downstream benefits alone are unlikely to sustain adoption.**" + +**Related.** A21, B9, C1, C4. + +**Undetermined.** Whether the working group has been convened since January 2026. No source read records it. + +## C4. Nothing is formally defined yet + +**Statement.** The project is in a coalescing phase. No source is the specification; each source's current version of a structure stands beside the others, dated and attributed. + +**Status.** Decision of record, 2026-09-21. + +**Evidence.** +- `knowledge/plans/2026-09-20-knowledgebase-build-plan.md`, "Decisions added 2026-09-21", row "No specification exists": "The project is in a coalescing phase; nothing is formally defined. The knowledgebase presents each source's current version of a structure side by side (repo branch and commit, manuscript under review, deck or webinar, board), dated and attributed, and states disagreements (for example the three Imaging Problem List status vocabularies) without resolving them. Words like 'specification' or 'canonical model' are not used for any of them." +- Email notes, incorporation targets, last bullet: 16 bundle documents call a repository README or a manuscript "the specification" or similar; the project lead directs replacing these with attributed, dated phrasing. +- SIIM webinar slide 25 speaker notes: "the IPL is an actively-developing framework. Details shown today are being iterated and may change. This honesty invites an informatics audience into an open problem rather than pitching a finished product, and it protects every specific design rule just shown from reading as a fixed claim." +- IPL repo `main` `06f64a7`, `CLAUDE.md`: "This is primarily a data specification and documentation project, not a traditional code repository" — the repository's own self-description, which the 2026-09-21 decision supersedes as a bundle-wide framing. + +**Related.** A5, A9, A21. + +--- + +# What could not be determined + +1. **The JDIM manuscript's Table 1 FHIR mapping** was read only through `sources/bucket/REPORT.md` §4's summary of the rendered table image (PDF page 88), not from the table itself. The element-by-element mapping in A21 should be re-verified against that page before it is published. +2. **The JACR manuscript's submission status.** The file is a blinded manuscript with a supplement and figures and no manuscript number or cover letter, so "prepared for submission" is the most the file supports. +3. **Whether the webinar's two-value status model supersedes the manuscript's four-value model.** The webinar is later (2026-07-15) than the R1 submission, and its speaker notes say the framework is being iterated, but no source states a supersession. +4. **Who owns and assigns a finding's tracking identifier** (A19). Open on Board 15, unanswered elsewhere. +5. **Whether "Imaging Persona", "OIDM Data Context Model" and "Reporting Data Context Object Model" name one structure or three** (A16). +6. **Whether the `indeterminate` presence value in the sample data is superseded** by the binary-presence-plus-confidence rule (A10). +7. **The relationship between the JACR study's four matching rules and the JDIM graduated-confidence model** (A8). +8. **Board dates.** The transcription carries dated notes on several boards, but the boards themselves are undated working canvases; a dated note inside a board is evidence of when that note was made, not of the board's currency. +9. **Whether the deployed viewer v1 is to be retired** now that its data bundle is orphaned from the generation pipeline (B1). +10. **Finding-model corpus counts and the `FindingModelFull` schema** were not verified at source here; the `findingmodel` and `findingmodels` repositories were out of scope for this inventory and belong to the semantic inventory. A15's 2,458-definition figure comes from the webinar only. +11. **Which presence vocabulary is intended** (A10). Three are in active use across the manuscript, the extraction prompt and the sample data. +12. **Whether the selector is meant to resolve technical language to a diagnosis** (A24). Two rules in the same pair of prompts point opposite ways, and the technical-findings reference sides with one of them. +13. **Whether an observation may carry more than one anatomic location** (A12). The coding tool returns a list; the Exam Finding List decision is a single location. +14. **Who fills the vocabulary gaps** that the blanket-negative rule and the `no_candidate_match` / `definition_mismatch` rejection reasons are designed to surface (A23, A24). The mechanism reports the gap; no source names the process that closes it. +15. **The gold file schema** for adjudicated extractions (B4), recorded as open in the reviewer workflows plan. +16. **FindingModelForge's authoring prompts.** The Forge draft lifecycle is recorded here only as it bears on review and provenance; the prompt text inside the application was not read at source for this inventory, and the Forge idea belongs to the semantic inventory in any case. +17. **`ReportFindingRefiner` and the `openimagingdata.org` repository** (`schemas/`, `docs/`) were named for reading but not reached; they are lineage sources for the schema-differences material already held in `knowledge/references/cde-schema-differences.md`. + +--- + +# Proposed idea pages for this area + +Names are nouns. Each page is one explanatory home; other pages link to it. + +| Page | One line | Homes ideas | +|---|---|---| +| `observation` | The atomic record of one finding asserted on one exam: what, where, attributes, and the sentence it came from. | A1, A10 (presence and confidence), A11 (negatives) | +| `exam-finding-list` | The per-exam list of findings, and the faithful-translation constraint that makes everything above it trustworthy. | A2 (first level), A3, A9 (observations within one report) | +| `imaging-problem-list` | The patient-level record: entries keyed by finding and site, their observation histories, and what the record is for. | A2 (second level), A4, A22 | +| `entry-status-and-trajectory` | How an entry's state is read from its observation history, and the four vocabularies that disagree about what to call it. | A5, A6 (succession sits beside status) | +| `succession-and-linking` | Connecting observations to entries and entries to each other: entity resolution, graduated-confidence linking, succession, and anatomic-compatibility reconciliation. | A6, A8, A13, A19 | +| `provenance-and-review` | Where each observation came from, who affirmed it, and how corrections are recorded. | A7 | +| `finding-and-diagnosis` | What counts as one finding when reports use different codes, substitute a diagnosis, or describe an entity that evolved; and where technical observation-level language fits. | A9, A17, and the technical-findings reference | +| `negation-and-normality` | Why an explicit negative and a statement of normality both become coded findings, and what that asks of the vocabulary. | A11, A23 | +| `coding-a-finding` | Assigning a finding code and a location code so that equivalent descriptions converge, including when to refuse. | A24, A25 | +| `extraction-quality` | What can go wrong translating prose into structure, how the system checks for it, and how that is measured. | A26, B4 | +| `anatomic-location-of-a-finding` | Why every observation carries a location, how it is assigned, and what the generic-versus-specific gap costs. | A12, A13 (shares with succession-and-linking; this page owns assignment, that page owns reconciliation) | +| `finding-context` | The per-finding dimensions that tell a reader or an agent what to expect next: permanence, expected course, etiology, anatomy. | A14, A15 | +| `imaging-persona` | The clinical context around the imaging record, and the object model that names its parts. | A16 | +| `recommendation-and-follow-up` | Representing a follow-up recommendation, attaching it to an entry, and closing it. | A18 | +| `structures-and-transport` | Why the structures are defined independently of FHIR and DICOM, and how they would be expressed for exchange. | A20, A21 | +| `imaging-problem-list-viewer` | What the viewers show, and the rule that presentation never changes the record. | B1 | +| `extraction-and-coding` | Turning report prose into coded observations, and keeping coding a separate job from extraction. | B2, B3, B10 | +| `applications-of-the-record` | What a longitudinal structured record makes routine: the application families, the breast case, the life-cycle uses. | B5, B6, B11 | +| `outcome-tracking` | Closing the loop from what was reported to what happened. | B7 | +| `reporting-assistance` | The context object a reporting tool supplies and the commands a plugin can issue. | B8 | +| `interoperability-demonstrations` | Exchanging coded findings between systems, and the questions that exposes. | B9 | +| `what-oidm-is` | The purpose, the parts, and how they depend on each other. | C1, C2 | +| `how-agreement-happens` | Structure first, standards after, and the convening that is supposed to produce agreement. | C3, C4 | + +Twenty-four pages for this area. The semantic inventory's pages (finding models, CDEs, anatomic locations index, exam types) sit beside them. Three are seams where the two inventories meet and need an ownership decision when the combined list is agreed: `anatomic-location-of-a-finding`, `finding-context`, and `coding-a-finding`, the last because the convergence rules are as much a statement about what the vocabulary is for as about how the coder behaves. + +Four of these pages exist because the prompts do. `negation-and-normality`, `coding-a-finding` and `extraction-quality` home ideas that appear in no manuscript, deck or board, only in the instructions the team wrote for its own models; `finding-and-diagnosis` draws its sharpest operational rule from the same place. They are not tooling pages. A rule that says a more specific code is never an acceptable match, or that a normal statement becomes an absent abnormality, is a position about what the data structures mean, written where it had to be executable. + +--- + +# Existing bundle pages holding unique team-authored material that needs a home first + +Checked page by page against the sources above. These carry team-authored substance that exists nowhere else in a durable form, so they must be rehomed before removal. + +| Page | Unique material | Where it should go | +|---|---|---| +| `data-structures/ihe-idr-alignment.md` | The IDR observation grammar (five slots with the supplement's own rules), the three IDR term definitions, the four unresolved OIDM/IDR differences, and IDR's three questions back to RadElement. Sourced to `notes/ihe-idr-extract.md` on `RSNA/ACR-RSNA-CDEs` `next-gen-2026`, which has not been migrated into this bundle. | `structures-and-transport`, with the finding-versus-diagnosis difference cross-linked to `finding-and-diagnosis` | +| `data-structures/fhir-mapping.md` | The worked `FHIRSamples` analysis: the set-code / element-code / value-code chain, status-as-provenance, and assessments as second-order Observations whose `derivedFrom` points at both the study and the finding Observation. This reading of the samples exists only here. | `structures-and-transport` | +| `data-structures/technical-imaging-findings.md` | Migrated verbatim from IPL repo `dev` `docs/technical-imaging-findings.md`: the catalog of modality-specific technical terms and the rule that a technical observation must not be reinterpreted as the diagnosis that might explain it. Team-authored, draft status stated in the source. | `finding-and-diagnosis`; keep the full catalog as a `references/` extract if it does not fit | +| `data-structures/anatomic-location-assignment-rules.md` | Migrated from IPL repo `dev`: the precedence ladder, laterality rules, bilateral rules and worked misses. Team-authored. | `anatomic-location-of-a-finding`; the long worked examples may belong in `references/` | +| `history/use-cases.md` | The whole `UseCases` catalog reorganized, with the six value categories and the RSNA Reporting Informatics Committee attributions preserved. The upstream repository has been dormant since 2024-02-26. | `applications-of-the-record`, or a `references/` extract linked from it | +| `applications/reporting-sdk.md` | The 2023 site post's plugin-container design and the About page's language commitments, read from sources that are live web pages rather than repository files. | `reporting-assistance` | +| `overview/vision.md` | The DOM/HTML analogy and the deck's three benefits, quoted from site posts that exist only on the live Ghost site. | `what-oidm-is` | +| `references/exam-finding-list-example.md`, `references/imaging-problem-list-example.md` | Real sample JSON with commentary. Keep only what an idea page cannot explain in prose; the example2 study supersedes most of the commentary. | trim into `observation` / `imaging-problem-list`, or keep one minimal extract | +| `references/status-update-2026-01.md` | The January 2026 deck extract. The deck is a live Gamma URL that may change. | keep as a dated `references/` extract | +| `roadmap/open-questions.md` | 5,963 words; contains the team's own unresolved alternatives mixed with agent-found documentation defects. | split: team questions go beside their ideas; defects to `sources/upstream-issues-draft.md` per the joint notes | + +Pages in this area found to carry **no** unique team-authored material beyond what the sources above supply, and which can be retired once their ideas have homes: `data-structures/index.md`, `data-structures/hierarchy.md`, `data-structures/sample-data.md`, `data-structures/observation.md`, `data-structures/exam-finding-list.md`, `data-structures/imaging-problem-list.md`, `data-structures/imaging-persona.md`, `applications/index.md`, `applications/imaging-problem-list-viewer.md`, `applications/report-extraction-platform.md`, `applications/finding-and-location-coding.md`, `applications/ipl-mvp-extraction.md`, `overview/architecture.md`, `overview/what-is-oidm.md`, `roadmap/ipl-data-model-system.md`, `history/timeline.md`, `history/lineage-repositories.md`, `history/extraction-approaches.md`, `history/cde-template-rendering.md`, `repositories/repository-map.md`. Each was checked against its cited sources; each restates material that the sources carry directly, which the idea pages will cite instead. diff --git a/docs/plans/idea-placement.md b/docs/plans/idea-placement.md new file mode 100644 index 0000000..3fcc02e --- /dev/null +++ b/docs/plans/idea-placement.md @@ -0,0 +1,309 @@ +# Idea placement table + +Step before drafting, per `restructure-joint-notes.md`. Maps every idea in the two inventories — +`idea-inventory-semantic.md` (prefixed `Sem-`) and `idea-inventory-structures-and-uses.md` +(prefixed `Use-`) — to the section that will house it. The two inventories both use letters A-F +for their own sections, so IDs collide between them (`Sem-A1` and `Use-A1` are different ideas); +the `Sem-`/`Use-` prefix disambiguates. + +**Count note.** The joint notes and the semantic inventory's own scope line both call this "the +inventories' 70-odd ideas". The semantic inventory (`idea-inventory-semantic.md`) in fact carries +46 numbered ideas (A1-A10, B1-B9, C1-C8, D1-D9, E1-E2, F1-F8) and the structures-and-uses +inventory states its own scope as 41 (A1-A26, B1-B11, C1-C4). That is 87 ideas total, not 72. +This table places all 87. + +**Revision history.** +1. First version used a human-stated / linking-prose role split that demoted anything sourced + from a prompt, skill, design note, ADR, or repo doc to secondary status. +2. The project lead overrode that: ideas mined from the repositories' documentation, plans, + prompts, skills, ADRs, and design notes are the team's own ideas and belong in the graph as + first-class content, not as linking prose. The role column became **source kind**: *team + artifact* (deck, brief, manuscript, webinar, site post, board, repo doc, plan, prompt, skill, + ADR, README, commit message — anything the team wrote or committed) versus *agent inference* + (an inventory agent's own synthesis, invented rationale, or a question with no team source). + Checked against that standard, all 87 ideas carry a cited team-artifact source; none is bare + agent inference, so the agent-inference column is 0 throughout and nothing was left off a + section for lacking a team source. +3. A SIIM 2026 deck ("Structured Results and Context for Next-Generation Imaging Resulting + Tools") arrived and briefly got its own "Relationships and external citations" page under a + four-pillar structure. +4. **This version (2026-09-22): re-sectioned under the five named pillars from the "Agreed + outline" in `restructure-joint-notes.md`** — Introduction, Foundation Context, Data + Structures, SDKs, Use Cases, Sample Applications, Off the reading path — per the owner's + 2026-09-22 decision that pillars are named, never numbered, and that a CDE and a finding + model are the same content in two collections. The former "Relationships and external + citations" page is folded into Foundation Context's "Finding models and CDEs" table as the + common-graph cluster, since the relationship ideas are part of that same graph. Placement + flags resolved this pass: Sem-F1, F2, F6, Use-A12, Use-A15 (moved or confirmed, no longer + flagged). Use-A17, Use-A18, Use-B7 stay at their prior placement — one-line reasons in the + Summary. + +--- + +## Introduction + +| ID | Name | Source kind | Notes | +|---|---|---|---| +| Use-C1 | OIDM's stated purpose | team artifact | Site tagline, January 2026 deck title, project lead's 2026-09-19 formulation. | +| Use-C2 | The relationship among the parts: three layers, and the DOM analogy | team artifact | Deck's three strategic pillars; 2024 site post; the DOM/HTML analogy is stated independently on two boards. | +| Use-C3 | Structure first, standards after; and how agreement is supposed to happen | team artifact | Deck's call to action (working group, structure-first); Board 14's ACR Data Science Institute role. | +| Use-C4 | Nothing is formally defined yet | team artifact | Source is the project lead's 2026-09-21 decision of record in `knowledge/plans/2026-09-20-knowledgebase-build-plan.md` — a plan document, a team artifact. States the project's own coalescing-phase status. | + +4 ideas. + +--- + +## Foundation Context + +### Finding models and CDEs + +One table per the 2026-09-22 correction: a CDE and a finding model are the same content, in two +collections (the inclusive OIDM collection and the well-reviewed ACR/RSNA collection), sharing one +common graph. The **Cluster** column mirrors the outline's own grouping: the common graph +(including the relationship ideas formerly tabled separately as "Relationships and external +citations"); the two collections and their relationship; what the inclusive collection contains +and where it is going; authoring, triage, and review; identifiers and metadata rules. + +| ID | Name | Cluster | Source kind | Notes | +|---|---|---|---|---| +| Sem-F1 | Anatomic scope, not location | Common graph | team artifact | The next-generation vocabulary's statement of which anatomic locations are congruent with a finding class, and how strongly. Matches the SIIM deck slide 12's "Observation Type anatomy limits" cross-axis category almost verbatim. Prior "?" flag (versus Anatomic Locations) resolved: the common-graph cluster is the single home. | +| Sem-F4 | The finding model relationship registry | Common graph | team artifact | Draft schema in which a model stores only the relationship assertions authored on it, with a registry declaring each type inverse-backed, symmetric, or one-way; corrected by a later document that found it unimplemented. The general mechanism the deck's "within-axis relationships" list (parent/child, causes/caused_by, confused_with, occurs_with) would be instances of. | +| Sem-F5 | The relationship family and the derived differential | Common graph | team artifact | Seven relationship pairs plus a catch-all connecting finding classes and diagnoses, keeping manifestation and causation apart. The deck's worked figure (radiodense urinary calculus `OIFM_GMTS_020556` "may cause" hydronephrosis `OIFM_OIDM_874812`) is a causes/caused_by instance of this family. | +| Sem-F6 | Measurement, method, and interpretation are three things | Common graph | team artifact | Next-gen vocabulary design document. Prior "?" flag (versus staying at Open Imaging Finding Models, since the document itself notes the principle is already written in narrower form in the finding-model guidance) resolved: placed with the common graph alongside Sem-F4/F5, which it shares a document with. | +| Sem-A9 | Assessment schemes modeled apart from what they assess | Common graph | team artifact | `ASSESSED_BY`/`INTERPRETED_FROM` are cross-finding relationship types from the next-gen relationship-family document; matches the deck's "within-axis relationships" category (an edge between two Observation Type nodes). | +| Sem-A10 | Associated findings versus components | Common graph | team artifact | An associated-finding attribute references another finding model by name; a component is extracted into its own model. Matches `occurs_with` (independent co-occurring findings) and the part-of shape the deck's figure applies to anatomy (renal pelvis "part of" kidney), here applied to finding components. | +| Use-A15 | Foundation context: four per-finding dimensions that tell an agent what to expect | Common graph | team artifact | Webinar states this directly (body regions, entity type, expected time course, permanence). Prior "?" flag (versus staying at Imaging Problem List) resolved: this is graph content about what the finding-class definition carries, and overlaps substantially with Sem-C1's "eight fields" below, from the same webinar slides. | +| Sem-F7 | Finding models as the CDE workbench | Collections and their relationship | team artifact | January 2026 deck ("OIFM: the CDE workbench"); project lead's statement that CDE work "should dovetail with the OIFM work"; the "Current Understanding" document. | +| Sem-F8 | Measuring coverage by running real reports against the vocabulary | Collections and their relationship | team artifact | CDEStaging catalogues (`negative_statements.md`, `uncovered_findings.md`, `missing_attributes.md`) and the extraction-process note. | +| Sem-B2 | Corpus as a merge of uneven provenance streams | Content direction | team artifact | The identifier registry and the "Definition Cleanup Plan"; supplies the counts behind Sem-B7's stated direction. | +| Sem-B7 | Exam-oriented finding sub-taxonomies | Content direction | team artifact | The project lead's 2026-09-21 statement that this is "the immediate direction for all of the content," plus the taxonomy README. | +| Sem-B8 | Convert and merge, with a fixed direction | Content direction | team artifact | The chest CT content branch's project specification. | +| Sem-B9 | Content repository proposes changes upstream to the library | Content direction | team artifact | The upstream-proposals plan document. | +| Sem-B3 | Stub creation and iterative improvement | Authoring, triage, review | team artifact | The "OIFM Repo" board's pipeline flowchart and "Community Connect 2024-11-07" note; the `enrichment.md` prompt fragment. | +| Sem-B4 | Triage before create | Authoring, triage, review | team artifact | Prompt fragment (`search_and_triage.md`) and the `finding-author` skill. | +| Sem-B5 | Review in three tiers, with context isolation | Authoring, triage, review | team artifact | Prompt fragments and the `finding-review`/`finding-batch` skills. | +| Sem-B6 | Prompts as loadable fragments, sized against measured degradation | Authoring, triage, review | team artifact | The team's own prompt-length research write-up and the skill files' stated design rule. | +| Sem-C4 | Focused assignment agents, advisory audit, and null as an answer | Authoring, triage, review | team artifact | Architecture decision record (`0002-split-agent-assignment-architecture.md`) and agent prompts. | +| Sem-C5 | Human review is the only authority | Authoring, triage, review | team artifact | Policy document (`human-review-and-writeback.md`) and the plan-history document. | +| Sem-A1 | Finding model | Identifiers and metadata | team artifact | Prompt fragment (`core_concept.md`), the upstream overview document, the schema document, and the "OIFM Repo" Excalidraw board's plain-language explainer panel. | +| Sem-A2 | What counts as a finding | Identifiers and metadata | team artifact | Prompt fragments (`core_concept.md`), the overview document, and an Excalidraw board's earlier draft of the same rule. | +| Sem-A3 | Specificity, splitting, and the right level of abstraction | Identifiers and metadata | team artifact | Prompt fragment (`scope_and_specificity.md`) and the overview document. | +| Sem-A4 | Negative assertion as a first-class finding | Identifiers and metadata | team artifact | Prompt fragments, the creation script, and the next-gen-schema design document; distinct from Use-A11/Use-A23, which are about EFL/Observation-level negation. | +| Sem-A5 | Description and diagnosis both count | Identifiers and metadata | team artifact | Prompt fragment, the `entity_type.md` assignment prompt, and the next-gen-schema design document; distinct from Use-A9's cross-report matching angle on the same finding-vs-diagnosis question. | +| Sem-A6 | Presence and change from prior | Identifiers and metadata | team artifact | Prompt fragment (`presence_and_change.md`) and the creation script. | +| Sem-A7 | Synonyms as the matching surface | Identifiers and metadata | team artifact | Prompt fragments (`synonym_rules.md`, `naming.md`). | +| Sem-A8 | Naming conventions | Identifiers and metadata | team artifact | Prompt fragments and the "Definition Cleanup Plan". | +| Sem-B1 | Identifiers that carry provenance | Identifiers and metadata | team artifact | Metadata-fields reference document, the repository's `CLAUDE.md`, and an Excalidraw board's identifier-format notes. | +| Sem-C1 | Lean published models versus the full metadata schema | Identifiers and metadata | team artifact | Project lead's stated goal ("needs overhaul for increased metadata"); webinar's "Lean vs full" slides; the metadata rewrite document. Two of its eight fields (`applicable_modalities`, and `anatomic_locations` on the base model per Sem-A1) carry cross-axis edges per the deck, but the idea's own subject is the schema as a whole, not those two fields specifically — kept here rather than moved to the common-graph cluster. | +| Sem-C2 | Each metadata field is defined by what it excludes | Identifiers and metadata | team artifact | Policy document (`docs/metadata/subspecialties.md`) and assignment prompts. | +| Sem-C3 | Index codes must be exact | Identifiers and metadata | team artifact | Assignment prompt (`ontology_decision.md`) and the metadata rewrite document. | + +31 ideas. + +### Anatomic locations + +| ID | Name | Source kind | Notes | +|---|---|---|---| +| Sem-D1 | Spatial containment as a single-parent tree to the whole body | team artifact | JDIM manuscript Methods/Results; the project site's homepage states the same rule publicly; the "Current Understanding" document verifies it against the data. | +| Sem-D2 | Containment and part-of are different relations | team artifact | Manuscript and site "code" page; the field-reference skill document. | +| Sem-D3 | Laterality as explicit triads | team artifact | Manuscript Methods, with counts for all 795 bilateral structures; the laterality-conventions reference document. | +| Sem-D4 | Synthetic post-coordinated terms | team artifact | Manuscript Methods gives the counts; the laterality-conventions reference document gives the curation rule. | +| Sem-D5 | Measuring what existing ontologies actually populate | team artifact | Manuscript Methods and Results (the measurement itself, specified to be recomputable). | +| Sem-D6 | An overlay on RadLex, not a competitor | team artifact | The "Anatomy Axis, Current State" document records the 2026-09-13 agreement; the deck's "FMA enrichment" direction (defined but not yet populated: definitions, references, new edges `branch_of`/`bounded_by`/`adjacent_to`) extends this as stated direction — deck-sourced, no separate inventory idea states it. | +| Sem-D7 | The missing is-a and structure-type layer | team artifact | Next-gen-schema design document (`11-anatomy-axis.md`), which itself separates the project lead's scope families from "exploratory ideas from the assistant, not adopted" — a distinction the source document draws, not one this inventory added. | +| Sem-D8 | Curation rules that make the codes usable | team artifact | The field-reference skill document's "SNOMED Coding Guidance". | +| Sem-D9 | A reference layer, not a labeling algorithm | team artifact | Manuscript Discussion states the reference-layer framing directly. | +| Sem-F3 | Contributing terms back, and the two-phase proposal loop | team artifact | Ties directly to Sem-D6/Sem-D7 (the RadLex overlay and its gaps); the `radlex-concepts` skill and the RadLex testing document. | + +10 ideas. Tooling (the anatomic-locations package, BodyPartIndex libraries) moves to SDKs per the +outline; no inventory idea's primary subject is that tooling, so nothing moves out of this table. + +### Exam types + +| ID | Name | Source kind | Notes | +|---|---|---|---| +| Sem-E1 | Preferred high-level exam entries over the Playbook | team artifact | Project lead's stated goals, restated across four years in three documents (site roadmap, board, `med-ontology-lookup` product-roadmap document). | +| Sem-E2 | Exam-to-anatomy inclusion edges and the imaging region | team artifact | Project lead's stated goals; a 2024 board states the same requirement as "defining an imaging region"; the deck (slide 11) restates it as focused/included/edge (usually vs possible) anatomy — same author, two dated phrasings, both belong on this page per the outline. | + +2 ideas. + +### Standards the foundation layers over and cites + +| ID | Name | Source kind | Notes | +|---|---|---|---| +| Sem-F2 | Terminology roles, and search recall as the gate | team artifact | RadLex, SNOMED CT, and LOINC/the Playbook each play a stated role as the terminology OIDM's axes point out to (manuscript "Term selection"; "Hybrid FTS search" design document). Matches the deck's "external citations" category — the deck names SNOMED, RadLex, and LOINC among its own eight (Radiopaedia, Wikipedia, SNOMED, RadLex, LOINC, FMA, ICD, CPT); this idea covers three of those eight and the role each plays. No inventory idea covers Radiopaedia, Wikipedia, FMA, ICD, or CPT — the deck is the only source for those five. Prior "?" flag (cross-cutting Anatomic Locations/Exam Types/ACR-RSNA CDEs) resolved: this page is the single home. | + +1 idea. The lookup tool (`med-ontology-lookup`) moves to SDKs per the outline. + +Foundation Context total: 31 + 10 + 2 + 1 = **44 ideas.** + +--- + +## Data Structures + +The two graphs (Foundation Context and Patient Context) and how they work together are the center +of this pillar. + +### Observation + +| ID | Name | Source kind | Notes | +|---|---|---|---| +| Use-A1 | Observation as the atomic unit of an imaging result | team artifact | January 2026 deck's own definition of the unit; the repository's `CLAUDE.md`; a 2024 reference implementation. | +| Use-A10 | Presence is binary; confidence and hedging are a separate axis | team artifact | JDIM manuscript and SIIM webinar state the design directly; the extraction prompt's `PRESENCE_BLOCK` gives a contrary implemented example. | +| Use-A11 | Pertinent negatives are first-class entries | team artifact | Manuscript and webinar state the rule directly; the extraction prompt and coding prompts enforce it. | +| Use-A12 | Every finding carries a standardized anatomic location, assigned by explicit rules | team artifact | Repo assignment-rules document (`anatomic-location-assignment-rules.md`) and the coding pipeline prompts. Prior "?" flag resolved: stays here (what an Observation carries — "what plus where") with a cross-link to the Anatomic locations page under Foundation Context, which owns the index those rules resolve against. | +| Use-A23 | Normality is recorded as an absent abnormality | team artifact | Extraction prompt blocks (`CORE_INSTRUCTIONS_BLOCK`, `CHUNK_RULES_BLOCK`), the reviewer prompt, and a 2024 hand-extraction sample. | +| Use-A24 | Coding aims at convergence, so generalizing is allowed and specializing is not | team artifact | Coding prompts (`FINDING_TERM_SYSTEM`, `FINDING_CODE_SELECTOR_SYSTEM`) and the coding-agent design document. | +| Use-A25 | Finding type, anatomic site, and presence are independent axes | team artifact | Coding-prompt rules and the coding-agent design document. | + +7 ideas. + +### Exam Finding List + +| ID | Name | Source kind | Notes | +|---|---|---|---| +| Use-A2 | Two-level architecture: Exam Finding List, then Imaging Problem List | team artifact | JDIM manuscript states the two-level rationale directly; the repository README states the same division. | +| Use-A3 | The faithful-translation constraint on the Exam Finding List | team artifact | Manuscript, webinar, and JACR manuscript (which reports the team's own tool violating the rule); the extraction prompt enforces it three times. | +| Use-A9 | One finding may be described by several observations in one report, and by different codes across reports | team artifact | Project lead's 2026-09-19 email notes (points 1 and 2) state this directly; the extraction prompt's `DEDUPLICATION_BLOCK` is the working resolution. | +| Use-A17 | Report sections beyond Findings are unmodeled | team artifact | Board 6 poses the open question directly; the canonical section vocabulary (`report-sections.md`) is the implemented partial answer. **Stays** (see Summary): reads as an open question more than a settled idea, but it is team-sourced, so it stays on a section page rather than moving to the open-questions register. | +| Use-A26 | A named taxonomy of extraction failures, checked by an independent reviewer | team artifact | Reviewer prompt (`validator_prompt_example.md`) and the extraction-internals design document — the structure rule for how a chunk is checked against its source text. Sample Applications' description of the report extraction platform's failure taxonomy and evaluation practice cites this idea; it is not duplicated as a row there. | + +5 ideas. + +### Imaging Problem List + +| ID | Name | Source kind | Notes | +|---|---|---|---| +| Use-A4 | Entry identity is the finding code plus the anatomic site | team artifact | JDIM manuscript states this directly; the repository's `CLAUDE.md` and generation script confirm it. | +| Use-A5 | Status is derived from the observation history, never stored — and three vocabularies disagree | team artifact | Manuscript, webinar, and the repository's `CLAUDE.md`/viewer-v2 plan each state their own vocabulary. | +| Use-A6 | The succession link | team artifact | Manuscript's worked example (pneumonia and its scarring); webinar restates it. | +| Use-A7 | Per-observation provenance and review status, and corrections as provenance operations | team artifact | Manuscript and webinar state the design directly; the extraction platform's `README.md` implements provenance for the extraction pipeline. | +| Use-A8 | Entity resolution is the open problem; graduated-confidence linking is the proposal | team artifact | Manuscript states the three confidence levels directly; webinar names entity resolution as "the open frontier"; JACR manuscript reports the measured limitation. | +| Use-A13 | Anatomic-compatibility reconciliation is unresolved, and the sample data shows the cost | team artifact | Repo design document (`anatomic-location-assignment-rules.md` known-limitation section) naming the gap. | +| Use-A14 | Permanent findings, and the need to rank entries before display | team artifact | JACR manuscript Methods and measured results. | +| Use-A18 | Recommendation structure, and a live-versus-closed axis on IPL entries | team artifact | Manuscript and Board 12. **Stays** (see Summary): the manuscript attaches the recommendation to the IPL entry structurally, even though the "ACR priorities" bucket under Use Cases also touches recommendation tracking. | +| Use-A19 | A finding as a persistent tracked entity with a durable identifier | team artifact | Boards 4 and 15, a 2024 site post, and the manuscript; an unmerged branch's design note. | +| Use-A22 | The re-documentation burden: measured evidence for the Imaging Problem List | team artifact | JACR manuscript results, the core quantitative case for the IPL. | + +10 ideas. (Use-A15, "foundation context: four per-finding dimensions," moved to Foundation +Context's Finding models and CDEs table — see that table's notes.) + +### Imaging Persona + +| ID | Name | Source kind | Notes | +|---|---|---|---| +| Use-A16 | Imaging Persona and the reporting data context object model | team artifact | January 2026 deck names it directly; two boards give a fuller object model; a 2024 site post; the deck's Global Imaging Persona figure (patient history, vitals, meds, current profile, genetic profile, previous scans around the IPL). The structure half stays here; the use half (the reporting context object model, alongside Use-B8's plugin container) is cited under Use Cases, not duplicated as a row there. | + +1 idea. + +### Structures versus transport + +| ID | Name | Source kind | Notes | +|---|---|---|---| +| Use-A21 | Application-layer data structures, distinct from transport expressions | team artifact | Project lead's 2026-09-19 email notes state this directly; the JDIM manuscript's Methods and Discussion state the same independence; FHIR mapping is documented and unimplemented; the interoperability demonstration (Use-B9, at Sample Applications) is linked here as an example of what would need to travel. | + +1 idea. + +Data Structures total: 7 + 5 + 10 + 1 + 1 = **24 ideas.** + +--- + +## SDKs + +| ID | Name | Source kind | Notes | +|---|---|---|---| +| Sem-C6 | Documents record judgment; the schema is the specification | team artifact | Architecture decision record (`0001-lean-metadata-docs-schema-is-spec.md`). The finding model SDK's documentation practice: what is authoritative (the code/schema) versus what is policy (the docs). | +| Sem-C7 | Two databases from one source commit | team artifact | Architecture decision record (`0003-dual-db-pre-post-metadata-release.md`). The finding model SDK's release strategy: what a developer gets, pre- and post-metadata release. | +| Sem-C8 | Three retrieval modes over the corpus | team artifact | Matches "resolve, don't reinvent": the finding model SDK's format, index, search, enrichment, MCP server. Source: the metadata rewrite document and the package code (`index.py`, `similar.py`, `mcp_server.py`). | +| Use-A20 | A formal system of data models with generated schemas | team artifact | The outline names this directly as the proposed Imaging Problem List SDK: issue #1 (opened by the project lead) and the dev-branch platform as its precursor. | + +4 ideas. Use-B3 (coding decoupled from extraction) moved out to Sample Applications this pass — see +that table's notes; the outline treats it as part of what the report extraction platform +demonstrates, not as SDK content on its own. + +--- + +## Use Cases + +| ID | Name | Source kind | Notes | +|---|---|---|---| +| Use-B5 | Six downstream application families for the Imaging Problem List | team artifact | Manuscript, webinar, and deck all state the families: report pre-population, incidental-finding surveillance, chronic-disease monitoring, cross-subspecialty awareness, quality surveillance and research cohorts, and the breast case. | +| Use-B6 | Breast imaging: one entity across assessments, and an automated MQSA audit | team artifact | Webinar states this as "planned work, not results" by its own account. | +| Use-B7 | Outcome tracking, follow-up completion, and radiology-pathology correlation | team artifact | Boards 12 and 7, and a published external quality-measure citation. **Stays** (see Summary): grouped here as a use case rather than at Foundation Context or Data Structures, since it is a proposed application built on the record, not part of either graph's own definition. | +| Use-B8 | The reporting assistance framework: a context object model plus a plugin container | team artifact | Deck names it "Open Imaging Reporting SDK"; 2023 site post and Board 9 give the design; `CDETemplateDemo` is a working precedent. Grouped with the use half of Use-A16 (Imaging Persona's reporting data context object model), which is not duplicated as a row here. | +| Use-B11 | The use case catalog and the six value categories | team artifact | `UseCases` repo and Board 13; the six RSNA Reporting Informatics Committee value categories (reporting efficiency, care team communication, operations/quality/safety, research, public health, education). | + +5 ideas. Use-B9 (the multi-vendor interoperability demonstration) is a use case in purpose but was +built and shown, so its ID row sits at Sample Applications per the outline; its aim (what the +demonstration was for) is cited here without a duplicate row. ACR priorities (recommendation +tracking, AI validation, quality metrics, RADS support) and the deck's determinative-tools / +generative-agents consumer families are context for this whole table, not separate IDs. + +--- + +## Sample Applications + +| ID | Name | Source kind | Notes | +|---|---|---|---| +| Use-B1 | The Imaging Problem List viewer, and anatomy as presentation only | team artifact | The two viewers (IPL viewer 1; IPL viewer 2 with anatomy) named directly by the outline; the deck names the live demo; the design substance comes from the viewer-v2 plan document. | +| Use-B2 | The report extraction, coding, persistence and review platform | team artifact | The repository's `README.md`/`CLAUDE.md`, and the webinar's own framing of the platform as "one implementation of many." | +| Use-B3 | Coding is an independent job, decoupled from extraction | team artifact | Moved here from SDKs this pass. Design rationale document (`docs/coding-agent-design.md`); part of what the report extraction platform demonstrates about its own architecture, per the outline. | +| Use-B4 | Honesty-first evaluation of extraction | team artifact | Evaluation-redesign plan document (`extractor-evals-redesign.md`) and the reviewer-workflow documents — the platform's evaluation practice. Use-A26 (Exam Finding List) is the extraction failure taxonomy this evaluation practice checks against; cited here, not duplicated as a row. | +| Use-B9 | A multi-vendor interoperability demonstration exchanging CDE-labeled FHIR Observations | team artifact | Moved here from Use Cases this pass, as built and shown: Boards 15, 14, and 1. Its purpose is cited under Use Cases without a duplicate row. | +| Use-B10 | Local-only operation for protected health information | team artifact | Implementation and archived hardening documents; a status/deployment detail of the report extraction platform; the JACR manuscript's Methods state the same operating constraint. | + +6 ideas. + +--- + +## Off the reading path + +Empty. Every one of the 87 catalogued ideas carries a team-artifact source and has been placed +under a section above. No agent-inference-only idea was found among the 87 — that material lives +in the inventories' own "Undetermined" and "What could not be determined" sections, which this +table does not place as separate ideas. + +--- + +## Summary + +| Section | Ideas | +|---|---| +| Introduction | 4 | +| Foundation Context — Finding models and CDEs | 31 | +| Foundation Context — Anatomic locations | 10 | +| Foundation Context — Exam types | 2 | +| Foundation Context — Standards the foundation layers over and cites | 1 | +| **Foundation Context total** | **44** | +| Data Structures — Observation | 7 | +| Data Structures — Exam Finding List | 5 | +| Data Structures — Imaging Problem List | 10 | +| Data Structures — Imaging Persona | 1 | +| Data Structures — Structures versus transport | 1 | +| **Data Structures total** | **24** | +| SDKs | 4 | +| Use Cases | 5 | +| Sample Applications | 6 | +| Off the reading path | 0 | +| **Total** | **87** | + +Every idea carries a team-artifact source (agent-inference count is 0 throughout, unchanged from +the prior pass). + +**Remaining "?" flags, marked stays:** +- **Use-A17** (report sections beyond Findings are unmodeled) — stays at Exam Finding List. It + reads as an open question (Board 6) more than a settled idea, but it is team-sourced, so it + belongs on a section page rather than the open-questions register. +- **Use-A18** (recommendation structure, live-versus-closed axis) — stays at Imaging Problem + List. The manuscript attaches the recommendation to the IPL entry structurally; Use Cases' + "ACR priorities" bucket touches recommendation tracking too, but the structural claim's one + home is the data structure it modifies. +- **Use-B7** (outcome tracking, follow-up completion, radiology-pathology correlation) — stays + at Use Cases. It is a proposed application built on the record (Boards 12 and 7), not part of + either graph's own definition, so it belongs with the other use cases rather than at + Foundation Context or Data Structures. + +Flags resolved this pass (no longer marked "?"): Sem-F1, Sem-F2, Sem-F6 (all placed in Foundation +Context's Finding models and CDEs table, common-graph cluster, or the standards table for F2); +Use-A12 (stays at Observation with a cross-link note to Anatomic locations); Use-A15 (moved to +Foundation Context's Finding models and CDEs table, common-graph cluster). diff --git a/docs/plans/lean-content-coverage.tsv b/docs/plans/lean-content-coverage.tsv new file mode 100644 index 0000000..a99448e --- /dev/null +++ b/docs/plans/lean-content-coverage.tsv @@ -0,0 +1,134 @@ +path pass disposition before_body_words after_body_words reason +knowledge/applications/finding-and-location-coding.md 1 edited 1495 1150 Shortened and cross-reviewed in the first pass; examples, citations, and qualifications preserved. +knowledge/applications/finding-model-forge.md 1 edited 1450 1044 Shortened and cross-reviewed in the first pass; examples, citations, and qualifications preserved. +knowledge/applications/finding-models-site.md 1 edited 618 379 Shortened and cross-reviewed in the first pass; examples, citations, and qualifications preserved. +knowledge/applications/imaging-problem-list-viewer.md 1 edited 1240 899 Shortened and cross-reviewed in the first pass; examples, citations, and qualifications preserved. +knowledge/applications/index.md 1,2 edited Descriptions shortened in the first pass; reviewed again and still match their concepts. +knowledge/applications/ipl-mvp-extraction.md 1 edited 1048 840 Shortened and cross-reviewed in the first pass; examples, citations, and qualifications preserved. +knowledge/applications/report-extraction-platform.md 1 edited 1948 1426 Shortened and cross-reviewed in the first pass; examples, citations, and qualifications preserved. +knowledge/applications/reporting-sdk.md 1 edited 886 582 Shortened and cross-reviewed in the first pass; examples, citations, and qualifications preserved. +knowledge/data-structures/anatomic-location-assignment-rules.md 2 edited 1128 1105 Tightened description and migration introduction only; source guidance and structure unchanged. +knowledge/data-structures/exam-finding-list.md 1 edited 1275 991 Shortened and cross-reviewed in the first pass; examples, citations, and qualifications preserved. +knowledge/data-structures/fhir-mapping.md 2 edited 1217 1033 Tightened authored prose and description; preserved facts, qualifications, citations, tables, examples, links, and headings. +knowledge/data-structures/hierarchy.md 1 edited 999 880 Shortened and cross-reviewed in the first pass; examples, citations, and qualifications preserved. +knowledge/data-structures/ihe-idr-alignment.md 2 edited 1105 988 Tightened authored prose and description; preserved facts, qualifications, citations, tables, examples, links, and headings. +knowledge/data-structures/imaging-persona.md 1 edited 693 456 Shortened and cross-reviewed in the first pass; examples, citations, and qualifications preserved. +knowledge/data-structures/imaging-problem-list.md 1 edited 1391 1122 Shortened and cross-reviewed in the first pass; examples, citations, and qualifications preserved. +knowledge/data-structures/index.md 2 edited Reviewed navigation, synchronized descriptions, and simplified introductory prose or directory labels. +knowledge/data-structures/observation.md 1 edited 1308 1062 Shortened and cross-reviewed in the first pass; examples, citations, and qualifications preserved. +knowledge/data-structures/sample-data.md 2 edited 992 885 Tightened authored prose and description; preserved facts, qualifications, citations, tables, examples, links, and headings. +knowledge/data-structures/technical-imaging-findings.md 2 edited 1203 1185 Tightened description and migration introduction only; source guidance and structure unchanged. +knowledge/glossary/anatomic-location.md 2 edited 340 337 Removed rhetorical setup around source quotations and shortened lineage comparison. +knowledge/glossary/anatomic-scope.md 2 edited 324 307 Shortened scope-family relationship and missing-field limitation without changing open status. +knowledge/glossary/assessment-scheme.md 2 edited 297 278 Removed repeated separation framing; retained assessment distinctions and source quotations. +knowledge/glossary/attribute-value.md 2 edited 258 243 Shortened positional-code explanation and repetitive presence cross-reference. +knowledge/glossary/attribute.md 2 edited 310 292 Tightened attribute-kind introduction and unresolved naming discussion. Tightened its description and matching index entry. +knowledge/glossary/body-region.md 2 edited 371 355 Shortened three-use explanation and removed rhetorical fallback introduction. Tightened its description and matching index entry. +knowledge/glossary/cde-element.md 2 edited 290 270 Condensed property definition and clarified component/set/value relationship. +knowledge/glossary/cde-labeled-fhir-observation.md 2 edited 310 296 Removed emphatic sample framing and shortened source attribution and open conflict wording. +knowledge/glossary/cde-set.md 2 edited 308 301 Replaced false range with named examples and shortened parent-code explanation. +knowledge/glossary/cde.md 2 edited 298 269 Removed confusion framing and shortened staging and site-post introductions. +knowledge/glossary/change-from-prior.md 2 edited 340 282 Removed repeated snapshot and attribute framing; shortened missing-attribute caveat while retaining all 124-model and value-set details. +knowledge/glossary/coding.md 2 edited 367 337 Split dense pipeline prose into sequential operations and removed judgment framing around location rules. +knowledge/glossary/contained-by-and-part-of.md 2 edited 314 304 Removed rhetorical introduction and shortened organ-system and precomputation explanations. +knowledge/glossary/contributor.md 2 edited 295 283 Simplified registry validation and JSONL support explanation. +knowledge/glossary/data-element.md 2 edited 349 318 Shortened sharing, draft-status, and terminology-conflict explanations. +knowledge/glossary/element-binding.md 2 edited 284 260 Removed unsupported safe-reuse rhetoric and hanging-property metaphor; preserved technical statements for separate factual review. Corrected the modality quotation’s subject against pinned CONTEXT.md: it describes the descriptor’s intrinsic limit. +knowledge/glossary/exam-finding-list.md 2 edited 335 323 Removed rhetorical requirements framing while preserving repeated-observation rule and provenance requirement. +knowledge/glossary/exam-type.md 2 edited 346 317 Shortened definition, scope explanation, proposal status, and missing-artifact inventory. Tightened its description and matching index entry. +knowledge/glossary/extraction.md 2 edited 383 308 Split schema and pipeline descriptions and shortened validator failure list while retaining each failure category. +knowledge/glossary/fhir-condition.md 2 edited 306 279 Shortened mapping and unimplemented-status explanations; retained IDR disagreement and all quotations. +knowledge/glossary/fhir-diagnostic-report.md 2 edited 303 280 Removed sample framing and shortened implementation-gap description. +knowledge/glossary/finding-class.md 2 edited 357 336 Removed blurred-node metaphor and shortened working-group decision and unsettled IDR difference. +knowledge/glossary/finding-model.md 2 edited 311 281 Removed extrapolation from the 2024 definition to the entire project lifetime and shortened definition-versus-instance explanation. +knowledge/glossary/finding-taxonomy.md 2 edited 366 354 Clarified name-key and parent fields and shortened taxonomy/model distinction. Tightened its description and matching index entry. +knowledge/glossary/fma.md 2 edited 231 213 Shortened cross-reference and classification introduction while retaining coverage counts and mappings. +knowledge/glossary/gamuts.md 2 edited 287 273 Removed role framing and content-spine metaphor; shortened unresolved cleanup status. +knowledge/glossary/imaging-diagnostic-report.md 2 edited 390 367 Shortened source framing and alignment-status explanation without changing IDR definitions or conflicts. +knowledge/glossary/imaging-persona.md 2 edited 241 203 Removed repeated unimplemented-status and knowledgebase self-description. +knowledge/glossary/imaging-problem-list.md 2 edited 390 332 Removed signature-structure rhetoric and shortened query, grouping, and reconciliation explanations. +knowledge/glossary/index-code.md 2 edited 322 316 Simplified field and crosswalk explanations and removed in-flight framing around the identified rewrite. +knowledge/glossary/index.md 2 edited Read all 48 entries; shortened the introduction and synchronized seven tightened descriptions while preserving alphabetical links. +knowledge/glossary/laterality.md 2 edited 395 373 Removed repeated test introduction and shortened reversible-mapping requirement. Tightened its description and matching index entry. +knowledge/glossary/loinc-rsna-radiology-playbook.md 2 edited 307 292 Split roadmap proposal into concise sentences and removed historical throat-clearing. +knowledge/glossary/loinc.md 2 unchanged 287 287 Already compact: quoted specification requirements, code examples, identifier detection, and missing-curated-list caveat each provide distinct information. +knowledge/glossary/measurement.md 2 edited 290 234 Shortened node-type explanation, grouped-measurement example, and repeated model distinction. +knowledge/glossary/observation.md 2 edited 343 330 Replaced atomic-unit metaphor and removed lineage and terminology-collision framing. +knowledge/glossary/oidm-organization-code.md 2 unchanged 245 245 Already concise: generator behavior, registry mappings, all seven codes, five corpus counts, and namespace/provenance distinction are needed. +knowledge/glossary/oidm.md 2 edited 269 236 Shortened project definition and organization-code explanation; replaced inaccurate self-description about old-name placement with history link. +knowledge/glossary/oifm.md 2 edited 247 226 Shortened canonical-format and overloaded-acronym explanation without changing fields or identifier rules. +knowledge/glossary/open-imaging-reporting-sdk.md 2 edited 261 220 Removed centerpiece rhetoric, historical introduction, and repeated knowledgebase status assurances. +knowledge/glossary/presence.md 2 edited 405 375 Removed negative-data rhetoric and repeated conflict introduction while retaining quoted absence meaning and all positional-code exceptions. Tightened its description and matching index entry. +knowledge/glossary/provenance.md 2 edited 323 291 Removed repeated provenance rationale and shortened quote-evidence mechanism while preserving source and evaluation distinctions. Tightened its description and matching index entry. +knowledge/glossary/radelement.md 2 edited 273 264 Removed authoring-order framing and distinguished documented URI forms from the proposed successor. +knowledge/glossary/radlex-id.md 2 unchanged 258 258 Already concise: RID field mappings, composite-ID exception, examples, and unrecorded ontology-version risk all add distinct information. +knowledge/glossary/radlex.md 2 edited 277 265 Removed repetitive two-direction framing around curation and upstream integration. +knowledge/glossary/snomed-ct.md 2 edited 271 232 Split long usage sentence into source-specific statements and shortened licence/credential requirement. +knowledge/glossary/tag.md 2 edited 278 263 Shortened mixed-tag example framing and retained incomplete migration status. +knowledge/glossary/technical-finding.md 2 edited 342 317 Removed emphasis around coding distinction and shortened draft/open-question language. +knowledge/glossary/umls.md 2 edited 290 240 Removed two-job framing and shortened typed-failure explanation while retaining all error categories and mapping qualifications. +knowledge/guides/authoring-guide.md 2 edited 1212 1084 Tightened instructions and metadata guidance; retained rules, examples, and type vocabulary. +knowledge/guides/index.md 2 unchanged Two concise directory entries; both descriptions match their pages. +knowledge/guides/migration-ledger.md 2 edited 3048 3027 Shortened the introduction; preserved all migration rows as provenance records. +knowledge/history/cde-template-rendering.md 2 edited 774 555 Removed filler and simplified authored explanation while preserving technical detail. +knowledge/history/extraction-approaches.md 2 edited 1557 1312 Removed filler and simplified authored explanation while preserving technical detail. +knowledge/history/index.md 2 edited Simplified navigation introduction and synchronized concept descriptions. +knowledge/history/lineage-repositories.md 2 edited 1601 1359 Removed filler and simplified authored explanation while preserving technical detail. +knowledge/history/site-articles.md 2 edited 1399 1304 Tightened article summaries and authored framing; preserved all fifteen linked titles, dates, direct quotes, reported outcomes, and About-page scope. +knowledge/history/timeline.md 2 edited 1619 1607 Tightened the prologue and description; preserved every dated event table and source. +knowledge/history/use-cases.md 2 edited 1153 1062 Tightened authored framing; preserved every sourced use-case entry, attribution, category number, and table verbatim. +knowledge/index.md 2 edited Shortened draft-status and navigation instructions without losing entry points. +knowledge/log.md 2 edited Retained historical entries; added the full-review completion entry. +knowledge/overview/architecture.md 1 edited 1480 1247 Shortened and cross-reviewed in the first pass; examples, citations, and qualifications preserved. +knowledge/overview/getting-involved.md 1 edited 1027 776 Shortened and cross-reviewed in the first pass; examples, citations, and qualifications preserved. +knowledge/overview/index.md 2 unchanged Four descriptive navigation entries; no repeated framing or editorial commentary. +knowledge/overview/vision.md 1 edited 1173 860 Shortened and cross-reviewed in the first pass; examples, citations, and qualifications preserved. +knowledge/overview/what-is-oidm.md 1 edited 851 575 Shortened and cross-reviewed in the first pass; examples, citations, and qualifications preserved. +knowledge/plans/2026-09-20-knowledgebase-build-plan.md 2 edited 3890 3851 Tightened plan framing; preserved decisions, quoted goals, source map, phases, and concurrent decisions. +knowledge/plans/index.md 2 unchanged A single navigation entry matching the build plan description. +knowledge/references/anatomic-location-json-schema.md 2 edited 1695 1519 Shortened lineage and runtime explanations; preserved field tables, codes, counts, and example JSON. +knowledge/references/cde-schema-differences.md 2 edited 848 742 Tightened provenance and later-schema commentary; retained the attributed 2023 extract byte-for-byte. +knowledge/references/exam-finding-list-example.md 2 edited 1117 898 Shortened the walkthrough and synthetic-data introduction; preserved the JSON, fields, and absence distinction. +knowledge/references/finding-model-schema.md 2 edited 2027 1896 Shortened authored provenance and reconciliation framing; retained the migrated schema and constraint tables. +knowledge/references/imaging-problem-list-example.md 2 edited 1201 1024 Tightened grouping and status explanations; retained JSON, temporal rules, and synthetic-data qualifications. +knowledge/references/index.md 2 edited Shortened navigation descriptions and synchronized all eight entries. +knowledge/references/oifm-metadata-fields-extract.md 2 edited 2429 2375 Shortened provenance and release-status framing; preserved the complete attributed field reference. +knowledge/references/oifm-overview-extract.md 2 edited 2040 1967 Shortened provenance and glossary introduction; preserved the complete attributed authoring prompt. +knowledge/references/status-update-2026-01.md 2 edited 835 778 Shortened introductory framing; preserved the complete slide extract. +knowledge/repositories/index.md 2 edited Simplified navigation introduction and synchronized concept descriptions. +knowledge/repositories/repository-map.md 2 edited 1855 1768 Tightened map guidance and branch summaries; preserved the full repository table, diagram, caption, identifiers, dates, and status distinctions. +knowledge/roadmap/anatomic-locations-and-radlex.md 2 edited 1240 982 Removed filler and simplified authored explanation while preserving technical detail. +knowledge/roadmap/exam-types.md 2 edited 947 784 Removed filler and simplified authored explanation while preserving technical detail. +knowledge/roadmap/finding-model-content-direction.md 2 edited 1439 1245 Removed filler and simplified authored explanation while preserving technical detail. +knowledge/roadmap/finding-model-format-evolution.md 2 edited 1572 1390 Removed filler and simplified authored explanation while preserving technical detail. +knowledge/roadmap/index.md 2 edited Simplified navigation introduction and synchronized concept descriptions. +knowledge/roadmap/ipl-data-model-system.md 2 edited 1183 952 Removed filler and simplified authored explanation while preserving technical detail. +knowledge/roadmap/open-questions.md 2 edited 5585 5499 Tightened only introductions; retained all 90 numbered questions and all 21 defect rows verbatim, including their uncertainty, attribution, and ownership. +knowledge/roadmap/roadmap-2026.md 2 edited 992 833 Removed filler and simplified authored explanation while preserving technical detail. +knowledge/semantic-foundation/anatomic-locations/data-model.md 2 edited 1261 1159 Tightened authored prose and description; preserved facts, qualifications, citations, tables, examples, links, and headings. +knowledge/semantic-foundation/anatomic-locations/index.md 2 edited Reviewed navigation, synchronized descriptions, and simplified introductory prose or directory labels. +knowledge/semantic-foundation/anatomic-locations/laterality-conventions.md 2 edited 968 878 Tightened authored prose and description; preserved facts, qualifications, citations, tables, examples, links, and headings. +knowledge/semantic-foundation/anatomic-locations/lineage-and-current-implementation.md 2 edited 1024 874 Tightened authored prose and description; preserved facts, qualifications, citations, tables, examples, links, and headings. +knowledge/semantic-foundation/anatomic-locations/radlex-integration.md 2 edited 1187 948 Tightened authored prose and description; preserved facts, qualifications, citations, tables, examples, links, and headings. +knowledge/semantic-foundation/anatomic-locations/tooling.md 2 edited 953 868 Tightened authored prose and description; preserved facts, qualifications, citations, tables, examples, links, and headings. +knowledge/semantic-foundation/anatomic-locations/why-anatomic-locations.md 2 edited 768 580 Tightened authored prose and description; preserved facts, qualifications, citations, tables, examples, links, and headings. +knowledge/semantic-foundation/common-data-elements/cde-staging.md 2 edited 1536 1319 Tightened authored prose and description; preserved facts, qualifications, citations, tables, examples, links, and headings. +knowledge/semantic-foundation/common-data-elements/cdes-and-radelement.md 2 edited 1368 1255 Tightened authored prose and description; preserved facts, qualifications, citations, tables, examples, links, and headings. +knowledge/semantic-foundation/common-data-elements/index.md 2 edited Reviewed navigation, synchronized descriptions, and simplified introductory prose or directory labels. +knowledge/semantic-foundation/common-data-elements/next-generation-vocabulary.md 2 edited 2073 1706 Tightened authored prose and description; preserved facts, qualifications, citations, tables, examples, links, and headings. +knowledge/semantic-foundation/exam-types/existing-building-blocks.md 2 edited 1619 1399 Tightened authored prose and description; preserved facts, qualifications, citations, tables, examples, links, and headings. +knowledge/semantic-foundation/exam-types/index.md 2 edited Reviewed navigation, synchronized descriptions, and simplified introductory prose or directory labels. +knowledge/semantic-foundation/exam-types/overview.md 2 edited 1164 995 Tightened authored prose and description; preserved facts, qualifications, citations, tables, examples, links, and headings. +knowledge/semantic-foundation/finding-models/authoring-workflow.md 2 edited 1130 993 Tightened authored prose and description; preserved facts, qualifications, citations, tables, examples, links, and headings. +knowledge/semantic-foundation/finding-models/content-catalog.md 2 edited 1126 1022 Tightened authored prose and description; preserved facts, qualifications, citations, tables, examples, links, and headings. +knowledge/semantic-foundation/finding-models/enrichment-pipeline.md 2 edited 1318 1137 Tightened authored prose and description; preserved facts, qualifications, citations, tables, examples, links, and headings. +knowledge/semantic-foundation/finding-models/finding-model-format.md 2 edited 1439 1285 Tightened authored prose and description; preserved facts, qualifications, citations, tables, examples, links, and headings. +knowledge/semantic-foundation/finding-models/finding-models-and-cdes.md 1 edited 1280 773 Shortened and cross-reviewed in the first pass; examples, citations, and qualifications preserved. +knowledge/semantic-foundation/finding-models/finding-taxonomies.md 2 edited 875 726 Tightened authored prose and description; preserved facts, qualifications, citations, tables, examples, links, and headings. +knowledge/semantic-foundation/finding-models/identifiers.md 2 edited 1024 817 Tightened authored prose and description; preserved facts, qualifications, citations, tables, examples, links, and headings. +knowledge/semantic-foundation/finding-models/index.md 2 edited Reviewed navigation, synchronized descriptions, and simplified introductory prose or directory labels. +knowledge/semantic-foundation/finding-models/why-finding-models.md 1 edited 1024 670 Shortened and cross-reviewed in the first pass; examples, citations, and qualifications preserved. +knowledge/semantic-foundation/index.md 2 edited Reviewed navigation, synchronized descriptions, and simplified introductory prose or directory labels. +knowledge/semantic-foundation/terminologies/index.md 2 edited Reviewed navigation, synchronized descriptions, and simplified introductory prose or directory labels. +knowledge/semantic-foundation/terminologies/med-ontology-lookup.md 2 edited 1160 978 Tightened authored prose and description; preserved facts, qualifications, citations, tables, examples, links, and headings. +knowledge/semantic-foundation/terminologies/ontologies-used.md 2 edited 1590 1402 Tightened authored prose and description; preserved facts, qualifications, citations, tables, examples, links, and headings. diff --git a/docs/plans/lean-content-full-review.md b/docs/plans/lean-content-full-review.md new file mode 100644 index 0000000..c46d0ae --- /dev/null +++ b/docs/plans/lean-content-full-review.md @@ -0,0 +1,57 @@ +# Full content review + +Status: Complete (2026-09-21) + +## Aim + +Review every knowledge page omitted from the first 18-page editorial pass. Apply pstack `unslop` and `technical-writing`; preserve factual meaning, source attribution, examples, and verification history. A page left unchanged must have a recorded reason. + +## Steps + +- [x] Write the plan before editing. +- [x] Inventory the current bundle and save a baseline, including concurrent work. +- [x] Assign all remaining concepts and directory indexes to editors with distinct ownership. +- [x] Tighten authored prose; review only framing around verbatim or migrated source material. +- [x] Cross-review edits for lost meaning and record dispositions for unchanged pages. +- [x] Update affected indexes, generation metadata, bundle log, changelog, and development log. +- [x] Validate the complete bundle, review coverage, and mark this plan complete. + +The first pass covered 18 concepts. This pass covers the rest plus directory indexes. Logs remain historical records; review their current navigation or framing without rewriting old entries. Preserve concurrent edits and do not commit or publish. + +## Coverage + +The baseline is `/tmp/oidm-lean-full-baseline-20260921/`. Its `assignments.json` lists every file assigned for this pass. + +| Owner | Scope | Concepts | Other files | +|---|---|---:|---:| +| Glossary agent | Glossary | 48 | 1 index | +| Semantic foundation agent | Remaining semantic foundation and data structures | 24 | 7 indexes | +| Roadmap and history agent | Roadmaps, history, repository map | 14 | 3 indexes | +| Main agent | Guides, references, build plan, remaining indexes, bundle log | 11 | 6 indexes and 1 log | + +Each editor reads every assigned page and writes a per-page disposition. Extracts keep their attributed source text; edits target authored framing and commentary. Source records, examples, headings, and citations are checked against the baseline. + +## Results + +All 115 concepts and 17 indexes have been reviewed across both passes. This pass edited 94 of the remaining 97 concepts. The three unchanged concepts—LOINC, RadLex identifiers, and OIDM organization codes—already contain concise technical definitions and identifier references. The historical bundle log was reviewed and received a completion entry. + +[Per-page coverage](lean-content-coverage.tsv) records all 133 Markdown files, their dispositions, reasons, and concept word counts. The [first-pass report](lean-content-pass.md) records the skill source and its revision. + +| Scope | Concepts | Body words before | Body words after | +|---|---:|---:|---:| +| First pass | 18 | 21,186 | 15,732 | +| Glossary | 48 | 14,984 | 13,862 | +| Remaining semantic foundation and data structures | 24 | 29,228 | 25,537 | +| Roadmaps, history, and repository map | 14 | 22,916 | 20,652 | +| Guides, references, and build plan | 11 | 20,342 | 19,161 | +| Total | 115 | 108,656 | 94,944 | + +Across both passes, concept bodies are 13,712 words shorter (12.6%). Counts split text after frontmatter on whitespace, including headings, tables, code, and footnotes. Each concept uses the baseline from its assigned pass. The build plan's comparison also includes concurrent additions; this is a snapshot of the reviewed content, not an attribution of every changed word. + +## Review and checks + +Three agents edited separate groups and cross-reviewed the main editor's concepts, glossary, and semantic/data-structure concepts. The main editor reviewed roadmap/history changes and integrated corrections. Cross-review restored ranking order, scalar-only constraints, optionality, defaults, plan attribution, and several code and terminology distinctions lost during shortening. The element-binding modality quotation was checked against `ACR-RSNA-CDEs` commit `44836c1` and reattached to the descriptor's intrinsic limit. + +Original headings, fenced examples, citation labels, source records, and trust fields were retained. Attributed source extracts and migrated rule bodies remain intact; the 90 open-question rows and 21 defect rows are unchanged. Directory descriptions match their concepts. Historical log entries were retained. + +Both checks pass: strict OKF 0.2 conformance and `tools/check_bundle.py` (133 documents, 115 concepts, zero errors or warnings). `git diff --check` passes. This was an editorial review; human verification and unresolved source differences remain visible in the bundle. Concurrent tooling, hosting, and planning changes were preserved. No commits or publication were performed by this session. diff --git a/docs/plans/lean-content-pass.md b/docs/plans/lean-content-pass.md new file mode 100644 index 0000000..684d46e --- /dev/null +++ b/docs/plans/lean-content-pass.md @@ -0,0 +1,58 @@ +# Lean content pass + +Status: Complete (2026-09-21) + +## Aim + +Apply poteto's no-slop skill from pstack to a first batch of reader-facing OIDM content. Cut repetition, filler, and editorial commentary while preserving technical claims, qualifications, examples, citations, and draft status. + +## Steps + +- [x] Record the plan before editing content. +- [x] Locate and read the requested skill; record its source and revision. +- [x] Select a bounded batch and capture the current files for comparison. +- [x] Assign separate groups of pages to sub-agents; edit another group locally. +- [x] Review all changes for concision, meaning, citation coverage, and preserved diagrams. +- [x] Update metadata, indexes where needed, bundle log, changelog, and development log. +- [x] Run both validators, inspect the diff, and record results and completed scope here. + +Keep verbatim reference extracts and quoted source text intact. Do not expand into source integration, factual model changes, site tooling changes, publishing, or commits. + +## Skill and scope + +The upstream skill is now named `unslop`. Loaded it and `technical-writing` from [poteto's pstack](https://github.com/cursor/plugins/tree/640ea3abfbdef74aad432b58d8586e4bf645f42d/pstack/skills), revision `640ea3abfbdef74aad432b58d8586e4bf645f42d`. Installed both under `~/.codex/skills/` for reuse. The prompt-engineering skill informed the agents' bounded assignments. + +Baseline copies of the current working files are at `/tmp/oidm-lean-content-baseline-20260921/`. They include the uncommitted diagram edits. + +| Owner | Pages | +|---|---| +| Overview agent | Four concepts under `knowledge/overview/` | +| Data structures agent | `hierarchy`, `observation`, `exam-finding-list`, `imaging-problem-list`, `imaging-persona` | +| Applications agent | Seven concepts under `knowledge/applications/` | +| Main agent | `why-finding-models` and `finding-models-and-cdes` under `knowledge/semantic-foundation/finding-models/`; integration and final review | + +This first pass covers 18 concept pages. Preserve quoted material and technical terms even where a general style rule would change them. Each agent reviews meaning and citations against the baseline before handing back its edits. + +## Results + +| Area | Pages | Body words before | Body words after | +|---|---:|---:|---:| +| Overview | 4 | 4,531 | 3,458 | +| Core data structures | 5 | 5,666 | 4,511 | +| Applications | 7 | 8,685 | 6,320 | +| Finding-model explanations | 2 | 2,304 | 1,443 | +| Total | 18 | 21,186 | 15,732 | + +Removed 5,454 words, a 25.7% reduction. Counts split the text after YAML frontmatter on whitespace, including headings, tables, code, and footnotes; indexes and logs are excluded. Per-page counts and baseline files remain in `/tmp/oidm-lean-content-baseline-20260921/`. + +Cut repeated explanations, rhetorical openings, unsupported flourishes, and commentary about the writing. Retained technical terms, branch distinctions, examples, source records, citation labels, and draft status. All original heading text, link targets, and fenced examples remain. Shortened descriptions in three directory indexes to match their concepts. Updated concept generation metadata, `knowledge/log.md`, `CHANGELOG.md`, and `DEV_LOG.md`. + +Each editor reviewed its changes. A second agent reviewed the applications and finding-model explanations; another reviewed the data structures. The main agent reviewed the overview and substantive diffs and applied review corrections. Restored details about absent findings, actor attribution, plugin triggers, evaluation inputs, and the scope of repository searches where shortening had lost precision. + +The architecture example still pairs urinary tract calculus with a left acromioclavicular joint location. Flagged for factual source review; this editorial pass did not change the example. Also removed unsupported assertions about committee authoring speed and presence being redefined exactly once per model; the latter conflicted with the same page's count of models lacking presence. + +## Closeout scope + +Final checks pass: OKF strict validation, the house checker (133 documents, 115 concepts, zero errors or warnings), and `git diff --check`. A comparison of the 18 pages confirms preservation of original heading text, link targets, citation labels, fenced examples, source metadata, and draft status. No site tooling or rendering structure changed, so this prose pass did not rebuild or publish the site. + +Only the 18 assigned concepts, their three affected indexes, and this pass's plan and log entries belong to this work. Concurrent work changed repository configuration, the original build plan, diagram instructions, and verification tooling. Those changes were preserved. The first-pass plan can close independently of the original knowledgebase build plan and its human review. diff --git a/docs/plans/renders/foundation-network-v6.png b/docs/plans/renders/foundation-network-v6.png new file mode 100644 index 0000000..f69e571 Binary files /dev/null and b/docs/plans/renders/foundation-network-v6.png differ diff --git a/docs/plans/renders/foundation-network-v7.png b/docs/plans/renders/foundation-network-v7.png new file mode 100644 index 0000000..dd10da7 Binary files /dev/null and b/docs/plans/renders/foundation-network-v7.png differ diff --git a/docs/plans/renders/foundation-network-v8.png b/docs/plans/renders/foundation-network-v8.png new file mode 100644 index 0000000..2482948 Binary files /dev/null and b/docs/plans/renders/foundation-network-v8.png differ diff --git a/docs/plans/renders/nodule-neighborhood-v1.png b/docs/plans/renders/nodule-neighborhood-v1.png new file mode 100644 index 0000000..7edf9b8 Binary files /dev/null and b/docs/plans/renders/nodule-neighborhood-v1.png differ diff --git a/docs/plans/renders/nodule-neighborhood-v2.png b/docs/plans/renders/nodule-neighborhood-v2.png new file mode 100644 index 0000000..7791dba Binary files /dev/null and b/docs/plans/renders/nodule-neighborhood-v2.png differ diff --git a/docs/plans/renders/nodule-neighborhood-v3.png b/docs/plans/renders/nodule-neighborhood-v3.png new file mode 100644 index 0000000..e71e0e9 Binary files /dev/null and b/docs/plans/renders/nodule-neighborhood-v3.png differ diff --git a/docs/plans/renders/pillars-v3.png b/docs/plans/renders/pillars-v3.png new file mode 100644 index 0000000..aeb4f9d Binary files /dev/null and b/docs/plans/renders/pillars-v3.png differ diff --git a/docs/plans/renders/pillars-v4a.png b/docs/plans/renders/pillars-v4a.png new file mode 100644 index 0000000..49894f4 Binary files /dev/null and b/docs/plans/renders/pillars-v4a.png differ diff --git a/docs/plans/renders/pillars-v4b.png b/docs/plans/renders/pillars-v4b.png new file mode 100644 index 0000000..b6688ed Binary files /dev/null and b/docs/plans/renders/pillars-v4b.png differ diff --git a/docs/plans/renders/pillars-v4c.png b/docs/plans/renders/pillars-v4c.png new file mode 100644 index 0000000..c699406 Binary files /dev/null and b/docs/plans/renders/pillars-v4c.png differ diff --git a/docs/plans/renders/pillars-v5-b1.png b/docs/plans/renders/pillars-v5-b1.png new file mode 100644 index 0000000..dbf5dac Binary files /dev/null and b/docs/plans/renders/pillars-v5-b1.png differ diff --git a/docs/plans/renders/pillars-v5-b2.png b/docs/plans/renders/pillars-v5-b2.png new file mode 100644 index 0000000..36dcfaa Binary files /dev/null and b/docs/plans/renders/pillars-v5-b2.png differ diff --git a/docs/plans/renders/pillars-v5-b3.png b/docs/plans/renders/pillars-v5-b3.png new file mode 100644 index 0000000..fcb7112 Binary files /dev/null and b/docs/plans/renders/pillars-v5-b3.png differ diff --git a/docs/plans/renders/pillars-v6-b3.png b/docs/plans/renders/pillars-v6-b3.png new file mode 100644 index 0000000..18ed1ef Binary files /dev/null and b/docs/plans/renders/pillars-v6-b3.png differ diff --git a/docs/plans/renders/pillars-v7-b3.png b/docs/plans/renders/pillars-v7-b3.png new file mode 100644 index 0000000..53de656 Binary files /dev/null and b/docs/plans/renders/pillars-v7-b3.png differ diff --git a/docs/plans/renders/pillars-v8-b3.png b/docs/plans/renders/pillars-v8-b3.png new file mode 100644 index 0000000..6ec816a Binary files /dev/null and b/docs/plans/renders/pillars-v8-b3.png differ diff --git a/docs/plans/renders/three-axes-v1.png b/docs/plans/renders/three-axes-v1.png new file mode 100644 index 0000000..33539b6 Binary files /dev/null and b/docs/plans/renders/three-axes-v1.png differ diff --git a/docs/plans/renders/three-axes-v2.png b/docs/plans/renders/three-axes-v2.png new file mode 100644 index 0000000..dc45432 Binary files /dev/null and b/docs/plans/renders/three-axes-v2.png differ diff --git a/docs/plans/renders/three-axes-v3.png b/docs/plans/renders/three-axes-v3.png new file mode 100644 index 0000000..fb2a155 Binary files /dev/null and b/docs/plans/renders/three-axes-v3.png differ diff --git a/docs/plans/renders/three-axes-v4.png b/docs/plans/renders/three-axes-v4.png new file mode 100644 index 0000000..9232407 Binary files /dev/null and b/docs/plans/renders/three-axes-v4.png differ diff --git a/docs/plans/renders/three-axes-v5.png b/docs/plans/renders/three-axes-v5.png new file mode 100644 index 0000000..8a084e7 Binary files /dev/null and b/docs/plans/renders/three-axes-v5.png differ diff --git a/docs/plans/renders/three-axes-v6.png b/docs/plans/renders/three-axes-v6.png new file mode 100644 index 0000000..5ec6104 Binary files /dev/null and b/docs/plans/renders/three-axes-v6.png differ diff --git a/docs/plans/renders/two-collections-v1.png b/docs/plans/renders/two-collections-v1.png new file mode 100644 index 0000000..17c0180 Binary files /dev/null and b/docs/plans/renders/two-collections-v1.png differ diff --git a/docs/plans/renders/two-planes-v10.png b/docs/plans/renders/two-planes-v10.png new file mode 100644 index 0000000..77af98f Binary files /dev/null and b/docs/plans/renders/two-planes-v10.png differ diff --git a/docs/plans/renders/two-planes-v4.png b/docs/plans/renders/two-planes-v4.png new file mode 100644 index 0000000..fdd6d09 Binary files /dev/null and b/docs/plans/renders/two-planes-v4.png differ diff --git a/docs/plans/renders/two-planes-v5.png b/docs/plans/renders/two-planes-v5.png new file mode 100644 index 0000000..4e778b7 Binary files /dev/null and b/docs/plans/renders/two-planes-v5.png differ diff --git a/docs/plans/renders/two-planes-v7.png b/docs/plans/renders/two-planes-v7.png new file mode 100644 index 0000000..9183fb7 Binary files /dev/null and b/docs/plans/renders/two-planes-v7.png differ diff --git a/docs/plans/renders/two-planes-v8.png b/docs/plans/renders/two-planes-v8.png new file mode 100644 index 0000000..9183fb7 Binary files /dev/null and b/docs/plans/renders/two-planes-v8.png differ diff --git a/docs/plans/renders/two-planes-v9.png b/docs/plans/renders/two-planes-v9.png new file mode 100644 index 0000000..6a8cf3d Binary files /dev/null and b/docs/plans/renders/two-planes-v9.png differ diff --git a/docs/plans/repository-review.md b/docs/plans/repository-review.md new file mode 100644 index 0000000..6940ff7 --- /dev/null +++ b/docs/plans/repository-review.md @@ -0,0 +1,64 @@ +# Repository review + +Status: Complete (2026-09-21) + +## Purpose + +Explain the repository's purpose, structure, current work, and verification state. + +## Steps + +- [x] Record this review plan in the repository. +- [x] Read project guidance, the OKF skill, and core documentation. +- [x] Examine the knowledge bundle, publishing tools, and uncommitted work. +- [x] Run relevant local verification and investigate any failures. +- [x] Review documentation for accuracy, record findings here, and mark the review complete. + +This review preserves existing work and does not publish or commit changes. Update reference documentation and active logs if the review results in changes that need documenting; a review alone does not warrant a user-facing changelog entry. + +## Repository purpose and state + +The repository is the intended canonical public knowledgebase for the Open Imaging Data Model. Its product is an OKF 0.2 Markdown bundle, rendered as a static site. Application implementations and vocabulary catalogs live in the source repositories documented by the bundle. + +- `knowledge/`: 115 concepts, 17 indexes, and one change log. All 115 concepts have `status: draft`; none has a `verified` entry. +- Coverage: 48 glossary terms, 21 semantic foundation concepts, 10 data structure documents, seven applications, seven roadmap documents, eight references, six history documents, four overview documents, two guides, one repository map, and one build plan. +- The original build plan records phases 0–5 as done and phase 6 (integration and human review) as in progress. Its open-question register contains 90 numbered questions and 21 defect rows, including four local bundle rows. +- Git: branch `main`, two commits, HEAD `313d085`. No remote URL is configured in this checkout; `remote.pushdefault=parent` does not define a remote. GitHub publication cannot be inferred from the workflows or README alone. +- Existing uncommitted work replaces three Mermaid diagrams with Excalidraw sources and SVG renders, adds Python diagram builders/rendering helpers and `links.txt`, ignores `sources/`, and extends the development log. + +## Publishing and verification + +`Taskfile.yml` provides check, build, serve, publish, and graph-generation tasks. `site/build.sh` stages normalized Markdown links, builds with pinned Quartz, and emits `public/`. The custom plugin displays OKF trust and provenance metadata. `task publish` validates, builds with a bucket configuration, rewrites links for literal object keys, and uploads to Tigris. A separate workflow is configured for GitHub Pages. + +The pinned upstream [Quartz package manifest](https://github.com/jackyzha0/quartz/blob/97a2d05f80c4c50534959b1d0d41cc4b3895625e/package.json) confirms version 5.0.0 and Node >=22, consistent with the local documentation. The development log records a Starlight experiment and a pending generator decision; the repository still implements Quartz. + +Checks performed: + +- OKF strict validator: passes, 115 concepts, no issues. +- House-rules checker: passes, 133 documents, zero errors and zero warnings. +- `bash site/build.sh`: succeeds, processes all 133 Markdown files, emits 546 files (245 HTML files). +- Three Excalidraw JSON files load and their corresponding SVG files parse as XML. This is structural validation, not a visual review. +- The build reports that the staging directory is outside a Git repository. This matches the staging design and means Git-derived content dates are unavailable there. npm also reports two install scripts not covered by `allowScripts`; neither prevented this build. + +The build regenerated ignored `public/` using the default GitHub Pages configuration. It did not upload anything. No live-site or browser interaction checks were performed, and the review did not independently re-audit the external OIDM repositories or manuscript claims. + +## Work awaiting integration + +The ignored `sources/bucket/REPORT.md` inventories manuscripts, supporting files, a reporting-schema deck, and a webinar deck; extracted text and figures are present. `sources/excalidraw-diagrams.md` contains transcriptions and gap assessments for 15 canvases. No concept currently references `sources/bucket`, the source bucket prefix, or the imported manuscript identifiers. These imports provide material for a further synthesis pass; their substantive claims still need source review. + +The source report documents extraction limits, including incomplete transcription of one PDF. Its existence should not be read as a complete verification of every imported document. Raw sources remain outside the public bundle. + +## Concrete follow-up findings + +1. **Human review remains the release gate.** Clean structural validation does not establish factual accuracy. The original build plan should remain in progress until its verification and release tasks actually finish. +2. **Deployment does not depend on validation.** `.github/workflows/site.yml` builds and deploys independently of `.github/workflows/validate.yml`; a failed validation workflow does not itself block this deployment. Its path filter also omits the `tools/` scripts used by the build, so changes only to those scripts do not trigger deployment. +3. **The advertised live reload misses source edits.** `site/build.sh` copies content once, then serves that temporary directory. The pinned Quartz watcher watches `argv.directory`; no process mirrors subsequent edits from `knowledge/` into the staging copy. This finding follows from the scripts and watcher implementation; it was not exercised in a browser. +4. **Direct publishing bypasses the documented validation step.** `task publish` has the validation dependency, but `bash site/publish-tigris.sh` does not run either checker. `site/README.md` currently presents both entry points as equivalent, including validation. +5. **Some status documentation needs reconciliation.** The open-question register still lists the SDK URL and eight-versus-ten exam count as bundle defects, although the referenced files contain the corrected URL and ten exams. The source-transcription introduction still says three diagrams although the body covers 15. The development log's source-extraction entry describes work as underway even though an inventory now exists. +6. **Diagram reproduction instructions need consolidation.** The new renderer's usage text refers to a `.claude/skills/excalidraw-diagram/references` location absent from this checkout, and there is no diagram task or local dependency declaration accompanying those instructions. + +Suggested next sequence: reconcile the imported sources with the draft bundle, review and resolve the resulting factual questions, then complete the generator decision and publishing workflow fixes before the first reviewed release. No implementation changes were made as part of this examination. + +## Documentation closeout + +Recorded the review and verification in `DEV_LOG.md`. Left the original build plan in progress because its human review remains outstanding. No reader-facing behavior changed, so no changelog entry was added. diff --git a/docs/plans/restructure-around-project-ideas.md b/docs/plans/restructure-around-project-ideas.md new file mode 100644 index 0000000..94008e8 --- /dev/null +++ b/docs/plans/restructure-around-project-ideas.md @@ -0,0 +1,132 @@ +# Restructure around the team's ideas + +Status: Proposed. Updated 2026-09-22 after reading the SIIM 2026 presentation. Restructuring has not started. + +## Purpose + +Recover the team's idea work scattered across the repositories and give each distinct idea a clear, stable home that the team can build out. Readers should understand the ideas, their relationships, their sources, and what remains unsettled. + +Explore code, data models, examples, design notes, discussions, and unfinished branches for the ideas they embody. Consolidate related work across repositories into an account of the idea, with links back to the evidence. The repositories remain the place to inspect files and implementation details. Repository coverage is not a measure of completeness. + +This plan replaces the sentence-shortening approach for the next revision. The previous editorial passes remain recorded as completed work. + +## Content rules + +- Capture both explicitly discussed ideas and ideas demonstrated by the team's implementations and examples. Use concise explanations with direct source references. +- Describe what code or an example actually represents or does. Attribute it to that implementation. Do not invent the team's motivation, intended generality, or agreement with another approach. +- Treat the existing generated pages as leads to sources. They are not evidence that the team endorsed a claim. +- Distinguish a stated goal, a working proposal, and an implemented example. Human verification of an account does not establish consensus on its subject. +- Preserve attributed disagreements when they affect an idea. Do not reconcile them through agent reasoning. +- Give each idea one explanatory home. Other pages link to it. +- Keep an example only when it explains something the prose cannot explain as clearly. +- Remove inferred benefits, causal histories, design conclusions, and questions invented by agents unless a team source supports them. +- Omit file catalogs, branch censuses, commit distances, issue inventories, package tours, dataset statistics, and development chronology from the core text. Cite a specific artifact when it provides evidence. +- Avoid copied schemas and full source extracts. Retain unique team-authored material that has no other durable home before removing its current page. + +The recorded [owner statements](../../knowledge/plans/2026-09-20-knowledgebase-build-plan.md#the-project-leads-stated-goals) orient the investigation. The [decisions added on 2026-09-21](../../knowledge/plans/2026-09-20-knowledgebase-build-plan.md#decisions-added-2026-09-21) require dated, attributed versions of unsettled structures and distinguish data structures from transport formats. The repository work itself, along with manuscripts, decks, and working notes, supplies the substance. A lack of polished explanatory prose is a reason to investigate the implementation, not to discard the idea. + +## Direction from the SIIM 2026 presentation + +The owner supplied [Structured Results and Context for Next-Generation Imaging Resulting Tools](https://oidm-public.t3.tigrisfiles.io/oidm-knowledge-sources/SIIM%202026%20Reports-of-the-Future.pptx) to guide this restructuring. Read all 15 slides, speaker notes, and embedded diagrams. Slide references below use file order because printed slide numbers repeat. + +The deck's central distinction is Patient Context and Foundation Context. Patient Context records observations and imaging history for a particular patient. Foundation Context supplies shared definitions, relationships, and references. Clinical history changes with the patient; shared knowledge develops through authoring and versioning. Codes connect the patient's observations to that knowledge. The opening purpose is reuse by clinicians and by the next radiologist, with support for subsequent reporting. These points appear in slides 3–8 and 12–15. + +The editorial implication is to lead with that purpose and connection, then explain the ideas that make it possible. The three axes of Foundation Context are Observation Type, Anatomic Location, and Exam Type. Their relationships deserve an explicit explanation alongside the axes. Repository work supplies the evidence and further development of these ideas. This deck guides the reading path without excluding ideas documented elsewhere. + +Preserve the deck's qualifications. Slide 9's notes treat "Observation Type" as a possible name and some attributes as illustrative. Slide 10 distinguishes existing anatomy content from unpopulated enrichment. Slide 14 describes SDK-mediated access and intended uses; it does not establish which capabilities have shipped or prove the stated benefits. The conceptual figures are not formal schemas. Preserve source-specific formulations, including the deck's focused/included/edge anatomy and other sources' always/usually/possibly wording, until the team reconciles them. + +## Connection to the CDE two-plane model + +The CDE work gives this distinction a concrete graph expression. Its [two-plane account](https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/docs/next-gen-schema/03-draft-structures.md#5-two-planes-reports-point-into-the-vocabulary) describes shared definitions and their relationships, plus report-specific observations and their relationships. The definition plane supplies part of Foundation Context; the observation plane represents the imaging assertions within Patient Context. These correspondences guide the explanation without declaring the two projects' models identical. + +Observations point to definitions for their subjects, locations, and data elements. Their relationships express assertions about the particular case. A definition-space potential and a radiologist's case-specific interpretation have different meanings. The [owner's report-plane decisions](https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/docs/plans/2026-09-03-report-plane-example.md#owner-decisions-taken-in-this-session-copy-these-into-10-verbatim) explicitly say that report edges do not point to the vocabulary relationships they parallel. Keep provisional edge names separate from those owner decisions. + +Use this connection to organize recovered ideas and their relationships. For example, anatomic scope and a particular observation's location belong in one connected explanation. Shared presence definitions and explicit negative observations belong in another. A few existing report examples can show these connections without repeating their definitions or creating an exhaustive example catalog. + +## Proposed reading structure + +Use the following sequence as a provisional reading path. Determine the actual idea pages after investigating the source work. An idea developed across several repositories gets one home. A distinct idea may need its own page even when several ideas share one repository. + +| Area | Material to recover and explain | +|---|---| +| Purpose and reuse | Why the team wants imaging findings to remain useful after the report, for subsequent care and the next interpretation. Introduce Patient Context and Foundation Context together. | +| Patient Context | Observations carrying codes and patient-specific attributes, connected by case-specific relationships; their organization by exam and across imaging history; their place alongside other clinical context. Recover the actual source alternatives for EFL, IPL, and Imaging Persona. Distinguish transport expressions from the structures. | +| Foundation Context | The three connected axes: observation types, anatomy, and exam types. Recover finding-model and CDE work, metadata, anatomic hierarchies and laterality, preferred exam families, and anatomy coverage. Explain each axis once, with a separate page only where its distinct idea work warrants one. | +| Relationships and code resolution | How observation codes refer to shared definitions; relationships within and between axes; external references; the proposed shared access through SDKs. Preserve the distinction between a general relationship and what is asserted about a patient. | +| Tools using the combined context | The team's intended uses in reporting, follow-up, longitudinal review, rule-based tools, and generative assistance. Link implementation examples to the ideas they demonstrate. Attribute proposed benefits and distinguish available capabilities from goals. | + +Each idea page should explain what the idea is, the problem or use it addresses where the sources establish that, the approach embodied in the work, its relationship to other ideas, and meaningful unresolved alternatives. Include a small example only when it helps explain the idea. Use stable descriptive names so later idea work can extend the same pages. + +Put each idea's stated direction and substantive open questions beside its explanation. Add a compact shared glossary only for terms readers need across topics. Consolidate aliases. Source references belong beside the claims they support. + +Set a small page and word budget after the idea investigation, before drafting. Include the introduction, glossary, and supporting notes in that budget. A page needs a distinct idea worth developing, not a corresponding source file. Start with the shortest explanation that makes the idea understandable and connects it to its evidence. Do not expand a page to fill a template or move excess text into appendices. The intended change is a substantially smaller authored account, not another sentence-trimming pass. + +## Treatment of existing material + +| Current material | Planned treatment | +|---|---| +| Overview, glossary, conceptual pages | Rebuild around the ideas recovered in step 1. Merge repeated definitions and delete superseded explanations. | +| Roadmaps and open questions | Retain explicit team directions and meaningful source disagreements within their topics. Remove agent research tasks and documentation defects from the public narrative. | +| Application profiles and repository map | Investigate the ideas embodied in the applications and connect them to their conceptual homes. Retain a short use and implementation link where helpful. Remove inventories and operational documentation. | +| History | Keep a historical fact only when it explains a team idea or an explicitly recorded decision. Link to the original account. | +| References and examples | Link to durable originals. Keep only indispensable examples and unique team-authored material, counted within the content budget. | +| Build plans, migration ledger, authoring instructions, editorial reports | Keep maintenance records outside the published reading path. Consolidate active instructions and mark superseded plans. Preserve provenance without presenting it as project exposition. | + +Delete superseded generated pages after checking their unique content and links. Do not reproduce them as a new public archive or appendices. Use repository history for recovery once the owner authorizes a commit. Preserve unrelated concurrent edits throughout. + +## Execution sequence + +### 1. Recover the idea work + +- [x] Write this plan before changing content. +- [x] Read the owner-supplied SIIM 2026 deck, notes, and diagrams; revise the proposed reading path around Patient Context and Foundation Context. +- [x] Read the CDE two-plane explanation and recorded owner decisions; incorporate their connection to the deck without merging distinct relationship meanings. +- [ ] Use the existing source map to find relevant code, models, worked examples, design notes, discussions, and branch work. Read the artifacts that contain the idea work rather than repeating a file census. +- [ ] Read across repositories to recover how an idea has been expressed, attempted, or developed. Include manuscripts and decks. Inspect implementation behavior when prose leaves the idea implicit. +- [ ] Make a temporary, compact list of distinct ideas with source locations, related ideas, and status. Where relevant, identify their role in the definition plane, observation plane, connections between them, or tools using them. Separate explicit intent from demonstrated behavior. Record disagreements and uncertain interpretation. +- [ ] Check every current page for a unique, sourced team idea before marking it for consolidation or removal. Do not carry agent-generated claims forward by default or mistake an implementation detail for the underlying idea. +- [ ] Identify unique team-authored material and give it a durable home before removing any wrapper page. +- [ ] Trace the deck's ideas and connections into the repository work. Preserve what that work adds, including disagreements with the presentation, without treating every depicted capability as implemented. +- [ ] Derive the proposed idea pages from this investigation. Check the reading structure and content budget against them. + +Completion condition: the distinct ideas found in the work have proposed homes and supporting evidence. Uncertain interpretation is explicit. No inferred intention has become a team position, and ideas have not been excluded merely because they lack a written statement. + +### 2. Draft the smaller account + +- [ ] Write the idea pages from the source investigation. Use the old pages to locate evidence, not as outlines to shorten. +- [ ] Add only necessary definitions, examples, and source references. Use a few existing report examples to explain relationships within and between the planes. Keep unsettled alternatives side by side where needed. +- [ ] Check each section for duplication and for agent-added interpretation. +- [ ] Record progress and unresolved attribution questions in this plan. + +Completion condition: the pages form a coherent reading path within the budget established after discovery, with no repository inventory chapters or hidden overflow. Check any conflict between brevity and retaining a distinct idea against its source rather than silently discarding it. + +### 3. Replace and reconnect + +- [ ] Replace the old reading structure and remove superseded pages after the unique-content check. +- [ ] Update indexes, diagrams, internal links, and provenance references to match the new organization. Inspect existing incoming links before deciding which moved URLs need redirects. +- [ ] Keep maintenance records accessible to maintainers while excluding them from the published reading path. Check the current site configuration before implementing that separation. +- [ ] Preserve source attribution and human verification history accurately. Rewritten content remains draft pending review; do not carry a verification stamp onto materially changed claims as if they were reviewed. +- [ ] Update authoring guidance to enforce these content rules and prevent future repository inventories. + +Completion condition: obsolete pages no longer compete with the new account; retained links and provenance resolve. + +### 4. Review and close + +- [ ] Have one reviewer trace retained claims to team sources and another check duplication, scope, and reading order. Their task is fidelity and clarity, not adding ideas. +- [ ] Check that the new account retains the distinct sourced ideas identified in step 1. Report unresolved attribution rather than guessing. +- [ ] Run strict OKF validation, the house checker, the site build, and link/navigation checks. Resolve failures caused by the new structure. +- [ ] Update this plan, relevant reference instructions, `DEV_LOG.md`, `CHANGELOG.md`, and the bundle log. Keep the changelog focused on the changed reading experience. +- [ ] Report final page and word counts alongside the source-fidelity review. Mark restructuring complete only after the content and documentation checks pass. + +No commits, publishing, or restructuring are authorized by the request to create this plan. + +## Acceptance criteria + +- A reader can follow the team's ideas through concise pages organized around concepts and their relationships. +- The introduction explains the deck's Patient Context/Foundation Context distinction, how they connect, and the team's intended uses. The three Foundation Context axes and their relationships have clear homes. +- The pages recover substantive idea work from the repositories, including ideas embodied in code and examples. They provide stable homes for further development. +- Every substantive claim is attributable to source evidence. Implementation behavior and explicit team intent remain distinguishable. +- Each idea has one explanatory home. Unsettled alternatives remain attributed and unresolved. +- No agent-created proposal, inference, or research question is presented as the team's position. +- Supporting material stays within the same scope and size constraints. Relocating bulk text does not count as reducing it. +- The site and bundle checks pass, and maintenance records describe the final state. diff --git a/docs/plans/restructure-codex-drafts.md b/docs/plans/restructure-codex-drafts.md new file mode 100644 index 0000000..22cb0a9 --- /dev/null +++ b/docs/plans/restructure-codex-drafts.md @@ -0,0 +1,47 @@ +# Data Structures, Use Cases, and Sample Applications drafts + +Status: Drafting and Codex's cross-review pass complete. Authorized by the project lead on 2026-09-22 through the drafting assignment and review handoff from Fable. + +## Scope + +Follow the agreed outline in `restructure-joint-notes.md` and the sources behind `idea-placement.md`. Create three concise pillar anchors in `knowledge/drafts/`: `data-structures.md`, `use-cases.md`, and `sample-applications.md`. Claude owns Foundation Context and SDKs. Existing pages and navigation remain until cross-review and replacement. + +## Steps + +1. Record this plan and the file ownership before drafting. Done. +2. Read the underlying sources, preserve dated related representations and their actual status, and draft the three anchors. Every substantive claim needs a source. Use draft status and session-specific `generated.by`. +3. Check coverage against the placement table, review source fidelity and prose, and run OKF validation and link checks. Update this plan with results and any remaining issues. +4. Hand the drafts to Claude for cross-review. Update the development log and bundle log to distinguish completed drafting from pending replacement and publication. Review the documentation for an accurate final state. + +No commits or publication are included in this drafting assignment. + +## Drafting results, 2026-09-22 + +- Created Data Structures, Use Cases, and Sample Applications in `knowledge/drafts/`, with draft status and session-specific authorship. Added their links to the shared draft index. Body counts, excluding frontmatter and footnote definitions, are 1,311, 680, and 713 words respectively, 2,704 total. Counts use whitespace-separated body tokens, including Markdown link syntax. +- Data Structures covers the 24 assigned ideas with the two graphs at its center. An independent review checked pinned CDE/IPL sources and the clean JDIM manuscript pages. Fixed unresolved coding, durable-identity limitations, the manuscript's human-review boundary, the deck's internally differing status labels, and the extraction review contract. Manuscript text was paraphrased. +- Use Cases covers the application half of Patient Context and the documented proposals. Corrected the inventory's webinar grouping: quality surveillance and research are separate application families; breast imaging is a separate planned example. +- Sample Applications distinguishes implemented work from evaluation plans and proposed exchange workflows. Public RSNA material supports the built interoperability demonstrations. The board's unique proposed element-role tagging was handed to Claude for Foundation Context or SDKs. +- Verified all citation IDs against frontmatter sources and all cited pinned Git paths against the local source repositories. Whitespace checks pass. Both bundle validators report no issues in these three pages. The latest full-bundle check still reports links and index entries for Claude's drafts as those files arrive; the combined gate must be rerun after drafting finishes. +- Sent all three pages to Claude for source cross-review. Updated the bundle and development logs. No changelog entry is warranted for staged, unpublished drafts. Existing pages have not been replaced by this session. + +## Remaining shared work + +Both sessions' cross-reviews have been delivered. Claude is applying findings to his pages; replacement of old pages and publication remain steps in the joint plan. These drafts carry no human verification stamp. + +## Cross-review handoff, 2026-09-22 + +Status: Complete for Codex's assigned pass, following the owner's relayed handoff. + +1. Record this review phase before further work. Done. +2. Review Claude's seven drafts against their cited sources. Write one findings file per page in `sources/review/drafts-.md`; do not edit Claude's pages. Distinguish factual errors from optional detail and substantiate every requested correction. +3. Resolve the incoming reviews of the three Codex drafts against primary evidence. Apply supported corrections to those three pages only; record any review findings that the sources do not support. Preserve a lean reading path. +4. Check citations, links, and bundle conformance. Append the handoff and update this plan and the development log with the completed scope and remaining work. Replacement, commits, and publication remain outside this pass. + +### Results + +- Reviewed all seven Claude drafts against primary sources, assisted by three agents. Findings are in `sources/review/drafts-.md`. No Claude page was edited by this session. Material corrections include commit/date mismatches, overstated implementation claims, dropped proposal provenance, and compatible source statements presented as conflicts. +- Addressed incoming findings in the three Codex pages. Dispositions are in `sources/review/drafts-{data-structures,use-cases,sample-applications}-response.md`, including supported corrections and reasons for rejecting unsupported portions. Claude withdrew the signed-report-scope finding after checking the manuscript evidence. +- Data Structures now uses the deck's calculus example to explain the graph connection and preserves dated differences in aggregation, status, entity resolution, and transport. Use Cases distinguishes the sources' application groupings and proposal status. Sample Applications links the working examples and uses team evidence for the demonstrated work. Manuscripts remain paraphrased and descriptively cited; reviewer correspondence was not used. +- Revised body counts are 1,551, 767, and 756 words respectively (3,074 total), using the same counting method as the initial results. Source corrections account for the additions; the initial counts above describe the first drafts. +- Strict OKF validation passes; the bundle checker reports 144 documents, 125 concepts, zero errors and zero warnings. All three pages retain draft status and session authorship; every footnote matches a declared source. Pinned source paths and application links were checked during review. Whitespace checks pass. +- Updated the shared handoff, development log, and bundle log. No reader-facing changelog entry is needed for staged, unpublished drafts. No commit, replacement, or publication by this session. diff --git a/docs/plans/restructure-dashboard.md b/docs/plans/restructure-dashboard.md new file mode 100644 index 0000000..1b93e1b --- /dev/null +++ b/docs/plans/restructure-dashboard.md @@ -0,0 +1,92 @@ +# Restructure dashboard + +Updated 2026-09-28 (two-planes figure added) by Claude. Layout per [the layout plan](/docs/plans/2026-09-22-layout-plan.md). Paths are repo-relative; Links open in peruse. Current figure renders are copied to [docs/plans/renders/](/docs/plans/renders/) so peruse can show them; the deck images under `sources/` stay gitignored until that is fixed. + +Status words: **agreed** = text settled with the project lead and on disk; **in discussion** = text proposed in conversation, not yet agreed; **material only** = the Tuesday ten-page draft holds the reviewed source material, page not yet written in the new layout; **not started**; **done** = figure accepted by Claude, awaiting the project lead; **needs pass** = known defects listed. + +## Pages + +| Page | Status | Where to look | +|---|---|---| +| **Overview** (root) | agreed; Astra-reviewed; two-planes figure embedded; pillars stack to follow once B3 is accepted | [knowledge/drafts/overview.md](/knowledge/drafts/overview.md) | +| **Foundation Context** index | agreed; both figures embedded | [knowledge/drafts/foundation-context.md](/knowledge/drafts/foundation-context.md) | +| Finding Models and Common Data Elements (hub) | **agreed and written**; Astra-reviewed, six provenance findings applied; prose byte-identical to the agreed text | [knowledge/drafts/finding-models-and-cdes-hub.md](/knowledge/drafts/finding-models-and-cdes-hub.md); material for the children in [knowledge/drafts/finding-models-and-cdes.md](/knowledge/drafts/finding-models-and-cdes.md) | +| OIFM content | material only | [knowledge/drafts/finding-models-and-cdes.md](/knowledge/drafts/finding-models-and-cdes.md), "What the inclusive collection holds" | +| Definition formats | material only | same file, "The two formats" | +| Identifiers | material only | same file, identifiers paragraph | +| Next-generation schema | **agreed and written**; Astra-reviewed, six provenance findings applied; prose byte-identical; CDE figure embedded | [knowledge/drafts/next-generation-schema.md](/knowledge/drafts/next-generation-schema.md) | +| Relationships | **agreed and written**; Astra-reviewed; the project lead's four prose decisions applied; figure (nodule neighborhood) pending accept | [knowledge/drafts/relationships.md](/knowledge/drafts/relationships.md) | +| Standard clinical metadata | material only | same file, "What the graph should carry" | +| Authoring and review | material only | same file, "Authoring and review" table | +| Anatomic locations | material only; Tuesday draft cross-reviewed and corrected | [knowledge/drafts/anatomic-locations.md](/knowledge/drafts/anatomic-locations.md) | +| Exam types | material only; cross-reviewed | [knowledge/drafts/exam-types.md](/knowledge/drafts/exam-types.md) | +| Standards | material only; cross-reviewed | [knowledge/drafts/standards.md](/knowledge/drafts/standards.md) | +| **Data Structures** index | not started | material in [knowledge/drafts/data-structures.md](/knowledge/drafts/data-structures.md) (Astra) | +| Observation | material only | same file | +| The two graphs | material only | same file, two-graphs section; in the ACR-RSNA-CDEs repository: `docs/next-gen-schema/03-draft-structures.md` §5 and `08-worked-examples.md` §4 | +| Exam Finding List | material only | same file | +| Imaging Problem List | material only | same file | +| Imaging Persona | material only | same file | +| Structures versus transport | material only | same file | +| **SDKs** index | not started | material in [knowledge/drafts/sdks.md](/knowledge/drafts/sdks.md) | +| Finding model SDK | material only | same file | +| Anatomic locations SDK | material only | same file | +| Terminology lookup | material only | same file | +| Imaging Problem List SDK (proposed) | material only | same file | +| **Use Cases** index (the list) | not started | material in [knowledge/drafts/use-cases.md](/knowledge/drafts/use-cases.md) (Astra) | +| Reporting assistance | material only | same file | +| Imaging history | material only | same file | +| Outcome tracking | material only | same file | +| Breast imaging | material only | same file | +| **Sample Applications** index (the list) | not started | material in [knowledge/drafts/sample-applications.md](/knowledge/drafts/sample-applications.md) (Astra) | +| Finding Model Forge | material only | same file | +| Imaging Problem List viewers | material only | same file | +| Report extraction platform | material only | same file | +| Rendering, search, and exchange | material only | same file | +| Glossary | decided 2026-09-29: dropped; rebuilt from the new pages as terms earn entries; directory removed at the replace step | [knowledge/glossary/](/knowledge/glossary/) (48 terms, obsolete) | + +## Figures + +| Figure | For | Status | Where to look | +|---|---|---|---| +| Two planes: a finding, its exam, and the shared knowledge they attach to | Overview (lead figure) | ACCEPTED by the project lead 2026-09-29 (v10); embedded in the Overview under "The two contexts" | [docs/plans/renders/two-planes-v10.png](/docs/plans/renders/two-planes-v10.png); [knowledge/drafts/two-planes.svg](/knowledge/drafts/two-planes.svg) | +| Five-pillar stack | Overview | v8 on B3: the SDK lane ends in Foundation Context as one tooth "attaches to · authors & maintains"; SDKs subtitle cut; applications joint widened; needs your accept, then replaces pillars.svg and goes into the Overview | [docs/plans/renders/pillars-v8-b3.png](/docs/plans/renders/pillars-v8-b3.png) | [docs/plans/renders/pillars-v3.png](/docs/plans/renders/pillars-v3.png); [knowledge/drafts/pillars.svg](/knowledge/drafts/pillars.svg) | +| Three axes | Foundation Context | v6 on Opus: full-width section bands in all three columns (node kinds; body regions; modalities), columns filled to equal density, measurements length and CT density only; embedded; needs your accept | [docs/plans/renders/three-axes-v6.png](/docs/plans/renders/three-axes-v6.png) | +| Foundation Context mini-network | Foundation Context | v8 on Opus: solid arrowheads, assessment scheme as an oval; embedded; needs your accept | [docs/plans/renders/foundation-network-v8.png](/docs/plans/renders/foundation-network-v8.png); embedded in `foundation-context.md` | +| Patient Context / Foundation Context table (deck slide 7) | Overview | permitted 2026-09-29; redundant with the two-planes figure, not planned | [sources/bucket/siim2026/media/ppt/media/image6.png](/sources/bucket/siim2026/media/ppt/media/image6.png) | +| One content, two collections | Finding models and CDEs hub | v1 on Opus; needs your accept, then embed in the hub | [docs/plans/renders/two-collections-v1.png](/docs/plans/renders/two-collections-v1.png) | +| Definition field table (deck slide 9) | Definition formats | permitted; planned | [sources/bucket/siim2026/media/ppt/media/image7.png](/sources/bucket/siim2026/media/ppt/media/image7.png) | +| Kidney field table (deck slide 10) | Anatomic locations | permitted; planned | [sources/bucket/siim2026/media/ppt/media/image8.png](/sources/bucket/siim2026/media/ppt/media/image8.png) | +| Containment, part-of, laterality example | Anatomic locations | not started | | +| CT Chest over the Playbook with anatomy edges | Exam types | not started | | +| Data-structure hierarchy | Data Structures index | existing diagram needs revision (Persona as concept, no "pointer") | [knowledge/data-structures/hierarchy.svg](/knowledge/data-structures/hierarchy.svg) | +| Report to Observation (deck slide 4) | Observation | permitted; planned | [sources/bucket/siim2026/media/ppt/media/image4.png](/sources/bucket/siim2026/media/ppt/media/image4.png) | +| The two graphs | The two graphs | permitted; planned: the CDE repository's one-report-two-planes (pyelonephritis) figure | `~/ACR-RSNA-CDEs/docs/next-gen-schema/diagrams/` | +| Foundation-context graph (deck slide 12) | Relationships | permitted; planned | [sources/bucket/siim2026/media/ppt/media/image9.png](/sources/bucket/siim2026/media/ppt/media/image9.png) | +| Pulmonary nodule neighborhood (nodes and edges from the pinned CDE graph) | Relationships page; could replace the dated 2026-09-03 figure on the schema page | v3 on Opus: illustrative per the project lead's intended CDE updates; assessment schemes now ovals; needs your accept and a placement decision (relationships page; replace the dated figure on the schema page) | [docs/plans/renders/nodule-neighborhood-v3.png](/docs/plans/renders/nodule-neighborhood-v3.png) | +| SDK resolution flow | SDKs index | not started | | + +## Decisions waiting on the project lead + +1. Accept the pillars stack v3, then the embed into the Overview. +2. The hub page text as revised on 2026-09-27. +3. Commit of everything since Tuesday to `bootstrap`. +4. Decided 2026-09-29: glossary dropped; rebuilt from the new pages. +5. Decided 2026-09-29: vendor generic; the two organizations generalized. Still open: commit of CDE decisions S53 to S67. +6. Decided 2026-09-29: deck and CDE-repository figures may be used. + +## References layer, first content + +Astra's 15 board summaries in [docs/references/linked-diagrams/](/docs/references/linked-diagrams/) are the first references-layer content (staged there until the layers plan runs); live board links and meeting names are being removed per the project lead, 2026-10-01. + +## Handoff + +Everything an agent needs, including the working rules, is in [docs/HANDOFF.md](/docs/HANDOFF.md). + +## Layers (2026-10-01) + +Three layers, per [the sources-and-layers plan](/docs/plans/2026-10-01-sources-and-layers.md): raw sources (private bucket, gitignored mirror), references (distilled summaries with figures, in `knowledge/references/`), the knowledge bundle (team-facing OKF, `knowledge/`), and the presentation (`pages/`, what the site builds). The pages in this dashboard are the presentation layer; the 115-page bundle is not replaced by them. + +## Process + +Content agreed in conversation, one page at a time; implementation in Opus sub-agents or the codex-impl tabs; Fable reviews. Astra cross-reviews for source fidelity. Diagrams: Excalidraw builders in [tools/diagrams/](/tools/diagrams/), rendered and looked at before use. diff --git a/docs/plans/restructure-joint-notes.md b/docs/plans/restructure-joint-notes.md new file mode 100644 index 0000000..3ac5043 --- /dev/null +++ b/docs/plans/restructure-joint-notes.md @@ -0,0 +1,98 @@ +# Restructure: joint working notes (Claude side) + +Status: Open. Companion to `restructure-around-project-ideas.md` (Codex). The project lead asked the two sessions to think through the restructure together. This file is Claude's side; Codex should append or reply in its own section below, or edit its plan and note the change here. Neither session edits the other's section. + +## Agreement + +Claude adopts the content rules in `restructure-around-project-ideas.md` as written. In particular: ideas are the subject and repositories are evidence; one explanatory home per idea; distinguish stated goal, working proposal, implemented example; keep disagreements attributed and unresolved; no agent-invented motivation, benefits, conclusions, or questions; no inventories in the core text. The project lead confirmed the direction on 2026-09-21 ("Let's get this working around the IDEAS"). + +## Where Claude proposes a variation + +1. **Supporting layers, not deletion.** The project lead's original brief asked for a public knowledgebase that collates the project's documentation, with a glossary of record and an open-questions register. Proposal: the idea pages become the entire reading path, and three things survive as supporting layers linked from idea pages but absent from navigation and search-first surfaces: (a) the glossary, cut to terms readers need across topics, as the plan says; (b) `references/` extracts that are the only durable copy of team-authored material (the Finding Models overview note, the metadata field reference, the schema-differences analysis); (c) an open-questions register reduced to the team's own unresolved alternatives, with agent-found documentation defects moved to `sources/upstream-issues-draft.md` and filed upstream. Everything else in `history/`, `repositories/`, application inventories, and the work-edge sections goes, with unique team-authored material rehomed first. +2. **Verification history.** Documents are all draft; nothing has a human verification stamp yet, so nothing is lost by rebuilding. New idea pages start as draft. +3. **Sources the current pages did not use.** Since the bundle was drafted, these arrived and are indexed under `sources/` (gitignored, raw): the JACR Imaging Problem List manuscript and figures; two JDIM manuscripts under review (Imaging Problem List; Anatomic Locations Index) with response-to-reviewer letters that must not be used; the SIIM webinar deck (July 2026, public); the reporting-schema deck; fifteen Excalidraw boards transcribed with a sensitivity section; the project lead's 2026-09-19 email notes (application-layer data structures versus transport); the dev-branch example2 study. Rules already decided with the project lead: paraphrase manuscripts and cite as under review, never quote, never touch reviewer letters; boards: public-facing content freely, internal boards only for schema and data-model ideas with organizations named and people and meeting histories omitted. +4. **No specification.** Decided 2026-09-21: nothing is formally defined; never call any source "the specification" or "canonical"; present each source's version side by side, dated. + +## Documents and prompts are primary sources + +Project lead, 2026-09-21: "there are IMPORTANT DOCUMENTS and PROMPTS in the repos whose ideas need to be captured and included! We can't just handwave at the repos." The idea inventory therefore reads, in full, the design documents, plans, skills, and LLM prompt files in the repositories (authoring prompts and fragments in findingmodels; extraction, validation, and coding prompts and design docs on imaging-problem-list dev; enrichment PRD, plans, ADRs, and agent prompts in findingmodel; the next-gen-2026 vocabulary documents; CDEStaging's report-representation notes; Forge's workflow docs), and cites the document and what it says, never the repository alone. Prompts count as the team's operational definitions. Also from the project lead: "the code documents don't need to be REPRODUCED, but the functionality and so on that's captured needs to be somehow reflected." Idea pages therefore state what the code implements of an idea, in the idea's terms, with a pointer to the code, and never copy install or usage documentation. + +## Proposed division of labor + +- Claude: step 1, the idea inventory (two Opus agents, one for the semantic ideas, one for imaging history, applications, and purpose), written to `docs/plans/idea-inventory-semantic.md` and `docs/plans/idea-inventory-structures-and-uses.md`. Codex reads them and challenges them. +- Both: agree the page list and names from the inventories before drafting (in this file). +- Drafting: split by area once the page list exists; each page names its author session in `generated.by`. Neither session edits a page the other is drafting. +- Review: the other session reviews for source fidelity. +- Site and diagrams: Claude (in progress: diagrams reoriented for the column; click-to-zoom plugin; Cloudflare targets). + + +## Decisions of 2026-09-22 (owner, relayed in the Claude and Codex sessions) + +These supersede the four-pillar page list that stood here earlier today. The owner's words are quoted; everything else is the two sessions' shared understanding, confirmed in conversation. + +1. **Five named pillars. Use the names, never numbers.** "1. Foundation Context / Semantic layer: includes both the schema/meta-definitions as well as the efforts to build out content. 2. Data Structures, most ESPECIALLY in the Observation layer, and how there are two graphs and they work together. 3. SDKs, the tools that wrap the data structures and enable developers working in the application layer to manipulate instances in real-world applications (and some around helping with definition of the foundation context, obviously). 4. Theoretical Use Cases: Imaging all the different kinds of applications/tools/plugins/output products we could create using an ecosystem built around this foundation. 5. ACTUAL sample applications we've created to try to illustrate some of these ideas." The fourth was then shortened to **Use Cases**. So: **Foundation Context**, **Data Structures**, **SDKs**, **Use Cases**, **Sample Applications**. +2. **A CDE and a finding model are the same content.** "A 'CDE' and a 'Finding Model' are the same thing, but they're in different repos. Open Imaging Finding Models are in the OIDM-maintained repo, and are intended to be very INCLUSIVE, can almost be drafts. Common Data Elements live in the ACR/RSNA repository, and are intended to be WELL-REVIEWED. They're more like something published. They BOTH should soon be using the schema and classes being defined in the CDE schema re-write, with FindingClass, DataElement, Measurement, etc." Consequence: explain the common model once, then the inclusive OIDM collection and the well-reviewed ACR/RSNA collection and their relationship. Collection expectations are not per-item facts. Migration is intended, not complete. The "Observation Type" umbrella name the sessions had floated is withdrawn as unnecessary and was never approved. +3. **The OIFM reorganization around the graph is urgent.** "OIFMs VERY soon need to get re-organized around the graph-based approach we're developing in the next-gen-schema effort in CDEs. They're currently document-oriented and we need to fix that SOON." A change of organization, not added fields. Stated prominently under Foundation Context; current implementation kept distinct from direction; no storage, schema, or migration design invented beyond the source work. +4. **Source eligibility rule.** Repository documents, prompts, plans, skills, ADRs, and code are team artifacts eligible for substantive content. They are not demoted for being agent-assisted, and no statement needs separate human approval to be cited. Committing a document does not make a draft proposal or one implementation project-wide consensus. Each claim carries its source's actual status, date, and any explicit provenance label the source supplies (the CDE decision record's OWNER and CLAUDE DEFAULT, for example). Differences between sources and the owner's later corrections are preserved, not reconciled. No speculative authorship audit. +5. **Terminology.** Foundation Context (shared definitions, relationships, references) and Patient Context (this patient's imaging results plus relevant clinical context), from the SIIM 2026 deck. The CDE report graph, the Imaging Problem List representations, and the broader Patient Context are *related representations* of the Observation idea, never "the same thing serialized differently". Foundation Context and Data Structures correspond to the two graphs at the explanatory level; the report graph is the imaging-assertion part of Patient Context, not a clinical-context schema. The deck's "connective tissue" means relationships and citations between foundation concepts and is used only in that sense. Retained artifact names are used where a source's current files are cited: OIFM finding model, CDE set and element, the next-generation FindingClass, Diagnosis, Grouping, DataElement, Measurement. +6. **Organizing method** (agreed with Codex). The introduction explains the two-graph connection once within the five pillars. Idea anchors carry the recovered substance. Patient-side ideas say which shared definitions they reference; foundation-side ideas say how observations use them; related anchors link both ways. Existing worked examples are used for what each actually shows (the CDE pyelonephritis report and the deck's calculus figure show both graphs; the IPL example2 study is patient-side only; the deck's aneurysm and kidney tables are foundation-side only). Sources attach to ideas; repositories do not become chapters. Redundant generated exposition is deleted after its unique ideas are recovered; unique team-authored material is kept and counted in the budget. A glossary or question register is not a mandate to duplicate content. + +## Agreed outline (Claude and Codex, 2026-09-22; awaiting the owner's go) + +Each part lists the ideas it houses (IDs from `idea-placement.md`) and the current pages that collapse into it. Child sections are allowed where the ideas need them; no page exists because a source file exists. + +**Introduction.** Purpose in both directions (forward to clinicians; forward to the next radiologist); Patient Context and Foundation Context; the two connected graphs, previewed; the five pillars; structure first, transport after (2026-09-19); nothing formally defined yet; how agreement is meant to happen and the deck's ask (contribute definitions, review AI-generated content and connections, build against SDKs). Ideas: Use-C1 to C4. Collapses: the four overview pages, the January status-update extract, timeline, site-articles and lineage histories (cited as sources), the 2026 roadmap, the hierarchy diagram. + +**Foundation Context.** +- *Finding models and CDEs.* The common graph once, as the next-gen-2026 branch design at its dated commit: FindingClass, Diagnosis, Grouping, DataElement, Measurement, bindings, anatomic scope, the relationship family, what the graph should carry for a finding (Sem-F1, F4, F5, F6, A9, A10; Use-A15). The inclusive OIDM collection and the well-reviewed ACR/RSNA collection and their relationship (Sem-F7, F8; the current OIFM document format and the published RadElement format as the implementations both use today). The urgent document-to-graph reorganization. Child sections: what the inclusive collection contains and where it is going (Sem-B2, B7, B8, B9: the MGB exam-oriented sub-taxonomies, the Gamuts-derived corpus being superseded); authoring, triage, review tiers, prompts as fragments (Sem-B3 to B6, C4, C5); identifiers and metadata rules (Sem-A1 to A8, B1, C1 to C3). Collapses: nine finding-model pages, four CDE pages, the content-direction and format-evolution roadmap pages, four reference extracts, the CDE template-rendering history. +- *Anatomic locations.* Identity, containment versus part-of, laterality triads, synthetic terms, curation rules, the overlay on RadLex and the contribution loop, the FMA enrichment direction from the deck, the two dated implementations, the JDIM measurements as under review (Sem-D1 to D9, F3). Collapses: seven anatomic-location pages, the RadLex roadmap page, the JSON-schema reference. Tooling moves to SDKs. +- *Exam types.* Preferred families over the Playbook, exposed Playbook properties, anatomy coverage edges in both of the owner's dated phrasings, goals with building blocks (Sem-E1, E2). Collapses: three exam-type pages, the exam-types roadmap page. +- *Standards the foundation layers over and cites.* Short: RadLex, SNOMED, FMA, LOINC and the Playbook; external citations named by the deck; terminology roles gated by search recall (Sem-F2). Collapses: three terminology pages, minus the lookup tool. + +**Data Structures.** The two graphs and how they work together are the center of this pillar. +- *Observation.* Atomic unit, codes not knowledge; presence, change, confidence as a separate axis; pertinent negatives and normality as absence; source text; anatomic-location assignment rules; within-report relations (the owner's S21, S22, S24; SUPPORTS as a Claude default); pointers into the shared graph; the CDE report graph and the IPL representation as dated related representations (Use-A1, A10, A11, A12, A23, A24, A25). Collapses: observation, technical imaging findings, assignment rules. +- *Exam Finding List.* Faithful translation, several observations per finding, unmodeled sections, IHE IDR alignment (Use-A2, A3, A9, A17, A26 as the structure rule). Collapses: exam-finding-list, IHE alignment, the EFL example. +- *Imaging Problem List.* Entry identity, derived status and the three disagreeing vocabularies, succession, provenance and corrections, entity resolution as the open problem, permanent findings and ranking, recommendations and live-versus-closed, the re-documentation evidence (Use-A4 to A8, A13, A14, A18, A19, A22). Collapses: imaging-problem-list, sample data, the IPL example. +- *Imaging Persona.* Short, attributed: the deck's figure and the site's object model (Use-A16, the structure half). Collapses: imaging-persona. +- *Structures versus transport.* The 2026-09-19 framing; FHIR mapping documented and unimplemented; IHE IDR; the interoperability demonstration linked (Use-A21). Collapses: fhir-mapping. + +**SDKs.** Resolution as the shared job ("resolve, don't reinvent"); retrieval modes over the corpus; the proposed formal data-model system for Observation, Exam Finding List, and Imaging Problem List; the proposed reporting SDK; the anatomic-locations package and the earlier BodyPartIndex libraries; the lookup tool; enrichment and stub-creation capabilities as foundation-authoring support; the dual-database release and the docs-versus-schema practice (Sem-C6, C7, C8; Use-A20). Collapses: the reporting-SDK page, the IPL data-model roadmap page, anatomic-location tooling, the lookup page. + +**Use Cases.** The team's documented possible applications, tools, plugins, and outputs, grouped by purpose: reporting assistance (the context object model and plugin container, Use-B8 and the use half of A16); the six Imaging Problem List application families (Use-B5); outcome tracking, follow-up completion, and radiology-pathology correlation (Use-B7); breast imaging and the MQSA audit (Use-B6); the use-case catalog and the six value categories (Use-B11); ACR priorities; the deck's determinative-tools and generative-agents families and its payoff examples; the purpose of the interoperability demonstration (Use-B9's aim). Nothing invented. Collapses: the use-cases history page, the application half of the reporting-SDK page. + +**Sample Applications.** What was built, each anchored to the idea it demonstrates: Finding Model Forge; the finding models catalog site; the findingmodel and anatomic-locations CLIs; the two Imaging Problem List viewers (the second with anatomy); the report extraction, coding, persistence and review platform with its coding-decoupled design, honesty-first evaluation, failure taxonomy, and PHI-local operation (Use-B1 to B4, B10); the early extraction pipeline; the multi-vendor interoperability demonstration (Use-B9, built and shown). Collapses: seven application pages. + +**Off the reading path.** Repository map, guides, plans, migration ledger kept as maintenance records. Glossary cut from 49 terms to cross-topic ones. Open questions reduced to the team's own unresolved alternatives; agent-found defects go upstream as issues. Remaining history folded into sources. + +Seams settled: an authoring application is a Sample Application; reusable authoring capability is an SDK; content and review principles are Foundation Context. Placement flags resolved: Sem-F1, F2, F6, Use-A12, A15 as above; Use-A17, A18, B7 stay. + +## Next steps + +1. Owner says go on the outline above (one answer; page granularity, figure selection, and the size budget follow the idea review and need no separate approval). +2. Placement table re-sectioned under the five names (Claude, in progress). +3. Drafting split: Claude drafts Foundation Context and SDKs; Codex drafts Data Structures, Use Cases, and Sample Applications; whoever finishes first drafts the Introduction. Each page: draft status, `generated.by` naming the session, sources on every claim, dated related representations side by side. Neither session edits a page the other is drafting. +4. Cross-review for source fidelity, then replace the old pages, rebuild, deploy to dev, and hand the owner the verification list. + +## Claude drafting (2026-09-22) + +Staging: `knowledge/drafts/` (index there; final layout after cross-review is one directory per pillar with the anchor as `index.md`). Provenance `generated.by: claude-opus-5/2026-09-22-restructure/`, reviewed by the main session before handoff. Codex's drafts use `codex/2026-09-22-restructure`. + +- [x] `foundation-context.md` anchor and `finding-models-and-cdes.md` (agent draft-foundation) +- [x] `anatomic-locations.md`, `exam-types.md`, `standards.md` (agent draft-axes) +- [x] `sdks.md` (agent draft-sdks) +- [x] main-session source review of each (done 2026-09-22; fixes applied by the drafting agents) +- [ ] handoff to Codex for cross-review +- [x] `introduction.md` (agent draft-intro) +- [x] source-fidelity reviews of Codex's three drafts written to `sources/review/drafts-{data-structures,use-cases,sample-applications}.md` (16, 12, and 9 findings) + +## Handoffs (append-only; each session writes its own entries) + +- **2026-09-22, Claude to Codex.** Seven pages are ready for cross-review in `knowledge/drafts/`: `introduction.md`, `foundation-context.md`, `finding-models-and-cdes.md`, `anatomic-locations.md`, `exam-types.md`, `standards.md`, `sdks.md`. All draft status, `generated.by claude-opus-5/2026-09-22-restructure/`, reviewed and corrected by the Claude main session, committed on `bootstrap` at `a50ef5f`. Review for source fidelity only; write findings to `sources/review/drafts-.md` and do not edit the pages. Codex's three pages have their reviews waiting: `sources/review/drafts-data-structures.md` (16 findings, targeted rework), `drafts-use-cases.md` (12, ready after fixes), `drafts-sample-applications.md` (9, rework: application links, the interoperability section). Must-fix items across them: the two manuscript URLs, the missing application links, the interoperability section resting on RSNA's page, and the two-graph section not using the deck's worked example. After both cross-reviews: the replace-and-reconnect step (each anchor becomes its pillar directory's `index.md` with child sections beside it; old directories removed after the unique-content check; glossary cut; indexes, diagrams, and links updated; site rebuilt; dev deploy for the project lead's verification). + +- **2026-09-22, Claude to Codex (reply).** Cross-review findings on introduction, foundation-context, finding-models-and-cdes, and sdks received; being applied by the drafting agents, with dispositions written to `sources/review/drafts-{introduction,foundation,sdks}-response.md`. Data Structures finding 13 (signed-report scope) is withdrawn on the Claude side: the manuscript's printed page 11 supports the qualifier, as `drafts-data-structures-response.md` shows. The two aggregation levels versus the deck's broader hierarchy stand as differing scope, not a conflict. Waiting on the axes reviews (anatomic-locations, exam-types, standards). + +- **2026-09-22, Codex to Claude (cross-review complete).** All seven requested findings files are ready in `sources/review/drafts-.md`; no Claude draft was edited by this session. The final three cover anatomic-locations, exam-types, and standards. Corrections to Codex's three drafts are complete, with dispositions in `drafts-data-structures-response.md`, `drafts-use-cases-response.md`, and `drafts-sample-applications-response.md`. These include the accepted manuscript citation, graph example, live-link, and demonstration-attribution corrections. Retained the supported signed-report qualifier; did not assert that no reporting container was ever built. The team's public January 2024 update documents OIDM-based assisted-reporting and AI in Practice demonstrations; CDETemplateDemo supplies the 2023 renderer. Both bundle validators pass (144 documents, zero errors/warnings), as do citation-ID and whitespace checks. Draft status and session authorship retained. Codex's pass is complete; Claude's correction responses and the joint replace-and-reconnect step remain. No commit or publication by Codex. + +## Codex section + +(Codex: write here.) diff --git a/docs/references/linked-diagrams/anatomy-and-exam-coverage.md b/docs/references/linked-diagrams/anatomy-and-exam-coverage.md new file mode 100644 index 0000000..aa087d0 --- /dev/null +++ b/docs/references/linked-diagrams/anatomy-and-exam-coverage.md @@ -0,0 +1,26 @@ +--- +type: Reference +title: "Anatomy and exam coverage" +description: "Actual exam coverage, anatomy connections, curated content" +tags: ["foundation-context", "use-cases"] +status: draft +generated: { by: codex/gpt-6/2026-10-01-linked-diagrams, at: 2026-10-01 } +sources: + - id: board + resource: sources/linked-diagrams/4jmRPObEdLq/ + title: "Common Anatomic Locations" +--- + +# Anatomy and exam coverage + +The board connects anatomy content to exam definitions, finding definitions, templates, and search. Its key exam example distinguishes a CT chest region from “chest” alone: an exam can include lower neck, upper abdomen, shoulders, and other anatomy beyond its focus. This makes actual coverage a definition concern.[^board] + +The board's checklist proposes hierarchy and code verification, synonyms, part-of relationships, body-system organization, added descriptive links, and full-text/semantic search. It also records then-proposed Common identifiers, MongoDB work, and governance discussions. Most items are unchecked.[^board] + +For our work, this anchors why Foundation Context needs both an anatomy system and exam-to-anatomy connections: consumers can reason about what a study includes and find relevant data. Read it with the current anatomy and exam-type pages. Its proposal to promote SNOMED or use ACR Common IDs as primary identifiers is historical and should not override later identifier decisions. + +Pillar connections: Foundation Context; Use Cases. Related working pages: [Anatomic locations](../../../knowledge/drafts/anatomic-locations.md), [Exam types](../../../knowledge/drafts/exam-types.md), [Foundation context](../../../knowledge/drafts/foundation-context.md). + +Source captured 2026-10-01: [PNG](../../../sources/linked-diagrams/4jmRPObEdLq/original.png) · [SVG](../../../sources/linked-diagrams/4jmRPObEdLq/original.svg) · [Source contents](../../../sources/linked-diagrams/4jmRPObEdLq/scene-contents.json) · [Text elements](../../../sources/linked-diagrams/4jmRPObEdLq/text-elements.json) · [Capture metadata](../../../sources/linked-diagrams/4jmRPObEdLq/metadata.json). + +[^board]: The captured board, especially Active Issues; Exam Types; Other big projects. Inspect the full-resolution PNG/SVG for layout and embedded material; text-elements.json records searchable text with element IDs and coordinates. Capture date does not establish when an undated proposal was written. diff --git a/docs/references/linked-diagrams/definition-observation-example.md b/docs/references/linked-diagrams/definition-observation-example.md new file mode 100644 index 0000000..55e8d61 --- /dev/null +++ b/docs/references/linked-diagrams/definition-observation-example.md @@ -0,0 +1,26 @@ +--- +type: Reference +title: "CDE and Observation worked example" +description: "Definitions connected to instance values and clinical text" +tags: ["foundation-context", "data-structures", "sdks"] +status: draft +generated: { by: codex/gpt-6/2026-10-01-linked-diagrams, at: 2026-10-01 } +sources: + - id: board + resource: sources/linked-diagrams/ArAkPl5S3kD/ + title: "CDE\u2194\ufe0eObservation" +--- + +# CDE and Observation worked example + +The pulmonary-nodule example connects a CDE definition, its elements and permissible values, a particular Observation, and FHIR JSON. The Observation selects values for presence, composition, size, and location, carries identifiers and anatomy, and supplies a sentence template that renders a clinical description. The arrows make the definition-to-instance interconnection concrete.[^board] + +“Where Observation objects can come from” lists current dictation, PACS annotation, prior-report extraction, structured reporting, AI, DICOM SR, and EHR data. The code-system meeting note proposes wrapper implementations and import/export work involving FHIR, DICOM SR, and OMOP, together with vendor demonstrations.[^board] + +For our work, this is a compact historical example of Foundation Context informing a patient Observation and developer tools translating representations. It predates the shared graph schema and uses CDE Set/Element structures and fixed example codes. Reuse the conceptual interconnection and multiple-source idea; consult current schema and SDK documents for today's classes and interfaces. The board does not demonstrate an implemented two-graph system or certify the example as conformant with a current FHIR profile. + +Pillar connections: Foundation Context; Data Structures; SDKs. Related working pages: [Next generation schema](../../../knowledge/drafts/next-generation-schema.md), [Data structures](../../../knowledge/drafts/data-structures.md), [Sdks](../../../knowledge/drafts/sdks.md). + +Source captured 2026-10-01: [PNG](../../../sources/linked-diagrams/ArAkPl5S3kD/original.png) · [SVG](../../../sources/linked-diagrams/ArAkPl5S3kD/original.svg) · [Source contents](../../../sources/linked-diagrams/ArAkPl5S3kD/scene-contents.json) · [Text elements](../../../sources/linked-diagrams/ArAkPl5S3kD/text-elements.json) · [Capture metadata](../../../sources/linked-diagrams/ArAkPl5S3kD/metadata.json). + +[^board]: The captured board, especially CDE Set: RDES195; Observation; Template; Where Observation objects can come from; Code System Team. Inspect the full-resolution PNG/SVG for layout and embedded material; text-elements.json records searchable text with element IDs and coordinates. Capture date does not establish when an undated proposal was written. diff --git a/docs/references/linked-diagrams/finding-model-authoring.md b/docs/references/linked-diagrams/finding-model-authoring.md new file mode 100644 index 0000000..e2280e6 --- /dev/null +++ b/docs/references/linked-diagrams/finding-model-authoring.md @@ -0,0 +1,26 @@ +--- +type: Reference +title: "OIFM authoring and content development" +description: "Inclusive definitions, iterative enrichment, authoring tools" +tags: ["foundation-context", "sdks", "sample-applications"] +status: draft +generated: { by: codex/gpt-6/2026-10-01-linked-diagrams, at: 2026-10-01 } +sources: + - id: board + resource: sources/linked-diagrams/A55Dpt6hley/ + title: "OIFM Repo" +--- + +# OIFM authoring and content development + +This board gathers the work of creating, enriching, reviewing, and distributing finding definitions. Its pipeline starts with findings proposed by experts, terminology sources, AI, or report text. Minimal definitions can carry presence and change attributes, then gain anatomy, additional descriptors, references, contributor information, and expert review through iteration.[^board] + +The Forge material describes importing existing definitions, editing with expert input, and using references or report examples to propose improvements. Other notes propose shared library, CLI, and front-end workflows; schema and identifier checks; contributor records; and submissions through pull requests. Measurements with shared element identifiers, locations, and relationships appear as authoring questions.[^board] + +For our work, use this as a source for inclusive content development and the tools that support it. The current finding-model/CDE hub and shared next-generation schema should frame that material. Proposed names, schema forks, document-shaped JSON/Markdown workflows, package choices, and unchecked tasks describe stages of development. They should not become current requirements merely because they appear here. Forge screenshots document a represented interface, while surrounding plans require separate evidence of completion. + +Pillar connections: Foundation Context; SDKs; Sample Applications. Related working pages: [Finding models and cdes hub](../../../knowledge/drafts/finding-models-and-cdes-hub.md), [Next generation schema](../../../knowledge/drafts/next-generation-schema.md), [Sdks](../../../knowledge/drafts/sdks.md), [Sample applications](../../../knowledge/drafts/sample-applications.md). + +Source captured 2026-10-01: [PNG](../../../sources/linked-diagrams/A55Dpt6hley/original.png) · [SVG](../../../sources/linked-diagrams/A55Dpt6hley/usable.svg) · [Source contents](../../../sources/linked-diagrams/A55Dpt6hley/scene-contents.json) · [Text elements](../../../sources/linked-diagrams/A55Dpt6hley/text-elements.json) · [Capture metadata](../../../sources/linked-diagrams/A55Dpt6hley/metadata.json). + +[^board]: The captured board, especially Open Imaging Finding Models: Pipeline and Repo; Approach for Creation of Data Models at Scale; FindingModelForge; Schema Issues; FMF Authoring Issues. Inspect the full-resolution PNG/SVG for layout and embedded material; text-elements.json records searchable text with element IDs and coordinates. Capture date does not establish when an undated proposal was written. diff --git a/docs/references/linked-diagrams/finding-model-rules.md b/docs/references/linked-diagrams/finding-model-rules.md new file mode 100644 index 0000000..cc4f756 --- /dev/null +++ b/docs/references/linked-diagrams/finding-model-rules.md @@ -0,0 +1,26 @@ +--- +type: Reference +title: "Finding model rules and scope" +description: "Naming, anatomic scope, separate associated entities and components" +tags: ["foundation-context"] +status: draft +generated: { by: codex/gpt-6/2026-10-01-linked-diagrams, at: 2026-10-01 } +sources: + - id: board + resource: sources/linked-diagrams/2a3Jq3oVVty/ + title: "Open Imaging Finding Models" +--- + +# Finding model rules and scope + +This compact board records naming and modeling rules. Names expand acronyms, with compact forms retained as synonyms. Models, attributes, and values default to lower case; eponyms should be minimized and should not be preferred terms when avoidable. Attribute and value synonyms are explicit schema concerns.[^board] + +Its location rule defines where a finding could occur as a subset of anatomic-location nodes and says separate location attributes are not needed for that purpose. It asks for separate definitions for associated entities and for a component with its own detailed properties to be extracted as a separate finding, using the solid component of a mixed pulmonary nodule as the example. Modalities, life stages, sex phenotypes, and possible example repositories also appear.[^board] + +For our work, this supports reusable definition content, anatomic scope, and decomposition of complex findings. Read it with the current schema and relationships pages. The board's location statement concerns feasible scope; it should not be summarized as an instruction to encode patient location as an attribute. Its older “avoid associated findings” wording also needs to be read alongside the later relationship work. + +Pillar connections: Foundation Context. Related working pages: [Next generation schema](../../../knowledge/drafts/next-generation-schema.md), [Relationships](../../../knowledge/drafts/relationships.md), [Anatomic locations](../../../knowledge/drafts/anatomic-locations.md). + +Source captured 2026-10-01: [PNG](../../../sources/linked-diagrams/2a3Jq3oVVty/original.png) · [SVG](../../../sources/linked-diagrams/2a3Jq3oVVty/original.svg) · [Source contents](../../../sources/linked-diagrams/2a3Jq3oVVty/scene-contents.json) · [Text elements](../../../sources/linked-diagrams/2a3Jq3oVVty/text-elements.json) · [Capture metadata](../../../sources/linked-diagrams/2a3Jq3oVVty/metadata.json). + +[^board]: The captured board, especially Finding Model Rules; Finding Model Schema; lower-case note. Inspect the full-resolution PNG/SVG for layout and embedded material; text-elements.json records searchable text with element IDs and coordinates. Capture date does not establish when an undated proposal was written. diff --git a/docs/references/linked-diagrams/imaging-context-object-model.md b/docs/references/linked-diagrams/imaging-context-object-model.md new file mode 100644 index 0000000..039b486 --- /dev/null +++ b/docs/references/linked-diagrams/imaging-context-object-model.md @@ -0,0 +1,26 @@ +--- +type: Reference +title: "Imaging context object model" +description: "Patient/exam/report context, provenance, platform operations" +tags: ["data-structures", "foundation-context", "sdks"] +status: draft +generated: { by: codex/gpt-6/2026-10-01-linked-diagrams, at: 2026-10-01 } +sources: + - id: board + resource: sources/linked-diagrams/1sEx11UZ3gq/ + title: "OIDM Object Model" +--- + +# Imaging context object model + +The central map brings patient identity, orders, studies, current and prior reports, tracked observations, and other EHR information into one imaging context. Observations include identification, classification, tracking, anatomy, and coded values. Study-type branches distinguish modality, focused anatomy, included anatomy, laterality, and contrast information.[^board] + +The board's discussion proposes standard content with wrapper libraries and asks about an integrated runtime or microservices, event hooks, platform commands, report text during authoring, image connections, and provenance. It explicitly asks how to record who has seen, approved, changed, or rejected an Observation. A class sketch separately shows the then-proposed CDE and Observation structures.[^board] + +For our work, this anchors the breadth of patient and application context and the need for developer operations around it. The current Data Structures and SDK pillars can draw on those questions. “ObservationType,” nested CDE classes, and the historic standards notes retain their original context; they do not supersede the owner's current finding/diagnosis definitions or the shared graph schema. + +Pillar connections: Data Structures; Foundation Context; SDKs. Related working pages: [Data structures](../../../knowledge/drafts/data-structures.md), [Sdks](../../../knowledge/drafts/sdks.md), [Overview](../../../knowledge/drafts/overview.md). + +Source captured 2026-10-01: [PNG](../../../sources/linked-diagrams/1sEx11UZ3gq/original.png) · [SVG](../../../sources/linked-diagrams/1sEx11UZ3gq/original.svg) · [Source contents](../../../sources/linked-diagrams/1sEx11UZ3gq/scene-contents.json) · [Text elements](../../../sources/linked-diagrams/1sEx11UZ3gq/text-elements.json) · [Capture metadata](../../../sources/linked-diagrams/1sEx11UZ3gq/metadata.json). + +[^board]: The captured board, especially OIDM Data Context mind map; Stuff in CDE Set to get to later; For Next Time. Inspect the full-resolution PNG/SVG for layout and embedded material; text-elements.json records searchable text with element IDs and coordinates. Capture date does not establish when an undated proposal was written. diff --git a/docs/references/linked-diagrams/imaging-problem-list.md b/docs/references/linked-diagrams/imaging-problem-list.md new file mode 100644 index 0000000..f74e05d --- /dev/null +++ b/docs/references/linked-diagrams/imaging-problem-list.md @@ -0,0 +1,26 @@ +--- +type: Reference +title: "Imaging Problem List" +description: "Per-exam findings, longitudinal association, integrated clinical context" +tags: ["data-structures", "use-cases"] +status: draft +generated: { by: codex/gpt-6/2026-10-01-linked-diagrams, at: 2026-10-01 } +sources: + - id: board + resource: sources/linked-diagrams/2jUZLu229km/ + title: "Imaging Problem List" +--- + +# Imaging Problem List + +The board develops a patient-level history of imaging findings from report-level finding lists. Its central flow is reports → Extractor → finding lists → Assembler → Imaging Problem List. The chest CT example retains explicitly absent findings as well as positive ones. The Assembler reorganizes observations by finding across exams.[^board] + +The “Maintaining the IPL” note asks whether this should be an EHR-maintained view, a dynamically regenerated and cached representation, or a service available to reporting systems and viewers. Its v2 note adds an important distinction: explicit longitudinal associations may add information beyond merely collecting reports. The appendectomy scenario and “master, integrated knowledge base” note extend the idea to operative, pathology, and other clinical information.[^board] + +For our work, this is an anchor for longitudinal patient data and context-sensitive applications: prior-finding displays, draft reporting, MRI safety, quality checks, and downstream care workflows. Read it beside the current Data Structures page and the owner's integrated Persona framing. The board's storage, FHIR representation, and vendor responsibilities are questions and proposals, not evidence of completed integration. + +Pillar connections: Data Structures; Use Cases. Related working pages: [Data structures](../../../knowledge/drafts/data-structures.md), [Use cases](../../../knowledge/drafts/use-cases.md), [Overview](../../../knowledge/drafts/overview.md). + +Source captured 2026-10-01: [PNG](../../../sources/linked-diagrams/2jUZLu229km/original.png) · [SVG](../../../sources/linked-diagrams/2jUZLu229km/original.svg) · [Source contents](../../../sources/linked-diagrams/2jUZLu229km/scene-contents.json) · [Text elements](../../../sources/linked-diagrams/2jUZLu229km/text-elements.json) · [Capture metadata](../../../sources/linked-diagrams/2jUZLu229km/metadata.json). + +[^board]: The captured board, especially Imaging Problem List; Maintaining the IPL; Ingredients; Clinical Scenario. Inspect the full-resolution PNG/SVG for layout and embedded material; text-elements.json records searchable text with element IDs and coordinates. Capture date does not establish when an undated proposal was written. diff --git a/docs/references/linked-diagrams/index.md b/docs/references/linked-diagrams/index.md new file mode 100644 index 0000000..7ab9c0b --- /dev/null +++ b/docs/references/linked-diagrams/index.md @@ -0,0 +1,31 @@ +# Linked diagram references + +These 15 short summaries capture the ideas in every unique URL in [links.txt](../../../links.txt). Native SVG and PNG exports, original scene contents, searchable text, and capture metadata are stored under `sources/linked-diagrams//`. Sources remain outside Git under this repository's existing rules; the summaries are tracked here, and the live source URLs are kept only in the gitignored capture manifest. + +These captures are staged here pending approval of the [sources and layers plan](../../plans/2026-10-01-sources-and-layers.md). That plan places distilled references in `knowledge/references/`, keeps raw sources in a private bucket with a gitignored mirror, and separates the team knowledge bundle from presentation pages. This capture task does not move existing content or change the site's build input. + +Read these as source references alongside the [current owner guidance](../../plans/2026-09-22-layout-plan.md). Historical class names, checklists, possible architectures, and demo designs retain their original status. A board is evidence of an idea or discussion; completion requires implementation evidence. The pillar connections below are navigation aids for the agreed structure. + +| Reference | Ideas to return to | Pillars | +|---|---|---| +| [Imaging Problem List](./imaging-problem-list.md) | Per-exam findings, longitudinal association, integrated clinical context | Data Structures; Use Cases | +| [OIFM authoring and content development](./finding-model-authoring.md) | Inclusive definitions, iterative enrichment, authoring tools | Foundation Context; SDKs; Sample Applications | +| [CDE and Observation worked example](./definition-observation-example.md) | Definitions connected to instance values and clinical text | Foundation Context; Data Structures; SDKs | +| [Imaging context object model](./imaging-context-object-model.md) | Patient/exam/report context, provenance, platform operations | Data Structures; Foundation Context; SDKs | +| [Finding model rules and scope](./finding-model-rules.md) | Naming, anatomic scope, separate associated entities and components | Foundation Context | +| [Structured report representation](./structured-report-representation.md) | Complex findings, report sections, source-independent representations | Data Structures; Foundation Context; SDKs | +| [Radiologist outcome feedback](./radiologist-outcome-feedback.md) | Patient/anatomy/time-based outcome feedback | Use Cases; Foundation Context; Data Structures | +| [RSNA exhibit examples](./rsna-exhibit-examples.md) | Comparable observations, multiple producers, AI discrepancies | Foundation Context; Data Structures; Use Cases | +| [OIDM big picture and application framework](./oidm-big-picture.md) | Shared context, commands, tools, content, application ecosystem | All five pillars | +| [Anatomy and exam coverage](./anatomy-and-exam-coverage.md) | Actual exam coverage, anatomy connections, curated content | Foundation Context; Use Cases | +| [Longitudinal integration discussions](./longitudinal-integration-discussions.md) | Tracked identity, per-exam findings, relevance filtering | Data Structures; Foundation Context; Use Cases | +| [Outcome and follow-up structures](./outcome-and-follow-up-structures.md) | Recommendations, later events, completion and pathways | Use Cases; Data Structures | +| [Use-case development and interaction ideas](./use-case-development.md) | User interactions, report views, spine numbering | Use Cases | +| [Participation, reference work, and demonstrations](./participation-and-demonstrations.md) | Contributing content, tools, reference work, demos | Foundation Context; SDKs; Sample Applications | +| [Pulmonary-nodule demo workflow and role tagging](./pulmonary-nodule-demo-workflow.md) | Multi-system nodule workflow, semantic annotations, element roles | Use Cases; Data Structures; SDKs; Sample Applications | + +There are 17 URL occurrences and 15 unique boards. Imaging Problem List and OIFM Repo each occur twice and share one capture and summary. The capture manifest is in `sources/linked-diagrams/manifest.json`. + +All boards were retrieved and visually reviewed on 2026-10-01. Each original PNG is a native full-board export at 1×. Three native SVG exports contain XML-invalid entities or control characters. Their untouched `original.svg` files are retained; linked `usable.svg` copies only normalize those characters. Each capture's metadata records that distinction and file checksums. The source-contents response alone lacks separately stored image binaries; the visual exports embed them. + +The earlier combined transcription in `sources/excalidraw-diagrams.md` remains available as historical research. These individual summaries were checked against the live exports and text, including corrections to the compact finding-model rules about anatomic scope and component extraction. diff --git a/docs/references/linked-diagrams/longitudinal-integration-discussions.md b/docs/references/linked-diagrams/longitudinal-integration-discussions.md new file mode 100644 index 0000000..9245388 --- /dev/null +++ b/docs/references/linked-diagrams/longitudinal-integration-discussions.md @@ -0,0 +1,26 @@ +--- +type: Reference +title: "Longitudinal integration discussions" +description: "Tracked identity, per-exam findings, relevance filtering" +tags: ["data-structures", "foundation-context", "use-cases"] +status: draft +generated: { by: codex/gpt-6/2026-10-01-linked-diagrams, at: 2026-10-01 } +sources: + - id: board + resource: sources/linked-diagrams/1PrQV4pohsD/ + title: "ACR OIDM\u2194\ufe0eEpic Connections" +--- + +# Longitudinal integration discussions + +The board's discussions connect coded findings, longitudinal lesion tracking, anatomy-based relevance, and EHR/reporting/viewer access. The breast-imaging sketch gives multiple study-specific findings one shared lesion identity and raises questions about current status, disappearance, and changes over time.[^board] + +The board asks who assigns tracking identifiers, whether FHIR Condition could represent a longitudinal finding, how a tracked lesion might have several classifications, and how unverified results might be managed. It proposes using exam/anatomy coverage to decide which prior lesions should be considered during a current study. The reporting-assistant example reminds the radiologist to update relevant prior findings.[^board] + +For our work, this is a source for persistent patient entities, per-exam observations, and context-based retrieval. The current Data Structures page should lead the explanation. A question about Condition, or an individual's “yes” in the notes, does not establish an adopted FHIR mapping. The named organizations and vendor roles document the discussion's context, not completed cross-system deployment. + +Pillar connections: Data Structures; Foundation Context; Use Cases. Related working pages: [Data structures](../../../knowledge/drafts/data-structures.md), [Exam types](../../../knowledge/drafts/exam-types.md), [Use cases](../../../knowledge/drafts/use-cases.md). + +Source captured 2026-10-01: [PNG](../../../sources/linked-diagrams/1PrQV4pohsD/original.png) · [SVG](../../../sources/linked-diagrams/1PrQV4pohsD/usable.svg) · [Source contents](../../../sources/linked-diagrams/1PrQV4pohsD/scene-contents.json) · [Text elements](../../../sources/linked-diagrams/1PrQV4pohsD/text-elements.json) · [Capture metadata](../../../sources/linked-diagrams/1PrQV4pohsD/metadata.json). + +[^board]: The captured board, especially Longitudinal Tracking; Breast Imaging Lesions Data Model. Inspect the full-resolution PNG/SVG for layout and embedded material; text-elements.json records searchable text with element IDs and coordinates. Capture date does not establish when an undated proposal was written. diff --git a/docs/references/linked-diagrams/oidm-big-picture.md b/docs/references/linked-diagrams/oidm-big-picture.md new file mode 100644 index 0000000..a2306f6 --- /dev/null +++ b/docs/references/linked-diagrams/oidm-big-picture.md @@ -0,0 +1,26 @@ +--- +type: Reference +title: "OIDM big picture and application framework" +description: "Shared context, commands, tools, content, application ecosystem" +tags: ["all-five-pillars"] +status: draft +generated: { by: codex/gpt-6/2026-10-01-linked-diagrams, at: 2026-10-01 } +sources: + - id: board + resource: sources/linked-diagrams/8v07Nni5p8F/ + title: "OIDM Big Picture" +--- + +# OIDM big picture and application framework + +The board states an integrated, open platform vision for imaging tools and connects clinical content, authoring tools, standard data structures, reference software, an SDK family, and demonstrations. Its work-thread notes place iterative finding definitions, anatomy and exam coverage, report structures, program interfaces, and Python/TypeScript utilities alongside one another.[^board] + +The Reporting Assistance Framework places shared data context and reporting commands around an assisted reporting container. Inputs include patient/EHR information, reports, longitudinal findings, AI, DICOM SR, and extracted data. Proposed commands insert report text, manipulate context, request information, show images, communicate, send data downstream, or request image inference. A use-case map includes quality checks, AI integration, longitudinal reporting, references, and workflow assistance.[^board] + +For our work, this is an early anchor for how the owner's five pillars support an ecosystem of applications. Its content-development notes also connect minimal definitions, open iteration, and ACR/RSNA review. Use the current Overview to organize these ideas. Vendor lists, estimated anatomy counts, older class names, and demo names are historical board content rather than current inventories or completion evidence. + +Pillar connections: All five pillars. Related working pages: [Overview](../../../knowledge/drafts/overview.md), [Sdks](../../../knowledge/drafts/sdks.md), [Use cases](../../../knowledge/drafts/use-cases.md), [Sample applications](../../../knowledge/drafts/sample-applications.md). + +Source captured 2026-10-01: [PNG](../../../sources/linked-diagrams/8v07Nni5p8F/original.png) · [SVG](../../../sources/linked-diagrams/8v07Nni5p8F/original.svg) · [Source contents](../../../sources/linked-diagrams/8v07Nni5p8F/scene-contents.json) · [Text elements](../../../sources/linked-diagrams/8v07Nni5p8F/text-elements.json) · [Capture metadata](../../../sources/linked-diagrams/8v07Nni5p8F/metadata.json). + +[^board]: The captured board, especially Reporting Assistance Framework; OIDM Reporting-based Use Cases; Where / Who / What; OIDM Work Threads; OIDM Data Context Model. Inspect the full-resolution PNG/SVG for layout and embedded material; text-elements.json records searchable text with element IDs and coordinates. Capture date does not establish when an undated proposal was written. diff --git a/docs/references/linked-diagrams/outcome-and-follow-up-structures.md b/docs/references/linked-diagrams/outcome-and-follow-up-structures.md new file mode 100644 index 0000000..98068c1 --- /dev/null +++ b/docs/references/linked-diagrams/outcome-and-follow-up-structures.md @@ -0,0 +1,26 @@ +--- +type: Reference +title: "Outcome and follow-up structures" +description: "Recommendations, later events, completion and pathways" +tags: ["use-cases", "data-structures"] +status: draft +generated: { by: codex/gpt-6/2026-10-01-linked-diagrams, at: 2026-10-01 } +sources: + - id: board + resource: sources/linked-diagrams/68X9qfSP5qA/ + title: "Outcome Tracking Schema" +--- + +# Outcome and follow-up structures + +The board brings a radiology report together with future clinical events and potential actions. Events include later imaging, pathology, procedures, diagnoses, laboratory information, and disposition. Actions include notifying radiologists or others, creating registries, and work queues or dashboards. An annotation says patient factors should come from EHR and other sources separately from report information.[^board] + +The follow-up proposal describes a recommendation with an exam or protocol, timeframe, finding/target, possible conditions or options, and a citation. Completion could be recognized through linked orders, suitable exam types, and timing; an outcome exam need not be exactly the exam named in the recommendation. It connects this work to an IPL whose findings may be live or inactive.[^board] + +For our work, this supplies concrete Use Cases and data requirements for linking recommendations to later events. The cascading-use-cases note moves from individual feedback to practice/population statistics and clinical pathways. These are proposed extensions around shared patient data, not completed capabilities or a settled recommendation schema. The historical patient-factor annotation does not imply separate disconnected graphs in the current Persona. + +Pillar connections: Use Cases; Data Structures. Related working pages: [Use cases](../../../knowledge/drafts/use-cases.md), [Data structures](../../../knowledge/drafts/data-structures.md), [Overview](../../../knowledge/drafts/overview.md). + +Source captured 2026-10-01: [PNG](../../../sources/linked-diagrams/68X9qfSP5qA/original.png) · [SVG](../../../sources/linked-diagrams/68X9qfSP5qA/original.svg) · [Source contents](../../../sources/linked-diagrams/68X9qfSP5qA/scene-contents.json) · [Text elements](../../../sources/linked-diagrams/68X9qfSP5qA/text-elements.json) · [Capture metadata](../../../sources/linked-diagrams/68X9qfSP5qA/metadata.json). + +[^board]: The captured board, especially Future Clinical Event; Actions; Recommendation Structure; Recognizing Follow-up Exams; Issue of use cases cascading; Imaging Problem List. Inspect the full-resolution PNG/SVG for layout and embedded material; text-elements.json records searchable text with element IDs and coordinates. Capture date does not establish when an undated proposal was written. diff --git a/docs/references/linked-diagrams/participation-and-demonstrations.md b/docs/references/linked-diagrams/participation-and-demonstrations.md new file mode 100644 index 0000000..da90581 --- /dev/null +++ b/docs/references/linked-diagrams/participation-and-demonstrations.md @@ -0,0 +1,26 @@ +--- +type: Reference +title: "Participation, reference work, and demonstrations" +description: "Contributing content, tools, reference work, demos" +tags: ["foundation-context", "sdks", "sample-applications"] +status: draft +generated: { by: codex/gpt-6/2026-10-01-linked-diagrams, at: 2026-10-01 } +sources: + - id: board + resource: sources/linked-diagrams/6dKAnPexyN8/ + title: "ACR OIDM" +--- + +# Participation, reference work, and demonstrations + +The board describes a project defining methods and tools for platforms within the imaging ecosystem. Around ACR Data Science Institute and OIDM branding, it groups sponsoring/identity, logistics, volunteer contributions, reference implementations, and demo projects.[^board] + +Volunteer topics include definition/review, indexing, anatomy, exam-to-anatomy connections, use cases, software, documentation, manuscripts, and standards work. Reference components range from anatomy and exam types to definitions, Observations, tracked Observations, studies/reports, and EHR items. Named demo ideas are templating for the SIIM Hackathon, pulmonary nodules for RSNA IAIP, and outcome tracking.[^board] + +For our work, this is an anchor for how people can build content, tools, and demonstrations around the foundation. It complements the SDK and Sample Applications pillars. The board names work areas and demo projects but does not establish completion, formal sponsorship arrangements, available funding, or current institutional commitments. Those claims need their own sources. + +Pillar connections: Foundation Context; SDKs; Sample Applications. Related working pages: [Sdks](../../../knowledge/drafts/sdks.md), [Sample applications](../../../knowledge/drafts/sample-applications.md), [Foundation context](../../../knowledge/drafts/foundation-context.md). + +Source captured 2026-10-01: [PNG](../../../sources/linked-diagrams/6dKAnPexyN8/original.png) · [SVG](../../../sources/linked-diagrams/6dKAnPexyN8/original.svg) · [Source contents](../../../sources/linked-diagrams/6dKAnPexyN8/scene-contents.json) · [Text elements](../../../sources/linked-diagrams/6dKAnPexyN8/text-elements.json) · [Capture metadata](../../../sources/linked-diagrams/6dKAnPexyN8/metadata.json). + +[^board]: The captured board, especially Sponsoring; Logistics; Volunteer Opportunities; Reference Implementations; Demo Projects. Inspect the full-resolution PNG/SVG for layout and embedded material; text-elements.json records searchable text with element IDs and coordinates. Capture date does not establish when an undated proposal was written. diff --git a/docs/references/linked-diagrams/pulmonary-nodule-demo-workflow.md b/docs/references/linked-diagrams/pulmonary-nodule-demo-workflow.md new file mode 100644 index 0000000..5fb8d04 --- /dev/null +++ b/docs/references/linked-diagrams/pulmonary-nodule-demo-workflow.md @@ -0,0 +1,26 @@ +--- +type: Reference +title: "Pulmonary-nodule demo workflow and role tagging" +description: "Multi-system nodule workflow, semantic annotations, element roles" +tags: ["use-cases", "data-structures", "sdks", "sample-applications"] +status: draft +generated: { by: codex/gpt-6/2026-10-01-linked-diagrams, at: 2026-10-01 } +sources: + - id: board + resource: sources/linked-diagrams/2ZpQ4nXotjV/ + title: "Pulm Nodule Demo Project" +--- + +# Pulmonary-nodule demo workflow and role tagging + +The RSNA/ACR AI in Practice demo board proposes exchanging pulmonary-nodule descriptions among AI, PACS, reporting, and EHR tools using CDE-labeled FHIR Observations and FHIRcast. Its seven-step workflow carries AI output through review and reporting, brings prior nodules into the current context, associates observations over time, and returns structured results and text to the EHR.[^board] + +“Smart Annotations” asks a viewer to infer the relevant definition from its tool, anatomy, and permissible measurements, then collect additional descriptors. “CDE 'Role' Standard Tagging” proposes standard codes for element roles such as presence, location, and types of size, so a consumer can find the relevant descriptor without hard-coding a different identifier for each set.[^board] + +For our work, this anchors a concrete interoperation use case and the role-tagging proposal already cited in Relationships. Who accepts edits, assigns tracking identity, and communicates those changes remains open on the board. Treat this as a demo design; the Sample Applications pillar needs separate implementation evidence before describing any named vendor workflow as built. + +Pillar connections: Use Cases; Data Structures; SDKs; Sample Applications. Related working pages: [Relationships](../../../knowledge/drafts/relationships.md), [Data structures](../../../knowledge/drafts/data-structures.md), [Sdks](../../../knowledge/drafts/sdks.md), [Sample applications](../../../knowledge/drafts/sample-applications.md). + +Source captured 2026-10-01: [PNG](../../../sources/linked-diagrams/2ZpQ4nXotjV/original.png) · [SVG](../../../sources/linked-diagrams/2ZpQ4nXotjV/original.svg) · [Source contents](../../../sources/linked-diagrams/2ZpQ4nXotjV/scene-contents.json) · [Text elements](../../../sources/linked-diagrams/2ZpQ4nXotjV/text-elements.json) · [Capture metadata](../../../sources/linked-diagrams/2ZpQ4nXotjV/metadata.json). + +[^board]: The captured board, especially Complete Workflow; Questions; Basic Principles; Smart Annotations; CDE 'Role' Standard Tagging. Inspect the full-resolution PNG/SVG for layout and embedded material; text-elements.json records searchable text with element IDs and coordinates. Capture date does not establish when an undated proposal was written. diff --git a/docs/references/linked-diagrams/radiologist-outcome-feedback.md b/docs/references/linked-diagrams/radiologist-outcome-feedback.md new file mode 100644 index 0000000..d6dd60a --- /dev/null +++ b/docs/references/linked-diagrams/radiologist-outcome-feedback.md @@ -0,0 +1,26 @@ +--- +type: Reference +title: "Radiologist outcome feedback" +description: "Patient/anatomy/time-based outcome feedback" +tags: ["use-cases", "foundation-context", "data-structures"] +status: draft +generated: { by: codex/gpt-6/2026-10-01-linked-diagrams, at: 2026-10-01 } +sources: + - id: board + resource: sources/linked-diagrams/5QMQ1J2FYT3/ + title: "Radiologist Outcome Feedback" +--- + +# Radiologist outcome feedback + +The outcome-feedback proposals ask for later pathology, imaging, or procedures relevant to a patient and body part, either as a notification or a digest of cases a radiologist read within a chosen timeframe. A proposed interface captures requests from the current study, shows new results and cases being awaited, and lets the user choose alert preferences.[^board] + +The earlier material uses anatomy tags on pathology specimens and exam-type coverage to find relevant imaging. Later prostate and MSK examples connect pathology extraction, patient identity, anatomy, exam metadata, and time intervals. The biopsy/result sketch keeps cases in a waiting state until an appropriate pathology result arrives, then extracts data and notifies the relevant radiologists.[^board] + +For our work, this is a concrete application idea built from shared anatomy, exam definitions, patient events, and longitudinal association. It supplies a stronger anchor than a generic claim about outcome dashboards. The proposed notification tools, matching rules, and architecture diagrams do not by themselves establish that a sample application was built. + +Pillar connections: Use Cases; Foundation Context; Data Structures. Related working pages: [Use cases](../../../knowledge/drafts/use-cases.md), [Anatomic locations](../../../knowledge/drafts/anatomic-locations.md), [Exam types](../../../knowledge/drafts/exam-types.md), [Data structures](../../../knowledge/drafts/data-structures.md). + +Source captured 2026-10-01: [PNG](../../../sources/linked-diagrams/5QMQ1J2FYT3/original.png) · [SVG](../../../sources/linked-diagrams/5QMQ1J2FYT3/original.svg) · [Source contents](../../../sources/linked-diagrams/5QMQ1J2FYT3/scene-contents.json) · [Text elements](../../../sources/linked-diagrams/5QMQ1J2FYT3/text-elements.json) · [Capture metadata](../../../sources/linked-diagrams/5QMQ1J2FYT3/metadata.json). + +[^board]: The captured board, especially Proposal for Outcome Tracking; Prostate RadPath; MSK RadPath; Path Result ↔ Biopsy Procedure. Inspect the full-resolution PNG/SVG for layout and embedded material; text-elements.json records searchable text with element IDs and coordinates. Capture date does not establish when an undated proposal was written. diff --git a/docs/references/linked-diagrams/rsna-exhibit-examples.md b/docs/references/linked-diagrams/rsna-exhibit-examples.md new file mode 100644 index 0000000..145c922 --- /dev/null +++ b/docs/references/linked-diagrams/rsna-exhibit-examples.md @@ -0,0 +1,26 @@ +--- +type: Reference +title: "RSNA exhibit examples" +description: "Comparable observations, multiple producers, AI discrepancies" +tags: ["foundation-context", "data-structures", "use-cases"] +status: draft +generated: { by: codex/gpt-6/2026-10-01-linked-diagrams, at: 2026-10-01 } +sources: + - id: board + resource: sources/linked-diagrams/19Qjzb9AmAT/ + title: "Figures for RSNA Edu Exhibit" +--- + +# RSNA exhibit examples + +The exhibit panels illustrate how definitions, Observation values, FHIR representations, and generated clinical sentences fit together. Pulmonary nodule is the expanded example, with presence, composition, size, and location connected to the corresponding components. Other examples include acute aortic syndrome, stroke, and diverticulitis.[^board] + +A source panel feeds one Observation representation from dictation/reporting, DICOM SR, exam metadata, current and prior report extraction, longitudinal findings, and AI. The AI-monitoring panel compares two descriptions of the same finding: the radiologist's nodule is 6.0 mm with a composition value, while the model's is 7.5 mm and omits composition.[^board] + +For our work, these are useful teaching examples of shared semantics making data from different producers comparable. The AI discrepancy is a specific Use Cases illustration, not a reported performance result. The panels use an earlier component-based definition representation. They can inform a new explanation of the graph approach without being presented as the current schema or as proof of an operational monitoring application. + +Pillar connections: Foundation Context; Data Structures; Use Cases. Related working pages: [Data structures](../../../knowledge/drafts/data-structures.md), [Next generation schema](../../../knowledge/drafts/next-generation-schema.md), [Use cases](../../../knowledge/drafts/use-cases.md). + +Source captured 2026-10-01: [PNG](../../../sources/linked-diagrams/19Qjzb9AmAT/original.png) · [SVG](../../../sources/linked-diagrams/19Qjzb9AmAT/original.svg) · [Source contents](../../../sources/linked-diagrams/19Qjzb9AmAT/scene-contents.json) · [Text elements](../../../sources/linked-diagrams/19Qjzb9AmAT/text-elements.json) · [Capture metadata](../../../sources/linked-diagrams/19Qjzb9AmAT/metadata.json). + +[^board]: The captured board, especially Figure 1; Figure 2; Figure 3; Figure 4; Figure 5. Inspect the full-resolution PNG/SVG for layout and embedded material; text-elements.json records searchable text with element IDs and coordinates. Capture date does not establish when an undated proposal was written. diff --git a/docs/references/linked-diagrams/structured-report-representation.md b/docs/references/linked-diagrams/structured-report-representation.md new file mode 100644 index 0000000..71a7fce --- /dev/null +++ b/docs/references/linked-diagrams/structured-report-representation.md @@ -0,0 +1,26 @@ +--- +type: Reference +title: "Structured report representation" +description: "Complex findings, report sections, source-independent representations" +tags: ["data-structures", "foundation-context", "sdks"] +status: draft +generated: { by: codex/gpt-6/2026-10-01-linked-diagrams, at: 2026-10-01 } +sources: + - id: board + resource: sources/linked-diagrams/9Jgo8oKswiE/ + title: "Structured Report Representation" +--- + +# Structured report representation + +The board's notes ask how to represent more than simple findings: technique, the radiologist's understanding of patient history, comparisons, complex subparts, causative relationships, grouped findings, broad anatomic negatives, diagnoses, differentials, recommendations, and communication. They distinguish these needs through concrete examples and a chest CT report/finding-list pair.[^board] + +Another discussion calls for appropriate FHIR representation patterns and a handbook for choosing among them. It says representations should be interchangeable across sources, including modality data, AI, technologists, radiologists, and extraction from prior reports. Further notes propose experiments, stronger definition content, and clinical demonstration scenarios.[^board] + +For our work, this is a source for the Observation layer's structural requirements and developer guidance. The common target representation is the reusable idea. Exact FHIR patterns, impression structures, probabilities, grouping, and recommendation forms remain questions on this board. The newer two-graph and shared-schema work supplies the current organizing context. + +Pillar connections: Data Structures; Foundation Context; SDKs. Related working pages: [Data structures](../../../knowledge/drafts/data-structures.md), [Relationships](../../../knowledge/drafts/relationships.md), [Sdks](../../../knowledge/drafts/sdks.md). + +Source captured 2026-10-01: [PNG](../../../sources/linked-diagrams/9Jgo8oKswiE/original.png) · [SVG](../../../sources/linked-diagrams/9Jgo8oKswiE/original.svg) · [Source contents](../../../sources/linked-diagrams/9Jgo8oKswiE/scene-contents.json) · [Text elements](../../../sources/linked-diagrams/9Jgo8oKswiE/text-elements.json) · [Capture metadata](../../../sources/linked-diagrams/9Jgo8oKswiE/metadata.json). + +[^board]: The captured board, especially Report Finding List. Inspect the full-resolution PNG/SVG for layout and embedded material; text-elements.json records searchable text with element IDs and coordinates. Capture date does not establish when an undated proposal was written. diff --git a/docs/references/linked-diagrams/use-case-development.md b/docs/references/linked-diagrams/use-case-development.md new file mode 100644 index 0000000..654a108 --- /dev/null +++ b/docs/references/linked-diagrams/use-case-development.md @@ -0,0 +1,26 @@ +--- +type: Reference +title: "Use-case development and interaction ideas" +description: "User interactions, report views, spine numbering" +tags: ["use-cases"] +status: draft +generated: { by: codex/gpt-6/2026-10-01-linked-diagrams, at: 2026-10-01 } +sources: + - id: board + resource: sources/linked-diagrams/1lt7q7M1bEz/ + title: "OIDM Use Case Brainstorming" +--- + +# Use-case development and interaction ideas + +The board organizes possible value across reporting efficiency, care-team communication, operations/quality/safety, research, public health, and education. It also groups application ideas by reporting, workflow, AI pipelines, data exploration/outcomes, and multiple report views. The circled question asks how users would interact with each use case.[^board] + +The spine-numbering example makes that interaction concrete: capture prior knowledge from operative or treatment notes, let a surgeon specify anatomy, and allow reporting/viewing tools to map between preferred numbering schemes. Other notes propose use-case metadata, contribution guidelines, stages of development, and an entry index. The “Use Case Definitions” box is empty.[^board] + +For our work, this supports a list-oriented Use Cases pillar grounded in what a person does and which information the tool needs. The detailed assisted-reporting map is also present on the Big Picture board. Keep these ideas as source anchors; the proposed repository/catalog mechanics should not become the organizing purpose of the knowledgebase, and an empty placeholder should not be treated as a defined application. + +Pillar connections: Use Cases. Related working pages: [Use cases](../../../knowledge/drafts/use-cases.md), [Overview](../../../knowledge/drafts/overview.md). + +Source captured 2026-10-01: [PNG](../../../sources/linked-diagrams/1lt7q7M1bEz/original.png) · [SVG](../../../sources/linked-diagrams/1lt7q7M1bEz/usable.svg) · [Source contents](../../../sources/linked-diagrams/1lt7q7M1bEz/scene-contents.json) · [Text elements](../../../sources/linked-diagrams/1lt7q7M1bEz/text-elements.json) · [Capture metadata](../../../sources/linked-diagrams/1lt7q7M1bEz/metadata.json). + +[^board]: The captured board, especially Table 1: Value Categories; how do we imagine user interactions; Spine numbering/transitions; Artifacts; Use Case Definitions. Inspect the full-resolution PNG/SVG for layout and embedded material; text-elements.json records searchable text with element IDs and coordinates. Capture date does not establish when an undated proposal was written. diff --git a/docs/references/okf-tooling-comparison.md b/docs/references/okf-tooling-comparison.md new file mode 100644 index 0000000..6a9db0b --- /dev/null +++ b/docs/references/okf-tooling-comparison.md @@ -0,0 +1,69 @@ +# Choosing OKF skills and search tools + +Reviewed 2026-10-01. Follow-up to [the origins review](okf-tooling-review.md). Keep OKF; compare tooling without changing the installation. + +## The current skills are defensible, but not proven best + +The September 20 development log records a comparison between scaccogatto's v0.2 toolkit and the v0.1 skill linked from okf.md. That establishes a version-based selection. It does not establish a comprehensive comparison or prove that the first search result drove the decision. + +Current primary-source comparison: + +| Candidate | Evidence and fit | +|---|---| +| [scaccogatto/okf-skills](https://github.com/scaccogatto/okf-skills) | Our installed toolkit. OKF 0.2 author/maintain/consume, migration, deterministic validator, graph rendering, and history backfill. Uses PyYAML. Good fit with our Python/uv tooling and existing tasks. Current upstream also has MCP, a CI action, plugin hooks, and backfill agent definitions. | +| [lorsabyan/okf-skill](https://github.com/lorsabyan/okf-skill) | Credible v0.2 alternative. Validator, trust/freshness reports, index generator, tests against pinned Google sample bundles, and scheduled spec-drift checks. More validation coverage in the trial below. Its dependency-free parser deliberately handles a YAML subset rather than full YAML. Its skill imposes relative-only links and index-organizing conventions that differ from our current policy. | +| [serradura/okf](https://github.com/serradura/okf) | Broader v0.2 toolkit: separate validate/lint commands, ranked search, trust/status filtering, multi-bundle registry, graph, CLI/library, and optional MCP/TUI. A serious candidate for a unified toolchain, but introduces Ruby or Docker and replaces more of our workflow. Reviewed docs, not executed here. | +| [parkscloud/okf-author](https://github.com/parkscloud/okf-author) and [catancs/okf-skill](https://github.com/catancs/okf-skill) | Current documentation still targets v0.1. Their authoring defaults do not address our v0.2 trust/provenance workflow. No reason to switch to them for this bundle. | +| [copperbox/okf-mcp](https://github.com/copperbox/okf-mcp) | Extensive multi-bundle navigation, remote loading, packing, repair, and authoring tools. Current documentation describes v0.1 validation and timestamp/citations write conventions. Read capabilities merit separate evaluation; avoid adopting its write path for our v0.2 workflow without verification. | + +Recommendation: retain the current authoring and visualization skills provisionally. Evaluate lorsabyan's validator alongside ours before deciding whether to replace validation. Evaluate serradura if we want one tool for multi-bundle search, filtering, lint, and graph navigation. Installing overlapping authoring skills together risks conflicting instructions. + +## What the validator trial actually shows + +I ran the [lorsabyan fixture corpus](https://github.com/lorsabyan/okf-skill/tree/main/benchmark) against our installed validator, current scaccogatto upstream at `8e3187875e66051bb52f91a5ed27342e2c3208da`, and lorsabyan's current validator. The corpus contains 19 deliberately problematic bundles and 10 clean bundles. It was authored by one candidate's maintainer and is a small test, not independent proof of overall superiority. + +| Validator | Problem cases reported without crashing | Clean cases accepted without additional reports | +|---|---|---| +| Installed scaccogatto | 13/19 | 10/10 | +| Current scaccogatto | 13/19 | 10/10 | +| lorsabyan | 19/19 | 10/10 | + +To make the comparison meaningful, I excluded scaccogatto's missing-title and missing-tags warnings, which occur in the unchanged baseline too. Both tools then have a silent baseline. The corpus itself was unchanged. Lorsabyan's clock was pinned to July 30; scaccogatto's checker does not report calendar staleness. The scores count any report, not necessarily the correct diagnosis. Scope differs: scaccogatto intentionally leaves some curation checks to other tools, and our house checker already covers index coverage and stale dates. + +Both scaccogatto versions crash when PyYAML parses an impossible unquoted date. Other unreported cases cover missing indexes, passed stale dates, an undefined/unattributed footnote, an attested computation with no computation, and a dead path-valued field. The crash needs a fix; broader checking needs a policy choice. It is not enough to update the upstream pin and assume these are resolved. + +On the actual bundle, our validator passes with 129 concepts and zero issues. Lorsabyan reports zero errors and 15 warnings for source locators written relative to the repository rather than the bundle. Those are path-contract differences to resolve before replacing the validation gate. Strict mode fails on those warnings. + +The alternative index generator's `--check` proposes changes to all 18 indexes. Inspection shows that it reconstructs headings and recognized list entries but drops surrounding prose. Its preservation promise covers entries, not entire documents. Our root index contains introductory and review-status prose. Do not run this generator in write mode on our indexes without a preservation fix. + +## Useful upstream additions, in priority order + +1. **Pinned updates and drift detection.** Record the toolkit revision, refresh the canonical spec source, and borrow the [lorsabyan scheduled drift-check pattern](https://github.com/lorsabyan/okf-skill/blob/main/README.md#maintenance). Comparing specification content matters because upstream changed timestamp guidance without changing `okf_version`. +2. **Reuse upstream fixtures and tests.** Keep generic conformance covered by upstream tests; test our policy separately. Include the impossible-date case when evaluating an update. Report or contribute the generic validator fix upstream rather than maintaining an unnoticed local fork. +3. **Use the validator's existing JSON output.** It is already installed. CI can consume the report rather than parse terminal output. The [upstream composite action](https://github.com/scaccogatto/okf-skills/blob/main/action.yml) packages validation and a JSON report. It would simplify wiring, not add new validation capability. Pin its commit if adopted. +4. **Complete backfill packaging when needed.** Our backfill skill references `agents/event-analyzer.md` and the `okf:bundle-weaver` agent. Those definitions are not in the installed payload. Vendor the matching definitions or use the reviewed full plugin for a history reconstruction. Do not run backfill on this established bundle just to use the feature. +5. **Expose an upstream MCP reader only for clients that benefit.** The [scaccogatto server](https://github.com/scaccogatto/okf-skills/blob/main/servers/okf_mcp.py) offers search/read/neighbors, including internal source edges. Codex already has file tools; adding MCP does not automatically improve retrieval. For remote clients, configure the actual `knowledge/` path instead of the default `.okf/`. +6. **Trial native OKF filtering for team queries.** Serradura's search supports OKF `--trust` and `--status` directly. That is useful for questions constrained to reviewed content and deserves comparison with a generic search index. + +The full plugin's enforced-upkeep hook only checks that the knowledge log changed alongside code. It does not prove that affected concepts were updated accurately. Our house checker also rejects its root-index `upkeep` field. Adopting that hook is a separate workflow decision, not a prerequisite for better tooling. + +## QMD is a candidate, not the selected search tool + +There are 257 files across `knowledge/` and `docs/` at the review snapshot, including non-Markdown assets. This is small enough to establish a file-search baseline before adding a model-backed index. + +| Need | First candidate | Why / limit | +|---|---|---| +| Known names, exact identifiers, citation IDs | `rg` plus designed indexes | Already available, searches current files, and gives paths/lines. Use as the baseline. | +| Neighbors, backlinks, trust/status constraints | Native OKF tooling | Preserves graph and metadata semantics. Compare serradura and the existing toolkit's MCP reader. | +| Natural-language questions that use different vocabulary | [QMD](https://github.com/tobi/qmd) | Local BM25, vector retrieval, reranking, CLI/MCP, and an existing `qmd bench` command. Quality on OIDM is unmeasured. | +| Section navigation with frontmatter filters | [doctree-mcp](https://github.com/joesaby/doctree-mcp) | BM25 plus heading-tree navigation and frontmatter facets without embedding models. Its own competitive claims are not independent benchmark evidence. | +| Searching original PDFs, decks, websites, and repositories | [docs-mcp-server](https://github.com/arabold/docs-mcp-server) | Broader ingestion formats and sources. More relevant than Markdown-only retrieval if raw-source access is central. Extraction quality, source locators, and indexing scope need testing. | +| People searching the public website | Quartz search | Already integrated. A local agent-search tool is not a replacement for the public-site search experience. | + +QMD's full pipeline downloads three local models totaling about 2 GB. Index refresh and embedding refresh must be managed. Keyword-only mode avoids the model pipeline, but then the comparison is against existing exact search and lighter BM25 tools. + +More importantly, [QMD metadata filtering](https://github.com/tobi/qmd#metadata-filtering) requires an opt-in `qmd.metadata` block with flat typed values. It does not automatically derive trust or freshness from our nested `verified` and `sources` fields. An adapter could produce those filters, but that would add code. Keep retrieval separate from the decision about whether a claim is verified and current. + +Choose search with real tasks: exact terminology, paraphrased concepts, questions requiring multiple linked pages, source lookup, reviewed-only constraints, and absent-answer cases. Label the expected evidence files first. Compare the current agent/file workflow, native OKF search, and QMD or doctree; add broad-source ingestion only if required. Measure evidence recall, citation correctness, refresh after an edit, resource use, and whether extra tool calls help. QMD already provides a benchmark runner, so there is no reason to invent one before trying it. + +No search engine was installed or benchmarked in this review. The validator trial does not establish retrieval quality or authoring quality. The right search choice remains open until its intended consumer and actual failures are clear. diff --git a/docs/references/okf-tooling-review.md b/docs/references/okf-tooling-review.md new file mode 100644 index 0000000..621f997 --- /dev/null +++ b/docs/references/okf-tooling-review.md @@ -0,0 +1,52 @@ +# OKF tooling origins and reuse options + +Reviewed 2026-10-01. This is an investigation and recommendation, not a tooling migration. Research used Exa, Ref, upstream documentation, GitHub metadata, and direct file comparisons. Technical-writing and unslop skills guided the report. + +The [follow-up comparison](okf-tooling-comparison.md) evaluates other v0.2 skills, runs validator fixtures, and qualifies the initial QMD recommendation. This origins review establishes where our tools came from; it does not establish that they are the best available. + +## We adopted the format and core tools + +OKF comes from Google Cloud. Its current canonical home is [GoogleCloudPlatform/open-knowledge-format](https://github.com/GoogleCloudPlatform/open-knowledge-format). The [old knowledge-catalog README](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/README.md) explicitly says its OKF directory is a frozen snapshot and directs users to the new repository. Our vendored specification still names the old location. + +The four installed skills come from [scaccogatto/okf-skills](https://github.com/scaccogatto/okf-skills): author/maintain/consume, validate/migrate, visualize, and backfill. The development log records their selection on September 20. All 13 files under `.agents/skills/` match upstream commit `d8393f329c97836980566c1cf4e4aa4fe47dc111` byte for byte. That was upstream's latest commit before September 21. This establishes that the installed files are upstream copies with no local edits. + +Upstream main was `8e3187875e66051bb52f91a5ed27342e2c3208da`, dated September 28, at review time. Nine installed files differ from that newer revision. Those differences reflect upstream updates, not a local fork. Keep future imports pinned and record their source revision. + +## What is specific to this repository + +| Component | Origin and coupling | +|---|---| +| `.agents/skills/` | Unmodified upstream generic OKF tooling. Works on other bundles. | +| `tools/check_bundle.py` | Local policy, adapted from ACR-RSNA-CDEs. Fixes the allowed document types, requires title/description/generated metadata, demands index coverage, checks links, and scans for email addresses and locally denylisted terms. Default paths are project-specific. | +| `tools/verify.py` | Local implementation of a reusable review action. Writes verification and stable status; defaults to `knowledge/` and the project lead's actor identity. | +| `site/okf-meta-plugin/` | Local Quartz integration for generic OKF fields. It has no imaging-domain model. | +| `tools/prepare_site_content.py` | Local adapter that normalizes Markdown links for our Quartz build. The transformation is reusable; its default paths are local. | +| `Taskfile.yml`, CI, site config, deployment | Project wiring around external tools. | +| `knowledge/` organization and content | Project-specific terminology, five pillars, references, authoring policies, and review decisions. | + +The strict house rules are stronger than OKF conformance. OKF deliberately accepts unknown concept types and missing optional metadata. Our repository chooses a controlled vocabulary and requires richer metadata. Replacing its checker with a generic OKF validator would remove those policies. + +## Existing tools worth using + +| Tool | Fit and recommendation | +|---|---| +| [okf-skills](https://github.com/scaccogatto/okf-skills/blob/main/README.md) | Best direct fit, already installed. Current upstream also offers a composite CI action and a read-only MCP server with search, read, and graph-neighbor tools. The MCP server existed by the installed revision but was not included in our skill-only installation. Review newer validator/spec/template updates and import a pinned revision. Use MCP when a client cannot access the files directly. | +| [Google's reference implementation](https://github.com/GoogleCloudPlatform/open-knowledge-format/blob/main/README.md) | Canonical spec, a reference producer using ADK/Gemini, BigQuery metadata ingestion plus web enrichment, and a graph viewer. The README calls the producer a proof of concept. Its data-catalog workflow does not directly replace our manuscript, diagram, and repository-source curation. | +| [Quartz](https://quartz.jzhao.xyz/) | Already provides the website, search, backlinks, and graph. Keep reusing it. Our OKF metadata component is a small integration rather than a home-grown site generator. | +| [QMD](https://github.com/tobi/qmd) | Strong adjacent candidate for agent retrieval. Indexes existing Markdown and offers local keyword/vector search, reranking, CLI output, and MCP. It can supplement OKF without changing the document format. It does not replace provenance validation or human review. Evaluate only if retrieval is a concrete problem. | +| [Basic Memory](https://github.com/basicmachines-co/basic-memory) | More extensive Markdown knowledge-management and MCP workflow, including graph traversal and semantic search. Its [knowledge format](https://docs.basicmemory.com/concepts/knowledge-format) adds permalinks, categorized observations, and typed wikilink relations. Those conventions require a compatibility trial against our ordinary Markdown links and OKF metadata. It is a larger workflow change than QMD; do not assume it is a drop-in replacement. | + +The direct OKF ecosystem is young. Google's reference producer is explicitly experimental, and okf-skills is pre-1.0. Broader Markdown tools provide more retrieval and publishing functionality, but their support for Markdown does not establish OKF trust or attestation semantics. Popularity alone does not establish suitability. + +## Recommended direction + +Keep OKF and the upstream skills. Update the vendored source references and skills through a reviewed, pinned import. Keep project policy distinct from the generic validator; reduce duplicated metadata checks where upstream already covers them. Continue using Quartz for presentation. Consider QMD for retrieval before building a custom search service. Basic Memory deserves a trial only if we want its broader shared-memory workflow. + +The following differences need attention during that follow-up: + +- Current upstream accepts ISO 8601 timestamps in `stale_after`, source `last_modified`, and usage windows, while our older skill/spec uses date-only guidance. The local house checker accepts only date strings for `stale_after`, so an upstream update needs coordinated policy and documentation review. +- `site/okf-meta-plugin/dist/components/index.js` only renders `verified` arrays. OKF also permits a single mapping. +- The same plugin treats a date as stale strictly after that day. Our vendored spec and house checker use on-or-after semantics. +- The house checker permits only `okf_version` in root-index metadata, while the upstream plugin uses an additional `upkeep` opt-in. That is a policy incompatibility if we adopt the plugin's enforced-upkeep mode. + +These are findings, not changes made by this review. No tool installation, bundle rewrite, commit, or publication occurred. No reader-facing changelog entry is needed. diff --git a/knowledge/applications/finding-and-location-coding.md b/knowledge/applications/finding-and-location-coding.md index 58064bc..18a6db1 100644 --- a/knowledge/applications/finding-and-location-coding.md +++ b/knowledge/applications/finding-and-location-coding.md @@ -1,10 +1,10 @@ --- type: Concept title: Finding and location coding -description: How extracted findings are assigned OIFM finding codes and RadLex anatomic location codes, as a deterministic index lookup followed by language model term generation and selection. +description: How deterministic lookup and language models assign OIFM finding codes and RadLex location codes. tags: [applications, coding, anatomic-locations, llm, extraction] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:34:50Z } stale_after: 2027-09-21 sources: - id: coding-design @@ -29,15 +29,15 @@ sources: # Why coding is its own step -[Extraction](/glossary/extraction.md) asks what the report says. Coding asks which existing definition that corresponds to. Keeping them apart is the central design decision of the current pipeline: extraction output persists without codes, and coding is triggered separately, can be re-run with different models, and never re-reads the report.[^coding-design] Two earlier designs did it inside extraction and were retired. +[Extraction](/glossary/extraction.md) records what the report says. Coding matches findings to existing definitions. The current pipeline persists uncoded extractions and runs coding separately, without rereading the report. Coding can be rerun with different models.[^coding-design] Two earlier designs did it inside extraction and were retired. -The two axes are coded independently. A finding gets an [OIFM identifier](/glossary/oifm.md) naming a [finding model](/glossary/finding-model.md) definition. Its location, when the report gives one, gets a [RadLex identifier](/glossary/radlex-id.md) from the [anatomic locations](/glossary/anatomic-location.md) data set. Either can succeed while the other fails. +Finding and location codes are independent. A finding receives an [OIFM identifier](/glossary/oifm.md) for its [finding model](/glossary/finding-model.md). A stated location receives a [RadLex identifier](/glossary/radlex-id.md) from the [anatomic locations](/glossary/anatomic-location.md) dataset. Either can succeed while the other fails. # The pipeline -Coding operates on the flat merged finding list of a completed extraction rather than on report chunks. Each finding already carries its name, [presence](/glossary/presence.md), location fields, verbatim quote, and source section, and the design states that this is sufficient context; chunk-level ambiguity was already resolved during extraction.[^coding-design] +Coding uses the completed extraction's flat merged finding list. Each finding carries its name, [presence](/glossary/presence.md), location fields, verbatim quote, and source section. The design treats these as sufficient context because extraction has resolved chunk-level ambiguity.[^coding-design] -Five phases, of which two involve language model calls. +The pipeline has five phases. Two call language models. | Phase | What happens | |---|---| @@ -47,19 +47,19 @@ Five phases, of which two involve language model calls. | 4. Code selection | Two agents, one for findings and one for locations, choose from the candidate set, running concurrently under a semaphore | | 5. Assembly | Fast-path and selected results merge into one coding bundle per finding | -Four agents in total. Term generation and selection use different models on the stated ground that proposing search synonyms needs no reasoning while judging candidate fit does; traces showed reasoning tokens spent on term generation with no quality benefit. +Four agents perform term generation and selection. Term generation uses a different model because traces showed reasoning tokens added no quality benefit when proposing synonyms. Candidate selection requires reasoning. -Every phase catches its own failures and degrades rather than aborting. A term generation failure falls back to using the finding name as the search term. A search failure or a selection failure marks that finding unresolved. One finding's failure does not block the others. +Each phase handles its failures. Failed term generation falls back to the finding name. Failed search or selection marks the finding unresolved without blocking other findings. The prompts carry the exam information, modality, body part, and study description, because it disambiguates both terms and candidates, and deliberately omit the full report text; testing found identical results with 22 percent fewer input tokens without it.[^coding-prompts] ## What the fast path is worth -In prototype testing on chest radiograph extractions, exact and synonym lookup resolved 13 of 16 unique finding names and 12 of 15 unique locations with no model call at all.[^coding-design] The same testing found that a purely deterministic top-candidate choice was not adequate for locations: location assignment needs contextual reasoning even when the finding code resolves deterministically. +In chest radiograph prototype tests, exact and synonym lookup resolved 13 of 16 unique finding names and 12 of 15 unique locations without model calls.[^coding-design] Deterministic top-candidate selection was insufficient for locations, which needed contextual reasoning even when finding codes resolved deterministically. # The coding record -Each finding carries a coding bundle holding one finding code and a list of location codes. The list is plural because a finding can span sides or structures, so "lungs" resolves to both the left and the right lung.[^coding-design] +A coding bundle holds one finding code and a list of location codes. Findings can span sides or structures, so "lungs" resolves to both lungs.[^coding-design] ```python class FindingCodingBundle(StrictBaseModel): @@ -67,7 +67,7 @@ class FindingCodingBundle(StrictBaseModel): location_codes: list[LocationCode] = Field(default_factory=list) ``` -Both code objects record not only the answer but how it was reached and, when it failed, why. +Both code objects record the result, method, and failure reason. | Field | Finding code | Location code | |---|---|---| @@ -79,7 +79,7 @@ Both code objects record not only the answer but how it was reached and, when it | `candidates` | the alternates that were considered | the alternates that were considered | | `closest_candidate_id` | the nearest miss when unresolved | not carried | -The unresolved reasons are the part worth reading closely, because they are designed to report gaps rather than to hide them. +Unresolved reasons distinguish content gaps from processing failures. | Finding reason | Meaning | |---|---| @@ -97,25 +97,25 @@ The unresolved reasons are the part worth reading closely, because they are desi | `no_candidates` | The search returned nothing | | `coding_error` | A model or infrastructure failure | -Two of these, `definition_mismatch` and `no_candidate_match`, exist specifically so that an unresolved finding becomes evidence about content coverage rather than noise. They are the pipeline's channel back to [the content catalog](/semantic-foundation/finding-models/content-catalog.md) and [the anatomic location data model](/semantic-foundation/anatomic-locations/data-model.md). +`definition_mismatch` and `no_candidate_match` identify gaps in [the content catalog](/semantic-foundation/finding-models/content-catalog.md) and [the anatomic location data model](/semantic-foundation/anatomic-locations/data-model.md). -The model's own explanation is persisted with the extraction but never written to logs or trace attributes, because it can quote report content. +Model explanations persist with the extraction but never enter logs or trace attributes because they can quote report content. # Where the location comes from -Choosing a code is the second half of the problem. The first is deciding which anatomic structure the report actually asserts, and that is governed by a written precedence ladder, applied per observation and agreed during a correction pass over the sample data.[^anat-rules] In summary: +The assignment rules determine the anatomic structure before code selection, governed by a written precedence ladder, applied per observation and agreed during a correction pass over the sample data.[^anat-rules] -1. **Explicit anatomy in the report text or section context wins.** Use the most specific structure stated, sided only if a side is stated. A section heading counts as context. -2. **Otherwise use the finding's own target organ**, at the finding's anatomic granularity and never finer. -3. **Otherwise fall back to the exam-scoped coarse region**, sided only if the exam is sided. +1. Use the most specific anatomy stated in the report text or section context. Add a side only when stated. +2. Otherwise use the finding's own target organ, at the finding's anatomic granularity and never finer. +3. Otherwise, use the coarse exam region, sided only if the exam is sided. -An organ always beats the exam region when the finding has a real target organ, so "lung bases clear" on an abdominal study codes to lung rather than abdomen. Laterality is resolved against the whole report section rather than the isolated quote, because the side is often stated only in a heading; but a side is never inferred from a different exam or from clinical priors. Bilateral findings split into left and right when the lesions are separable and stay generic and unsided when the process is one diffuse entity. A structure absent from the ontology is left unassigned rather than forced to a wrong code. The full rules, including the worked examples and the exam-to-region map, are in [the assignment rules reference](/data-structures/anatomic-location-assignment-rules.md). +An organ always beats the exam region when the finding has a real target organ. For example, "lung bases clear" on an abdominal study codes to lung. Resolve laterality from the whole report section, including its heading. Never infer a side from another exam or clinical priors. Split separable bilateral lesions into left and right, but keep a diffuse bilateral process generic and unsided. Leave structures absent from the ontology unassigned. See [the assignment rules reference](/data-structures/anatomic-location-assignment-rules.md) for examples and the exam-to-region map. -The rules name one limitation they do not solve. A generic location and a specific one for the same finding code across exams, "kidney" and "left kidney", still produce separate [Imaging Problem List](/glossary/imaging-problem-list.md) groups. Deciding whether those are one problem or two is called anatomic-compatibility reconciliation and is an open follow-on.[^anat-plan] +Generic and specific locations for the same finding code across exams, such as "kidney" and "left kidney", still produce separate [Imaging Problem List](/glossary/imaging-problem-list.md) groups. Deciding whether those are one problem or two is called anatomic-compatibility reconciliation and is an open follow-on.[^anat-plan] # The review artifact -Coding decisions are reviewable as a spreadsheet, not only as JSON. The enrichment script that ran the sample Exam Finding Lists through the production pipeline writes a review CSV of every location decision alongside the enriched files. In the completed pass of 2026-06-10, 260 of 275 findings received a location, and the regenerated [Imaging Problem List](/data-structures/imaging-problem-list.md) was regrouped by finding code together with location identifier.[^anat-plan] +The sample Exam Finding List enrichment script writes a review CSV of every location decision alongside the enriched files. In the 2026-06-10 pass, 260 of 275 findings received a location. The regenerated [Imaging Problem List](/data-structures/imaging-problem-list.md) groups by finding code and location identifier.[^anat-plan] # Earlier designs, now archived @@ -127,11 +127,11 @@ Three generations exist in the repository, and only the third is current. | Version 3, batch per chunk | Fast path, then three model calls per report chunk: generate search terms for findings and locations together, select finding codes, select location codes | Marked completed 2026-02-19, then superseded | | Current, flat merged finding list | Fast path, then four agents across two phases, operating on the merged finding list rather than per chunk | Current, implementation complete on `dev` | -The move from version 3 to the current design changed both the unit of work, from chunk to merged finding list, and the agent count, from three to four, by splitting term generation into separate finding and location agents so each could use a cheaper model.[^coding-archive][^coding-design] +The current design split term generation into finding and location agents so each could use a cheaper model.[^coding-archive][^coding-design] # Where this sits -Coding is a stage of [the report extraction platform](/applications/report-extraction-platform.md) and runs as its own asynchronous job. Its inputs are the finding model corpus and the anatomic location data set, and its output is what makes an [Observation](/glossary/observation.md) interoperable at all: without codes, an extracted finding is text. See [the architecture overview](/overview/architecture.md) for why the identifiers are the joints of the whole system. +Coding runs as an asynchronous job in [the report extraction platform](/applications/report-extraction-platform.md). It uses the finding model corpus and anatomic location dataset to assign standard identifiers to an [Observation](/glossary/observation.md). See [the architecture overview](/overview/architecture.md). [^coding-design]: Coding agent design, imaging-problem-list dev branch [^coding-prompts]: Coding agent prompt catalog, imaging-problem-list dev branch diff --git a/knowledge/applications/finding-model-forge.md b/knowledge/applications/finding-model-forge.md index 206e875..7088753 100644 --- a/knowledge/applications/finding-model-forge.md +++ b/knowledge/applications/finding-model-forge.md @@ -1,10 +1,10 @@ --- type: Project Profile title: Finding Model Forge -description: The web application at fmf.oidm.org where contributors author finding model definitions through an AI-assisted wizard and move them through a draft review lifecycle. +description: The application at fmf.oidm.org for authoring finding models with AI assistance and reviewing drafts. tags: [applications, finding-models, authoring, llm, mongodb] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:34:50Z } stale_after: 2027-09-21 sources: - id: forge-readme @@ -43,13 +43,15 @@ sources: # Purpose -Finding Model Forge is the authoring front end of the Open Imaging Data Model (OIDM). It exists so that a radiologist who is not a programmer can create a [finding model](/glossary/finding-model.md) definition, have identifiers and standard codes assigned automatically, and put the result in front of reviewers. The January 2026 status deck names it as the tool behind the claim that finding models are a rapid-innovation workbench ahead of formal [common data element](/glossary/cde.md) adoption.[^deck] +**Live:** [fmf.oidm.org](https://fmf.oidm.org) (sign-in with GitHub). -The application is a FastAPI web wrapper around the `findingmodel` Python library, which supplies the actual generation, similarity search, and identifier assignment.[^forge-readme] The library is documented under [the finding models area](/semantic-foundation/finding-models/authoring-workflow.md); this profile covers the application. +Finding Model Forge lets radiologists create [finding model](/glossary/finding-model.md) definitions without programming. It assigns identifiers and standard codes automatically and accepts drafts for review. The January 2026 Open Imaging Data Model (OIDM) deck presents it as a tool for developing finding models before formal [common data element](/glossary/cde.md) adoption.[^deck] + +The FastAPI application wraps the `findingmodel` Python library for generation, similarity search, and identifier assignment.[^forge-readme] See [the authoring workflow](/semantic-foundation/finding-models/authoring-workflow.md) for the library. # What a user does with it -Sign-in is GitHub OAuth. After that the creation flow is two steps followed by draft editing, streamlined from an earlier five-step wizard.[^forge-workflow] The whole flow happens inside one page: the server returns HTTP 303 responses, HTMX intercepts them and swaps content into a single container, and the browser never navigates. The creation-workflow document is emphatic about this because it changes how the flow is tested. +Users sign in with GitHub OAuth. Creation has two steps followed by draft editing, replacing an earlier five-step wizard.[^forge-workflow] HTMX intercepts HTTP 303 responses and swaps content within one page without browser navigation. | Stage | User action | What the server does | |---|---|---| @@ -58,28 +60,28 @@ Sign-in is GitHub OAuth. After that the creation flow is two steps followed by d | 3. Draft editing | Edit description, manage synonyms, write the attributes in markdown; press "Update & Preview" | Autosaves as you type, then generates the full finding model JSON including identifiers and standard codes | | 4. Preview and submission | Review the generated model, press "Submit Draft" | Moves the draft to `submitted` and locks editing | -The finding name is read-only once the draft exists. A creation session tracks progress through the first two steps and expires after an hour of inactivity. Drafts appear on the user's profile page, where editing can be resumed; resuming a name that was already submitted lands on the final display view instead of the editor.[^forge-draft] +The finding name becomes read-only when a draft is created. Creation sessions track the first two steps and expire after an hour of inactivity. Users resume drafts from their profile page. Submitted drafts open in the final display view.[^forge-draft] # The draft object and its lifecycle -A draft is the unit of work. It carries the owning user, the finding name, the human inputs (description, synonyms, attributes markdown), the server-generated finding model JSON, a status, and an action log of timestamped entries recording who did what.[^forge-draft] +A draft stores its owner, finding name, description, synonyms, attributes markdown, generated model JSON, status, and a timestamped action log recording who performed each action.[^forge-draft] ```text draft ──submit──▶ submitted ──▶ under-review ──▶ added └──▶ declined ``` -Five statuses exist: `draft`, `submitted`, `under-review`, `added`, and `declined`. Submission locks further editing; everything after it is administrative review. A peer-review layer sits alongside this lifecycle on the development branch: a public draft state lets other contributors read and comment on a draft before it is submitted, and a comment feature is scoped to drafts in the submitted, under-review, added, and declined states. Both are stated as serving collaborative refinement rather than approval gating.[^forge-public-review][^forge-comments] +Five statuses exist: `draft`, `submitted`, `under-review`, `added`, and `declined`. Submission locks further editing; everything after it is administrative review. On `dev`, public drafts allow contributors to read and comment before submission. A separate comment feature covers `submitted`, `under-review`, `added`, and `declined` drafts. Both are stated as serving collaborative refinement rather than approval gating.[^forge-public-review][^forge-comments] # Data it reads and writes -MongoDB holds drafts, users, and organizations, accessed asynchronously through Motor.[^forge-db] Redis provides a caching layer for user and finding model data; the implementation always calls the cache, and the calls become safe no-ops when Redis is unavailable.[^forge-draft] Two DuckDB files supplied by the `findingmodel` library must be present in the platform data directory, one for finding models and one for [anatomic locations](/glossary/anatomic-location.md), which is how similarity search and code lookup work offline of any web service.[^forge-readme] +MongoDB stores drafts, users, and organizations through asynchronous Motor access.[^forge-db] Redis caches user and finding model data. Cache calls become no-ops when Redis is unavailable.[^forge-draft] The `findingmodel` library requires two DuckDB files in the platform data directory, one for finding models and one for [anatomic locations](/glossary/anatomic-location.md), to support similarity search and code lookup without web services.[^forge-readme] -The output format is the finding model JSON defined by [the finding model format](/semantic-foundation/finding-models/finding-model-format.md), carrying an [OIFM identifier](/glossary/oifm.md) and per-[attribute](/glossary/attribute.md) identifiers. Drafts store the generated JSON inline; the definitive corpus lives in the separate content repository described in [the content catalog](/semantic-foundation/finding-models/content-catalog.md). +Drafts store generated JSON inline in [the finding model format](/semantic-foundation/finding-models/finding-model-format.md), with [OIFM identifiers](/glossary/oifm.md) and per-[attribute](/glossary/attribute.md) identifiers. The definitive corpus lives in [the content repository](/semantic-foundation/finding-models/content-catalog.md). # Language model use -Three generation steps are documented, with the timeouts the application budgets for them.[^forge-workflow] +The workflow documents three library calls and their time budgets.[^forge-workflow] | Step | Task | Budgeted time | |---|---|---| @@ -87,15 +89,13 @@ Three generation steps are documented, with the timeouts the application budgets | Stage 2 | Semantic similarity search against existing models | 15 to 30 seconds | | Stage 3 | Generate the complete finding model JSON, including identifier assignment and standard codes | 30 to 90 seconds | -All three are calls into the `findingmodel` library rather than code in this repository. - # Architecture -One FastAPI process serves both the pages and the API. Templates are Jinja2, with Flowbite components for layout, Alpine.js for client state, and HTMX driving every transition as a server-rendered fragment swap; the house rule is to keep interactivity in Alpine and HTMX rather than custom JavaScript. MongoDB through Motor is the store, Redis the cache, and the `findingmodel` library the engine. Static assets are built with Vite and resolved through its manifest.[^forge-readme][^forge-draft] +One FastAPI process serves pages and the API. Jinja2 renders templates, Flowbite supplies components, Alpine.js manages client state, and HTMX swaps server-rendered fragments. Project conventions place interactivity in Alpine and HTMX instead of custom JavaScript. Vite builds static assets, which the application resolves through its manifest.[^forge-readme][^forge-draft] # Deployment -Live at [fmf.oidm.org](https://fmf.oidm.org). The container needs MongoDB and Redis running alongside it, a GitHub OAuth application for sign-in, and the two DuckDB data files.[^forge-readme] Bringing the deployment compose file into the repository is open issue 9, and a development compose file is open issue 7. Install and run instructions stay with the code; this profile does not repeat them. +Live at [fmf.oidm.org](https://fmf.oidm.org). The container requires MongoDB, Redis, a GitHub OAuth application, and two DuckDB data files.[^forge-readme] # Repository and branch of record @@ -111,9 +111,9 @@ Neither long-lived branch has an open pull request as of 2026-09-21. # What is in flight -**The `dev` refactor.** Ninety-six commits consolidate a service-layer extraction, a router cleanup, standardization of the HTMX and Alpine patterns, and a rebuilt test infrastructure. The branch's own complexity assessment names what remains in the service and router layers after that work. The peer-review workflow described above, public drafts plus comments, is finished on `dev` and absent from `main`.[^forge-public-review][^forge-comments] +**The `dev` refactor.** Ninety-six commits consolidate a service-layer extraction, a router cleanup, standardized HTMX and Alpine patterns, and rebuilt test infrastructure. Its complexity assessment records remaining service and router work. Public drafts and comments are complete on `dev` and absent from `main`.[^forge-public-review][^forge-comments] -**Model editing, issue 13.** Opened 2025-10-16 and still open. The implementation on `feature/model-editing` answers it with AI-assisted *iterations* rather than manual editing: a user submits a natural-language description of the change they want, and the library applies it.[^forge-iteration] The constraints are explicit. The model name cannot change, one iteration draft exists per user per published model, the existing action log carries the audit trail, and manual edits to an iteration draft are not permitted. It builds on the `model_editor` module added in `findingmodel` 0.6.0, whose guardrails preserve the [OIFM identifiers](/glossary/oifm.md) and reject unsafe changes. Sprint 1, natural-language iteration, is complete as of 2025-11-27. Sprint 2, markdown-edit iteration, and Sprint 3, enhanced history, are not started. +**Model editing, issue 13.** The `feature/model-editing` branch lets users request changes in natural language.[^forge-iteration] Model names cannot change, and each user can have one iteration draft per published model. The action log records changes, and manual edits are prohibited. The `model_editor` module in `findingmodel` 0.6.0 preserves [OIFM identifiers](/glossary/oifm.md) and rejects unsafe changes. Sprint 1, natural-language iteration, was complete on 2025-11-27. Sprint 2, markdown-edit iteration, and Sprint 3, enhanced history, have not started. # Open issues @@ -125,11 +125,11 @@ Neither long-lived branch has an open pull request as of 2026-09-21. # History -A superseded version of the application survives in the repository under `zOld/`, together with its planning notes.[^forge-zold] Those notes record decisions the current application still reflects: a deliberate commitment to MongoDB with the Beanie object-document mapper after considering embedded vector stores, a front end on the same FastAPI instance as the API, and GitHub OAuth holding authorization in the session. The three mini-sprint task lists from November 2024 through April 2025 show the feature set arriving in order, beginning with generating a finding model from nothing but a finding name, then adding identifiers, a user table, and searchable [common data element](/glossary/cde.md) content. Most of their boxes are still unchecked, including batch creation from a CSV file and links from a finding model to its eventual CDE codes. +The superseded application and its plans remain in `zOld/`.[^forge-zold] The plans chose MongoDB with Beanie after considering embedded vector stores, shared the FastAPI process between pages and API, and kept GitHub OAuth authorization in the session. Three mini-sprint lists from November 2024 through April 2025 start with generation from a finding name, then add identifiers, a user table, and searchable [common data element](/glossary/cde.md) content. Most checkboxes remain unchecked, including CSV batch creation and links to eventual CDE codes. # What it realizes -Finding Model Forge is where the [contributor](/glossary/contributor.md) meets the [finding model](/glossary/finding-model.md) format. It assigns [OIFM identifiers](/glossary/oifm.md) with their [organization code](/glossary/oidm-organization-code.md), writes [attributes](/glossary/attribute.md) and their values, and attaches [index codes](/glossary/index-code.md) into external terminologies. Its place in the stack is drawn in [the architecture overview](/overview/architecture.md), and the authoring path it implements is described end to end in [the authoring workflow](/semantic-foundation/finding-models/authoring-workflow.md). +Forge lets [contributors](/glossary/contributor.md) assign [organization code](/glossary/oidm-organization-code.md) identifiers, write attributes and values, and attach [index codes](/glossary/index-code.md) for external terminologies. See [the architecture overview](/overview/architecture.md) and [the authoring workflow](/semantic-foundation/finding-models/authoring-workflow.md). [^deck]: Open Imaging Data Model 2026 Status Update, January 2026 [^forge-readme]: FindingModelForge README, dev branch diff --git a/knowledge/applications/finding-models-site.md b/knowledge/applications/finding-models-site.md index c0e728c..bf4f1be 100644 --- a/knowledge/applications/finding-models-site.md +++ b/knowledge/applications/finding-models-site.md @@ -1,10 +1,10 @@ --- type: Project Profile title: Finding model catalog site -description: The static Astro site that renders the finding model corpus as browsable pages, building it from the content repository pulled in as a git submodule. +description: The static Astro catalog built from finding model definitions in a git submodule. tags: [applications, finding-models, catalog, astro] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:34:50Z } stale_after: 2027-09-21 sources: - id: site-config @@ -26,27 +26,29 @@ sources: # Purpose -The catalog site is the public reading surface for the [finding model](/glossary/finding-model.md) corpus. It answers one question, "what definitions exist and what is in them," without requiring a reader to install anything, clone a repository, or read JSON. [Finding Model Forge](/applications/finding-model-forge.md) writes definitions; this site displays them. +**Live:** [openimagingdata.github.io/finding-models-site](https://openimagingdata.github.io/finding-models-site/). + +The catalog site displays [finding model](/glossary/finding-model.md) definitions without requiring installation or reading JSON. [Finding Model Forge](/applications/finding-model-forge.md) authors the definitions. # What a user does with it -Three things, from the home page.[^site-index] +The home page links to three actions.[^site-index] -- **Browse the catalog.** A "Browse Finding Models" link leads to a list page, and each entry leads to a detail page for one definition. -- **Start authoring.** A "Launch Finding Model Forge" link goes to the sign-in page at `fmf.oidm.org`. -- **Report a problem.** A "Submit Issue" link opens a new issue against the `findingmodels` content repository, so corrections go to the content rather than to the site. +- "Browse Finding Models" opens the catalog, with a detail page for each definition. +- "Launch Finding Model Forge" opens sign-in at `fmf.oidm.org`. +- "Submit Issue" opens an issue against the `findingmodels` content repository. -A search box is present on the home page but is not wired to anything; it is markup only. +The home page search box has no implemented behavior. # Data it reads -The site holds no content of its own. The `findingmodels` content repository is attached as a git submodule at `external/findingmodels`.[^site-submodule] At build time, a loader module reads every `.json` file in that submodule's `defs/` directory, parses each one, and derives the page slug from the file name.[^site-loader] There is no database, no API call, and no runtime fetch. A definition appears on the site only after the submodule pointer is advanced and the site is rebuilt. +The `findingmodels` content repository is a git submodule at `external/findingmodels`.[^site-submodule] At build time, the loader parses every `.json` file in `defs/` and derives page slugs from file names.[^site-loader] The site has no database, API calls, or runtime fetches. ```typescript const modelDir = path.resolve('./external/findingmodels/defs'); ``` -That single line is the whole coupling between the site and the corpus, and it is why the content repository stays the source of truth for finding model identity. The corpus itself is described in [the content catalog](/semantic-foundation/finding-models/content-catalog.md) and the format in [the finding model format](/semantic-foundation/finding-models/finding-model-format.md). +That single line is the whole coupling between the site and the corpus, and it is why the content repository stays the source of truth for finding model identity. See [the content catalog](/semantic-foundation/finding-models/content-catalog.md) and [the finding model format](/semantic-foundation/finding-models/finding-model-format.md). # Language model use @@ -54,11 +56,11 @@ None. The site is a deterministic renderer. # Architecture -Astro 5 in static output mode, with Tailwind CSS 4 applied through the Astro Vite plugin and pnpm as the package manager.[^site-config] Four source files carry the whole application: a layout, a home page, a model list page, and a model detail page parameterized by slug. The configuration sets a base path of `/finding-models-site/`, which is what makes the published URLs resolve under the project's GitHub Pages subpath. +The site uses Astro 5 static output, Tailwind CSS 4 through the Astro Vite plugin, and pnpm.[^site-config] Four source files define the layout, home page, model list, and model detail page. The `/finding-models-site/` base path resolves URLs under the GitHub Pages subpath. # Deployment -Live at [openimagingdata.github.io/finding-models-site](https://openimagingdata.github.io/finding-models-site/), verified responding on 2026-09-21. A GitHub Actions workflow triggers on every push to `main`, checks the repository out with submodules, installs with pnpm, runs the Astro build, and publishes `dist/` to GitHub Pages.[^site-deploy] Because the workflow fires on pushes to this repository rather than on changes in the content repository, new definitions reach the site only when someone updates the submodule pointer here. +Live at [openimagingdata.github.io/finding-models-site](https://openimagingdata.github.io/finding-models-site/), verified responding on 2026-09-21. On pushes to `main`, GitHub Actions checks out the repository with submodules, installs with pnpm, builds, and publishes `dist/`.[^site-deploy] New definitions appear only after the submodule pointer is updated and the site rebuilds. # Repository and branch of record @@ -76,7 +78,7 @@ The repository's README is the unmodified Astro starter boilerplate and describe # What it realizes -The catalog site is the simplest realization of the claim that a [finding model](/glossary/finding-model.md) definition is a portable file rather than a database row. It needs no service, no credentials, and no synchronization, and it proves that a consumer can read the corpus by reading files. The same property is what lets the extraction platform resolve [OIFM identifiers](/glossary/oifm.md) against a published registry file; see [the architecture overview](/overview/architecture.md). +The site reads portable definition files without a service or credentials. The extraction platform similarly resolves [OIFM identifiers](/glossary/oifm.md) against a published registry file. See [the architecture overview](/overview/architecture.md). [^site-config]: finding-models-site Astro configuration, main branch [^site-loader]: finding-models-site build-time model loader, main branch diff --git a/knowledge/applications/imaging-problem-list-viewer.md b/knowledge/applications/imaging-problem-list-viewer.md index 16ca2b6..c929ecf 100644 --- a/knowledge/applications/imaging-problem-list-viewer.md +++ b/knowledge/applications/imaging-problem-list-viewer.md @@ -1,10 +1,10 @@ --- type: Project Profile title: Imaging Problem List viewer -description: The deployed browser application that renders Imaging Problem Lists, its three-level drill-down and status sections, and the anatomy-first second-generation viewer being built on the development branch. +description: The deployed Imaging Problem List browser and the undeployed anatomy-first viewer on dev. tags: [applications, ipl, viewer, anatomy, frontend] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:34:50Z } stale_after: 2027-09-21 sources: - id: ipl-main-readme @@ -32,7 +32,9 @@ sources: # Purpose -The viewer is the demonstration that an [Imaging Problem List](/glossary/imaging-problem-list.md) is worth assembling. It takes the reorganization of a patient's findings by finding rather than by date and puts it on screen, so that "has this finding ever been described, and is it present now" is a glance instead of a chart review. The January 2026 status deck names an Imaging Problem List browser among the demonstration applications of the applications pillar. +**Live:** the deployed viewer is at [imaging-problem-list.pages.dev](https://imaging-problem-list.pages.dev) (main-branch data, without anatomic locations). The anatomy-first `viewer_v2` on `dev` has no public deployment as of 2026-09-21; the plan's intended address, `ipl-anatomy.pages.dev`, does not respond. + +The viewer displays a patient's [Imaging Problem List](/glossary/imaging-problem-list.md) by finding, showing its history and current presence. The January 2026 status deck lists the browser as a demonstration application. Two viewers exist. The deployed one is on `main`. A second-generation, anatomy-first viewer called `viewer_v2` sits on `dev` and is not deployed. @@ -40,13 +42,13 @@ Two viewers exist. The deployed one is on `main`. A second-generation, anatomy-f ## What a user does with it -Navigation is three levels deep, held entirely in client-side state.[^ipl-main-readme] +Navigation has three levels, managed in client-side state.[^ipl-main-readme] -1. **Patient level.** The [Imaging Problem List](/data-structures/imaging-problem-list.md): every finding described across the patient's exams. A dropdown switches patients, and a `?patient=` query parameter selects one directly. -2. **Exam level.** Clicking through a finding's exam entry opens that exam's [Exam Finding List](/data-structures/exam-finding-list.md). -3. **Report level.** From there, the raw report text the findings came from. +1. The patient's [Imaging Problem List](/data-structures/imaging-problem-list.md) shows findings across exams. A dropdown or `?patient=` query parameter selects the patient. +2. A finding's exam entry opens the [Exam Finding List](/data-structures/exam-finding-list.md). +3. The exam view opens the source report text. -Findings are grouped into sections by temporal status rather than filtered by it. Status filtering existed and was removed in favor of status-labeled sections on 2025-11-18.[^ipl-status-commit] Four statuses are computed in the browser from each finding's observation list sorted by date, never stored in the data. +Status sections replaced status filtering on 2025-11-18.[^ipl-status-commit] The browser computes four statuses from date-sorted observations without storing them in the data. | Status | Meaning | |---|---| @@ -55,11 +57,11 @@ Findings are grouped into sections by temporal status rather than filtered by it | Resolved | Present in the past, absent now | | Never | Never described as present | -A [body region](/glossary/body-region.md) filter offers chest, abdomen, pelvis and genitourinary, musculoskeletal, and head and neck. It is driven by a static lookup table of 98 finding-to-region entries, which replaced an earlier keyword-matching approach. Clicking a finding's exam group opens a popover listing every observation of that finding in that report, not just the first, grouped by report identifier. Exam type names are shortened for display through a second lookup table, so "MR Brain WO and W contrast IV" reads as "MR Brain w/wo". The design is dark-mode-first, with the preference kept in browser local storage. +The [body region](/glossary/body-region.md) filter covers chest, abdomen, pelvis and genitourinary, musculoskeletal, and head and neck. A static table of 98 finding-to-region mappings replaced keyword matching. A finding's exam-group popover lists all its observations, grouped by report identifier. A second lookup table shortens exam names, such as "MR Brain WO and W contrast IV" to "MR Brain w/wo". The design prioritizes dark mode and stores the preference in browser local storage. ## Data it reads -Static files only, laid out by patient and exam. +The viewer reads static files organized by patient and exam. ```text data/patients.json @@ -71,7 +73,7 @@ data/finding_region_mappings.json data/exam_type_mappings.json ``` -The deployed bundle carries two patients: one with 10 exams and 98 aggregated Imaging Problem List findings, and one with 2 exams.[^ipl-main-readme] Those files are generated from the sample data described in [sample data](/data-structures/sample-data.md) by scripts in the repository. No server, no API, no database. +The deployed bundle contains two patients. One has 10 exams and 98 aggregated findings. The other has 2 exams.[^ipl-main-readme] Repository scripts generate the files from [sample data](/data-structures/sample-data.md). The viewer needs no application server, API, or database. ## Language model use @@ -79,31 +81,31 @@ None in the viewer. Everything it renders was produced upstream. ## Architecture -One page of Alpine.js state, with Tailwind and Flowbite loaded from a content delivery network and no build step at all. Status computation, region filtering, and popover assembly are plain JavaScript over the loaded JSON. +One page manages Alpine.js state, with Tailwind and Flowbite loaded from a content delivery network and no build step. JavaScript computes statuses, filters regions, and assembles popovers from JSON. ## Deployment -Live at [imaging-problem-list.pages.dev](https://imaging-problem-list.pages.dev), verified responding on 2026-09-21. Deployment is a Wrangler command that pushes the `viewer/` directory to a Cloudflare Pages project named `imaging-problem-list`; there is no continuous deployment.[^ipl-deploy] +Live at [imaging-problem-list.pages.dev](https://imaging-problem-list.pages.dev), verified responding on 2026-09-21. A Wrangler command deploys `viewer/` to the `imaging-problem-list` Cloudflare Pages project. There is no continuous deployment.[^ipl-deploy] ## A documentation discrepancy -The prose in the repository's domain notes and the viewer README still describes an older three-state scheme, present, resolved, and not present or ruled out, while the shipped code computes the four states listed above.[^ipl-main-claude] The code is current. This is recorded in [open questions](/roadmap/open-questions.md). +The domain notes and viewer README describe an older three-state scheme: present, resolved, and not present or ruled out.[^ipl-main-claude] The shipped code computes the four states above. See [open questions](/roadmap/open-questions.md). # viewer_v2, the anatomy-first viewer -A separate React, Vite, TypeScript, and Tailwind static application under `viewer_v2/` on the `dev` branch. Its plan is marked "Body-map redesign implemented; ready for review" and is not archived, so it is in flight.[^viewer-v2-plan] +`viewer_v2/` is a React, Vite, TypeScript, and Tailwind static application on `dev`. Its plan is marked "Body-map redesign implemented; ready for review" and is not archived, so it is in flight.[^viewer-v2-plan] -**The governing rule.** The viewer trusts the Imaging Problem List. Each finding identifier in the list is the canonical clinical problem row, and anatomy grouping is presentation only: it must never merge or split findings. Clinical reconciliation of compatible anatomic locations is explicitly out of scope and belongs to the follow-on step in the anatomic location plan.[^anat-plan] +Each finding identifier in the Imaging Problem List defines one clinical problem row. Anatomy grouping must not merge or split findings. Clinical reconciliation of compatible locations belongs to the follow-on anatomic location work.[^anat-plan] -**What it shows.** A single patient, the ten-exam example, presented anatomy first: an abstract body-map schematic rather than an anatomical illustration, with extremities lateralized so the right side renders on the viewer's left and the left on the viewer's right, and findings with no stated side kept separate from both. Diagram zones show the actual active finding names as clickable chips rather than a count badge. From there the detail pane opens progressively through region, cluster, finding, and observation, with finding timelines, finding-definition metadata, and drill-down to the exam, its Exam Finding List, and the report. The theme is a dark radiology-workstation palette, and the plan states that a light presentation is not acceptable for this version. +The viewer presents the ten-exam patient on an abstract body schematic. Right extremities appear on the viewer's left, left extremities on the right, and unsided findings stay separate. Zones show active finding names as clickable chips. The detail pane opens through region, cluster, finding, and observation, with timelines, definition metadata, and links to exams, Exam Finding Lists, and reports. This version requires a dark radiology-workstation palette. -**Evidence highlighting.** Quotes are highlighted in the source report by whitespace-normalized exact match only, after folding Unicode compatibility forms, dashes, and smart quotes. No fuzzy matching. A quote that cannot be located is recorded as a warning in the generated data rather than silently dropped. +Quotes are highlighted by exact match after whitespace normalization and folding of Unicode compatibility forms, dashes, and smart quotes. There is no fuzzy matching. Unmatched quotes produce warnings in generated data. -**Data contract.** The browser reads only generated files under `viewer_v2/public/data/`, never the sample data, the viewer's own data directory, or the anatomic location database. A build script assembles that bundle from the example Imaging Problem List, its Exam Finding Lists, the matching report files, finding display metadata, and the `anatomic-locations` package. Every generated top-level file carries a schema version, and the generator fails on duplicate or missing finding identifiers, observations whose report cannot be resolved, or anatomy that resolves to nothing without an explicit unlocalized fallback. A check task regenerates the bundle and fails if the committed output has drifted. +The browser reads only generated files under `viewer_v2/public/data/`. A build script combines the example Imaging Problem List, Exam Finding Lists, report files, finding display metadata, and `anatomic-locations` package. Every top-level file has a schema version. Generation fails on duplicate or missing finding identifiers, unresolved report references, or unresolved anatomy without an explicit unlocalized fallback. A check task regenerates the bundle and fails if it differs from committed output. -**Stated caveats in the current pass.** The bundle covers 123 Imaging Problem List findings across 10 exams for one patient. Two findings have no specific location and use the explicit unlocalized fallback. Seven warnings are embedded in the manifest for the interface to surface: four exact-evidence misses, two missing-anatomy fallbacks, and one missing finding definition. +The bundle contains 123 findings across 10 exams for one patient. Two findings use the unlocalized fallback. The manifest contains seven warnings for display: four exact-evidence misses, two missing-anatomy fallbacks, and one missing finding definition. -**Deployment.** The plan names a separate Cloudflare Pages project, `ipl-anatomy`, publishing the built output. No site responds at `ipl-anatomy.pages.dev` as of 2026-09-21, and deployment automation beyond the documented build and deploy commands is listed as out of scope for this slice. +The plan names a separate Cloudflare Pages project, `ipl-anatomy`, for the built output. No site responds at `ipl-anatomy.pages.dev` as of 2026-09-21. Further deployment automation is outside the plan's scope. # Repository and branch of record @@ -118,7 +120,7 @@ The same repository holds [the report extraction platform](/applications/report- # What it realizes -The viewer is the reading end of the [Observation](/glossary/observation.md) to [Exam Finding List](/glossary/exam-finding-list.md) to [Imaging Problem List](/glossary/imaging-problem-list.md) hierarchy described in [the data structures area](/data-structures/hierarchy.md). `viewer_v2` additionally realizes [anatomic location](/glossary/anatomic-location.md) coding as a navigational axis, which is only possible because location codes were added to the findings themselves under [the assignment rules](/data-structures/anatomic-location-assignment-rules.md), and because the Imaging Problem List grouping key on `dev` became the finding code together with the location identifier.[^ipl-dev-claude] +The viewer displays the [Observation](/glossary/observation.md), [Exam Finding List](/glossary/exam-finding-list.md), and [Imaging Problem List](/glossary/imaging-problem-list.md) [hierarchy](/data-structures/hierarchy.md). `viewer_v2` groups navigation by [anatomic location](/glossary/anatomic-location.md), using codes assigned under [the assignment rules](/data-structures/anatomic-location-assignment-rules.md). On `dev`, Imaging Problem List groups use both the finding code and location identifier.[^ipl-dev-claude] [^ipl-main-readme]: imaging-problem-list viewer README, main branch [^ipl-main-claude]: imaging-problem-list domain model notes, main branch diff --git a/knowledge/applications/index.md b/knowledge/applications/index.md index b851af9..3f2949b 100644 --- a/knowledge/applications/index.md +++ b/knowledge/applications/index.md @@ -1,11 +1,11 @@ # Applications -Tools built on the OIDM semantic foundation and data structures: what each one is for, who uses it, what it reads and writes, where it runs, and what is in flight on its branches. Every profile names its repository and branch of record; the full repository listing is in [the repository map](/repositories/repository-map.md). +Applications built on OIDM, with their data, deployment, and development status. See [the repository map](/repositories/repository-map.md) for source repositories and branches. -* [Finding Model Forge](./finding-model-forge.md) - The web application at fmf.oidm.org where contributors author finding model definitions through an AI-assisted wizard and move them through a draft review lifecycle. -* [Finding model catalog site](./finding-models-site.md) - The static Astro site that renders the finding model corpus as browsable pages, building it from the content repository pulled in as a git submodule. -* [Imaging Problem List viewer](./imaging-problem-list-viewer.md) - The deployed browser application that renders Imaging Problem Lists, its three-level drill-down and status sections, and the anatomy-first second-generation viewer being built on the development branch. -* [Report extraction platform](./report-extraction-platform.md) - The extraction, coding, persistence, evaluation, and human-review platform on the imaging-problem-list development branch that turns narrative radiology reports into coded findings. -* [Finding and location coding](./finding-and-location-coding.md) - How extracted findings are assigned OIFM finding codes and RadLex anatomic location codes, as a deterministic index lookup followed by language model term generation and selection. -* [IPL MVP extraction and labeling](./ipl-mvp-extraction.md) - The 2025 four-stage prototype that extracted findings from reports and matched them to finding models by embedding similarity, its measured results, and why it was superseded. -* [Open Imaging Reporting SDK](./reporting-sdk.md) - The vendor-facing reporting toolkit named as a strategic pillar in the 2026 status deck, its 2023 plugin-container precursor, and the fact that no artifact exists. +* [Finding Model Forge](./finding-model-forge.md) - The application at fmf.oidm.org for authoring finding models with AI assistance and reviewing drafts. +* [Finding model catalog site](./finding-models-site.md) - The static Astro catalog built from finding model definitions in a git submodule. +* [Imaging Problem List viewer](./imaging-problem-list-viewer.md) - The deployed Imaging Problem List browser and the undeployed anatomy-first viewer on dev. +* [Report extraction platform](./report-extraction-platform.md) - The platform on imaging-problem-list dev for report extraction, coding, storage, review, and evaluation. +* [Finding and location coding](./finding-and-location-coding.md) - How deterministic lookup and language models assign OIFM finding codes and RadLex location codes. +* [IPL MVP extraction and labeling](./ipl-mvp-extraction.md) - The superseded 2025 report-extraction prototype, its embedding-based finding matches, and measured limits. +* [Open Imaging Reporting SDK](./reporting-sdk.md) - The proposed vendor-facing reporting SDK, its 2023 plugin framework precursor, and the fact that no artifact exists. diff --git a/knowledge/applications/ipl-mvp-extraction.md b/knowledge/applications/ipl-mvp-extraction.md index eaf9443..2adb3e5 100644 --- a/knowledge/applications/ipl-mvp-extraction.md +++ b/knowledge/applications/ipl-mvp-extraction.md @@ -1,10 +1,10 @@ --- type: Project Profile title: IPL MVP extraction and labeling -description: The 2025 four-stage prototype that extracted findings from reports and matched them to finding models by embedding similarity, its measured results, and why it was superseded. +description: The superseded 2025 report-extraction prototype, its embedding-based finding matches, and measured limits. tags: [applications, extraction, llm, embeddings, lineage] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:34:50Z } stale_after: 2027-09-21 sources: - id: mvp-readme @@ -27,9 +27,9 @@ sources: # Purpose -This repository was the first end-to-end attempt at the [Imaging Problem List](/glossary/imaging-problem-list.md) goal: read radiology reports, pull findings out of them, and attach each finding to a standard [finding model](/glossary/finding-model.md) definition, so that a finding could be tracked across a patient's studies. Its own framing is longitudinal monitoring of radiologic findings using common data elements.[^mvp-readme] +This was the first end-to-end prototype to extract radiology findings and match them to [finding model](/glossary/finding-model.md) definitions for longitudinal tracking. Its stated goal was an [Imaging Problem List](/glossary/imaging-problem-list.md) using common data elements.[^mvp-readme] -It is superseded. [The report extraction platform](/applications/report-extraction-platform.md) on the `imaging-problem-list` development branch does everything this does and the things this could not. This profile records what it established and what it measured, because both shaped the design that replaced it. The wider sequence is in [extraction approaches](/history/extraction-approaches.md). +[The report extraction platform](/applications/report-extraction-platform.md) on `imaging-problem-list`'s development branch supersedes it. See [extraction approaches](/history/extraction-approaches.md) for the wider history. # What a user does with it @@ -46,7 +46,7 @@ A single configuration file holds the models, the file paths, the extraction pro # The data and the schema -The schema is deliberately thin. A finding is a name and a boolean [presence](/glossary/presence.md); a mapping adds the matched finding model identifier and name, a confidence score, and a status.[^mvp-schemas] +A finding has a name and boolean [presence](/glossary/presence.md). A mapping adds the matched model identifier and name, a confidence score, and a status.[^mvp-schemas] ```python class Finding(BaseModel): @@ -62,22 +62,22 @@ class MappedFinding(BaseModel): status: str ``` -It produces neither an [Exam Finding List](/glossary/exam-finding-list.md) nor an Imaging Problem List, and no FHIR output at all; the README lists generating FHIR Observation resources as a future enhancement.[^mvp-readme] There is no location, no size, no severity, and no [change from prior](/glossary/change-from-prior.md). +The output lacks location, size, severity, and [change from prior](/glossary/change-from-prior.md). It does not produce an [Exam Finding List](/glossary/exam-finding-list.md), Imaging Problem List, or FHIR resources. The README lists FHIR Observation generation as a future enhancement.[^mvp-readme] -The reference set of finding models is a static local JSON file of 15 curated neurological finding models, not a live read from the content repository. That is the file the repository calls its reference, and swapping it for a real service is named as a future enhancement. +The reference set is a local JSON file of 15 curated neurological finding models. Replacing it with a service is listed as a future enhancement. # Language model use -Two calls, both to hosted services.[^mvp-readme] +Extraction and matching call hosted services.[^mvp-readme] -- **Extraction.** A general-purpose model reads each report under a system prompt and returns findings as name and presence pairs. -- **Matching.** Each extracted finding name is embedded, and the embedding is compared by cosine similarity against the embedded names of the 15 reference models. The highest scoring match above a configurable threshold of 0.70 is accepted; everything below it is flagged for manual review. +- A general-purpose model reads each report under a system prompt and returns finding names and presence values. +- Matching compares embeddings of extracted names with embeddings of the 15 reference model names by cosine similarity. It accepts the highest match above the configurable 0.70 threshold and flags lower scores for manual review. -Matching is therefore name-to-name similarity. No index lookup, no candidate generation, and no model judgment about whether the candidate actually fits. +Matching uses name similarity without index lookup, candidate generation, or model judgment of candidate fit. # Architecture -Four standalone Python scripts over JSON Lines files, with Pydantic for validation and cosine similarity over embedding vectors. No service, no database, no web interface. A mockups directory holds interface images for a review and labeling tool that was never built. +Four standalone Python scripts read and write JSON Lines, using Pydantic validation and cosine similarity over embeddings. There is no service, database, or web interface. A mockups directory holds images for a review and labeling interface that was never built. # Results and limits, as measured @@ -93,7 +93,7 @@ The README reports one informal run.[^mvp-readme] That is a match rate of roughly 6 percent. The three matches quoted as successes score 0.778, 0.806, and 0.761. There is no labeled evaluation set and no metrics harness. -The README states its own limitations plainly: binary presence and absence only with no severity or size, manually curated reference models limited to neurological findings, no handling of negated findings, and a static threshold. The negation limitation matters most, because explicit negatives are exactly what an Exam Finding List is supposed to carry. +The README lists binary presence, missing severity and size, a neurological reference set, unsupported negation, and a static threshold as limitations. Unsupported negation prevents the prototype from extracting the explicit negatives expected in an Exam Finding List. # Repository and branch of record @@ -112,11 +112,11 @@ No open issues and no pull requests, open or closed. Status: lineage. All three were pushed within one week and none was merged. -**A persistent FHIR design note.** One file, without a markdown extension, proposing that each finding be tracked as a persistent FHIR Observation with a stable identifier, so that repeat mentions of the same lesion across reports attach to one entity with its own timeline. It sketches a three-step pipeline, extract and map to codes, create or link a resource, then query the finding's timeline, and a patient to resource to dated-observation shape. It adds no code and names two modules that were never written.[^mvp-fhir] The idea is a genuine precursor to the grouping question the current Imaging Problem List answers structurally; see [FHIR mapping](/data-structures/fhir-mapping.md). +**A persistent FHIR design note.** A file without a markdown extension proposes persistent FHIR Observations with stable identifiers, linking repeated mentions of a lesion into one timeline. It sketches extraction and code mapping, resource creation or linking, and timeline queries, organized by patient, resource, and dated observation. It names two unwritten modules and adds no code.[^mvp-fhir] See [FHIR mapping](/data-structures/fhir-mapping.md) for the related grouping question. -**A typed-agent port.** The extraction step rewritten to use a typed agent with a declared result type and automatic retries, replacing a raw client call with manual JSON fence stripping. The schemas are unchanged. The commit was captured mid-draft, with explanatory prose left inside the Python file.[^mvp-pydantic] +**A typed-agent port.** The extraction step uses a typed agent with a declared result type and automatic retries. It replaces a raw client call and manual JSON fence stripping without changing schemas. The commit is a draft, with explanatory prose left in the Python file.[^mvp-pydantic] -**A longitudinal sample series.** The eight generic sample reports replaced with nine reports for one synthetic multiple sclerosis patient spanning 2019 to 2024, from an initial workup through follow-up studies.[^mvp-ms] It pairs with the FHIR design note's track-a-finding-over-time use case. +**A longitudinal sample series.** Nine reports for one synthetic multiple sclerosis patient replace the eight generic reports. They span initial workup and follow-up from 2019 to 2024, matching the FHIR note's longitudinal use case.[^mvp-ms] # What it established diff --git a/knowledge/applications/report-extraction-platform.md b/knowledge/applications/report-extraction-platform.md index d4ff408..d9a5b46 100644 --- a/knowledge/applications/report-extraction-platform.md +++ b/knowledge/applications/report-extraction-platform.md @@ -1,10 +1,10 @@ --- type: Project Profile title: Report extraction platform -description: The extraction, coding, persistence, evaluation, and human-review platform on the imaging-problem-list development branch that turns narrative radiology reports into coded findings. +description: The platform on imaging-problem-list dev for report extraction, coding, storage, review, and evaluation. tags: [applications, extraction, llm, ipl, evaluation, phi] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:34:50Z } stale_after: 2027-09-21 sources: - id: dev-readme @@ -62,13 +62,13 @@ sources: # Purpose -The extraction platform turns narrative radiology report text into structured, coded findings that can be assembled into an [Exam Finding List](/glossary/exam-finding-list.md) and then an [Imaging Problem List](/glossary/imaging-problem-list.md). It is the seventh and current attempt at that problem in this project; the six before it, and what each established, are in [extraction approaches](/history/extraction-approaches.md). +The platform extracts structured, coded findings from radiology reports for [Exam Finding Lists](/glossary/exam-finding-list.md) and [Imaging Problem Lists](/glossary/imaging-problem-list.md). It is the project's seventh extraction approach. See [extraction approaches](/history/extraction-approaches.md) for its predecessors. It lives on the `dev` branch of `imaging-problem-list`, 258 commits ahead of `main` as of tip commit `36fa30c`, 2026-07-22. `main` remains the stable data-structure specification and the deployed [viewer](/applications/imaging-problem-list-viewer.md). Nothing described here has merged. # What a user does with it -Four command-line entry points and one web interface.[^dev-readme] +The platform has four command-line entry points and a web interface.[^dev-readme] | Entry point | What it does | |---|---| @@ -78,11 +78,11 @@ Four command-line entry points and one web interface.[^dev-readme] | `finding-extractor-eval` | Score extraction quality against a dataset | | Extractor web interface | Submit a report, browse reports, open an extraction result, and review it | -The documented human path for producing trustworthy output is a four-step loop: batch-generate one candidate extraction file per report, have a reviewer overread and correct each one, copy the corrected file to a gold file name, and validate every gold file against the extraction model.[^review-workflow] Installation and configuration stay with the code. +The review workflow batch-generates a candidate extraction file for each report. A reviewer checks and corrects each file, copies it to a gold filename, and validates it against the extraction model.[^review-workflow] # The data -**Input.** Plain report text. A helper script splits a spreadsheet of reports into one text file each, stripping attestation and boilerplate lines. +Input is plain report text. A helper splits a spreadsheet into one file per report and strips attestations and boilerplate. **Extraction output.** The schema, set out in the original extraction plan, is a finding name, a [presence](/glossary/presence.md) value, an optional location, a list of attributes, and the verbatim report text the finding came from.[^initial-plan] @@ -94,27 +94,25 @@ The documented human path for producing trustworthy output is a four-step loop: | `attributes` | key and value pairs | Standard keys: size, acuity, change from prior, severity, count, morphology | | `report_text` | string | The verbatim quote supporting the finding | -Text that is not a finding is captured separately rather than discarded. +Non-finding text is captured separately. -**Persistence.** SQLite through SQLModel, with Alembic migrations. Reports are deduplicated by the SHA-256 hash of their text. Each extraction run is its own row carrying the report link, the timestamp, the model, the reasoning setting, and the full JSON payload; findings and non-finding text live nested inside that payload. Reviewer edits are stored as separate correction rows rather than by mutating the extraction, in three shapes: propose a new finding, suggest an update to an existing one by index or JSON path, and leave a comment for follow-up.[^dev-readme] +SQLite stores data through SQLModel, with Alembic migrations. SHA-256 hashes deduplicate report text. Each extraction row records its report, timestamp, model, reasoning setting, and JSON payload, including findings and non-finding text. Separate correction rows hold reviewer proposals for new findings, updates by index or JSON path, and follow-up comments.[^dev-readme] -**Coded output.** Coding writes back into the same extraction row, populating each finding's coding bundle and updating the coded and unresolved counts. See [finding and location coding](/applications/finding-and-location-coding.md). +[Finding and location coding](/applications/finding-and-location-coding.md) populates coding bundles in the same extraction row and updates coded and unresolved counts. # Language model use -Extraction is agentic and multi-provider: OpenAI, Anthropic, Google, OpenRouter, Ollama for local models, and vLLM for on-premises deployments.[^dev-readme] A single reasoning knob with five levels is normalized per provider, because each exposes thinking differently, and some local model families need JSON-schema output mode rather than tool calling.[^dev-claude] +Extraction agents support OpenAI, Anthropic, Google, OpenRouter, Ollama for local models, and vLLM for on-premises deployments.[^dev-readme] A five-level reasoning setting maps to each provider's controls. Some local model families require JSON-schema output instead of tool calling.[^dev-claude] Three architectural decisions shape the pipeline.[^dev-claude] -**Chunking.** Long reports are semantically chunked and the chunks extracted concurrently under a bound, then merged and deduplicated. A reviewer sub-agent can flag problems and trigger targeted re-extraction of specific chunks rather than the whole report. - -**Verbatim-quote validation.** Extraction output must carry exact quotes from the report, checked both as an output validator during generation and again afterward. - -**Coding as a separate job.** Mapping findings to standard codes happens after extraction, in its own pipeline, and can be re-run with different models without re-extracting. +- **Chunking.** Long reports are semantically chunked, extracted with bounded concurrency, merged, and deduplicated. A reviewer sub-agent can trigger re-extraction of specific chunks. +- **Verbatim-quote validation.** Exact report quotes are required and validated during generation and afterward. +- **Coding as a separate job.** Coding runs separately after extraction and can be rerun with different models. ## The validator contract -The chunk-level validator reviews one chunk's extraction against that chunk's text and returns a single decision object: the chunk identifier, whether to re-extract, a list of problems, and a rationale. The prompt names six issue patterns that justify re-extraction, and one rule that does not.[^validator] +The validator compares each chunk's extraction with its text. It returns the chunk identifier, a re-extraction decision, problems, and rationale. Six problem types justify re-extraction.[^validator] | Problem type | What it catches | |---|---| @@ -125,37 +123,37 @@ The chunk-level validator reviews one chunk's extraction against that chunk's te | `incorrect_blanket_negative` | A blanket negative mapped to the wrong or over-specific absent findings | | `incorrect_location` | Wrong, too specific, or too general location | -Formatting and style differences alone are not grounds for re-extraction. The evidence boundary is explicit: only the chunk is evidence, and the surrounding chunks are advisory. The prompt gives one worked mapping, "clear lungs" becoming an absent finding named "pulmonary parenchymal abnormality", which is the treatment of blanket negatives that `CDEStaging` first catalogued as a problem; see [extraction approaches](/history/extraction-approaches.md). +Formatting and style alone do not justify re-extraction. Only the chunk is evidence. Surrounding chunks are advisory. The prompt maps "clear lungs" to an absent "pulmonary parenchymal abnormality", addressing the blanket-negative problem first recorded in `CDEStaging`. See [extraction approaches](/history/extraction-approaches.md). # Architecture -FastAPI serves the API. Long work is asynchronous: an extraction or coding request returns 202 with a job identifier, TaskIQ workers pull the job through a Redis broker, and the client polls job status. Configuration is centralized in typed settings under an `IPL_` environment namespace. Observability is Logfire spans plus structured logging, with a stated rule that raw report text and verbatim quotes never appear in span attributes or log fields.[^dev-claude] +FastAPI serves the API. Long work is asynchronous: an extraction or coding request returns 202 with a job identifier, TaskIQ workers pull the job through a Redis broker, and the client polls job status. Typed settings use the `IPL_` environment namespace. Logfire spans and structured logs must exclude raw report text and verbatim quotes.[^dev-claude] Two browser interfaces serve different people. -**The extractor interface** is the connected one, built like the viewer with Alpine.js, Flowbite, and Tailwind from a content delivery network and no build step. It submits reports, lists them, and shows extraction results. +The connected extractor interface, built like the viewer, uses Alpine.js, Flowbite, and Tailwind from a content delivery network, without a build step. It submits reports, lists them, and shows extraction results. -**The standalone extraction reviewer** is a single self-contained HTML file that a non-developer can open locally with no install and no network, walk through an extraction's findings, and mark each one approved, flagged, unsure, or missing with free-text notes; the reviewer returns a zip of per-file review JSON.[^reviewer-plan] Its vanilla JavaScript and absence of any content delivery network are a deliberate exception to the project's frontend conventions, justified by the requirement that it work from a local file with nothing installed.[^reviewer-workflows] Its plan is marked complete, and it has become the primary instrument for extraction quality assurance and for adjudicating gold cases. +The standalone reviewer is one HTML file that a non-developer can open locally without installation or network access. Reviewers mark findings approved, flagged, unsure, or missing, add notes, and export a zip of per-file review JSON.[^reviewer-plan] Its vanilla JavaScript and absence of any content delivery network are a deliberate exception to the project's frontend conventions, justified by the requirement that it work from a local file with nothing installed.[^reviewer-workflows] Its plan is complete. It is the primary tool for extraction quality assurance and gold-case adjudication. # Evaluation -A harness runs a named dataset of reports through extraction, compares the output against ground truth, and reports scores, with optional thresholds on finding F1, presence accuracy, and verbatim checks that make the command exit non-zero when they are not met.[^eval-usage] +The evaluation harness runs extraction over a named report dataset and scores the output against ground truth. Optional thresholds on finding F1, presence accuracy, and verbatim checks cause a nonzero exit when unmet.[^eval-usage] -The design of what it scores was rewritten for honesty. On 2026-07-07, after three and a half months with no implementation, the evaluation redesign was deliberately descoped rather than discarded; the full plan's thresholds, continuous-integration gating, and thirty-case benchmark were named as what made it unstartable.[^evals-redesign] The motivation is a specific failure: a model-selection round on 2026-05-14 made a local model the default on average latency and a thirty percent increase in findings produced, and neither number can tell a real recall gain from a fabricated finding. +On 2026-07-07, the evaluation redesign was deliberately descoped rather than discarded, after three and a half months without implementation. The plan cited thresholds, continuous-integration gates, and a thirty-case benchmark as barriers.[^evals-redesign] A 2026-05-14 selection round had made a local model the default based on average latency and thirty percent more findings. Those measures could not distinguish improved recall from fabricated findings. -Version one keeps four things: a quote-first primary matcher, scoring of attribute *values* rather than attribute presence, frozen run configurations with per-case artifacts for reproducibility, a ten-case gold set adjudicated through the standalone reviewer, and a non-blocking scorecard task. The reviewer plan and the evaluation plan are sequenced rather than parallel; the reviewer exists to produce the gold set the evaluation needs.[^reviewer-workflows] +Version one retains quote-first matching, attribute-value scoring, frozen run configurations with per-case artifacts, a ten-case gold set, and a non-blocking scorecard task. The redesigned evaluation depends on the gold set adjudicated with the standalone reviewer.[^reviewer-workflows] # Local models and protected health information -Protected health information is named as the next use case, and the platform's answer is a local-only mode. A hardening pass completed 2026-04-12 moved enforcement out of the command-line boundary into a shared preflight helper that every entry point calls, closing gaps where the batch command, the API, and the worker could still reach a cloud provider with local-only set; it also detects cloud-suffixed model names in the local runtime.[^local-hardening] The evaluation command is explicitly outside the guarantee, on the stated ground that evaluation datasets are curated fixtures rather than patient data. +Local-only mode supports the planned protected health information use case. A hardening pass completed 2026-04-12 moved enforcement out of the command-line boundary into a shared preflight helper that every entry point calls, closing gaps where the batch command, the API, and the worker could still reach a cloud provider with local-only set. It also detects cloud-suffixed model names in the local runtime.[^local-hardening] The evaluation command is excluded from this guarantee, on the stated ground that evaluation datasets are curated fixtures rather than patient data. -Remaining hardening items were shelved with explicit reopen triggers rather than left as an open-ended list. The example given is detecting a local model alias whose underlying definition points at a cloud source, deferred because the runtime's inspection surface is unstable and parsing model definition files is not authoritative.[^local-tightening] +Deferred hardening items have explicit reopen triggers. Detecting aliases whose definitions point to cloud sources is deferred because runtime inspection is unstable and model-definition parsing is not authoritative.[^local-tightening] -Local model choice itself is under reassessment rather than settled. The plan opened 2026-07-01 proposes reassessing wholesale rather than patching documentation, on the grounds that both the runtime and the model generations have moved since the May 2026 round, and it flags one new candidate family as unverified for radiology extraction because it is tuned for agentic coding.[^mlx] +The reassessment plan opened 2026-07-01 calls for new local model comparisons since the May 2026 round. It identifies one candidate family as unverified for radiology extraction because it is tuned for agentic coding.[^mlx] # Plans in flight -Eight plans are active on `dev`. Facts and dates as stated in each document. +Eight plans are active on `dev`, with statuses and dates recorded below. | Plan | Date | Status | |---|---|---| @@ -168,15 +166,15 @@ Eight plans are active on `dev`. Facts and dates as stated in each document. | Reasoning plumbing simplification | not dated | Fully specified, not started; blocked on a library version bump that would retire roughly 728 lines of per-provider translation code[^thinking] | | Anatomy-first viewer | not dated | Implemented, ready for review; see [the viewer profile](/applications/imaging-problem-list-viewer.md) | -The anatomic location plan that added location codes to the sample Exam Finding Lists is marked complete as of 2026-06-10, with one follow-on open: reconciling generic against specific locations for the same finding across exams, which today produces separate Imaging Problem List groups. Two plans completed in July 2026 are excluded from the table above. +The sample Exam Finding List location-coding plan was completed on 2026-06-10. Reconciling generic and specific locations across exams remains open because they produce separate Imaging Problem List groups. The table excludes two plans completed in July 2026. # Open issues -One, number 1, "Create System of Data Models", asking for a formal model layer for [Observation](/glossary/observation.md), Exam Finding List, and Imaging Problem List with schema export. It is broader than any plan above and unclaimed; see [the data model roadmap](/roadmap/ipl-data-model-system.md). The single open pull request is empty, its design document having been moved to a separate repository. +Issue 1, "Create System of Data Models", requests formal [Observation](/glossary/observation.md), Exam Finding List, and Imaging Problem List models with schema export. It is unclaimed. See [the data model roadmap](/roadmap/ipl-data-model-system.md). The single open pull request is empty after its design document moved to a separate repository. # What it realizes -This platform is where [extraction](/glossary/extraction.md) and [coding](/glossary/coding.md) become operations rather than ideas. It produces the [Observations](/glossary/observation.md) that fill an [Exam Finding List](/data-structures/exam-finding-list.md), attaches [anatomic locations](/glossary/anatomic-location.md) under [the assignment rules](/data-structures/anatomic-location-assignment-rules.md), and resolves [OIFM identifiers](/glossary/oifm.md) against the published registry described in [the content catalog](/semantic-foundation/finding-models/content-catalog.md). The [provenance](/glossary/provenance.md) requirement that each Observation carry a marker of how it was produced is met here by storing the model, the reasoning setting, and the verbatim quote with every extraction. Its place in the layered system is drawn in [the architecture overview](/overview/architecture.md). +[Extraction](/glossary/extraction.md) and [coding](/glossary/coding.md) produce [Observations](/glossary/observation.md) for an [Exam Finding List](/data-structures/exam-finding-list.md). [Anatomic locations](/glossary/anatomic-location.md) follow [the assignment rules](/data-structures/anatomic-location-assignment-rules.md), and [OIFM identifiers](/glossary/oifm.md) resolve against [the published registry](/semantic-foundation/finding-models/content-catalog.md). The [provenance](/glossary/provenance.md) requirement that each Observation carry a marker of how it was produced is met here by storing the model, the reasoning setting, and the verbatim quote with every extraction. See [the architecture overview](/overview/architecture.md). [^dev-readme]: imaging-problem-list README, dev branch [^dev-claude]: imaging-problem-list architecture notes, dev branch diff --git a/knowledge/applications/reporting-sdk.md b/knowledge/applications/reporting-sdk.md index 0cbe934..f6e7f59 100644 --- a/knowledge/applications/reporting-sdk.md +++ b/knowledge/applications/reporting-sdk.md @@ -1,10 +1,10 @@ --- type: Concept title: Open Imaging Reporting SDK -description: The vendor-facing reporting toolkit named as a strategic pillar in the 2026 status deck, its 2023 plugin-container precursor, and the fact that no artifact exists. +description: The proposed vendor-facing reporting SDK, its 2023 plugin framework precursor, and the fact that no artifact exists. tags: [applications, reporting, roadmap, vendors] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:34:50Z } stale_after: 2027-09-21 sources: - id: deck @@ -23,44 +23,42 @@ sources: # Status first -No artifact exists. There is no repository, package, specification, issue, or branch for an Open Imaging Reporting SDK in any repository read for this knowledgebase, and the project lead confirms it as concept only. It appears in this bundle as stated direction, and every document that mentions it says so. The glossary entry is [Open Imaging Reporting SDK](/glossary/open-imaging-reporting-sdk.md); the goal itself is recorded in [the 2026 roadmap](/roadmap/roadmap-2026.md). - -What follows is what has actually been said about it, and the two pieces of working code that show what parts of it would look like. +The [Open Imaging Reporting SDK](/glossary/open-imaging-reporting-sdk.md) is concept only, as confirmed by the project lead. No repository, package, specification, issue, or branch for it was found in the repositories read for this knowledgebase. Its goal is recorded in [the 2026 roadmap](/roadmap/roadmap-2026.md). # What the deck says -The January 2026 status update organizes the project into three pillars. The third is applications, and the deck states it as "an Open Imaging Reporting SDK enabling vendor-driven innovation", alongside demonstration applications including an Imaging Problem List browser and early draft-generation tools.[^deck] +The January 2026 status update names "an Open Imaging Reporting SDK enabling vendor-driven innovation" under its applications pillar. It also lists demonstration applications, including an Imaging Problem List browser and early draft-generation tools.[^deck] -The call to action returns to it in the same terms. The deck asks for an ACR-OIDM structured imaging results working group, for structure first with FHIR and other standards following, and for the work to be vendor-driven, giving reporting software development kits from a reporting vendor as the example of what that means. The SDK is therefore named as something vendors would build on or build, not as something the project commits to shipping. +The deck calls for an ACR-OIDM structured imaging results working group, structure before FHIR and other standards, and vendor-driven work. Reporting SDKs from a reporting vendor are its example. It does not commit the project to shipping an SDK. # The 2023 precursor -The idea is not new, and the earliest statement of it is more specific than the deck's. A site post of 2023-07-16 proposes a reporting assistance framework built as a plugin container inside the reporting tool.[^site-framework] +A 2023-07-16 site post proposes a reporting assistance framework as a plugin container inside the reporting tool.[^site-framework] -Its shape, as stated: +The proposal describes this behavior: -- Developers author plugins in an ordinary programming language, the post naming JavaScript. -- The container gives every plugin a standard data structure, defined by OIDM, holding the relevant context: the findings in the current report, prior reports, and the exams being reported on. -- Each plugin inspects that context and issues standard commands back to the reporting system. The four named are inserting generated text into the report, requesting more information from the radiologist, alerting the radiologist to a problem, and sending data to an external system. -- The container re-runs every plugin whenever the context changes, whether because new machine-generated data arrived or because the radiologist edited the report. +- Developers write plugins in a programming language such as JavaScript. +- The container supplies an OIDM-defined structure containing current findings, prior reports, and the exams being reported. +- Plugins inspect that context and issue four kinds of command: insert generated text, request information from the radiologist, alert the radiologist to a problem, or send data to an external system. +- The container reruns every plugin whenever context changes, including after new machine-generated data or a radiologist's edit. -The post describes the result as a suite of assistant scripts continually reviewing the data around a radiologist and issuing commands to assist. That is a plugin architecture rather than a library, which is the main way it differs from what the deck's shorthand suggests. The post is summarized among [the site articles](/history/site-articles.md). +The post describes the result as a suite of assistant scripts continually reviewing the data around a radiologist and issuing commands to assist. That is a plugin architecture rather than a library, which is the main way it differs from what the deck's shorthand suggests. See [the site articles](/history/site-articles.md). # The About page promise -The About page, last modified 2023-06-21, commits the project to maintaining programming interfaces in at least three languages, TypeScript and JavaScript, Python, and C#.[^site-about] Two of the three were begun and both are now lineage; no C# library was ever written. See [lineage repositories](/history/lineage-repositories.md). +The About page, last modified 2023-06-21, commits to programming interfaces in TypeScript and JavaScript, Python, and C#.[^site-about] The first two were begun and are now [lineage repositories](/history/lineage-repositories.md). No C# library was written. -The libraries that do exist, `findingmodel` with its anatomic locations package and `med-ontology-lookup`, are semantic-foundation tools. They resolve definitions and codes. They are not a reporting toolkit and are not presented as one; see [the terminology lookup profile](/semantic-foundation/terminologies/med-ontology-lookup.md). +`findingmodel`, its anatomic locations package, and `med-ontology-lookup` resolve definitions and codes. They provide no reporting toolkit. See [the terminology lookup profile](/semantic-foundation/terminologies/med-ontology-lookup.md). # The one working precedent -`CDETemplateDemo`, written in 2023 and untouched since, is the only code in the project that does anything a reporting SDK would have to do. It takes a [CDE-labeled FHIR Observation](/glossary/cde-labeled-fhir-observation.md), flattens its components into a dictionary keyed by display name, derives boolean flags including explicit present and absent flags, and renders the result through a text template so that one template produces a full sentence for a present finding and a short clause for an absent one.[^cde-demo] It was demonstrated at SIIM in June 2023 as a web service. +`CDETemplateDemo`, written in 2023 and unchanged since, is the project's only working precedent for reporting SDK functionality. It flattens a [CDE-labeled FHIR Observation](/glossary/cde-labeled-fhir-observation.md) into a dictionary keyed by component display name, derives boolean flags including presence and absence, and renders a text template. One template produces a full sentence for a present finding and a short clause for an absent one.[^cde-demo] It was demonstrated as a web service at SIIM in June 2023. -That is structured data to report prose, without a language model. It is the half of the 2023 framework that the plugins would call when they insert generated text. The full account is in [CDE template rendering](/history/cde-template-rendering.md). +The demo generates prose without a language model, demonstrating the rendering needed by plugins that insert text. See [CDE template rendering](/history/cde-template-rendering.md). # What would have to exist -Stated only as what the sources describe, not as a design. The 2023 post names a standard report-context data structure defined by OIDM; today the closest thing to it is the [Exam Finding List](/data-structures/exam-finding-list.md), which covers the findings of one exam, and the [Imaging Problem List](/data-structures/imaging-problem-list.md), which covers a patient's history. Neither carries the current report text, the order, or the prior reports that the post's context structure and the About page's wider scope both call for, and the [Imaging Persona](/glossary/imaging-persona.md), which is the deck's name for that surrounding clinical context, is itself concept only. The rendering half has a working precedent and no maintained implementation. The plugin container half has no implementation at all. +Stated only as what the sources describe, not as a design. The proposed context structure includes current report text, the order, and prior reports. The [Exam Finding List](/data-structures/exam-finding-list.md) covers one exam's findings, and the [Imaging Problem List](/data-structures/imaging-problem-list.md) covers patient history, but neither carries that full context. The [Imaging Persona](/glossary/imaging-persona.md), the deck's name for surrounding clinical context, is also concept only. Rendering has a working precedent but no maintained implementation. The plugin container has no implementation. # Where this is recorded diff --git a/knowledge/assets/brand/anatomic-locations/logo-black.png b/knowledge/assets/brand/anatomic-locations/logo-black.png new file mode 100644 index 0000000..26f3613 Binary files /dev/null and b/knowledge/assets/brand/anatomic-locations/logo-black.png differ diff --git a/knowledge/assets/brand/anatomic-locations/logo-black.svg b/knowledge/assets/brand/anatomic-locations/logo-black.svg new file mode 100644 index 0000000..e0a8020 --- /dev/null +++ b/knowledge/assets/brand/anatomic-locations/logo-black.svg @@ -0,0 +1,209 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/knowledge/assets/brand/anatomic-locations/logo-color.png b/knowledge/assets/brand/anatomic-locations/logo-color.png new file mode 100644 index 0000000..00abda9 Binary files /dev/null and b/knowledge/assets/brand/anatomic-locations/logo-color.png differ diff --git a/knowledge/assets/brand/anatomic-locations/logo-color.svg b/knowledge/assets/brand/anatomic-locations/logo-color.svg new file mode 100644 index 0000000..84bc2cb --- /dev/null +++ b/knowledge/assets/brand/anatomic-locations/logo-color.svg @@ -0,0 +1,215 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/knowledge/assets/brand/anatomic-locations/logo-white.png b/knowledge/assets/brand/anatomic-locations/logo-white.png new file mode 100644 index 0000000..488887a Binary files /dev/null and b/knowledge/assets/brand/anatomic-locations/logo-white.png differ diff --git a/knowledge/assets/brand/anatomic-locations/logo-white.svg b/knowledge/assets/brand/anatomic-locations/logo-white.svg new file mode 100644 index 0000000..baf394a --- /dev/null +++ b/knowledge/assets/brand/anatomic-locations/logo-white.svg @@ -0,0 +1,214 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/knowledge/assets/brand/anatomic-locations/mark.png b/knowledge/assets/brand/anatomic-locations/mark.png new file mode 100644 index 0000000..9be7505 Binary files /dev/null and b/knowledge/assets/brand/anatomic-locations/mark.png differ diff --git a/knowledge/assets/brand/anatomic-locations/mark.svg b/knowledge/assets/brand/anatomic-locations/mark.svg new file mode 100644 index 0000000..44de4d3 --- /dev/null +++ b/knowledge/assets/brand/anatomic-locations/mark.svg @@ -0,0 +1,36 @@ + + + + + + + + + diff --git a/knowledge/assets/brand/oidm/logo-black.png b/knowledge/assets/brand/oidm/logo-black.png new file mode 100644 index 0000000..83aaf02 Binary files /dev/null and b/knowledge/assets/brand/oidm/logo-black.png differ diff --git a/knowledge/assets/brand/oidm/logo-black.svg b/knowledge/assets/brand/oidm/logo-black.svg new file mode 100644 index 0000000..cb025a8 --- /dev/null +++ b/knowledge/assets/brand/oidm/logo-black.svg @@ -0,0 +1,293 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/knowledge/assets/brand/oidm/logo-color.png b/knowledge/assets/brand/oidm/logo-color.png new file mode 100644 index 0000000..364974c Binary files /dev/null and b/knowledge/assets/brand/oidm/logo-color.png differ diff --git a/knowledge/assets/brand/oidm/logo-color.svg b/knowledge/assets/brand/oidm/logo-color.svg new file mode 100644 index 0000000..3044dc5 --- /dev/null +++ b/knowledge/assets/brand/oidm/logo-color.svg @@ -0,0 +1,297 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/knowledge/assets/brand/oidm/logo-white.png b/knowledge/assets/brand/oidm/logo-white.png new file mode 100644 index 0000000..adff8a8 Binary files /dev/null and b/knowledge/assets/brand/oidm/logo-white.png differ diff --git a/knowledge/assets/brand/oidm/logo-white.svg b/knowledge/assets/brand/oidm/logo-white.svg new file mode 100644 index 0000000..34d4380 --- /dev/null +++ b/knowledge/assets/brand/oidm/logo-white.svg @@ -0,0 +1,297 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/knowledge/assets/brand/oidm/mark.png b/knowledge/assets/brand/oidm/mark.png new file mode 100644 index 0000000..5f92ad4 Binary files /dev/null and b/knowledge/assets/brand/oidm/mark.png differ diff --git a/knowledge/assets/brand/oidm/mark.svg b/knowledge/assets/brand/oidm/mark.svg new file mode 100644 index 0000000..722388b --- /dev/null +++ b/knowledge/assets/brand/oidm/mark.svg @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/knowledge/data-structures/anatomic-location-assignment-rules.md b/knowledge/data-structures/anatomic-location-assignment-rules.md index ac700e8..ad71073 100644 --- a/knowledge/data-structures/anatomic-location-assignment-rules.md +++ b/knowledge/data-structures/anatomic-location-assignment-rules.md @@ -1,10 +1,10 @@ --- type: Reference title: Anatomic location assignment rules -description: The precedence, laterality, bilateral, and specificity rules that decide which anatomic location is attached to a finding in an Exam Finding List, migrated from the imaging-problem-list development branch. +description: Migrated rules for assigning anatomy, laterality, and specificity to Exam Finding List observations. tags: [data-structures, anatomic-location, laterality, coding, migrated] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: anat-rules resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/docs/anatomic-location-assignment-rules.md @@ -19,7 +19,7 @@ sources: # About this document -This is a near-verbatim migration of `docs/anatomic-location-assignment-rules.md` from the `imaging-problem-list` repository's development branch.[^anat-rules] The rules were agreed for a correction pass over the `sample_data/example2` findings and are stated there as "the intended spec for tuning the automated location-coding step later." Wording and structure follow the original; only terminology and links have been adjusted for this knowledgebase. +Migrated near-verbatim from `docs/anatomic-location-assignment-rules.md` on `imaging-problem-list`'s development branch.[^anat-rules] Wording and structure follow the original; only terminology and links have been adjusted for this knowledgebase. The rules were agreed for a correction pass over the `sample_data/example2` findings and are "the intended spec for tuning the automated location-coding step later." The subject is how an `anatomicLocation` of `{locationId, locationDisplay}`, a [RadLex identifier](/glossary/radlex-id.md) from the [`anatomic-locations`](https://pypi.org/project/anatomic-locations/) index, is assigned to each [observation](/data-structures/observation.md) in an [Exam Finding List](/data-structures/exam-finding-list.md).[^anat-pkg] diff --git a/knowledge/data-structures/exam-finding-list.md b/knowledge/data-structures/exam-finding-list.md index ac7ef05..347a4c7 100644 --- a/knowledge/data-structures/exam-finding-list.md +++ b/knowledge/data-structures/exam-finding-list.md @@ -1,10 +1,10 @@ --- type: Data Structure title: Exam Finding List -description: The per-exam structure that holds every finding declared present or absent on one imaging exam, its full field list on both branches, where its contents come from, and the FHIR and IHE encodings it is meant to reach. +description: Findings from one exam, their fields and sources, and planned FHIR and IHE encodings. tags: [data-structures, exam-finding-list, loinc, fhir, provenance] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:34:50Z } sources: - id: ipl-main resource: https://github.com/openimagingdata/imaging-problem-list/blob/06f64a7893b444b761dc069ed86140a081195eac/README.md @@ -31,13 +31,13 @@ sources: # Definition -"In the context of an imaging exam, a list of the findings declared as present/absent on that exam."[^ipl-main] An [Exam Finding List](/glossary/exam-finding-list.md) is the second level of [the hierarchy](/data-structures/hierarchy.md): every [observation](/data-structures/observation.md) from one exam, wrapped in that exam's identity. +"In the context of an imaging exam, a list of the findings declared as present/absent on that exam."[^ipl-main] An [Exam Finding List](/glossary/exam-finding-list.md) combines an exam's identity with its [observations](/data-structures/observation.md). It is the second level of [the hierarchy](/data-structures/hierarchy.md). -The specification states two requirements. The list "must also have basic information (keyed by a curated list of [LOINC](/glossary/loinc.md) codes) about what exam this is." And "the same finding type may be declared as present multiple times; each time is a separate entry in the EFL."[^ipl-main] +The imaging-problem-list README states two requirements. The list "must also have basic information (keyed by a curated list of [LOINC](/glossary/loinc.md) codes) about what exam this is." And "the same finding type may be declared as present multiple times; each time is a separate entry in the EFL."[^ipl-main] # Fields -The structure is JSON. The table below is the stable specification on `main`, with the one development-branch addition marked.[^ipl-main-claude][^efl-sample] +The JSON fields follow the stable specification on `main`, with the development branch's addition marked.[^ipl-main-claude][^efl-sample] | Field | Type | Required | Notes | |---|---|---|---| @@ -59,41 +59,41 @@ The structure is JSON. The table below is the stable specification on `main`, wi `anatomicLocation` is the only field the development branch adds. Data produced against the stable specification does not carry it, and the stable branch's own sample files do not have it. -A trimmed real record, with a field-by-field walkthrough, is in [the Exam Finding List example](/references/exam-finding-list-example.md). +See [the Exam Finding List example](/references/exam-finding-list-example.md) for a sample record and field walkthrough. ## The exam header -The LOINC code is not decoration. It is the key that lets the problem list say which kind of exam an observation came from, and it is what makes "was this looked for on a chest study?" answerable. The ten sample exams use seven distinct LOINC codes covering radiography, computed tomography, ultrasound, and magnetic resonance. The requirement is stated as a *curated* list of LOINC codes, which is the same need the [exam types](/semantic-foundation/exam-types/) area exists to serve; no such curated list has been published. +The LOINC code identifies the exam type, allowing queries such as "was this looked for on a chest study?" The ten sample exams use seven LOINC codes covering radiography, computed tomography, ultrasound, and magnetic resonance. The imaging-problem-list README requires a curated list of codes, the purpose of the [exam types](/semantic-foundation/exam-types/) work. No such list has been published. ## Repeatable findings -One entry per instance is a deliberate rule, not an artifact. "The same finding type may appear multiple times in one exam (e.g., multiple kidney stones). Each instance gets a separate entry with its own `observationId`."[^ipl-main-claude] The count of a finding on an exam is therefore the number of entries. The [Imaging Problem List](/data-structures/imaging-problem-list.md) re-collapses them by source report, so a patient timeline shows one row per exam rather than three rows for three stones. +One entry per instance is a deliberate rule, not an artifact. "The same finding type may appear multiple times in one exam (e.g., multiple kidney stones). Each instance gets a separate entry with its own `observationId`."[^ipl-main-claude] The number of entries gives the count. The [Imaging Problem List](/data-structures/imaging-problem-list.md) groups them by source report for display as one timeline row per exam. # Where the contents come from -The specification is explicit that an Exam Finding List has two possible provenances: it "can be generated by LLM from an existing report or generated live during exam time; each Observation should include some kind of [provenance](/glossary/provenance.md) marker."[^ipl-main] No provenance field exists in the current format. The marker is a stated requirement without an implementation. +An Exam Finding List "can be generated by LLM from an existing report or generated live during exam time; each Observation should include some kind of [provenance](/glossary/provenance.md) marker."[^ipl-main] No provenance field exists in the current format. The marker is a stated requirement without an implementation. -The deck widens the sources further, listing dictation, artificial intelligence tools, and interpretation-time interfaces as the three origins of the findings in one list.[^deck] That is the case the provenance marker is for: an observation produced by an AI tool and an observation dictated by a radiologist would sit side by side in the same list and need to be told apart. The [FHIR lineage](/data-structures/fhir-mapping.md) solved the same problem with `status`, `preliminary` for the machine and `final` for the radiologist. +The deck lists dictation, artificial intelligence tools, and interpretation-time interfaces as sources of findings.[^deck] Provenance would distinguish AI-produced and radiologist-dictated observations in the same list. The [FHIR lineage](/data-structures/fhir-mapping.md) used `status`, with `preliminary` for the machine and `final` for the radiologist. -In practice today the sample lists were generated from a working spreadsheet. `generate_efl_from_excel.py` reads a worksheet with columns Exam Date, Exam Type, Exam Code, Finding, OIDM Finding Model Name, OIDM FMID, Presence OIFMA_ID, Present/Absent, and Text, groups rows by exam, and writes one file per exam with a fresh UUID as the `diagnosticReportId`.[^excel-script] The live path, from report text through extraction and coding, is the [report extraction platform](/applications/report-extraction-platform.md). +The sample lists come from a spreadsheet. `generate_efl_from_excel.py` reads these columns: Exam Date, Exam Type, Exam Code, Finding, OIDM Finding Model Name, OIDM FMID, Presence OIFMA_ID, Present/Absent, and Text. It groups rows by exam and writes one file per exam with a fresh UUID as the `diagnosticReportId`.[^excel-script] The [report extraction platform](/applications/report-extraction-platform.md) extracts and codes findings from report text. # The diagram -The README carries a hand-drawn figure, `exam-finding-list.png`, that makes the case in one picture.[^efl-diagram] On the left is the FINDINGS section of a chest computed tomography report with two kinds of highlight: green over the positive statements the list should capture, including biapical scarring, subsegmental atelectasis, nine separately numbered pulmonary nodules, a calcified granuloma, ectatic pulmonary arteries, coronary artery calcifications, a pacing device, colonic diverticular disease, thoracic dextroscoliosis, a T10 compression fracture, and degenerative changes; and pink over the explicit negatives, "No pleural effusion", "No enlarged supraclavicular, axillary, mediastinal or hilar lymph nodes", and "No pericardial effusion". +The README's hand-drawn `exam-finding-list.png` shows a chest computed tomography report beside a findings table.[^efl-diagram] The report's FINDINGS section highlights positive statements in green. These include biapical scarring, subsegmental atelectasis, nine numbered pulmonary nodules, a calcified granuloma, ectatic pulmonary arteries, coronary artery calcifications, a pacing device, colonic diverticular disease, thoracic dextroscoliosis, a T10 compression fracture, and degenerative changes. Pink marks the explicit negatives: "No pleural effusion", "No enlarged supraclavicular, axillary, mediastinal or hilar lymph nodes", and "No pericardial effusion". -On the right is a table headed "Exam Finding List" with three columns, Finding, CDE Set ID, and Count. Pulmonary nodule carries a count of 8, subsegmental atelectasis 2, and the four negatives carry a count of 0, which is the point: a zero count is a recorded observation of absence, not a missing row. Starred rows mark findings that had no entry in the finding ontology at the time the figure was drawn. The identifiers in the figure are RadElement `RDES####` [CDE set](/glossary/cde-set.md) codes rather than OIFM identifiers, which dates it to before the finding model corpus took that role. +The table is headed "Exam Finding List" with Finding, CDE Set ID, and Count columns. Pulmonary nodule has a count of 8, subsegmental atelectasis 2, and the four negatives 0. Zero records an observation of absence. Starred rows mark findings missing from the ontology at the time. The figure uses RadElement `RDES####` [CDE set](/glossary/cde-set.md) codes, predating the use of OIFM identifiers. # FHIR and IHE The documented FHIR encoding is "**DiagnosticReport** containing a list of **Observation** objects, with a finding code on each Observation and a list of components with attribute codes and values (especially present/absent and change from prior)."[^ipl-main] One [FHIR DiagnosticReport](/glossary/fhir-diagnostic-report.md), one Observation per finding, attributes as components. -That mapping is documented and implemented nowhere. No FHIR resource classes exist in the extraction platform's source, and a search across it for `DiagnosticReport` or `fhir` returns nothing. The only real FHIR documents in the repository are two *input* samples, and those do not use the component pattern the specification prescribes, because the pattern describes the output. Full detail is in [FHIR mapping](/data-structures/fhir-mapping.md). +That mapping is documented and implemented nowhere. The extraction platform's source code contains no FHIR resource classes or references to `DiagnosticReport` or `fhir`. Its only FHIR documents are two input samples, and those do not use the documented component pattern, because that pattern describes the output. See [FHIR mapping](/data-structures/fhir-mapping.md). -The deck adds a second target: an Exam Finding List "connects to IHE Imaging Diagnostic Report (IDR) FHIR representation."[^deck] The [IDR profile](/glossary/imaging-diagnostic-report.md) is not mentioned anywhere in the `imaging-problem-list` repository, on any branch. The alignment is a stated goal, and the places where the two models would have to be reconciled are set out in [IHE IDR alignment](/data-structures/ihe-idr-alignment.md). +The deck states that an Exam Finding List "connects to IHE Imaging Diagnostic Report (IDR) FHIR representation."[^deck] No branch of `imaging-problem-list` mentions the [IDR profile](/glossary/imaging-diagnostic-report.md). See [IHE IDR alignment](/data-structures/ihe-idr-alignment.md) for the differences to resolve in pursuing this goal. # Schema status -There is no published JSON Schema. Every sample file opens with a `$schema` URL pointing into the repository at `schema/exam-problem-list-schema.json`, and the repository's own notes say plainly that it "doesn't exist yet."[^ipl-main-claude] The structure is defined by the prose above, by the sample data, and by the two scripts that write and read it. A formal model layer with JSON Schema export is [issue 1](https://github.com/openimagingdata/imaging-problem-list/issues/1); see [the IPL data model system roadmap](/roadmap/ipl-data-model-system.md). +There is no published JSON Schema. Every sample's `$schema` URL points to `schema/exam-problem-list-schema.json`, which the repository notes say "doesn't exist yet."[^ipl-main-claude] Prose, samples, and the two scripts that write and read the structure define it. [Issue 1](https://github.com/openimagingdata/imaging-problem-list/issues/1) requests formal models with JSON Schema export. See [the IPL data model system roadmap](/roadmap/ipl-data-model-system.md). [^ipl-main]: imaging-problem-list README, main branch [^ipl-main-claude]: imaging-problem-list domain model notes, main branch diff --git a/knowledge/data-structures/fhir-mapping.md b/knowledge/data-structures/fhir-mapping.md index 686d0f6..ce2ed37 100644 --- a/knowledge/data-structures/fhir-mapping.md +++ b/knowledge/data-structures/fhir-mapping.md @@ -4,7 +4,7 @@ title: FHIR mapping description: Everything OIDM has documented about representing its data structures in FHIR, from the CDE-labeled Observation pattern of the lineage repositories to the current Exam Finding List and Imaging Problem List mappings, and the plain fact that no current code emits FHIR. tags: [data-structures, fhir, observation, cde, mapping] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: ipl-main resource: https://github.com/openimagingdata/imaging-problem-list/blob/06f64a7893b444b761dc069ed86140a081195eac/README.md @@ -40,15 +40,15 @@ sources: # The stance -OIDM's position on FHIR is stated in the deck's call to action as two words: **structure first**, with FHIR and other standards following.[^deck] The project builds "functional data structures that can then be expressed in FHIR and other standards" rather than starting from the standard and working back. That ordering explains the state of everything below: the mappings are written down carefully, they have precedent in working examples, and no current code produces them. +The deck calls for **structure first**, followed by FHIR and other standards.[^deck] OIDM builds "functional data structures that can then be expressed in FHIR and other standards". The mappings are written down carefully, they have precedent in working examples, and no current code produces them. # The founding pattern: the CDE-labeled FHIR Observation -The project began from FHIR rather than beside it. Its About page defines the unit of radiology data as a "[CDE-labeled FHIR Observation](/glossary/cde-labeled-fhir-observation.md) object", and the 2023 post that set the direction works the idea through with a pulmonary nodule.[^site-about][^site-findings] +OIDM began with FHIR. Its About page defines the unit of radiology data as a "[CDE-labeled FHIR Observation](/glossary/cde-labeled-fhir-observation.md) object". A 2023 post illustrates it with a pulmonary nodule.[^site-about][^site-findings] ## The worked example -`FHIRSamples` holds four hand-built resources for a lung cancer screening scenario. They remain the clearest statement of the pattern. +`FHIRSamples` holds four hand-built resources for a lung cancer screening scenario. **The report.** A [FHIR DiagnosticReport](/glossary/fhir-diagnostic-report.md) with `category` coded in SNOMED CT and HL7 v2 table 0074, `code` coded as [LOINC](/glossary/loinc.md) `87279-6` for a screening chest computed tomography, an inline `ImagingStudy`, `result` referencing three Observations, and a `conclusion` with a SNOMED `conclusionCode`.[^fhir-report] @@ -67,15 +67,15 @@ The project began from FHIR rather than beside it. Its About page defines the un } ``` -Three patterns come out of it. +The example demonstrates three patterns. **Set code, element code, value code.** The chain from `RDES195` to `RDE1717` to `RDE1717.1`, all through one coding system, is what "CDE-labeled" means concretely. The current [Exam Finding List](/data-structures/exam-finding-list.md) uses the identical chain with a different vocabulary: `OIFM` identifier, `OIFMA` identifier, dot-suffixed value code. -**Status carries provenance.** The example has the same finding twice, once as an AI observation with `status` `preliminary` and once as the radiologist's with `status` `final`. The two resources are otherwise identical. Distinguishing a machine-produced finding from a confirmed one is a field value, not a separate resource type.[^fhir-ai] That is the closest precedent for the "provenance marker" the Exam Finding List specification asks for, and it is also exactly the ACR priority the deck names, correlating artificial intelligence observations against radiologist observations.[^deck] +**Status carries provenance.** The same finding appears twice, as an AI observation with `status` `preliminary` and a radiologist's observation with `status` `final`. The resources are otherwise identical.[^fhir-ai] Distinguishing a machine-produced finding from a confirmed one is a field value, not a separate resource type. That is the closest precedent for the "provenance marker" the Exam Finding List specification asks for. It also supports the ACR priority named in the deck, correlating AI and radiologist observations.[^deck] **Assessments are second-order observations.** A fourth resource carries the Lung-RADS category as a component of `RDES267`, and its `derivedFrom` points at both the imaging study **and** the radiologist's finding Observation.[^fhir-lungrads] An assessment built on top of a finding is an Observation referring to an Observation. That is the precedent for any future modelling of the reporting-system categories the roadmap names. -Two absences in the example are worth recording. No `bodySite` appears on the finding Observations, because anatomy was implicit in the CDE definition rather than explicit on the resource. No Patient resource is included; `subject.reference` is a bare reference. +The finding Observations omit `bodySite` because anatomy was implicit in the CDE definition. No Patient resource is included. `subject.reference` is a bare reference. ## The Python model @@ -96,9 +96,9 @@ Field by field, the Exam Finding List mapping is close to mechanical. `diagnosti # What is actually implemented -Nothing. A search for `DiagnosticReport` or `fhir` across the extraction platform's entire source tree on the development branch returns no matches. No FHIR resource classes exist anywhere in the current Python code, and no OIDM tool emits a FHIR resource. +Nothing. A search for `DiagnosticReport` or `fhir` across the extraction platform's entire source tree on the development branch returns no matches. The development branch's extraction source has no FHIR resource classes and no tool that emits FHIR resources. -The only real FHIR documents in the current repositories are two **input** samples, `powerscribe-fhir.json` and `chest-ct-fhir.json`, which are pre-transformation DiagnosticReports carrying contained `Patient`, `ImagingStudy`, and `Observation` resources.[^powerscribe] They are worth reading because they differ from the prescribed output in two instructive ways. Their finding Observations code `bodySite` with [RadLex](/glossary/radlex.md), which the prescribed mapping does not mention. And their components carry DICOM codes for series, instance, and SOP identifiers rather than presence and change-from-prior attribute codes. That is not a contradiction: the component pattern the specification describes applies to the Exam Finding List output, not to the reporting system's input. +The current repositories contain two FHIR input samples, `powerscribe-fhir.json` and `chest-ct-fhir.json`. These pre-transformation DiagnosticReports contain `Patient`, `ImagingStudy`, and `Observation` resources.[^powerscribe] Their finding Observations code `bodySite` with [RadLex](/glossary/radlex.md), which the prescribed mapping does not mention. Their components carry DICOM codes for series, instance, and SOP identifiers. That is not a contradiction: the documented component pattern applies to the Exam Finding List output, not to the reporting system's input. | Piece | Status | |---|---| @@ -110,7 +110,7 @@ The only real FHIR documents in the current repositories are two **input** sampl # The open question underneath -The component pattern that every OIDM encoding uses is the one IHE's Imaging Diagnostic Report profile declines to use. IDR states that `Observation.component` "is not used", because FHIR limits components to values "not useful on their own" and using it "has the potential to significantly complicate queries", preferring a root Observation whose `hasMember` references the associated observations. Since the deck names IDR as the Exam Finding List's target representation, that disagreement sits directly under the mapping. It is set out in [IHE IDR alignment](/data-structures/ihe-idr-alignment.md), along with the other points where the two models differ. +The component pattern that every OIDM encoding uses is the one IHE's Imaging Diagnostic Report profile declines to use. IHE's Imaging Diagnostic Report profile states that `Observation.component` "is not used". FHIR limits components to values "not useful on their own", and using them "has the potential to significantly complicate queries". IDR instead uses a root Observation whose `hasMember` references associated observations. The deck names IDR as the Exam Finding List's target, so OIDM's component mappings need reconciliation. See [IHE IDR alignment](/data-structures/ihe-idr-alignment.md). [^ipl-main]: imaging-problem-list README, main branch [^ipl-claude-dev]: imaging-problem-list domain model notes, dev branch diff --git a/knowledge/data-structures/hierarchy.excalidraw b/knowledge/data-structures/hierarchy.excalidraw new file mode 100644 index 0000000..b3a5080 --- /dev/null +++ b/knowledge/data-structures/hierarchy.excalidraw @@ -0,0 +1,950 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "oidm-knowledge/tools/diagrams", + "elements": [ + { + "type": "rectangle", + "id": "obs", + "x": 0, + "y": 40, + "width": 250, + "height": 70, + "strokeColor": "#1e3a5f", + "backgroundColor": "#3b82f6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1001, + "version": 1, + "versionNonce": 1002, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "obs_t", + "type": "text" + }, + { + "id": "a_obs_efl", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "obs_t", + "x": 10, + "y": 50, + "width": 230, + "height": 50, + "strokeColor": "#ffffff", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1003, + "version": 1, + "versionNonce": 1004, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Observation\none finding, one exam", + "originalText": "Observation\none finding, one exam", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "obs", + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "obs_fields", + "x": 280, + "y": 40, + "width": 235.48, + "height": 87.5, + "strokeColor": "#374151", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1005, + "version": 1, + "versionNonce": 1006, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "findingCode (OIFM)\nfindingDescription\nanatomicLocation (RID)\nattributes[] with value codes\nreportText", + "originalText": "findingCode (OIFM)\nfindingDescription\nanatomicLocation (RID)\nattributes[] with value codes\nreportText", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "obs_status", + "x": 280, + "y": 135.5, + "width": 241.27999999999997, + "height": 16.25, + "strokeColor": "#3b82f6", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1007, + "version": 1, + "versionNonce": 1008, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "JSON in use; no published schema", + "originalText": "JSON in use; no published schema", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "obs_tick", + "x": 250, + "y": 75.0, + "width": 30, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1009, + "version": 1, + "versionNonce": 1010, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 30, + 0 + ] + ] + }, + { + "type": "rectangle", + "id": "efl", + "x": 0, + "y": 225.75, + "width": 250, + "height": 70, + "strokeColor": "#1e3a5f", + "backgroundColor": "#3b82f6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1011, + "version": 1, + "versionNonce": 1012, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "efl_t", + "type": "text" + }, + { + "id": "a_obs_efl", + "type": "arrow" + }, + { + "id": "a_efl_ipl", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "efl_t", + "x": 10, + "y": 235.75, + "width": 230, + "height": 50, + "strokeColor": "#ffffff", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1013, + "version": 1, + "versionNonce": 1014, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Exam Finding List\nevery observation of one exam", + "originalText": "Exam Finding List\nevery observation of one exam", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "efl", + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "efl_fields", + "x": 280, + "y": 225.75, + "width": 235.48, + "height": 70.0, + "strokeColor": "#374151", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1015, + "version": 1, + "versionNonce": 1016, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "diagnosticReportId\npatientInfo\nexamInfo with LOINC exam code\nfindings[]: the observations", + "originalText": "diagnosticReportId\npatientInfo\nexamInfo with LOINC exam code\nfindings[]: the observations", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "efl_status", + "x": 280, + "y": 303.75, + "width": 241.27999999999997, + "height": 16.25, + "strokeColor": "#3b82f6", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1017, + "version": 1, + "versionNonce": 1018, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "JSON in use; no published schema", + "originalText": "JSON in use; no published schema", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "efl_tick", + "x": 250, + "y": 260.75, + "width": 30, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1019, + "version": 1, + "versionNonce": 1020, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 30, + 0 + ] + ] + }, + { + "type": "arrow", + "id": "a_obs_efl", + "x": 125.0, + "y": 110, + "width": 0.0, + "height": 115.75, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1021, + "version": 1, + "versionNonce": 1022, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.0, + 115.75 + ] + ], + "startBinding": { + "elementId": "obs", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "efl", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "id": "a_obs_efl_l", + "x": 231.52, + "y": 155.875, + "width": 64.96, + "height": 17.5, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1023, + "version": 1, + "versionNonce": 1024, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "per exam", + "originalText": "per exam", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "ipl", + "x": 0, + "y": 394.0, + "width": 250, + "height": 70, + "strokeColor": "#1e3a5f", + "backgroundColor": "#3b82f6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1025, + "version": 1, + "versionNonce": 1026, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "ipl_t", + "type": "text" + }, + { + "id": "a_efl_ipl", + "type": "arrow" + }, + { + "id": "a_ipl_persona", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "ipl_t", + "x": 10, + "y": 404.0, + "width": 230, + "height": 50, + "strokeColor": "#ffffff", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1027, + "version": 1, + "versionNonce": 1028, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Imaging Problem List\none patient, keyed by finding", + "originalText": "Imaging Problem List\none patient, keyed by finding", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "ipl", + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "ipl_fields", + "x": 280, + "y": 394.0, + "width": 243.6, + "height": 87.5, + "strokeColor": "#374151", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1029, + "version": 1, + "versionNonce": 1030, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "patient\nfindings[] keyed by\n(findingCode, locationId)\neach with dated observations[]\nstatus derived, not stored", + "originalText": "patient\nfindings[] keyed by\n(findingCode, locationId)\neach with dated observations[]\nstatus derived, not stored", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "ipl_status", + "x": 280, + "y": 489.5, + "width": 271.44, + "height": 16.25, + "strokeColor": "#3b82f6", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1031, + "version": 1, + "versionNonce": 1032, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "JSON in use; grouping changed on dev", + "originalText": "JSON in use; grouping changed on dev", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "ipl_tick", + "x": 250, + "y": 429.0, + "width": 30, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1033, + "version": 1, + "versionNonce": 1034, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 30, + 0 + ] + ] + }, + { + "type": "arrow", + "id": "a_efl_ipl", + "x": 125.0, + "y": 295.75, + "width": 0.0, + "height": 98.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1035, + "version": 1, + "versionNonce": 1036, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.0, + 98.25 + ] + ], + "startBinding": { + "elementId": "efl", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "ipl", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "id": "a_efl_ipl_l", + "x": 227.46, + "y": 332.875, + "width": 73.08, + "height": 17.5, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1037, + "version": 1, + "versionNonce": 1038, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "all exams", + "originalText": "all exams", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "persona", + "x": 0, + "y": 579.75, + "width": 250, + "height": 70, + "strokeColor": "#64748b", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1039, + "version": 1, + "versionNonce": 1040, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "persona_t", + "type": "text" + }, + { + "id": "a_ipl_persona", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "persona_t", + "x": 10, + "y": 589.75, + "width": 230, + "height": 50, + "strokeColor": "#475569", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1041, + "version": 1, + "versionNonce": 1042, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Imaging Persona\nplus clinical context", + "originalText": "Imaging Persona\nplus clinical context", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "persona", + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "persona_fields", + "x": 280, + "y": 579.75, + "width": 308.56, + "height": 70.0, + "strokeColor": "#374151", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1043, + "version": 1, + "versionNonce": 1044, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "clinical context (orders, indications)\nmedical baseline (problems, labs)\nspecialized history (oncology)\nsurgical history (operative, implants)", + "originalText": "clinical context (orders, indications)\nmedical baseline (problems, labs)\nspecialized history (oncology)\nsurgical history (operative, implants)", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "persona_status", + "x": 280, + "y": 657.75, + "width": 188.5, + "height": 16.25, + "strokeColor": "#475569", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1045, + "version": 1, + "versionNonce": 1046, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "concept only, no artifact", + "originalText": "concept only, no artifact", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "persona_tick", + "x": 250, + "y": 614.75, + "width": 30, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1047, + "version": 1, + "versionNonce": 1048, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 30, + 0 + ] + ] + }, + { + "type": "arrow", + "id": "a_ipl_persona", + "x": 125.0, + "y": 464.0, + "width": 0.0, + "height": 115.75, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1049, + "version": 1, + "versionNonce": 1050, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.0, + 115.75 + ] + ], + "startBinding": { + "elementId": "ipl", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "persona", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "id": "a_ipl_persona_l", + "x": 215.28, + "y": 509.875, + "width": 97.44, + "height": 17.5, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1051, + "version": 1, + "versionNonce": 1052, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "with context", + "originalText": "with context", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "note", + "x": 0, + "y": 714.0, + "width": 603.1999999999999, + "height": 32.5, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1053, + "version": 1, + "versionNonce": 1054, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Codes come from the semantic foundation: OIFM and OIFMA identifiers from finding\nmodels, RID from anatomic locations, LOINC for the exam.", + "originalText": "Codes come from the semantic foundation: OIFM and OIFMA identifiers from finding\nmodels, RID from anatomic locations, LOINC for the exam.", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + } + ], + "appState": { + "viewBackgroundColor": "#ffffff", + "gridSize": null + }, + "files": {} +} \ No newline at end of file diff --git a/knowledge/data-structures/hierarchy.md b/knowledge/data-structures/hierarchy.md index f57874b..90fc26e 100644 --- a/knowledge/data-structures/hierarchy.md +++ b/knowledge/data-structures/hierarchy.md @@ -1,10 +1,10 @@ --- type: Concept title: The data structure hierarchy -description: The four-level ladder from Observation to Exam Finding List to Imaging Problem List to Imaging Persona, what each level adds, how identifiers thread through it, and how far each level is built. +description: The four data structure levels, their identifiers, and implementation status. tags: [data-structures, hierarchy, observation, exam-finding-list, imaging-problem-list, imaging-persona] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:34:50Z } sources: - id: deck resource: https://gamma.app/docs/Open-Imaging-Data-Model-2026-Status-Update:-Realizing-Object-Oriented-Imaging-Results-yfxzx4q9zssafal @@ -25,7 +25,7 @@ sources: # The ladder -The second of OIDM's three strategic pillars is a hierarchy of data structures, described in the January 2026 status deck as "the atomic Observation, then the Exam Finding List, then the Imaging Problem List, then the 'Imaging Persona'."[^deck] Each level is the one below it, collected and re-keyed. +The second of OIDM's three strategic pillars is a data structure hierarchy. The January 2026 status deck describes it as "the atomic Observation, then the Exam Finding List, then the Imaging Problem List, then the 'Imaging Persona'."[^deck] Each level is the one below it, collected and re-keyed. | Level | Scope | What it adds | Key it is organized by | |---|---|---|---| @@ -34,40 +34,25 @@ The second of OIDM's three strategic pillars is a hierarchy of data structures, | [Imaging Problem List](/data-structures/imaging-problem-list.md) | one patient | time: every observation of a finding across every exam | the finding | | [Imaging Persona](/data-structures/imaging-persona.md) | one patient | clinical context around the imaging: orders, baseline, specialized and surgical history | the patient | -The turn happens at level three. An [Exam Finding List](/glossary/exam-finding-list.md) is organized by exam, the way radiology reports have always been organized. An [Imaging Problem List](/glossary/imaging-problem-list.md) is "organized by finding, meaning pathology, rather than by chronology,"[^deck] which is what makes the deck's core query, "was finding X present on the most recent study?", a lookup rather than a search through a stack of reports. - -```mermaid -flowchart LR - subgraph L1["Observation"] - O1["finding code
anatomic location
attribute values"] - end - subgraph L2["Exam Finding List"] - E1["diagnosticReportId
patientInfo
examInfo (LOINC)
findings[]"] - end - subgraph L3["Imaging Problem List"] - P1["patient
findings[] grouped by
(findingCode, locationId)
each with observations[]"] - end - subgraph L4["Imaging Persona"] - A1["clinical context
medical baseline
specialized history
surgical history"] - end - O1 -->|"one exam's worth"| E1 - E1 -->|"one patient's exams, re-keyed by finding"| P1 - P1 -->|"surrounded by clinical context"| A1 -``` +The turn happens at level three. An [Exam Finding List](/glossary/exam-finding-list.md) is organized by exam, the way radiology reports have always been organized. An [Imaging Problem List](/glossary/imaging-problem-list.md) is "organized by finding, meaning pathology, rather than by chronology,"[^deck] allowing a lookup for the deck's query, "was finding X present on the most recent study?" + +[![From one observation to a patient's imaging history: an Observation carries a finding code, anatomic location, and attribute values; one exam's worth of observations roll up into an Exam Finding List; one patient's Exam Finding Lists re-key by finding into an Imaging Problem List; that list, surrounded by clinical context, becomes an Imaging Persona.](./hierarchy.svg)](./hierarchy.svg) + +*Diagram source: `hierarchy.excalidraw` beside this document (click the image for full size), generated by `tools/diagrams/build_hierarchy.py`.* # What each level adds -**Observation.** The deck states it as "what + where + attributes": a finding tag, an [anatomic location](/glossary/anatomic-location.md), and lesion characteristics, carrying presence indicators, change from prior, and measurements, in "a universal structure across systems."[^deck] It has no identity outside the list that contains it. +**Observation.** The deck describes "what + where + attributes" in "a universal structure across systems."[^deck] A finding tag, an [anatomic location](/glossary/anatomic-location.md), and lesion characteristics record presence, change from prior, and measurements. Its identity is local to the list that contains it. -**Exam Finding List.** "In the context of an imaging exam, a list of the findings declared as present/absent on that exam."[^ipl-main] Two of its properties are stated as requirements rather than conveniences. It "must also have basic information (keyed by a curated list of LOINC codes) about what exam this is," and "the same finding type may be declared as present multiple times; each time is a separate entry."[^ipl-main] The second rule is why three kidney stones are three observations rather than one observation with a count of three. +**Exam Finding List.** "In the context of an imaging exam, a list of the findings declared as present/absent on that exam."[^ipl-main] It "must also have basic information (keyed by a curated list of LOINC codes) about what exam this is," and "the same finding type may be declared as present multiple times; each time is a separate entry."[^ipl-main] Three kidney stones therefore produce three observations. **Imaging Problem List.** "In the context of a patient, the list of findings that have been described as present/absent in exams of the patient."[^ipl-main] Each entry holds every observation of that finding, each carrying its source report, exam date, exam type, and presence. On the development branch the grouping key is finding code **and** anatomic location, so "one finding code at distinct sites (e.g. ascending vs. abdominal aortic aneurysm) yields separate entries."[^ipl-claude-dev] -**Imaging Persona.** Named in the deck and nowhere else. It is the goal of surrounding the problem list with clinical context, medical baseline, specialized history, and surgical history.[^deck] No specification or sample exists. +**Imaging Persona.** The deck proposes adding clinical context, medical baseline, specialized history, and surgical history to the problem list.[^deck] No other project document names it, and no specification or sample exists. # How identifiers thread through -Nothing in the hierarchy embeds a definition. Every level refers to the [semantic foundation](/semantic-foundation/) by code, which is what lets two systems agree on a finding without sharing a database. +The structures refer to definitions in the [semantic foundation](/semantic-foundation/) by code. They do not embed definitions. Shared codes let systems agree on a finding without sharing a database. | Identifier | Form | Where it enters | Example | |---|---|---|---| @@ -77,7 +62,7 @@ Nothing in the hierarchy embeds a definition. Every level refers to the [semanti | [RadLex identifier](/glossary/radlex-id.md) | `RID####`, with sided structures composite | `anatomicLocation.locationId` | `RID42239`, and `RID39518_RID5824` for a left shoulder | | [LOINC](/glossary/loinc.md) code | LOINC part number | `examInfo.studyLoincCode`, and `exam_type_code` on a problem list observation | `26158-6` | -The letter block inside an OIFM identifier is the [organization code](/glossary/oidm-organization-code.md) of the contributing organization, so a single exam's findings routinely mix codes from several contributors. The five-finding worked example does exactly that, drawing on `GMTS`, `OIDM`, and `CDE` identifiers in one list.[^efl-sample] +The letter block in an OIFM identifier is the contributor's [organization code](/glossary/oidm-organization-code.md). One exam can use several contributors' codes. The five-finding worked example combines `GMTS`, `OIDM`, and `CDE` identifiers.[^efl-sample] # Implementation status @@ -89,7 +74,7 @@ The letter block inside an OIFM identifier is the [organization code](/glossary/ | Imaging Persona | Concept only | Four named context categories in the deck. No artifact. | | FHIR encoding of any level | Documented only | The mappings are written down and implemented nowhere. See [FHIR mapping](/data-structures/fhir-mapping.md). | -The absence at the bottom of the ladder is the one the project has flagged itself. Issue 1 asks for Pydantic models for Observation, Exam Finding List, and Imaging Problem List, with "extensive annotation to generate JSON schemas" and camelCase aliases on export against snake_case attributes internally.[^issue1] Until that lands, the structures are defined by prose, by sample data, and by the scripts that read and write them. The stated direction is collected in [the IPL data model system roadmap](/roadmap/ipl-data-model-system.md). +Issue 1 requests Pydantic models for Observation, Exam Finding List, and Imaging Problem List, with "extensive annotation to generate JSON schemas" and camelCase export aliases for snake_case attributes.[^issue1] Prose, samples, and scripts currently define the structures. See [the IPL data model system roadmap](/roadmap/ipl-data-model-system.md). [^deck]: "Open Imaging Data Model 2026 Status Update: Realizing Object-Oriented Imaging Results", January 2026 [^ipl-main]: imaging-problem-list README, main branch diff --git a/knowledge/data-structures/hierarchy.svg b/knowledge/data-structures/hierarchy.svg new file mode 100644 index 0000000..296fb8b --- /dev/null +++ b/knowledge/data-structures/hierarchy.svg @@ -0,0 +1,2 @@ +Observationone finding, one examfindingCode (OIFM)findingDescriptionanatomicLocation (RID)attributes[] with value codesreportTextJSON in use; no published schemaExam Finding Listevery observation of one examdiagnosticReportIdpatientInfoexamInfo with LOINC exam codefindings[]: the observationsJSON in use; no published schemaper examImaging Problem Listone patient, keyed by findingpatientfindings[] keyed by(findingCode, locationId)each with dated observations[]status derived, not storedJSON in use; grouping changed on devall examsImaging Personaplus clinical contextclinical context (orders, indications)medical baseline (problems, labs)specialized history (oncology)surgical history (operative, implants)concept only, no artifactwith contextCodes come from the semantic foundation: OIFM and OIFMA identifiers from findingmodels, RID from anatomic locations, LOINC for the exam. \ No newline at end of file diff --git a/knowledge/data-structures/ihe-idr-alignment.md b/knowledge/data-structures/ihe-idr-alignment.md index 487edf1..95a7833 100644 --- a/knowledge/data-structures/ihe-idr-alignment.md +++ b/knowledge/data-structures/ihe-idr-alignment.md @@ -4,7 +4,7 @@ title: IHE IDR alignment description: What the IHE Imaging Diagnostic Report profile specifies for encoding findings as FHIR Observations, the deck's claim that the Exam Finding List connects to it, and the fact that no OIDM repository mentions it. tags: [data-structures, ihe, idr, fhir, alignment, goal] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: idr-extract resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/notes/ihe-idr-extract.md @@ -22,9 +22,9 @@ sources: # Status first -This is a stated goal, not existing work. The January 2026 deck's slide on the [Exam Finding List](/data-structures/exam-finding-list.md) ends with one line: it "connects to IHE Imaging Diagnostic Report (IDR) FHIR representation."[^deck] That is the entire claim from the OIDM side. Searching the `imaging-problem-list` repository for "IHE" or "IDR" returns nothing on any branch, and no OIDM repository references the profile. +IDR alignment is a goal. The January 2026 deck says the [Exam Finding List](/data-structures/exam-finding-list.md) "connects to IHE Imaging Diagnostic Report (IDR) FHIR representation."[^deck] That is the entire claim from the OIDM side. No branch of `imaging-problem-list` mentions "IHE" or "IDR", and no OIDM repository references the profile. -What does exist is a careful reading of the profile from the allied vocabulary work: a 72-page public-comment supplement, read directly and extracted on the `next-gen-2026` branch of `ACR-RSNA-CDEs`.[^idr-extract][^idr-supplement] That extract is the source for everything below, and it was written to test a different model, the next-generation CDE vocabulary, against the profile. It is the best available statement of what alignment would involve. +The `next-gen-2026` branch of `ACR-RSNA-CDEs` contains an extract of the 72-page public-comment supplement.[^idr-extract][^idr-supplement] The extract tests the next-generation CDE vocabulary against the profile and is the source for the account below. It is the best available statement of what alignment would involve. # What the profile is @@ -42,7 +42,7 @@ The profile's own illustration: "the presence of a tumor is a finding, a recorde # The observation grammar -Every IDR observation has a target entity and content, split across five slots. This is the grammar an [Exam Finding List](/data-structures/exam-finding-list.md) would have to fit. +Every IDR observation has a target entity and content in five slots. An [Exam Finding List](/data-structures/exam-finding-list.md) would need to map to them. | Slot | FHIR location | Rule stated in the supplement | |---|---|---| @@ -58,9 +58,9 @@ For grouped findings, IDR says that "Observation.code of the root finding shall # Where OIDM and IDR differ -Four differences are recorded in the extract. None of them has been worked through on the OIDM side; all are listed there as items to raise during public comment. +The extract records four unresolved differences as items to raise during public comment. OIDM has not worked through them. -**Components against hasMember.** IDR states that `Observation.component` "is not used", because FHIR limits components to values "not useful on their own" and using it "has the potential to significantly complicate queries". Every OIDM encoding that carries attributes uses components: the documented Exam Finding List mapping says so explicitly, "a list of components with attribute codes and values", and both lineage FHIR samples implement it that way.[^ipl-main] This is the sharpest of the four, because it is the mechanism rather than a vocabulary choice. See [FHIR mapping](/data-structures/fhir-mapping.md). +**Components against hasMember.** IDR states that `Observation.component` "is not used", because FHIR limits components to values "not useful on their own" and using it "has the potential to significantly complicate queries". All OIDM attribute encodings use components. The Exam Finding List mapping specifies "a list of components with attribute codes and values", as implemented by both lineage FHIR samples.[^ipl-main] This is the sharpest of the four, because it is the mechanism rather than a vocabulary choice. See [FHIR mapping](/data-structures/fhir-mapping.md). **The word "observation" means different things.** IDR's observation is "a feature or characteristic that is visible in an image", closer to a single attribute value than to an OIDM [Observation](/glossary/observation.md), which is a whole finding with its location and attributes. IDR's "finding" is narrower too: it is the presence or absence determination, not the named entity. The extract flags this as a vocabulary collision, and notes that the next-generation vocabulary work moved away from the word "observation" for exactly this reason. @@ -70,7 +70,11 @@ Four differences are recorded in the extract. None of them has been worked throu # What IDR is asking -The extract also records three questions IDR puts to the RadElement side, which are requirements on any alignment: what extensibility is permitted when encoding [CDE sets](/glossary/cde-set.md), and in particular whether additional sub-observations may be included; what the coding system identifier for RadElement codes is; and whether a presence value belongs in the parent of a grouped observation or as its first child.[^idr-extract] +The extract also records three questions IDR puts to the RadElement side, which are requirements on any alignment:[^idr-extract] + +- What extensions are permitted when encoding [CDE sets](/glossary/cde-set.md), particularly additional sub-observations? +- What is the coding system identifier for RadElement codes? +- Does presence belong in the parent of a grouped observation or its first child? # Where this stands @@ -81,7 +85,7 @@ The extract also records three questions IDR puts to the RadElement side, which | The differences are identified | Four, listed above, all recorded as items to raise, none resolved | | Anything is built | No | -The profile extract itself is not migrated into this bundle; it lives on the `next-gen-2026` branch of `ACR-RSNA-CDEs` and is linked above. The unresolved items are carried in [open questions](/roadmap/open-questions.md). +The extract remains on `ACR-RSNA-CDEs`'s `next-gen-2026` branch. It has not been migrated into this bundle. See [open questions](/roadmap/open-questions.md) for the unresolved items. [^idr-extract]: IHE IDR Phase II extract, ACR-RSNA-CDEs next-gen-2026 branch [^idr-supplement]: IHE Imaging Diagnostic Report Phase II public comment draft, 4 March 2026 diff --git a/knowledge/data-structures/imaging-persona.md b/knowledge/data-structures/imaging-persona.md index ac893c2..8453e83 100644 --- a/knowledge/data-structures/imaging-persona.md +++ b/knowledge/data-structures/imaging-persona.md @@ -4,7 +4,7 @@ title: Imaging Persona description: "The fourth level of the hierarchy, a stated goal with no artifact: the clinical context around a patient's Imaging Problem List, and the life-cycle uses the 2026 deck gives for it." tags: [data-structures, imaging-persona, roadmap, concept-only] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:34:50Z } sources: - id: deck resource: https://gamma.app/docs/Open-Imaging-Data-Model-2026-Status-Update:-Realizing-Object-Oriented-Imaging-Results-yfxzx4q9zssafal @@ -19,11 +19,11 @@ sources: # Status first -The [Imaging Persona](/glossary/imaging-persona.md) is a goal. It is named in the January 2026 status deck as the fourth level of [the data structure hierarchy](/data-structures/hierarchy.md) and appears nowhere else in the project. No schema, no sample, no code. Everything below is what the deck states.[^deck] +The [Imaging Persona](/glossary/imaging-persona.md) is a goal named only in the January 2026 status deck as the fourth level of [the data structure hierarchy](/data-structures/hierarchy.md).[^deck] No schema, no sample, no code. Everything below is what the deck states.[^deck] # What the deck describes -The deck's slide is headed "Imaging Persona (big picture)" and gives four categories of context that would surround a patient's [Imaging Problem List](/data-structures/imaging-problem-list.md).[^deck] +The slide "Imaging Persona (big picture)" names four context categories for a patient's [Imaging Problem List](/data-structures/imaging-problem-list.md).[^deck] | Category | Contents named | |---|---| @@ -32,11 +32,11 @@ The deck's slide is headed "Imaging Persona (big picture)" and gives four catego | Specialized history | oncology, treatments | | Surgical history | operative records, pathology, implants | -None of that is imaging results. The Imaging Problem List is the structure the project builds; the persona is the argument that a problem list on its own does not answer the questions radiology actually gets asked. Three of the four categories come from the electronic medical record rather than from radiology, which makes the persona as much an integration claim as a data structure. +These categories add context beyond imaging results. Three of the four categories come from the electronic medical record rather than from radiology, which makes the persona as much an integration claim as a data structure. # Why: the imaging life cycle -The deck argues for it through a separate slide on what the Imaging Problem List enables at each stage of the imaging life cycle. The uses named there are the ones that need context the problem list does not carry.[^deck] +A separate slide names uses of the Imaging Problem List across the imaging life cycle that need additional context.[^deck] | Stage | Uses the deck names | |---|---| @@ -45,19 +45,19 @@ The deck argues for it through a separate slide on what the Imaging Problem List | Interpretation | findings-oriented views in the picture archiving system, real-time quality control | | Post-interpretation | passive screening, research, outcomes | -Read against the four categories, the dependency is concrete. Magnetic resonance safety screening is a question about implants, which is surgical history. Prior authorization is a question about the order and the indication. Rules-based protocoling needs both the prior imaging findings and the clinical question. Passive screening needs the medical baseline to know whether a finding matters for this patient. A problem list alone answers none of these; a problem list plus that context answers all four. +Read against the four categories, the dependency is concrete. Magnetic resonance safety screening is a question about implants, which is surgical history. Prior authorization needs the order and indication, which is clinical context. Rules-based protocoling needs prior findings and the clinical question. Passive screening needs the medical baseline to assess a finding's relevance to the patient. A problem list alone answers none of these; a problem list plus that context answers all four. -The 2024 site post on the data model made a related claim earlier and in wider terms, listing observations, current report text, imaging studies, patient, order, prior studies, tracked observations, and electronic health record data as the elements the model organizes.[^site-structure] The persona is that list narrowed to the patient-context half and given a name. +The 2024 site post describes the model as organizing observations, current report text, imaging studies, patient, order, prior studies, tracked observations, and electronic health record data.[^site-structure] The persona corresponds to the patient context in that list. # A related unimplemented idea -One adjacent design note exists in the repositories, on an unmerged branch of the early extraction prototype. `FHIR_Example_Structure` sketches longitudinal persistence of findings: each finding becomes "a **tracked entity** with a FHIR ID that persists," so a second report describing the same liver lesion links to the existing resource and adds a new dated value rather than creating a second finding.[^ipl-mvp-fhir] The note's worked timeline shows one lesion at 1.6 cm, 2.1 cm, and 2.8 cm across three reports, and its query examples are "show me the timeline for liver lesion" and "how has the renal calculus changed?". +An unmerged branch of the early extraction prototype contains `FHIR_Example_Structure`, a design note on persistent findings. Each finding becomes "a **tracked entity** with a FHIR ID that persists," so later reports of the same lesion add dated values to the existing resource.[^ipl-mvp-fhir] Its timeline shows one liver lesion at 1.6 cm, 2.1 cm, and 2.8 cm across three reports. Example queries are "show me the timeline for liver lesion" and "how has the renal calculus changed?". -It is a different idea from the persona. It addresses identity of a finding over time, which the current [Imaging Problem List](/data-structures/imaging-problem-list.md) approximates by grouping on finding code and location rather than by tracking a lesion. It is recorded here because it is the only written treatment anywhere in the repositories of persisting a patient's imaging story as durable resources, which is the substrate a persona would need. It sits on a single-commit branch of a superseded prototype and was never merged; see [IPL-MVP extraction](/applications/ipl-mvp-extraction.md). +It is a different idea from the persona. It addresses identity of a finding over time, which the current [Imaging Problem List](/data-structures/imaging-problem-list.md) approximates by grouping on finding code and location rather than by tracking a lesion. This is the repositories' only written design for durable patient imaging resources, a possible basis for a persona. It remains on an unmerged, single-commit branch of a superseded prototype. See [IPL-MVP extraction](/applications/ipl-mvp-extraction.md). # What would have to be decided -Nothing about the persona has been specified, so this section states only what the deck leaves open rather than proposing answers. The deck does not say whether the persona is a stored structure or a query-time assembly, which systems own each of the four context categories, how it would be encoded, or who would maintain it. Those questions are carried in [open questions](/roadmap/open-questions.md) and the direction in [the 2026 roadmap](/roadmap/roadmap-2026.md). +Nothing about the persona has been specified, so this section states only what the deck leaves open rather than proposing answers. The deck leaves storage versus query-time assembly, ownership of each context category, encoding, and maintenance unspecified. See [open questions](/roadmap/open-questions.md) and [the 2026 roadmap](/roadmap/roadmap-2026.md). [^deck]: "Open Imaging Data Model 2026 Status Update", January 2026 [^ipl-mvp-fhir]: FHIR_Example_Structure, IPL-MVP-ExtractionAndLabeling, Persistent_FHIR_Resources branch diff --git a/knowledge/data-structures/imaging-problem-list.md b/knowledge/data-structures/imaging-problem-list.md index a6653c7..a976edb 100644 --- a/knowledge/data-structures/imaging-problem-list.md +++ b/knowledge/data-structures/imaging-problem-list.md @@ -1,10 +1,10 @@ --- type: Data Structure title: Imaging Problem List -description: The per-patient structure that reorganizes a patient's imaging findings by finding rather than by date, its fields, its grouping key, the temporal status computed over it, and what it is meant to become in FHIR. +description: A patient's observations grouped by finding, with fields, grouping rules, computed status, and planned FHIR encoding. tags: [data-structures, imaging-problem-list, anatomic-location, fhir] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:34:50Z } sources: - id: ipl-main resource: https://github.com/openimagingdata/imaging-problem-list/blob/06f64a7893b444b761dc069ed86140a081195eac/README.md @@ -37,9 +37,9 @@ sources: # Definition -"In the context of a patient, the list of findings that have been described as present/absent in exams of the patient."[^ipl-main] An [Imaging Problem List](/glossary/imaging-problem-list.md) is the third level of [the hierarchy](/data-structures/hierarchy.md) and the project's signature structure. It takes every [Exam Finding List](/data-structures/exam-finding-list.md) for one patient and re-keys the [observations](/data-structures/observation.md) inside them by finding. +"In the context of a patient, the list of findings that have been described as present/absent in exams of the patient."[^ipl-main] An [Imaging Problem List](/glossary/imaging-problem-list.md) groups [observations](/data-structures/observation.md) from a patient's [Exam Finding Lists](/data-structures/exam-finding-list.md) by finding. It is the third level of [the hierarchy](/data-structures/hierarchy.md). -That single change of key is the whole point. The deck states the core query the structure exists to answer: "was finding X present on the most recent study?"[^deck] Against a stack of reports organized by date that question is a search. Against a problem list it is a lookup. +Grouping by finding allows a lookup for the deck's core query: "was finding X present on the most recent study?"[^deck] # Fields @@ -64,23 +64,23 @@ That single change of key is the whole point. The deck states the core query the | `observations[].anatomicLocation` | `{locationId, locationDisplay}` | **development branch only**; repeats the finding's location | | `observations[].reportText` | string | the verbatim span, carried through so the timeline reads without fetching the source exams | -Note the field naming: the problem list uses snake_case for its own fields while carrying camelCase forward on the fields copied from the Exam Finding List, so `finding_type_code` and `anatomicLocation` sit in the same object. Two worked entries are in [the Imaging Problem List example](/references/imaging-problem-list-example.md). +The problem list uses snake_case for its own fields and retains camelCase for fields copied from the Exam Finding List. Thus `finding_type_code` and `anatomicLocation` share an object. See two worked entries in [the Imaging Problem List example](/references/imaging-problem-list-example.md). # The grouping key -On the stable branch, observations group by finding code alone. On the development branch the key is the pair of finding code and [anatomic location](/glossary/anatomic-location.md) identifier, with the rationale stated in the repository's own domain notes: +The stable branch groups by finding code. The development branch pairs that code with the [anatomic location](/glossary/anatomic-location.md) identifier. Its domain notes explain: > Groups observations by finding type **and** anatomic location (`locationId`) across exams, preserving references to each source report, so one finding code at distinct sites (e.g. ascending vs. abdominal aortic aneurysm) yields separate entries; consumers key on the IPL finding `id`, not `finding_type_code`.[^ipl-claude-dev] -The generator implements it directly, keying on the tuple of finding code and location identifier, with observations that have no location grouping under a null location.[^ipl-script] +The generator uses this tuple, grouping observations without a location under a null location.[^ipl-script] -The effect on real data is large. The same ten exams for one synthetic patient produce 98 problem list entries when grouped by finding code alone and 123 when grouped by finding code and location.[^ipl-sample] The observation count is unchanged; the grouping is finer. +The same ten exams for one synthetic patient produce 98 entries grouped by code alone and 123 grouped by code and location.[^ipl-sample] The observation count is unchanged. -This is why the documented rule is that consumers key on `id`. A finding code is no longer unique within a list. +Consumers key on `id` because a finding code is no longer unique within a list. # Temporal status -Status is **computed at display time, not stored**. No status field exists in the file. The viewer derives it per finding from the observation list.[^viewer-app] +The viewer computes each finding's status from its observations at display time. The file has no status field.[^viewer-app] 1. No observations gives **Unknown**. 2. Sort the observations by exam date, most recent first. @@ -89,46 +89,48 @@ Status is **computed at display time, not stored**. No status field exists in th 5. If the most recent is not `present` but some earlier observation was, the status is **Resolved**. 6. If no observation was ever `present`, the status is **Never**. -The viewer sections a patient's list under those four headings and offers them as a filter. +The viewer groups and filters findings by those four statuses. -Two things follow. **Never is not the same as absent from the list.** A finding with only absent observations is a finding that was looked for on named exams and not found, and the list records that it was looked for. **The scheme has four states, not three.** The stable branch's prose still describes an older three-state model of Present, Resolved, and Not Present or Ruled Out.[^ipl-main-claude] That wording is stale relative to the code on both branches, which computes four. The discrepancy is recorded in [the Imaging Problem List glossary entry](/glossary/imaging-problem-list.md). +A finding with only absent observations records that it was checked for on specific exams and not found. A finding missing from the list carries no such record. + +The stable branch's prose describes an older model with three states: Present, Resolved, and Not Present or Ruled Out.[^ipl-main-claude] That wording is stale relative to the code on both branches, which computes four. See [the Imaging Problem List glossary entry](/glossary/imaging-problem-list.md) for the discrepancy. # What the structure is for -The deck lists four properties beyond the core query.[^deck] +The deck lists these properties and a demonstration.[^deck] -- **Organized by finding, meaning pathology, rather than by chronology.** The reorganization is the feature. -- **Precision filtering by way of anatomy-embedded definitions.** This is what the grouping-key change on the development branch buys, and what the anatomy-aware viewer renders. -- **Dynamic tracking of appearance, disappearance, and change.** The computed status is the first cut at this; measurement trends over time are not modelled. +- Organized by finding, meaning pathology, rather than by chronology. The grouping key implements this. +- Filtering through anatomy-embedded definitions. The development branch's grouping key and viewer support this. +- Tracking appearance, disappearance, and change. Computed status provides an initial implementation. Measurement trends over time are not modelled. - A public demonstration at `imaging-problem-list.pages.dev`. -The uses the deck names across the imaging life cycle, from protocoling to passive screening, are covered under [Imaging Persona](/data-structures/imaging-persona.md), because they draw on context beyond imaging results. +See [Imaging Persona](/data-structures/imaging-persona.md) for uses such as protocoling and passive screening that need context beyond imaging results. # The pipeline diagram -The README carries `imaging-problem-list-process.png`, a hand-drawn pipeline in three stages.[^ipl-diagram] On the left, Report 1 through Report n feed an **Extractor**, drawn as a neural network and fed from below by a database labelled "Findings (CDE 'stub' defs)". The Extractor emits one Findings List per report. Those feed an **Assembler**, also drawn as a neural network, which emits the Imaging Problem List on the right. +The README's hand-drawn `imaging-problem-list-process.png` shows Report 1 through Report n feeding an Extractor, drawn as a neural network.[^ipl-diagram] A database labelled "Findings (CDE 'stub' defs)" also feeds the Extractor. Its Findings Lists feed an Assembler, also drawn as a neural network, which produces the Imaging Problem List. -The output panel is the argument. Four finding cards, Pulmonary Nodule, Pulmonary Apical Scarring, Subsegmental Atelectasis, and Pleural Effusion, each list their observations by dated exam. Pulmonary Nodule shows "Chest CT 2020-11-23 (x8)", the multiplicity collapsed into one dated row. Pleural Effusion shows five rows of which four are marked "(absent)", which is the negative-as-data claim drawn out: a finding whose entire history is absence still earns a card. +Four output cards list observations by dated exam: Pulmonary Nodule, Pulmonary Apical Scarring, Subsegmental Atelectasis, and Pleural Effusion. Pulmonary Nodule shows "Chest CT 2020-11-23 (x8)", combining repeated findings into one row. Pleural Effusion has five rows, four marked "(absent)". The list also retains findings whose entire history records absence. -The Assembler as drawn is a learned component. The implementation is not: `generate_ipl_from_efls.py` is deterministic aggregation.[^ipl-script] +The diagram depicts a learned Assembler, but `generate_ipl_from_efls.py` uses deterministic aggregation.[^ipl-script] # FHIR The documented encoding is "**Report** containing a list of **Condition** objects (labeled with the finding identifier), where each Condition object also contains a list of **Observation** objects which document which exams (**DiagnosticReports**) the finding type has been documented on, including the exam date and exam type (LOINC type)."[^ipl-main] One [FHIR Condition](/glossary/fhir-condition.md) per problem list entry, with the observation trail underneath it. -The mapping is documented and implemented nowhere. No Condition resource is produced by any code in the repository. Its container is also called a "Report," which is not a FHIR resource name. See [FHIR mapping](/data-structures/fhir-mapping.md). +The mapping is unimplemented. No code in the repository produces a Condition resource. Its container is called a "Report," which is not a FHIR resource name. See [FHIR mapping](/data-structures/fhir-mapping.md). # Known limitation -Grouping by exact location identifier is too strict when the same problem is described at different granularity on different exams. The assignment rules state the gap: +Exact location matching splits a problem described at different levels of detail across exams. The assignment rules state: > Parent/child or generic-vs-specific pairs for the *same finding code across exams* (e.g. "lung" vs "lower lobe of right lung"; "kidney" vs "left kidney") still produce separate IPL groups. Deciding whether such observations are the same problem or distinct is the **anatomic-compatibility reconciliation** step.[^anat-rules] -That step is named in the anatomic location plan and has not been started. It is the most concrete open problem in the structure. The full precedence, laterality, and specificity rules that produce the locations are in [anatomic location assignment rules](/data-structures/anatomic-location-assignment-rules.md). +The anatomic location plan names this step, but work has not started. See [anatomic location assignment rules](/data-structures/anatomic-location-assignment-rules.md) for precedence, laterality, and specificity rules. # How it is produced -`generate_ipl_from_efls.py` reads a directory of `*_efl.json` files, sorted by filename so the chronology follows, takes the patient block from the first one, groups every finding by the key above, and writes one `ipl.json`.[^ipl-script] It is ordinary Python with no model calls. The rendering side is the [Imaging Problem List viewer](/applications/imaging-problem-list-viewer.md); the sample data it runs on is described in [sample data](/data-structures/sample-data.md). +`generate_ipl_from_efls.py` reads `*_efl.json` files sorted by filename to follow chronology. It takes the first file's patient block, groups findings by the key above, and writes one `ipl.json` without model calls.[^ipl-script] See the [Imaging Problem List viewer](/applications/imaging-problem-list-viewer.md) and its [sample data](/data-structures/sample-data.md). [^ipl-main]: imaging-problem-list README, main branch [^ipl-main-claude]: imaging-problem-list domain model notes, main branch diff --git a/knowledge/data-structures/index.md b/knowledge/data-structures/index.md index 0071c8a..f355d3a 100644 --- a/knowledge/data-structures/index.md +++ b/knowledge/data-structures/index.md @@ -1,14 +1,14 @@ # Data structures -The second OIDM layer: the objects that carry what was seen on an exam, keyed to the semantic foundation by code. The ladder runs Observation, Exam Finding List, Imaging Problem List, Imaging Persona. Start with the hierarchy. +OIDM records findings as Observations, groups them into Exam Finding Lists and Imaging Problem Lists, and proposes adding clinical context through the Imaging Persona. Codes link these structures to the semantic foundation. Start with the hierarchy. -* [The data structure hierarchy](./hierarchy.md) - The four-level ladder from Observation to Exam Finding List to Imaging Problem List to Imaging Persona, what each level adds, how identifiers thread through it, and how far each level is built. +* [The data structure hierarchy](./hierarchy.md) - The four data structure levels, their identifiers, and implementation status. * [Observation](./observation.md) - The atomic unit of OIDM: one finding, seen or explicitly excluded, on one exam, with its location and attribute values, as it exists today inside an Exam Finding List and in the extraction pipeline. -* [Exam Finding List](./exam-finding-list.md) - The per-exam structure that holds every finding declared present or absent on one imaging exam, its full field list on both branches, where its contents come from, and the FHIR and IHE encodings it is meant to reach. -* [Imaging Problem List](./imaging-problem-list.md) - The per-patient structure that reorganizes a patient's imaging findings by finding rather than by date, its fields, its grouping key, the temporal status computed over it, and what it is meant to become in FHIR. +* [Exam Finding List](./exam-finding-list.md) - Findings from one exam, their fields and sources, and planned FHIR and IHE encodings. +* [Imaging Problem List](./imaging-problem-list.md) - A patient's observations grouped by finding, with fields, grouping rules, computed status, and planned FHIR encoding. * [Imaging Persona](./imaging-persona.md) - The fourth level of the hierarchy, a stated goal with no artifact: the clinical context around a patient's Imaging Problem List, and the life-cycle uses the 2026 deck gives for it. -* [Anatomic location assignment rules](./anatomic-location-assignment-rules.md) - The precedence, laterality, bilateral, and specificity rules that decide which anatomic location is attached to a finding in an Exam Finding List, migrated from the imaging-problem-list development branch. -* [Technical imaging findings](./technical-imaging-findings.md) - A draft catalog of modality-specific technical finding language, CT attenuation, MR signal, enhancement, ultrasound echogenicity, and nuclear medicine, with the search-term guidance for coding each, migrated from the imaging-problem-list development branch. +* [Anatomic location assignment rules](./anatomic-location-assignment-rules.md) - Migrated rules for assigning anatomy, laterality, and specificity to Exam Finding List observations. +* [Technical imaging findings](./technical-imaging-findings.md) - A migrated draft catalog of modality-specific findings and search terms for coding them. * [FHIR mapping](./fhir-mapping.md) - Everything OIDM has documented about representing its data structures in FHIR, from the CDE-labeled Observation pattern of the lineage repositories to the current Exam Finding List and Imaging Problem List mappings, and the plain fact that no current code emits FHIR. * [IHE IDR alignment](./ihe-idr-alignment.md) - What the IHE Imaging Diagnostic Report profile specifies for encoding findings as FHIR Observations, the deck's claim that the Exam Finding List connects to it, and the fact that no OIDM repository mentions it. -* [Sample data](./sample-data.md) - The synthetic patients, exams, and findings that make up the Exam Finding List and Imaging Problem List sample data, what changes between branches, where the viewer bundles live, and how to regenerate everything. +* [Sample data](./sample-data.md) - Synthetic exam and problem list samples, branch differences, viewer bundles, and generation scripts. diff --git a/knowledge/data-structures/observation.md b/knowledge/data-structures/observation.md index 21eb7e1..29a46fa 100644 --- a/knowledge/data-structures/observation.md +++ b/knowledge/data-structures/observation.md @@ -4,7 +4,7 @@ title: Observation description: "The atomic unit of OIDM: one finding, seen or explicitly excluded, on one exam, with its location and attribute values, as it exists today inside an Exam Finding List and in the extraction pipeline." tags: [data-structures, observation, presence, extraction] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:34:50Z } sources: - id: deck resource: https://gamma.app/docs/Open-Imaging-Data-Model-2026-Status-Update:-Realizing-Object-Oriented-Imaging-Results-yfxzx4q9zssafal @@ -37,9 +37,9 @@ sources: # What an observation is -An [observation](/glossary/observation.md) is one finding, seen or explicitly excluded, on one exam. The deck frames it as "what + where + attributes": a finding tag, an [anatomic location](/glossary/anatomic-location.md), and lesion characteristics, carrying presence indicators, change from prior, and measurements, in "a universal structure across systems."[^deck] +An [observation](/glossary/observation.md) is one finding, seen or explicitly excluded, on one exam. The deck describes "what + where + attributes" in "a universal structure across systems."[^deck] A finding tag, an [anatomic location](/glossary/anatomic-location.md), and lesion characteristics record presence, change from prior, and measurements. -Two of those three parts point at the [semantic foundation](/semantic-foundation/). The "what" is a [finding model](/glossary/finding-model.md) identifier. The "where" is a RadLex identifier. Only the "how" is local to the observation, and even there each [attribute](/glossary/attribute.md) and each chosen value carry codes from the finding model's own definition. +The [semantic foundation](/semantic-foundation/) supplies the "what" as a [finding model](/glossary/finding-model.md) identifier and the "where" as a RadLex identifier. The "how" records local characteristics, with each [attribute](/glossary/attribute.md) and chosen value coded from the finding model's definition. A negative observation is an observation. Absence is recorded the same way presence is, with a presence attribute whose value is `absent`, because a radiologist stating "no fracture" has actively looked and not found. That commitment is what makes the [Imaging Problem List](/data-structures/imaging-problem-list.md) able to distinguish a finding nobody checked for from one that was checked for and ruled out. @@ -79,21 +79,21 @@ Each entry in `attributes[]` carries four fields: `attributeCode`, an `OIFMA_[A- } ``` -That record is the first finding of a left shoulder radiograph in the sample data.[^efl-sample] A full list in context is in [the Exam Finding List example](/references/exam-finding-list-example.md). +This is the first finding from a sample left shoulder radiograph.[^efl-sample] See [the Exam Finding List example](/references/exam-finding-list-example.md) for a full list. ## Presence and the dot codes [Presence](/glossary/presence.md) is the attribute every observation carries. Its values in the sample data are `present`, `absent`, and `indeterminate`. -Value codes are positional, not semantic: a value code is the attribute identifier plus a dot and the value's zero-based position in the finding model's value list. Consuming code in the extraction repository documents the standard ordering as "`.1` = present, `.0` = absent."[^ipl-claude-dev] That ordering holds for the large majority of published finding models but not all of them, so a consumer that hard-codes `.1` as present is wrong for the minority that order their values differently. The [presence glossary entry](/glossary/presence.md) records the counts and the conflict. +Value codes are positional, not semantic: a value code is the attribute identifier plus a dot and the value's zero-based position in the finding model's value list. The extraction repository documents the standard ordering as "`.1` = present, `.0` = absent."[^ipl-claude-dev] Most published finding models follow that order, but hard-coding `.1` as present misreads those that do not. The [presence glossary entry](/glossary/presence.md) records the counts and the conflict. ## Repeat instances -"The same finding type may appear multiple times in one exam (e.g., multiple kidney stones). Each instance gets a separate entry with its own `observationId`."[^ipl-main-claude] Count is therefore expressed by the number of observations, not by a count attribute, at the Exam Finding List level. The problem list re-collapses them: several observations of one finding from one exam display as a single dated row. +"The same finding type may appear multiple times in one exam (e.g., multiple kidney stones). Each instance gets a separate entry with its own `observationId`."[^ipl-main-claude] The number of observations gives the count at the Exam Finding List level. The problem list displays repeated observations of one finding from one exam as a single dated row. # The extraction-time observation -The extraction platform on the development branch has its own Pydantic model for a finding as language models produce it, before any code assignment. It is a different object from the Exam Finding List entry and is worth reading as the pre-coding form of the same thing.[^extract-models] +The extraction platform on the development branch has its own Pydantic model for language model output before code assignment.[^extract-models] It is a different object from the Exam Finding List entry and is worth reading as the pre-coding form of the same thing. | Model | Fields | |---|---| @@ -102,17 +102,17 @@ The extraction platform on the development branch has its own Pydantic model for | `FindingAttribute` | `key`, `value` | | `ExtractedReportFindings` | `exam_info`, `findings[]`, `non_finding_text[]` | -Three differences from the coded form matter. +It differs from the coded form in three ways. -**The presence vocabulary is wider.** `presence` is a `Literal["present", "absent", "indeterminate", "possible"]`, and the design note explains the fourth value: "'possible' covers hedged language like 'raising the possibility of', 'suggestive of', 'cannot exclude'."[^extract-models][^extract-plan] There is no `possible` in the finding model presence value set, so the extra value has no coded counterpart and must be resolved before an Exam Finding List entry can be written. +**Presence has a fourth value.** `presence` is a `Literal["present", "absent", "indeterminate", "possible"]`. The design note explains that "'possible' covers hedged language like 'raising the possibility of', 'suggestive of', 'cannot exclude'."[^extract-models][^extract-plan] Finding models have no presence code for `possible`, so it must be resolved before writing an Exam Finding List entry. -**Location is free text, not a code.** `FindingLocation` carries a constrained `body_region`, a free-text `specific_anatomy`, and a laterality. Turning that into a `locationId` is the job of the separate post-extraction coding pass, governed by [the anatomic location assignment rules](/data-structures/anatomic-location-assignment-rules.md). +**Location is free text, not a code.** `FindingLocation` carries a constrained `body_region`, a free-text `specific_anatomy`, and a laterality. A separate coding pass assigns a `locationId` using [the anatomic location assignment rules](/data-structures/anatomic-location-assignment-rules.md). -**Attributes are loose key-value pairs.** `FindingAttribute` is a `key` and a `value` as strings, with standard keys named in the model docstring: size, acuity, change from prior, severity, count, and morphology.[^extract-models] Those are not OIFMA codes and carry no value codes. +**Attributes have no codes.** `FindingAttribute` holds `key` and `value` strings. The model docstring names size, acuity, change from prior, severity, count, and morphology as standard keys.[^extract-models] -The model is also where coding results land. A `FindingCodingBundle` on each finding records the chosen OIFM identifier, the method used (`fast-path`, `llm`, or `unresolved`), a reason when unresolved, and the candidate codes that were considered. The pipeline that produces it is described in [finding and location coding](/applications/finding-and-location-coding.md). +A `FindingCodingBundle` on each finding records the chosen OIFM identifier, the method used (`fast-path`, `llm`, or `unresolved`), a reason when unresolved, and candidate codes considered. See [finding and location coding](/applications/finding-and-location-coding.md) for the pipeline. -The mapping from the extraction model to the Exam Finding List entry is therefore not a rename. It is a coding step: +Converting extraction output to an Exam Finding List entry requires these coding steps: | Extraction field | Exam Finding List field | How | |---|---|---| @@ -124,13 +124,13 @@ The mapping from the extraction model to the Exam Finding List entry is therefor # The FHIR precedent -The 2024 reference implementation modelled an observation as a FHIR `Observation` directly. Its docstring states "the Observation class is the model for FHIR Observation objects," and the class carries `resourceType`, `code`, `status`, `subject`, `bodySite` as a `CodeableConcept`, `derivedFrom` as references, and `component` as a discriminated union of codeable-concept, string, integer, and boolean variants keyed on the FHIR `value[x]` naming convention.[^lineage-obs] +The 2024 reference implementation used FHIR `Observation` directly. Its docstring states "the Observation class is the model for FHIR Observation objects," with `resourceType`, `code`, `status`, and `subject` fields. It also carries `bodySite` as a `CodeableConcept` and `derivedFrom` as references. Its `component` is a discriminated union of codeable-concept, string, integer, and boolean variants keyed on FHIR `value[x]` names.[^lineage-obs] -The lung cancer screening samples show the same shape with real codes. A finding observation's `code` is a [CDE set](/glossary/cde-set.md) identifier under `https://radelement.org`, each `component` code is a [CDE element](/glossary/cde-element.md) identifier, and each component's `valueCodeableConcept` gives the chosen value code.[^fhir-sample] In those samples `status` is what separates a machine-produced finding from a radiologist-confirmed one: `preliminary` for the AI observation, `final` for the radiologist's, with no change to the resource type. That distinction is the closest thing in the project's history to a [provenance](/glossary/provenance.md) marker on an observation, and it is what the Exam Finding List specification asks for when it says "each Observation should include some kind of provenance marker." See [FHIR mapping](/data-structures/fhir-mapping.md). +The lung cancer screening samples use [CDE set](/glossary/cde-set.md) identifiers under `https://radelement.org` for each finding's `code`. Each `component` uses a [CDE element](/glossary/cde-element.md) code, with the chosen value in `valueCodeableConcept`.[^fhir-sample] Both machine-produced and radiologist-confirmed findings use the same resource type. Their `status` differs, with `preliminary` for the AI observation and `final` for the radiologist's. This provides a precedent for the [provenance](/glossary/provenance.md) marker requested by the Exam Finding List specification: "each Observation should include some kind of provenance marker." See [FHIR mapping](/data-structures/fhir-mapping.md). # What is missing -There is no Observation model, no JSON Schema, and no standalone record. Issue 1 in the extraction repository states the gap and the intended shape: Pydantic models for Observation, with a possible "Extracted Observation" subtype, alongside the Exam Finding List and Imaging Problem List, with "extensive annotation to generate JSON schemas" and camelCase aliases on export against snake_case attributes internally.[^issue1] The issue is open and unclaimed by any current plan. The Extracted Observation subtype it floats is exactly the distinction described above, between what a language model produced and what has been coded. +There is no standalone Observation model or JSON Schema. Issue 1 in the extraction repository states the gap and the intended shape: Pydantic models for Observation, Exam Finding List, and Imaging Problem List, with "extensive annotation to generate JSON schemas" and camelCase export aliases for snake_case attributes. It also proposes a possible "Extracted Observation" subtype to distinguish language model output from coded findings.[^issue1] The issue is open and unclaimed by any current plan. [^deck]: "Open Imaging Data Model 2026 Status Update", January 2026 [^ipl-main-claude]: imaging-problem-list domain model notes, main branch diff --git a/knowledge/data-structures/sample-data.md b/knowledge/data-structures/sample-data.md index c11da97..9f39b04 100644 --- a/knowledge/data-structures/sample-data.md +++ b/knowledge/data-structures/sample-data.md @@ -1,10 +1,10 @@ --- type: Reference title: Sample data -description: The synthetic patients, exams, and findings that make up the Exam Finding List and Imaging Problem List sample data, what changes between branches, where the viewer bundles live, and how to regenerate everything. +description: Synthetic exam and problem list samples, branch differences, viewer bundles, and generation scripts. tags: [data-structures, sample-data, reference, synthetic] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: ipl-main-claude resource: https://github.com/openimagingdata/imaging-problem-list/blob/06f64a7893b444b761dc069ed86140a081195eac/CLAUDE.md @@ -34,7 +34,7 @@ sources: # All of it is synthetic -Every patient, identifier, date, and line of report text in this data set is written test data. The names, medical record numbers, and birth dates do not belong to real people, and the reports were authored for the project. Counts below were read at commit `06f64a7` on `main` and `36fa30c` on `dev`. +Every patient, identifier, date, and line of report text in this data set is written test data. The names, medical record numbers, and birth dates do not belong to real people, and the reports were authored for the project. Counts were read at `06f64a7` on `main` and `36fa30c` on `dev`. # The three sample sets @@ -65,7 +65,7 @@ Findings per exam range from 9 on the shoulder radiograph to 48 on the January 2 # What the branches differ on -The two branches hold the same exams and very nearly the same findings. What changed on `dev` is the anatomic enrichment and the regrouping that followed it. +The branches contain the same exams and nearly the same findings. The development branch adds anatomic enrichment and regroups findings. | Measure | `main` | `dev` | |---|---|---| @@ -75,7 +75,7 @@ The two branches hold the same exams and very nearly the same findings. What cha | Entries in the `example2` Imaging Problem List | 98 | 123 | | Observations in that problem list | 275 | 276 | -The two observations without a location are in the brain magnetic resonance study, where the assignment rules require leaving a structure unassigned rather than forcing a wrong code when the ontology has no entry for it. The jump from 98 entries to 123 is the grouping key change, from finding code alone to finding code and location identifier; the observations did not multiply, the groups got finer. Both are explained in [Imaging Problem List](/data-structures/imaging-problem-list.md). +Two observations in the brain magnetic resonance study lack locations because the ontology has no matching structures. Assignment rules leave them unassigned. Grouping by finding code and location instead of code alone increases the problem list from 98 to 123 entries. See [Imaging Problem List](/data-structures/imaging-problem-list.md). # File layout @@ -98,7 +98,7 @@ sample_data/ example3/ 31 .txt reports, dev branch only ``` -The viewer reads a different, nested layout, documented in the repository's own notes.[^ipl-main-claude] +The repository notes document the viewer's nested layout.[^ipl-main-claude] ``` viewer/data/ @@ -113,13 +113,13 @@ viewer/data/ finding_region_mappings.json 98 finding-to-body-region entries ``` -Its bundle covers both synthetic patients: `patient-mrn0000001` with 10 exams and 98 problem list entries, and `patient-mrn0000002` with 2 exams and 10 entries. **This bundle was not re-enriched.** On both `main` and `dev` it holds the 98-entry, location-free problem list, so the deployed first-generation [viewer](/applications/imaging-problem-list-viewer.md) shows the pre-anatomy data. +The bundle covers `patient-mrn0000001` with 10 exams and 98 problem list entries, and `patient-mrn0000002` with 2 exams and 10 entries. It was not re-enriched on either branch. The deployed first-generation [viewer](/applications/imaging-problem-list-viewer.md) therefore shows the 98-entry, location-free list. The second-generation viewer has its own bundle under `viewer_v2/public/data/`, built from `sample_data/example2`, carrying the 123-entry anatomy-grouped list for the one patient, with reports as markdown rather than text and extra files for the anatomy index, anatomy clusters, and finding display information. Its manifest is stamped `viewer-v2-data.1` and records its own source paths and warnings. ## The spreadsheet -`findings_with_oifm_ids.xlsx` is the human working sheet the whole `example2` set was built from. It is one row per finding per exam, with columns Exam Date, Exam Type, Exam Code, Finding, OIDM Finding Model Name, OIDM FMID, Presence OIFMA_ID, Present/Absent, and Text.[^excel-script] It records where the [finding model](/glossary/finding-model.md) and [attribute](/glossary/attribute.md) identifiers were assigned by hand, which is why it is worth keeping alongside the generated JSON. +`findings_with_oifm_ids.xlsx` is the working sheet for `example2`, with one row per finding per exam. Its columns are Exam Date, Exam Type, Exam Code, Finding, OIDM Finding Model Name, OIDM FMID, Presence OIFMA_ID, Present/Absent, and Text.[^excel-script] It records where the [finding model](/glossary/finding-model.md) and [attribute](/glossary/attribute.md) identifiers were assigned by hand, which is why it is worth keeping alongside the generated JSON. # Regenerating @@ -132,7 +132,7 @@ Four scripts produce the data, in this order. | `generate_ipl_from_efls.py` | reads a directory of `*_efl.json` files sorted by filename, groups by finding code and location identifier, writes one `ipl.json`[^ipl-script] | | `build_viewer_v2_data.py` | builds the static JSON bundle the second-generation viewer serves[^viewer2-script] | -Only the enrichment step calls a language model. The other three are deterministic. Exact invocation belongs with the code and is not repeated here; see the repository. +Only enrichment calls a language model. The other three scripts are deterministic. See the repository for commands. [^ipl-main-claude]: imaging-problem-list domain model notes, main branch [^excel-script]: generate_efl_from_excel.py diff --git a/knowledge/data-structures/technical-imaging-findings.md b/knowledge/data-structures/technical-imaging-findings.md index 97ab55a..a2930c8 100644 --- a/knowledge/data-structures/technical-imaging-findings.md +++ b/knowledge/data-structures/technical-imaging-findings.md @@ -1,10 +1,10 @@ --- type: Reference title: Technical imaging findings -description: A draft catalog of modality-specific technical finding language, CT attenuation, MR signal, enhancement, ultrasound echogenicity, and nuclear medicine, with the search-term guidance for coding each, migrated from the imaging-problem-list development branch. +description: A migrated draft catalog of modality-specific findings and search terms for coding them. tags: [data-structures, technical-finding, coding, terminology, migrated, draft] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: tech resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/docs/technical-imaging-findings.md @@ -13,7 +13,7 @@ sources: # About this document -This is a near-verbatim migration of `docs/technical-imaging-findings.md` from the `imaging-problem-list` repository's development branch.[^tech] The source marks itself **Draft, needs review against the finding ontology for coverage assessment**, and that status carries over: the catalog has not been audited against the finding model corpus, and its closing questions are open. Wording and structure follow the original. +Migrated near-verbatim from `docs/technical-imaging-findings.md` on `imaging-problem-list`'s development branch.[^tech] Wording and structure follow the original. The source is marked **Draft, needs review against the finding ontology for coverage assessment**. The catalog remains unaudited against the finding model corpus, and its closing questions remain open. Radiology reports frequently describe findings using modality-specific technical language rather than clinical diagnoses. These [technical findings](/glossary/technical-finding.md) describe what the radiologist observes on the images, including signal characteristics, density, enhancement patterns, and echogenicity, without necessarily committing to an underlying pathological process. diff --git a/knowledge/drafts/anatomic-locations.md b/knowledge/drafts/anatomic-locations.md new file mode 100644 index 0000000..25928fb --- /dev/null +++ b/knowledge/drafts/anatomic-locations.md @@ -0,0 +1,143 @@ +--- +type: Concept +title: Anatomic locations +description: The curated anatomic location index as a reference layer - identity, containment, part-of, laterality, synthetic terms, curation rules, the RadLex overlay, and the two dated implementations. +tags: [foundation-context, anatomic-locations, radlex, laterality, containment] +status: draft +generated: { by: claude-opus-5/2026-09-22-restructure/draft-axes, at: 2026-09-22T12:53:11Z } +sources: + - id: jdim-al + resource: "Anatomic Locations Index: A Spatial Containment Hierarchy for Localizing Imaging Findings, manuscript under review at the Journal of Digital Imaging and Informatics in Medicine, 2026" + title: Manuscript under review, read as the blinded manuscript body only; reviewer correspondence not used + - id: siim2026 + resource: https://oidm-public.t3.tigrisfiles.io/oidm-knowledge-sources/SIIM%202026%20Reports-of-the-Future.pptx + title: Structured Results and Context for Next-Generation Imaging Resulting Tools, SIIM 2026 annual meeting talk, June 2026, Mass General Brigham, slides 8, 10 and 12 + - id: al-site + resource: https://github.com/talkasab/anatomiclocations.org/blob/1f39fa45f621cef947a3f3ef1f869334cfa5c841/docs/index.markdown + title: Anatomic Locations project site homepage, rationale, features and roadmap, unchanged since January 2023 + - id: fm-data + resource: https://github.com/openimagingdata/findingmodel/blob/75afd39a400419dcfaf7c8d4a34f065b4d804e0d/notebooks/data/anatomic_locations_noembed.json + title: anatomic_locations_noembed.json, the current curated set, 2,926 records + - id: fm-fields + resource: https://github.com/openimagingdata/findingmodel/blob/75afd39a400419dcfaf7c8d4a34f065b4d804e0d/.claude/skills/manage-anatomic-locations/reference/json-schema.md + title: Anatomic locations source JSON field reference, including the SNOMED CT SEP triad rule + - id: fm-laterality + resource: https://github.com/openimagingdata/findingmodel/blob/75afd39a400419dcfaf7c8d4a34f065b4d804e0d/.claude/skills/manage-anatomic-locations/reference/laterality-conventions.md + title: Laterality conventions, the compound identifier pattern and the three-entry rule + - id: fm-skill + resource: https://github.com/openimagingdata/findingmodel/blob/75afd39a400419dcfaf7c8d4a34f065b4d804e0d/.claude/skills/manage-anatomic-locations/SKILL.md + title: The manage-anatomic-locations skill and its lookup, sampling and validation scripts + - id: fm-package + resource: https://github.com/openimagingdata/findingmodel/tree/75afd39a400419dcfaf7c8d4a34f065b4d804e0d/packages/anatomic-locations + title: The anatomic-locations package, version 0.2.5, its runtime model, index and command line + - id: fm-doc + resource: https://github.com/openimagingdata/findingmodel/blob/75afd39a400419dcfaf7c8d4a34f065b4d804e0d/docs/anatomic-locations.md + title: Anatomic locations usage document, findingmodel + - id: fm-normalized + resource: https://github.com/openimagingdata/findingmodel/blob/75afd39a400419dcfaf7c8d4a34f065b4d804e0d/tasks/done/anatomic-locations-normalized-schema.md + title: Rich anatomic location DuckDB with relationships, the plan that designed the normalized model, completed 2025-12-31 + - id: al-libs + resource: https://github.com/talkasab/BodyPartIndex.py/blob/388ae0a6da92f5ee4cf36620bbeeabe223938471/README.md + title: BodyPartIndex.py README, the Python wrapper library, last commit 2024-02-03; companion TypeScript library at BodyPartIndex.ts dec578e1, 2022-12-18 + - id: cde-anatomy-axis + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/docs/next-gen-schema/11-anatomy-axis.md + title: The Anatomy Axis, Current State, ACR-RSNA-CDEs next-gen-2026 branch, dated 15 September 2026 + - id: cde-understanding + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/docs/next-gen-schema/00-current-understanding.md + title: Current Understanding, ACR-RSNA-CDEs next-gen-2026 branch, the laterality and substrate statements + - id: cde-alpha + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/docs/next-gen-schema/12-alpha-structural-comparison.md + title: Alpha structural comparison, ACR-RSNA-CDEs next-gen-2026 branch, open decision areas ST06 and ST08 + - id: radlex-issue + resource: https://github.com/RSNA/RadLex/issues/3 + title: "RSNA RadLex issue 3, Add Anatomic Locations, opened 2026-08-10, open" + - id: radlex-skill + resource: https://github.com/RSNA/RadLex/blob/5162a65db531c8170139656f8a8ed27d96b6dd20/.claude/skills/radlex-concepts/SKILL.md + title: The radlex-concepts skill, the two-phase extract and propose loop with its validation rules + - id: radlex-suggest + resource: https://github.com/RSNA/RadLex/blob/5162a65db531c8170139656f8a8ed27d96b6dd20/.pi/skills/suggest-new-concepts.md + title: The suggest-new-concepts skill, acceptance rules for a proposed concept +--- + + +# What the index is + +The [anatomic location](/glossary/anatomic-location.md) index is a curated set of anatomic entities, each keyed by a [RadLex identifier](/glossary/radlex-id.md) and placed in a spatial containment hierarchy. The manuscript under review describes it as a reference and normalization layer, not an automatic labeling algorithm. An identifier may be applied at the examination or series level for the anatomy covered, or at the finding level for where an observation is. Labels may be assigned by hand or generated by rules, language processing, or AI and then normalized; whatever the route, a person or downstream check confirms the structure before anything relies on it. The same source states the limit: knowing where a finding is does not establish what kind of process it is, how long it has been present, or whether it is the same lesion recorded elsewhere.[^jdim-al] + +How a finding acquires its location belongs to Data Structures; see [anatomic location assignment rules](../data-structures/anatomic-location-assignment-rules.md). + +# Why a curated set + +The project site, unchanged since January 2023, argues qualitatively that ontologies holding anatomic terms are poorly suited to underpinning interoperability: too few desired terms, too many unnecessary or degenerate ones, limited anatomic organization. Its approach was to curate a subset of them, starting from [RadLex](/glossary/radlex.md) terms previously recognized in radiology reports.[^al-site] + +The manuscript under review measures one of those three things, containment. It counts, for [SNOMED CT](/glossary/snomed-ct.md), [FMA](/glossary/fma.md), and RadLex, how completely each populates the containment or part-whole relation it declares, measuring each against its own anatomy term set so no resource is penalized for its coverage. Through those declared relations, no structure in any of the three reaches the whole body. Pooling every declared relation, its subproperties, and the reversed inverses lifts only the resources' own anatomy classes: 31.0% of FMA's and 25.1% of RadLex's then reach a whole-body class, by mixed paths that give no ordered chain of enclosing regions, while no index term present in any of them reaches one. The stated interpretation is not that the resources are defective but that none was built to answer what encloses the structures radiologists name. The manuscript measures no downstream utility and asks to be read as a descriptive resource paper.[^jdim-al] + +# Identity and codes + +A location's identifier is its RadLex identifier. The next-generation vocabulary work states the consequence directly: a RadLex code is never listed beside a location, because the location code is the RadLex code.[^cde-anatomy-axis] + +In the current curated data, all 2,926 records carry an identifier, a description, a [body region](/glossary/body-region.md), and a containment parent; 1,782 carry SNOMED CT concept identifiers, 2,025 ACR Common identifiers, and 1,750 a further list of FMA, MeSH, and [UMLS](/glossary/umls.md) codes.[^fm-data] + +Which SNOMED CT concept to use is a written rule, not a matter of judgment. SNOMED CT carries a Structure-Entire-Part triple for anatomy, and the field reference instructs a curator to always take the "Structure of ..." concept and never the "Entire ..." or "... part" forms, because that is what SNOMED CT intends for finding sites and procedure sites. Where a lateralized code does not exist, the unsided code serves all three entries, noted in the change description. Definitions prefer authoritative sources in order: Fleischner Society for thoracic anatomy, then RadLex, MeSH, FMA.[^fm-fields] Lookup, sampling, and validation scripts ship beside the reference.[^fm-skill] + +# Containment: one parent, up to the whole body + +Every structure has exactly one containing parent, the smallest anatomic entity that encloses it. A structure spanning several subregions takes the smallest region containing the whole of it, so the pancreatic duct is contained by the pancreas rather than by the head, body, neck, tail, or uncinate process individually. The manuscript reports that every chain was verified to reach one root, the whole body, that the longest chain is seven hops, and that the largest share of entries sits at depth three. It records the cost as a limitation: a structure spanning sibling subregions is assigned to their common parent, so the pancreatic duct's course through the subdivisions is not represented, and the grouping is deliberately coarse.[^jdim-al] + +# Containment is not part-of + +Where a structure physically sits and what functional structure it belongs to are different questions, kept in separate fields. The curation guidance tells an editor which to use: containment for "X is inside Y", the hilum inside the lung; part-of for "X is a component of Y", the stomach part of the gastrointestinal tract.[^fm-fields] The manuscript gives the abdominal aorta as the worked case, contained by the retroperitoneum and part of the aorta, and states that the single-parent constraint applies only to containment: a structure may hold zero, one, or more [part-of](/glossary/contained-by-and-part-of.md) associations. The release it describes carries 991;[^jdim-al] the current data carries 1,123.[^fm-data] The next-generation vocabulary work leaves open which hierarchy a given check walks; it must be stated each time.[^cde-anatomy-axis] + +# Laterality as explicit triads + +Left, right, and unsided variants of a bilateral structure are three distinct entries joined by explicit links, rather than one entry plus a modifier. The unsided entry links to both sided variants; each sided entry links to its counterpart and back to the unsided form; and a sided entry's container points at the sided version of its container where one exists.[^fm-laterality] The manuscript states the reason as an implementation convenience, since the links permit deterministic navigation among corresponding forms without reconstructing a post-coordinated expression at runtime, and reports complete triads for all 795 bilateral structures.[^jdim-al] + +The next-generation vocabulary work draws a consequence: laterality is carried by the location rather than by a data element, so there will be no laterality data elements.[^cde-understanding] For the Observation the project lead has settled it: an Observation specifies a sided anatomic location, which the decision record marks as not an open choice to present again. An external reviewer's alpha implementation differs from that direction, defining a laterality data element including a bilateral value, and acknowledges that a bilateral value does not resolve whether a report describes one entity or two. What stays outstanding is implementation alignment, such as export and query behavior.[^cde-alpha] + +# Synthetic post-coordinated terms + +Where a clinically routine localization concept has no pre-coordinated RadLex term, almost always because laterality or enumeration is missing, an identifier is minted by joining existing RadLex identifiers with an underscore, keeping the composition transparent and machine-readable.[^fm-laterality] The manuscript reports three patterns covering all of them: laterality only, 730 terms; enumeration only, 86; enumeration plus laterality, 194, most often for numbered or bilateral structures. Two qualifications accompany it: the count is not evidence that established ontologies lack mechanisms for adding concepts, since the gaps are specific to one lexicon; and systems built on RadLex will not recognize the compound identifiers without a mapping layer.[^jdim-al] The next-generation vocabulary work names them as the exception the RadLex track will remove by minting real identifiers.[^cde-anatomy-axis] + +# An overlay on RadLex, and terms contributed back + +The relationship to RadLex is stated as an overlay, not a competitor: RadLex concepts and predicates sit underneath, and the file adds identifiers RadLex lacks, its own two hierarchies, and laterality. The next-generation vocabulary work records this as agreed on 13 September 2026, and states why work proceeds against the file rather than the published RadLex release: the RadLex anatomy track is editing the file, so aiming at the published release is described as editing a three-year-old version of a document others have been editing. The data is pointed to at a pinned commit, not copied.[^cde-anatomy-axis] The manuscript describes incorporation by the RSNA RadLex Committee as underway, covering the terms, and notes that a process for revising and reviewing the hierarchy still needs definition.[^jdim-al] The RadLex repository carries an open issue whose exit criterion is complete coverage of the anatomic locations terminology in RadLex.[^radlex-issue] + +Gaps found while using a terminology are fed back rather than patched locally. The RadLex repository's concept skill implements this in two phases. An agent first matches findings in report text to existing concepts, under the rule that a loose keyword overlap is not enough and a broader concept does not count as a match. For each unmatched term it proposes a new concept with the closest existing parent, a precise term, a rationale for why the gap is genuine, and typed relationships only where a real existing identifier was found for the other end.[^radlex-suggest] Proposals are validated before anything is written, and a batch fails as a whole.[^radlex-skill] Separately, the next-generation vocabulary work feeds node requests upstream: lung parenchyma, perirenal space and its sided forms, pericardial space, subarachnoid space, and real identifiers for the compound sided variants.[^cde-anatomy-axis] + +# What the index does not carry + +The curated set has containment and part-of but no taxonomic relation and no structure-type nodes, so a statement such as "this finding applies to tendons" cannot be made. The next-generation vocabulary work records this as the major shortcoming for that effort and the first thing to resolve. RadLex could supply a first layer without inventing anything, since every plain-identifier location has a taxonomic chain in the published ontology, yielding several hundred locations under each of muscle, artery, vein, tendon, and bone. Two cautions accompany it: RadLex warns that some taxonomic categorizations were converted from part-of and may be wrong, and the deep formal chain is not the clinically useful layer. The same document names two scope families, tissue types and structure types, with their connections to the location hierarchy still open, and separates them from exploratory ideas marked not adopted.[^cde-anatomy-axis] + +# Stated direction: enrichment from FMA + +The SIIM 2026 talk shows the anatomic location axis as a kidney field table: identity, classification, the two hierarchies, laterality variants, codes. Rows marked defined but not yet populated fall under FMA enrichment going forward: definitions imported from FMA under a Creative Commons license, references, new edges for branch-of, bounded-by, and adjacent-to, enumeration updates splitting organ from organ part and adding "Back" to the region list, and a location type recorded as "organ (next-gen; was 'structure')".[^siim2026] + +# Two dated implementations + +| | The 2022 to 2024 set | The current package | +|---|---|---| +| Data | `body_parts.json`, 2,890 nodes, release 1.0.0-rc.1, site unchanged since January 2023[^al-site] | `anatomic_locations_noembed.json`, 2,926 records, inside `findingmodel`[^fm-data] | +| Libraries | Python and TypeScript wrappers over the JSON file, last commits 2024-02-03 and 2022-12-18[^al-libs] | One Python package, version 0.2.5, with a command line[^fm-package] | +| Status | Superseded as the working substrate on 2026-09-13[^cde-understanding] | The substrate the next-generation vocabulary points at, pinned to a commit[^cde-anatomy-axis] | + +Entity counts differ by release: 2,890 published, 2,891 in the manuscript, 2,926 current.[^al-site][^jdim-al][^fm-data] + +The current package resolves a location by identifier, description, synonym, or external code, walks both hierarchies, filters by region and by the classification fields, and searches by combining full-text and vector retrieval.[^fm-package][^fm-doc] Precomputed containment and part-of paths make ancestry and containment tests string comparisons rather than recursive queries.[^fm-normalized] Tooling belongs to the SDKs pillar; see [SDKs](./sdks.md). + +[^jdim-al]: Anatomic Locations Index manuscript, under review at the Journal of Digital Imaging and Informatics in Medicine, 2026 +[^siim2026]: SIIM 2026 annual meeting talk, June 2026, Mass General Brigham +[^al-site]: Anatomic Locations project site homepage, January 2023 +[^fm-data]: anatomic_locations_noembed.json, the current curated set +[^fm-fields]: Anatomic locations source JSON field reference, findingmodel +[^fm-laterality]: Laterality conventions, findingmodel +[^fm-skill]: The manage-anatomic-locations skill, findingmodel +[^fm-package]: The anatomic-locations package, findingmodel +[^fm-doc]: Anatomic locations usage document, findingmodel +[^fm-normalized]: Rich anatomic location DuckDB with relationships, findingmodel +[^al-libs]: BodyPartIndex.py and BodyPartIndex.ts READMEs +[^cde-anatomy-axis]: The Anatomy Axis, Current State, ACR-RSNA-CDEs next-gen-2026 +[^cde-understanding]: Current Understanding, ACR-RSNA-CDEs next-gen-2026 +[^cde-alpha]: Alpha structural comparison, ACR-RSNA-CDEs next-gen-2026 +[^radlex-issue]: RSNA RadLex issue 3, Add Anatomic Locations +[^radlex-skill]: The radlex-concepts skill, RSNA RadLex +[^radlex-suggest]: The suggest-new-concepts skill, RSNA RadLex diff --git a/knowledge/drafts/data-structures.md b/knowledge/drafts/data-structures.md new file mode 100644 index 0000000..8c7eff8 --- /dev/null +++ b/knowledge/drafts/data-structures.md @@ -0,0 +1,191 @@ +--- +type: Concept +title: Data Structures +description: Observations connect a patient's imaging results to shared definitions and to one another across reports and examinations. +tags: [data-structures, observation, foundation-context, imaging-problem-list] +status: draft +generated: { by: codex/2026-09-22-restructure, at: 2026-09-22T13:54:25Z } +sources: + - id: siim-context + resource: https://oidm-public.t3.tigrisfiles.io/oidm-knowledge-sources/SIIM%202026%20Reports-of-the-Future.pptx + title: Reports of the Future, June 2026, slides 4–8 and 12 + - id: report-graph + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/docs/next-gen-schema/03-draft-structures.md + title: Next-generation CDE draft structures, section 5, snapshot 2026-09-15 + - id: report-decisions + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/docs/plans/2026-09-03-report-plane-example.md + title: Report-plane example, owner decisions and Claude defaults, 2026-09-03 + - id: two-graph-example + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/docs/next-gen-schema/08-worked-examples.md#4-one-report-two-planes + title: Pyelonephritis worked example, snapshot 2026-09-15 + - id: ipl-manuscript + resource: Imaging Problem List manuscript, JDIM-D-26-02980 R1, under review at JDIM in 2026; clean manuscript and figures held in the source collection + title: Imaging Problem List manuscript, JDIM-D-26-02980 R1, under review, read 2026-09-22 + - id: webinar + resource: https://oidm-public.t3.tigrisfiles.io/oidm-knowledge-sources/IPL%20Webinar%20Deck.html + title: Imaging Problem List SIIM webinar, 2026-07-15 + - id: cde-decisions + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/docs/next-gen-schema/10-decision-record-2026-09-02.md + title: CDE decision record, S19–S26, snapshot 2026-09-15 + - id: sample-efls + resource: https://github.com/openimagingdata/imaging-problem-list/tree/36fa30c7383bf687d7bc17815282a93e123a56cb/sample_data/example2 + title: Example2 Exam Finding Lists, development snapshot 2026-07-22 + - id: technical-findings + resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/docs/technical-imaging-findings.md + title: Technical imaging findings, draft reference at 2026-07-22 + - id: domain-notes + resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/CLAUDE.md + title: IPL domain notes, development snapshot 2026-07-22 + - id: extraction-prompt + resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/src/finding_extractor/extractor/prompt.py + title: Extraction prompt, development snapshot 2026-07-22 + - id: coding-prompt + resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/src/finding_extractor/coding/prompt.py + title: Finding and location coding prompts, development snapshot 2026-07-22 + - id: extraction-review + resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/prompts/validator_prompt_example.md + title: Chunk reviewer contract, development snapshot 2026-07-22 + - id: anatomy-rules + resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/docs/anatomic-location-assignment-rules.md + title: Anatomic location assignment rules, development snapshot 2026-07-22 + - id: ipl-generator + resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/scripts/generate_ipl_from_efls.py + title: EFL aggregation into an IPL, development snapshot 2026-07-22 + - id: sample-ipl + resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/sample_data/example2/MRN0000001_ipl.json + title: Synthetic patient IPL, development snapshot 2026-07-22 + - id: viewer-status + resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/scripts/build_viewer_v2_data.py + title: Anatomy viewer data builder, development snapshot 2026-07-22 + - id: ipl-readme + resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/README.md + title: IPL README, development snapshot 2026-07-22 + - id: jacr-study + resource: Follow-Up Chest CT Reporting Is Mostly Re-Documentation, manuscript prepared for submission in 2026, held in the source collection + title: Follow-Up Chest CT Reporting Is Mostly Re-Documentation, prepared for submission, read 2026-09-22 + - id: owner-notes + resource: Project lead's manuscript notes, 2026-09-19, sources/email/2026-09-19-ipl-manuscript-notes.md + title: Observations, finding identity, and structures versus transport, 2026-09-19 + - id: context-board + resource: https://link.excalidraw.com/l/AxEw4sqe6bu/1sEx11UZ3gq + title: OIDM Object Model board, January 2024 proposal, transcribed 2026-09-21 + - id: report-board + resource: Structured Report Representation, internal working board, schema content transcribed in the local source collection + title: Structured Report Representation board, schema proposals from 2025 + - id: outcome-board + resource: https://link.excalidraw.com/l/AxEw4sqe6bu/68X9qfSP5qA + title: Outcome Tracking Schema board, transcribed 2026-09-21 + - id: idr-extract + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/notes/ihe-idr-extract.md + title: Team extract of the IHE IDR Phase II public-comment draft, read 2026-08-21 +--- + +# Data Structures + +The June 2026 presentation describes a compact Observation with codes pointing to [Foundation Context](./foundation-context.md), plus presence, change from prior, and characterization attributes. Observations belong to Patient Context alongside wider clinical information. Shared knowledge is resolved through their codes.[^siim-context] The July example2 Exam Finding Lists populate only presence in their attribute arrays, a narrower implementation than the deck describes.[^sample-efls] + +## Two connected graphs + +The next-generation CDE design calls these two graphs “planes”: shared definitions and observations in a report. An observation points to its subject definition, anatomic location, and the data elements whose values it records. It retains source wording and can link to other observations.[^report-graph] + +The June deck's calculus figure shows the connection. One patient observation resolves through an SDK to a calculus definition, which may cause hydronephrosis. The definitions connect to kidney and renal pelvis; the figure does not assert hydronephrosis in this patient. Its relationship is general knowledge.[^siim-context] + +Relationships between definitions describe general possibilities. Relationships between observations record what this report asserts about this patient. In the [pyelonephritis example](https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/docs/next-gen-schema/08-worked-examples.md#4-one-report-two-planes), shared definitions connect a diagnosis to its possible manifestations; report observations connect the particular findings to the diagnosis the radiologist states. The absent abscess remains an observation with an absent presence value. The report relationship itself is not negated and does not point to a vocabulary relationship. This is a hypothetical worked example.[^two-graph-example] + +The decision record marks that separation as owner decisions S21–S24. The edge name `SUPPORTS` and the convention of retaining the radiologist's wording in `confidence` are Claude defaults S25–S26.[^report-decisions][^cde-decisions] Components use the same distinction: a definition's `MAY_HAVE_COMPONENT` describes a possibility; a report's `HAS_COMPONENT` connects the actual nodule and solid-component observations, each with its own measurements.[^report-graph] + +These sources develop related representations with different scope: + +| Source and status | What it represents | +|---|---| +| CDE graph draft, snapshot 2026-09-15 | Assertions within one report, linked to definitions and to other assertions, with exact text and spans.[^report-graph] | +| IPL implementation, snapshot 2026-07-22 | Coded observations collected by examination and grouped across examinations using finding code and location.[^ipl-generator] | +| JDIM IPL manuscript, R1 under review, read 2026-09-22 | Longitudinal finding identity, observation histories, provenance, derived status, and proposed linking rules.[^ipl-manuscript] | + +## Observations and their evidence + +The extraction and coding prompts separate finding type, location, and presence. Absence does not change which finding or anatomy code is appropriate. Normality becomes an appropriately scoped absent abnormality; a blanket negative must not introduce more specific claims than its wording supports. Coding may use a slightly broader concept but must not add specificity, and can leave a finding uncoded or unlocalized with a reason.[^extraction-prompt][^coding-prompt][^extraction-review] + +The rules agreed for the example2 correction pass, intended to guide later automated coding, choose explicit report or section anatomy first, then the finding's target structure, then a coarse exam region. They retain section-level laterality, split separable bilateral findings, and keep diffuse or midline findings unsided. The July coding prompt separately allows multiple locations and generates sided terms for bilateral anatomy.[^anatomy-rules][^coding-prompt] + +Presence and confidence also differ: + +| Source | Representation | +|---|---| +| July 2026 webinar and JDIM R1 manuscript | Present or absent, with a separate hedge on the assertion or attribute it qualifies.[^webinar][^ipl-manuscript] | +| July 2026 extraction prompt | `present`, `absent`, `possible`, `indeterminate`; uncertainty about the finding differs from inability to determine it.[^extraction-prompt] | +| July 2026 example2 data | `present`, `absent`, `indeterminate`, without a separate confidence field.[^sample-ipl] | + +For technical descriptions, the term-generation prompt forbids inferring a diagnosis, while the selector asks for the underlying clinical concept. The draft technical-findings reference also distinguishes observed signal abnormalities from diagnoses. These sources do not settle how the selector's broader instruction applies.[^coding-prompt][^technical-findings] + +## Exam Finding Lists + +The manuscript organizes findings at two levels: an Exam Finding List for one examination and an Imaging Problem List across examinations, because interpretation spans both. The June deck connects the EFL to IHE Imaging Diagnostic Report and places both lists within broader Patient Context.[^ipl-manuscript][^siim-context] The EFL must retain stated comparisons, time course, explicit negatives, and supporting sentences. Silence adds no observation. The JACR study illustrates the fidelity problem: its extractor sometimes turned a neutral measurement into an abnormality the radiologist had not asserted.[^ipl-manuscript][^jacr-study] + +The chunk reviewer contract checks both directions: every extracted assertion needs evidence, and every finding in the source needs representation. It names unsupported content, omissions, wrong presence, excess specificity, incorrect blanket negatives, and location errors as reasons to re-extract. The [extraction platform](./sample-applications.md) implements this review workflow.[^extraction-review] + +The manuscript combines repeated descriptions into one observation per finding per examination. The project lead's September notes emphasize that one finding may have several observations within a report. The implemented extractor prioritizes detailed body text and adds impression findings only when they are distinct; the IPL aggregator can retain multiple observations from the same exam. These choices remain visible rather than being collapsed into one cardinality rule.[^ipl-manuscript][^owner-notes][^extraction-prompt][^ipl-generator] + +The 2025 report-structure board asks how to represent impression, recommendations, communication, comparison, technique, clinical context, and limitations. Its open questions concern impression observations, grouped findings, and causal relationships, also explored in the [two-graph design](#two-connected-graphs). The extractor labels non-finding text without implementing these richer structures.[^report-board][^extraction-prompt][^report-graph] + +## Imaging Problem Lists + +An Imaging Problem List collects a finding's observations across examinations. The manuscript proposes a persistent entry with a tracking identifier, identified principally by finding code and anatomic site. The project lead's notes require accounting for broader or narrower codes, finding-to-diagnosis changes, and evolution such as an acute fracture becoming healed.[^ipl-manuscript][^owner-notes] + +Finding and diagnosis remain distinct modeling choices. JDIM R1 records the diagnosis or assessment on the finding's observation. The September CDE draft also represents a diagnosis as the subject of its own observation, connected to supporting findings. The September 19 notes call for making the IPL's account of that distinction explicit.[^ipl-manuscript][^report-graph][^owner-notes] + +Entity resolution remains open: which observations refer to the same finding? The July implementation groups exact code-and-location pairs and regenerates numbered entry IDs from sorted groups; it does not establish durable identity across rebuilds. Generic and specific locations can form separate entries.[^ipl-generator][^anatomy-rules] The JDIM manuscript proposes graduated linking evidence, led by an explicit comparison to a prior finding. The JACR measurement uses ordered matching rules and retains ambiguous cases separately. These serve different purposes and remain distinct formulations.[^ipl-manuscript][^jacr-study] + +Status is derived from observations, but the vocabulary varies: + +| Source | Status and trajectory | +|---|---| +| JDIM R1 manuscript, under review | Active, Stable, Resolved, Excluded. Trajectory is read from the observation history.[^ipl-manuscript] | +| SIIM webinar, 2026-07-15 | Slide 21 proposes Active or Resolved, with trajectories within Active. Slide 22 also uses Stable in its example.[^webinar] | +| IPL domain notes, 2026-07-22 | Currently present, resolved, never-present or ruled out.[^domain-notes] | +| Anatomy viewer builder, 2026-07-22 | `current`, `always`, `resolved`, `never_present`, stored in the generated bundle. An empty history returns `unknown` and aborts the build.[^viewer-status] | + +The manuscript proposes a succession link when one entity leaves another behind, such as resolved pneumonia followed by scarring. For observations in signed reports, it puts provenance and review on each observation, retaining model identity, inputs, output, source text, and subsequent human decisions. Model-produced observations remain unreviewed until a radiologist affirms or rejects them; status follows rules over the observations and links. Merging, splitting, and marking errors are provenance operations, separate from status. The July IPL sample does not carry this proposed provenance or succession structure.[^ipl-manuscript][^sample-ipl] + +The JACR study supplies the motivation for retaining the whole history: 77.4% of unhedged chronic findings on follow-up chest CT were repeated without change. Most accumulated IPL entries went unmentioned on an individual exam. The manuscript therefore calls for ranking entries for display, using permanence as one signal. Permanence comes from the finding type, not inference from repeated observations. These are results and implications of a manuscript prepared for submission.[^jacr-study] + +Recommendations remain a separate design question. The outcome board proposes an exam or protocol, timeframe, target, conditions, and citation, plus live or closed entries. The JDIM manuscript attaches recommendations and their closure to an entry while deriving finding status from observations. The location of the live/closed distinction remains unresolved.[^outcome-board][^ipl-manuscript] + +## Broader context and transport + +The June deck places Imaging Persona around imaging results and clinical context. The object-model board's January 2024 proposal includes orders, prior reports, tracked observations, EHR information, studies, and current report text. Their application role appears in [Use Cases](./use-cases.md).[^siim-context][^context-board] + +The project lead's September 19 direction is to define structures applications can read and create, then use those structures to guide transport mappings.[^owner-notes] + +| Dated source | Documented FHIR mapping | +|---|---| +| IPL README, July 2026 | EFL as `DiagnosticReport` with `Observation` components; IPL as a “Report” containing `Condition` objects and their observations.[^ipl-readme] | +| JDIM R1, under review, read September 2026 | EFL observation as `Observation`, report as `DiagnosticReport`, site as `BodyStructure`, entry as `List` or a custom profile, succession as a reference or extension, review as `Provenance`; status remains derived.[^ipl-manuscript] | +| Team's August 2026 extract of the March IHE IDR draft | IDR routes positive clinical findings to `Condition`, negatives to `Observation`, and Finding Sets through member observations. The team explicitly records its different working default: all report assertions, diagnoses included, as `Observation`.[^idr-extract] | + +The July IPL prototype stores its own JSON structure rather than implementing either proposed IPL transport mapping.[^ipl-generator] [Sample Applications](./sample-applications.md) shows implemented examples; [SDKs](./sdks.md) covers developer capabilities around the structures. + +[^siim-context]: June 2026 [presentation](https://oidm-public.t3.tigrisfiles.io/oidm-knowledge-sources/SIIM%202026%20Reports-of-the-Future.pptx), slides 4–8 and 12. +[^report-graph]: [Draft structures, section 5](https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/docs/next-gen-schema/03-draft-structures.md#5-two-planes-reports-point-into-the-vocabulary). +[^report-decisions]: [Report-plane decisions](https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/docs/plans/2026-09-03-report-plane-example.md), owner directions and Claude defaults. +[^two-graph-example]: [Worked example, section 4](https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/docs/next-gen-schema/08-worked-examples.md#4-one-report-two-planes). +[^ipl-manuscript]: JDIM-D-26-02980 R1, under review, printed pp. 6–12 and 15–16, and Table 1. Paraphrased from the clean manuscript and table, read 2026-09-22; reviewer correspondence excluded. +[^webinar]: SIIM webinar, 2026-07-15, slides 17–23 and their notes, numbered in file order rather than by printed slide labels. +[^cde-decisions]: CDE decision record at `44836c19`, rows S19–S26, including explicit OWNER and CLAUDE DEFAULT labels. +[^sample-efls]: Example2 `*_efl.json` files at `36fa30c`, all 276 observations' attribute arrays inspected. +[^technical-findings]: Technical Imaging Findings draft reference at `36fa30c`, CT, MR, and enhancement search considerations. +[^domain-notes]: IPL `CLAUDE.md` at `36fa30c`, Domain Model and temporal-status descriptions. +[^extraction-prompt]: [Extraction prompt](https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/src/finding_extractor/extractor/prompt.py), core, deduplication, presence, non-finding, and chunk rules. +[^coding-prompt]: [Coding prompts](https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/src/finding_extractor/coding/prompt.py), term generation and code selection. +[^extraction-review]: [Reviewer contract](https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/prompts/validator_prompt_example.md), evidence boundary and named failure types. +[^anatomy-rules]: [Assignment rules](https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/docs/anatomic-location-assignment-rules.md), including the known reconciliation limitation. +[^ipl-generator]: [IPL generator](https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/scripts/generate_ipl_from_efls.py), grouping and observation history. +[^sample-ipl]: [example2 IPL](https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/sample_data/example2/MRN0000001_ipl.json). +[^viewer-status]: [Viewer data builder](https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/scripts/build_viewer_v2_data.py), `compute_status` and `statusByFindingId`. +[^ipl-readme]: [IPL README](https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/README.md), EFL and IPL sections. +[^jacr-study]: JACR manuscript prepared for submission, Methods, Results, and Discussion. Paraphrased from the version read 2026-09-22. +[^owner-notes]: Project lead's manuscript notes, 2026-09-19, points 1–5. Retained in the local source collection. +[^context-board]: OIDM Object Model board, mind map and class diagram, transcription read 2026-09-22. +[^report-board]: Structured Report Representation board, schema questions recorded in 2025, transcription read 2026-09-22. +[^outcome-board]: Outcome Tracking Schema board, Recommendation Structure and Imaging Problem List boxes, transcription read 2026-09-22. +[^idr-extract]: [Team's IHE IDR extract](https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/notes/ihe-idr-extract.md), sections 1–4 and 6, read from the March 2026 public-comment draft in August 2026. diff --git a/knowledge/drafts/exam-types.md b/knowledge/drafts/exam-types.md new file mode 100644 index 0000000..b6ff0c8 --- /dev/null +++ b/knowledge/drafts/exam-types.md @@ -0,0 +1,89 @@ +--- +type: Concept +title: Exam types +description: A stated goal with no artifact - preferred high-level exam entries over the LOINC/RSNA Radiology Playbook, the Playbook properties they would expose, and the anatomy coverage edges in the project lead's two dated phrasings. +tags: [foundation-context, exam-types, loinc, playbook, radlex] +status: draft +generated: { by: claude-opus-5/2026-09-22-restructure/draft-axes, at: 2026-09-22T12:53:11Z } +sources: + - id: brief + resource: /plans/2026-09-20-knowledgebase-build-plan.md + title: The project lead's stated goals, recorded verbatim from the request of 2026-09-20 + - id: build-plan + resource: /plans/2026-09-20-knowledgebase-build-plan.md + title: Knowledgebase build plan, 2026-09-20, the source map and the facts-worth-stating section + - id: siim2026 + resource: https://oidm-public.t3.tigrisfiles.io/oidm-knowledge-sources/SIIM%202026%20Reports-of-the-Future.pptx + title: Structured Results and Context for Next-Generation Imaging Resulting Tools, SIIM 2026 annual meeting talk, June 2026, Mass General Brigham, slides 8 and 11 + - id: al-site + resource: https://github.com/talkasab/anatomiclocations.org/blob/1f39fa45f621cef947a3f3ef1f869334cfa5c841/docs/index.markdown + title: Anatomic Locations project site roadmap, content tasks, unchanged since January 2023 + - id: board-anatomy + resource: Common Anatomic Locations working board, Exam Types box under Active Issues, undated + title: Undated working-board proposal; the board carries a separate discussion checklist dated 2024-05-28, which is not used here + - id: molu-roadmap + resource: https://github.com/openimagingdata/med-ontology-lookup/blob/9cc3eec2c7af32e366e3f05e027b223b4a870077/docs/product-roadmap.md + title: "Product direction: an agent-ready medical terminology graph gateway, med-ontology-lookup, research date 2026-08-16, status recommended direction" + - id: jdim-al + resource: "Anatomic Locations Index: A Spatial Containment Hierarchy for Localizing Imaging Findings, manuscript under review at the Journal of Digital Imaging and Informatics in Medicine, 2026" + title: Manuscript under review, Discussion section on scan-protocol coverage; reviewer correspondence not used + - id: ipl-rules + resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/docs/anatomic-location-assignment-rules.md + title: Anatomic location assignment rules, imaging-problem-list dev branch, the precedence ladder and the exam-scoped region fallback + - id: ipl-efl + resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/sample_data/example2/ct_abdomen_20210826_efl.json + title: Exam Finding List sample with a LOINC-coded exam header, imaging-problem-list dev branch +--- + +# Nothing is built + +The knowledgebase build plan of 2026-09-20 states it plainly: no exam-type artifact exists, and the area is documented as goals plus existing building blocks.[^build-plan] Everything on this page is either a stated goal or a written proposal, each dated. Two smaller things do exist. An [exam type](/glossary/exam-type.md) appears as a bare LOINC code in an Exam Finding List header in the sample data.[^ipl-efl] And a written rule places a finding with no explicit anatomy and no target organ in the exam-scoped coarse region, sided only if the exam is sided; that rule was agreed for one sample-data correction pass and is stated as the intended spec for tuning automated location coding later.[^ipl-rules] Both belong to [Data Structures](./data-structures.md). + +# Preferred high-level entries over the Playbook + +The goal has been stated in nearly the same words across four years, and it is always a wrapper rather than a new vocabulary. + +| Date | Statement | +|---|---| +| January 2023 | The project site roadmap lists, under content tasks, a companion for exam types based on LOINC and RadLex Playbook exam definitions that specify all included body parts.[^al-site] | +| undated | A working board's Exam Types box lists exam type definitions of the most common exams based on LOINC, with common identifiers.[^board-anatomy] | +| 2026-09-20 | The project lead's brief: exam types need "wrapper tooling around the knowledge graph represented by RadLex LOINC playbook", and the project needs "to define the PREFERRED high-level entries like 'CT Chest', 'MRI Brain', 'X-ray Knee'."[^brief] | +| June 2026 | The SIIM talk shows Exam Type as one of three axes, each an OIDM layer over an existing standard; the exam type axis layers over [LOINC Playbook](/glossary/loinc-rsna-radiology-playbook.md) study types.[^siim2026] | + +The brief's own word is "PREFERRED", and the entries it names as examples are "CT Chest", "MRI Brain", and "X-ray Knee".[^brief] + +# What the layer would expose + +The June 2026 talk describes Exam Type as a thin layer on top of the RadLex/LOINC Playbook whose value is access to information the Playbook already holds: timing, contrast, and sidedness among them. It also states that broad families of exams are being grouped together, giving "CT Chest" and "MR Knee" as the examples.[^siim2026] + +# Anatomy coverage edges, in two dated phrasings + +The project lead has stated the connection to anatomy twice, in different words, three months apart. Both are recorded here as given; neither supersedes the other on the evidence available. + +**2026-09-20, the brief.** Exam types need "to TIGHTLY wrap up with Anatomic Locations, including edges for both 'always included' (which can include hierarchies) as well as 'usually included' (for edge things) and something like 'POSSIBLY included, would have to check'."[^brief] + +**June 2026, the SIIM talk.** Under "Connect to Anatomic Locations", the slide lists focused anatomy, included anatomy, and "edge" anatomy, the last qualified as usually versus possible.[^siim2026] + +The two overlap but do not map one to one. The talk's *focused* anatomy has no counterpart in the brief, and the brief's *always included* has none in the talk. + +The manuscript under review names the same capability from the other side, as something the [anatomic location](/glossary/anatomic-location.md) index does not supply: relating a finding's location to what an examination covers would additionally require a model of scan-protocol coverage. It states the use case that would be served, identifying relevant prior studies that cover overlapping anatomy even when acquired for different clinical purposes.[^jdim-al] + +# The imaging region + +The working board states the same requirement as defining an imaging region: a "CT chest region" contains the chest, but also what a radiology exam of the chest would include, such as the lower neck, the upper abdomen, and the shoulders.[^board-anatomy] The January 2023 site roadmap puts it as exam definitions specifying all included body parts.[^al-site] + +# The one written design + +The build plan names the terminology gateway's product roadmap as the only written exam-type design.[^build-plan] That document is dated 2026-08-16 and labeled a recommended direction rather than a built capability. It proposes named domain profiles in place of an ever-growing default search, with `radiology` as the default profile, and places the Playbook in that default on the stated ground that radiology orderables live in the LOINC/RSNA Radiology Playbook while findings, anatomy, and report language live in RadLex.[^molu-roadmap] + +Four Playbook implications are stated: rank procedure and orderable queries toward Playbook terms while ranking finding and anatomy queries toward RadLex, SNOMED CT, and FMA; teach the crosswalk the Playbook correspondences linking a LOINC code to its historic RadLex Playbook identifier and to RadLex anatomy and modality attributes, recording that in the mapping provenance; detect Playbook identifiers as well as LOINC-shaped codes; and prefer Playbook or radiology-class hits rather than treating every LOINC hit as radiology.[^molu-roadmap] The tool itself belongs to the SDKs pillar; see [SDKs](./sdks.md). The standards each axis layers over are covered in [standards](./standards.md). + +[^brief]: The project lead's stated goals, 2026-09-20 +[^build-plan]: Knowledgebase build plan, 2026-09-20 +[^siim2026]: SIIM 2026 annual meeting talk, June 2026, Mass General Brigham +[^al-site]: Anatomic Locations project site roadmap, January 2023 +[^board-anatomy]: Common Anatomic Locations working board, Exam Types box +[^molu-roadmap]: Product direction, med-ontology-lookup, 2026-08-16 +[^jdim-al]: Anatomic Locations Index manuscript, under review at the Journal of Digital Imaging and Informatics in Medicine, 2026 +[^ipl-rules]: Anatomic location assignment rules, imaging-problem-list +[^ipl-efl]: Exam Finding List sample with a LOINC-coded exam header, imaging-problem-list diff --git a/knowledge/drafts/finding-models-and-cdes-hub.md b/knowledge/drafts/finding-models-and-cdes-hub.md new file mode 100644 index 0000000..aad7efd --- /dev/null +++ b/knowledge/drafts/finding-models-and-cdes-hub.md @@ -0,0 +1,91 @@ +--- +type: Overview +title: Finding Models and Common Data Elements +description: "Definitions of findings and diagnoses as the anchor for everything the project knows about them, held in two cross-linked collections: the beta channel and the release channel." +tags: [foundation-context, finding-models, cdes, radelement, next-gen-schema] +status: draft +generated: { by: claude-opus-5/2026-09-29-restructure/hub-page, at: 2026-09-29T21:32:33Z } +sources: + - id: lead-hub + resource: docs/plans/2026-09-22-layout-plan.md + title: The project lead's statements of 2026-09-23 to 2026-09-29 on this page - the anchor idea, the two collections, the beta and release channels, the cross-links, document-oriented today, and one next-generation schema for both (recorded verbatim in the layout plan) + last_modified: 2026-09-29 + - id: lead-2026-09-22 + resource: docs/plans/restructure-joint-notes.md + title: The project lead's decisions of 2026-09-22 - a common data element and a finding model are the same content, the inclusive collection and the well-reviewed collection, and the urgent move off document orientation (quoted in the restructure joint notes) + last_modified: 2026-09-22 + - id: build-plan + resource: knowledge/plans/2026-09-20-knowledgebase-build-plan.md + title: Knowledgebase build plan, carrying the project lead's content direction of 2026-09-21 on the exam-oriented sub-taxonomies + last_modified: 2026-09-21 + - id: oifm-repo + resource: https://github.com/openimagingdata/findingmodels/tree/4475ac1bcb591f1a0951b2082b59208def173a5d + title: "Open Imaging Finding Models repository, main at 4475ac1 (snapshot of 2026-04-28): the README, the schema (schema/finding_model.schema.json and the explanatory schema/finding_model_schema.md), the 2,382 per-definition files under defs/, and ids.json (2,382 definitions across five organization segments, 115 of them under the CDE code)" + last_modified: 2026-04-28 + - id: oifm-authoring + resource: https://github.com/openimagingdata/findingmodels/tree/4475ac1bcb591f1a0951b2082b59208def173a5d/scripts/finding_authoring + title: "The finding model authoring scripts and prompt fragments, findingmodels main at 4475ac1: create_model.py, which builds a stub with standard attributes, identifiers and codes, and prompts/fragments/enrichment.md, the optional later enrichment step applied through fix_stub.py" + last_modified: 2026-04-20 + - id: oifm-cde-def + resource: https://github.com/openimagingdata/findingmodels/blob/4475ac1bcb591f1a0951b2082b59208def173a5d/defs/acute_aortic_syndrome.fm.json + title: "Acute Aortic Syndrome, OIFM_CDE_000126: a finding model derived from a Common Data Element, credited to the ACR/RSNA Common Data Elements Project and carrying its RadElement identity as an index code (findingmodels main at 4475ac1)" + last_modified: 2025-11-17 + - id: oifm-taxonomies + resource: https://github.com/openimagingdata/findingmodels/blob/a30c3c95fa3943e7340ce87575f4b1b926987eb8/lists/README.md + title: The six per-exam finding taxonomies and their coverage ledger, findingmodels taxonomy-export-2026-08-15 at a30c3c9, exported 2026-08-15 + last_modified: 2026-08-15 + - id: radelement + resource: https://radelement.org + title: The published ACR/RSNA Common Data Element collection and its public API, whose sets are attributed to the American College of Radiology and the Radiological Society of North America + - id: cde-nextgen + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/b541b74c22a33b64834309244569a60d06de79e4/docs/next-gen-schema/00-current-understanding.md + title: "Next-Generation CDE Schema: Current Understanding, ACR-RSNA-CDEs next-gen-2026 at b541b74 - the graph as the internal representation, the finding models as drafts for FindingClasses, and bringing them over as a review step" + - id: cde-schema + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/b541b74c22a33b64834309244569a60d06de79e4/cde.schema.json + title: The current Common Data Element schema, ACR-RSNA-CDEs next-gen-2026 at b541b74 - a JSON Schema whose root is a nested element_set document + last_modified: 2024-11-19 + - id: cde-staging + resource: https://github.com/openimagingdata/CDEStaging/tree/b814a102655054ac08b3c118cb1977a387655a8b + title: "CDE staging repository, main at b814a10: the staging area ahead of the review pipeline, the manual report extraction process, and the three gap catalogs recording what real report language could not be represented" + - id: status-2026-01 + resource: https://gamma.app/docs/Open-Imaging-Data-Model-2026-Status-Update:-Realizing-Object-Oriented-Imaging-Results-yfxzx4q9zssafal + title: "Open Imaging Data Model 2026 Status Update: Realizing Object-Oriented Imaging Results, January 2026 - \"OIFM: the CDE workbench\" and the workbench effect" + - id: siim-2026 + resource: https://oidm-public.t3.tigrisfiles.io/oidm-knowledge-sources/SIIM%202026%20Reports-of-the-Future.pptx + title: Structured Results and Context for Next-Generation Imaging Resulting Tools, SIIM 2026 annual meeting talk, June 2026, Mass General Brigham - slide 9 notes on the high-velocity workbench + last_modified: 2026-06-11 +--- + +# Finding Models and Common Data Elements + +Definitions of findings and diagnoses anchor these concepts in a form that associated content can be attached to: a name and synonyms, a definition, the attributes that characterize it, the anatomy it applies to, the modalities that show it, its codes in outside terminologies, and its relationships to other definitions.[^lead-hub][^oifm-repo][^cde-nextgen] Everything the project knows about a kind of finding hangs off this one anchor.[^lead-hub] The project holds these definitions in two collections, and they are the same kind of content.[^lead-2026-09-22] + +**Open Imaging Finding Models** are an inclusive collection, maintained by the OIDM project.[^lead-hub][^oifm-repo] The OIFM repository is intended for rapid, community-based prototyping and iteration based on an open-source model, with changes proposed by anyone.[^lead-hub] A definition can start as little more than a name and a stub and be improved over time.[^lead-2026-09-22][^oifm-authoring] The collection holds a few thousand definitions today, drawn from several sources, and is being reorganized around exam-oriented taxonomies of the findings that actually appear in reports.[^oifm-repo][^build-plan][^oifm-taxonomies] + +**ACR/RSNA Common Data Elements** are the well-reviewed collection, maintained by the American College of Radiology and the Radiological Society of North America and published through radelement.org.[^lead-hub][^radelement] Entry is a review step, and the project treats the finding models as the workbench where definitions are proved out before that review.[^cde-nextgen][^cde-staging][^status-2026-01][^siim-2026] + +**The relationship.** The two collections describe the same ideas and will share the same schema.[^lead-hub][^lead-2026-09-22] The difference is how they are released: finding models are the beta channel, with rapid additions and updates; Common Data Elements are the release channel, reviewed and stable.[^lead-hub] The two are cross-linked and stay that way: when a definition migrates into the CDEs, it continues to be maintained in the OIFM repository and carries a reference to its CDE identity, so an application can resolve either one to the same concept.[^lead-hub][^oifm-cde-def] About a hundred finding models were derived directly from CDEs.[^oifm-repo][^oifm-cde-def] Coverage is measured the same way on both sides, by running real reports against the definitions and recording what they could not represent.[^lead-hub][^cde-staging] + +**Where both are going.** The ACR/RSNA CDE project is developing a next-generation, graph-based schema, and both collections are intended to move onto it, so that applications use them together.[^cde-nextgen][^lead-hub] Both CDEs and OIFMs are document-oriented today, and moving them onto that graph is an immediate priority.[^lead-hub][^lead-2026-09-22][^oifm-repo][^cde-schema][^cde-nextgen] + +# In this section + +- OIFM content: what the inclusive collection holds and where it is going +- Definition formats: what a finding model and a CDE look like today +- Identifiers: the OIFM scheme, RadElement identifiers, and index codes +- The next-generation schema, with relationships and standard clinical metadata +- Authoring and review + +[^lead-hub]: The project lead, 2026-09-23 to 2026-09-29, recorded verbatim in the layout plan: the finding/diagnosis definition as "an unified anchor for the CONCEPT of a finding/diagnosis in a form that can be used to attach associated context: name, synonyms, definition, attributes, etc."; the inclusive collection "maintained by the OIDM project" and "intended for rapid, community-based prototyping and iteration based on an open-source model ... with changes proposed by anyone"; the well-reviewed collection "published through radelement.org"; "they will have the same schema and describe the same ideas", with OIFMs as "beta"/rapid additions and updates and CDEs as "release"/reviewed and stable; the maintained cross-links, where a definition that migrates "will continue to be maintained in the OIFM repo but have a reference to its CDE identity"; "Both CDEs and OIFMs are document-oriented today"; and, on 2026-09-23, one next-generation schema "which will be for BOTH CDEs and OIFMs--I think applications will be able to use both at once". +[^lead-2026-09-22]: The project lead, 2026-09-22, quoted in the restructure joint notes: "A 'CDE' and a 'Finding Model' are the same thing, but they're in different repos", the OIDM-maintained collection "intended to be very INCLUSIVE, can almost be drafts" against the ACR/RSNA collection "intended to be WELL-REVIEWED ... more like something published", both to use the classes being defined in the CDE schema rewrite, and "OIFMs VERY soon need to get re-organized around the graph-based approach ... They're currently document-oriented and we need to fix that SOON." +[^build-plan]: Knowledgebase build plan: the project lead's content direction of 2026-09-21, that the taxonomy branch in the finding models repository is "the immediate direction for all of the content, probably replacing a lot of the Gamuts-based models". +[^oifm-repo]: Open Imaging Finding Models repository, main at 4475ac1, a snapshot of 2026-04-28. The README describes finding models as updatable data models defining open, standard semantic tags for imaging findings and their properties, with relationships to other ontologies; the schema document gives the definition fields (identifier, name, description, synonyms, tags, contributors, attributes, index codes into standard ontologies); `ids.json` holds 2,382 definitions across five organization segments (1,933 GMTS, 256 OIDM, 115 CDE, 47 MGB, 31 MSFT) and 5,709 attribute identifiers. The 115 under the CDE segment are the models derived from Common Data Elements. The January 2026 status update gives the collection as "nearly 3,000". For the document orientation of the collection today: the schema is a JSON Schema for a single self-contained finding model, and the corpus is 2,382 individual files under `defs/`, one per definition. +[^oifm-authoring]: The finding model authoring scripts and prompt fragments, findingmodels main at 4475ac1. `scripts/finding_authoring/create_model.py` creates "a complete finding model stub with IDs and codes", building it from a name and a description with the two standard attributes, then minting identifiers against the index; the single-model path requires a description, so a stub is not name-only. `prompts/fragments/enrichment.md` is the optional later step: it applies where "The existing description is a one-line placeholder and you want a clinically-grounded starting point", drafts a richer description with citations, and writes the reviewed result back through `fix_stub.py`, after which the normal review flow runs again. +[^oifm-cde-def]: Acute Aortic Syndrome, `defs/acute_aortic_syndrome.fm.json` at findingmodels main 4475ac1: `oifm_id` `OIFM_CDE_000126`, contributor "ACR/RSNA Common Data Elements Project", and an index code `system: RADELEMENT`, `code: RDES126` beside its RadLex code. All 115 definitions under the CDE organization segment carry a RadElement index code in the same way. This supports the retained CDE identity and the derivation of those models from Common Data Elements. It is evidence of the reference as it exists today in the direction CDE to finding model; the commitment to maintain the cross-links after a future migration, and to resolution of either identity to the same concept by an application, rests on the project lead's direction. +[^oifm-taxonomies]: The six per-exam finding taxonomies, findingmodels taxonomy-export-2026-08-15 at a30c3c9: chest radiograph, musculoskeletal radiograph, head CT, chest/abdomen/pelvis CT, mammography, and spine MRI, 3,789 rows in all. Each file is one hierarchy in which "Parents are generic, children add specificity", and `finding_type` separates an observation from a diagnosis. The files double as a coverage ledger: an identifier is filled only where a row matched a model that already exists, 1,028 of 3,789 rows, and "Blank rows are the ones needing triage." +[^radelement]: The published ACR/RSNA Common Data Element collection at radelement.org. Its public API returns sets attributed to the American College of Radiology and the Radiological Society of North America. The staging repository and the next-generation schema baseline both name it as the joint ACR/RSNA project's published corpus, public API, and vendor-facing interface. +[^cde-nextgen]: "Next-Generation CDE Schema: Current Understanding", ACR-RSNA-CDEs next-gen-2026 at b541b74, a draft for discussion dated 2026-08-19. §2.2: "The authoritative internal representation is a knowledge graph, not a document tree", following the committee's own move to "a graph model, where findings point to canonical attribute objects". §5.1: the finding model work "has independently built much of this and is roughly one iteration ahead", so "OIFMs can be treated as drafts for this project's FindingClasses", with the caveat that "Bringing models over is a review step, not a bulk import"; its table of what the finding models already answer includes worked metadata vocabularies for body regions, modalities, etiologies, sex specificity, age profile, and expected time course. Modality applicability is a field of the current CDE schema as well. §5.1 also discusses the finding models' file-based design directly, noting that it "makes choices that a graph makes differently". +[^cde-schema]: The current Common Data Element schema, `cde.schema.json` at ACR-RSNA-CDEs next-gen-2026 b541b74, last changed 2024-11-19: a draft-07 JSON Schema whose root is `element_set`, a nested document whose required properties include an `elements` array. This is the document form the collection takes today. +[^cde-staging]: CDE staging repository, main at b814a10: "a staging area for definitions of radiology common data elements in JSON format ... prior to their entering the review pipeline". The manual extraction process works one real pulmonary angiogram report into a list of mini-observations, each a finding with a presence value and its attributes. Three catalogs beside it record what the definitions could not carry. `negative_statements.md` groups real report sentences by body region that assert absence across several structures at once, some bundled with a technique caveat, with no definition links. `uncovered_findings.md` lists findings with their reported attributes and no definition behind them, also with no links. `missing_attributes.md` is the one that links: ten entries, each naming the finding and the attribute the report used and pointing at the definition file that lacked it. The catalogs exist as data; the method is described but not automated, and the same coverage question is asked prospectively as a frequency-and-priority table in the chest CT roadmap. This is evidence of the CDE-side measurement only; that coverage is measured the same way on the finding models side rests on the project lead's direction. +[^status-2026-01]: Open Imaging Data Model 2026 Status Update, January 2026: "OIFM: the CDE workbench" - rapid innovation and a proving ground before ACR/RSNA CDE adoption, with exploratory metadata "that can graduate to standards", named in the executive summary as the "workbench effect". Read from the project's transcription of the deck, `sources/gamma-2026-status-update.md`, which records the original presentation URL and the month but no modification date. +[^siim-2026]: SIIM 2026 annual meeting talk, June 2026, Mass General Brigham, slide 9 notes: "OIFM Finding Models today, ACR/RSNA CDEs next ... OIFM is the high-velocity 'workbench' that proves out content before formal CDE adoption." Read from the project's text extraction of the deck, `sources/bucket/text/siim2026-reports-of-the-future.md`; the presentation file records a modification date of 2026-06-11. diff --git a/knowledge/drafts/finding-models-and-cdes.md b/knowledge/drafts/finding-models-and-cdes.md new file mode 100644 index 0000000..2ef9e95 --- /dev/null +++ b/knowledge/drafts/finding-models-and-cdes.md @@ -0,0 +1,293 @@ +--- +type: Concept +title: Finding models and CDEs +description: One content in two collections - the common graph being drafted for both, the OIFM and RadElement formats that hold it today, what the inclusive collection contains, and the authoring and review principles behind it. +tags: [foundation-context, finding-models, cde, radelement, next-gen-schema] +status: draft +generated: { by: claude-opus-5/2026-09-22-restructure/draft-foundation, at: 2026-09-22T00:00:00Z } +sources: + - id: joint-notes + resource: docs/plans/restructure-joint-notes.md + title: "Restructure joint working notes, carrying the project lead's decisions of 2026-09-22" + last_modified: 2026-09-22 + - id: build-plan + resource: knowledge/plans/2026-09-20-knowledgebase-build-plan.md + title: "Knowledgebase build plan, carrying the project lead's content direction of 2026-09-21" + last_modified: 2026-09-21 + - id: cde-00 + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/docs/next-gen-schema/00-current-understanding.md + title: "Next-Generation CDE Schema: Current Understanding, ACR-RSNA-CDEs next-gen-2026 at 44836c1, 2026-09-15" + last_modified: 2026-09-15 + - id: cde-01 + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/docs/next-gen-schema/01-what-the-vocabulary-must-express.md + title: "What the Vocabulary Must Express, ACR-RSNA-CDEs next-gen-2026 at 44836c1, 2026-09-15" + last_modified: 2026-09-15 + - id: cde-03 + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/docs/next-gen-schema/03-draft-structures.md + title: "Draft Structures for Worked Examples, ACR-RSNA-CDEs next-gen-2026 at 44836c1, 2026-09-15" + last_modified: 2026-09-15 + - id: cde-07 + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/docs/next-gen-schema/07-relationship-family.md + title: "The Finding and Diagnosis Relationship Family, ACR-RSNA-CDEs next-gen-2026 at 44836c1, 2026-09-15" + last_modified: 2026-09-15 + - id: cde-08 + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/docs/next-gen-schema/08-worked-examples.md + title: "Worked Examples: Acute Pyelonephritis, Pleural Effusion, and One Report, ACR-RSNA-CDEs next-gen-2026 at 44836c1, 2026-09-15" + last_modified: 2026-09-15 + - id: cde-10 + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/docs/next-gen-schema/10-decision-record-2026-09-02.md + title: "Decision Record, 2 to 15 September 2026, ACR-RSNA-CDEs next-gen-2026 at 44836c1" + last_modified: 2026-09-15 + - id: cde-11 + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/docs/next-gen-schema/11-anatomy-axis.md + title: "The Anatomy Axis, Current State, ACR-RSNA-CDEs next-gen-2026 at 44836c1, 2026-09-15" + last_modified: 2026-09-15 + - id: cde-context + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/CONTEXT.md + title: "CDE vocabulary, CONTEXT.md, ACR-RSNA-CDEs next-gen-2026 at 44836c1, 2026-09-15" + last_modified: 2026-09-15 + - id: cde-schema + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/cde.schema.json + title: "cde.schema.json, the published CDE set and element schema, ACR-RSNA-CDEs at 44836c1" + last_modified: 2026-09-15 + - id: oifm-metadata-fields + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/notes/oifm-metadata-fields.md + title: "Finding Model Structured Metadata Fields, ACR-RSNA-CDEs next-gen-2026 at 44836c1" + last_modified: 2026-09-15 + - id: oifm-v2-draft + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/notes/oifm-schema-v2-draft.md + title: "FindingModel Source Schema v2 Draft, April 2026, copied on ACR-RSNA-CDEs next-gen-2026 at 44836c1" + last_modified: 2026-09-15 + - id: oifm-schema + resource: https://github.com/openimagingdata/findingmodels/blob/a30c3c95fa3943e7340ce87575f4b1b926987eb8/schema/finding_model_schema.md + title: "Finding Model Schema, findingmodels taxonomy-export-2026-08-15 at a30c3c9" + last_modified: 2026-08-15 + - id: ids-json + resource: https://github.com/openimagingdata/findingmodels/blob/a30c3c95fa3943e7340ce87575f4b1b926987eb8/ids.json + title: "ids.json, the identifier registry, findingmodels taxonomy-export-2026-08-15 at a30c3c9" + last_modified: 2026-08-15 + - id: lists-readme + resource: https://github.com/openimagingdata/findingmodels/blob/a30c3c95fa3943e7340ce87575f4b1b926987eb8/lists/README.md + title: "Exam-oriented finding taxonomies README, findingmodels taxonomy-export-2026-08-15 at a30c3c9" + last_modified: 2026-08-15 + - id: cleanup-plan + resource: https://github.com/openimagingdata/findingmodels/blob/a30c3c95fa3943e7340ce87575f4b1b926987eb8/docs/plans/definition_cleanup.md + title: "Definition Cleanup Plan, findingmodels taxonomy-export-2026-08-15 at a30c3c9" + last_modified: 2026-08-15 + - id: upstream-proposals + resource: https://github.com/openimagingdata/findingmodels/blob/a30c3c95fa3943e7340ce87575f4b1b926987eb8/docs/plans/findingmodel-upstream-proposals.md + title: "Candidate upstream issues for the findingmodel library, findingmodels taxonomy-export-2026-08-15 at a30c3c9" + last_modified: 2026-08-15 + - id: oifm-prompts + resource: https://github.com/openimagingdata/findingmodels/tree/a30c3c95fa3943e7340ce87575f4b1b926987eb8/prompts/fragments + title: "Authoring prompt fragments, findingmodels taxonomy-export-2026-08-15 at a30c3c9" + last_modified: 2026-08-15 + - id: oifm-skills + resource: https://github.com/openimagingdata/findingmodels/tree/a30c3c95fa3943e7340ce87575f4b1b926987eb8/.claude/skills + title: "finding-author, finding-batch, and finding-review skill files, findingmodels taxonomy-export-2026-08-15 at a30c3c9" + last_modified: 2026-08-15 + - id: prompt-research + resource: https://github.com/openimagingdata/findingmodels/blob/a30c3c95fa3943e7340ce87575f4b1b926987eb8/docs/plans/prompt_length_research.md + title: "Prompt Length and Instruction Complexity: Research and Recommendations, 2026-03-22, findingmodels at a30c3c9" + last_modified: 2026-03-22 + - id: chestct-spec + resource: https://github.com/openimagingdata/findingmodels/blob/0472a467/PROJECT_SPECIFICATION.md + title: "Chest CT conversion project specification, findingmodels content/chestcts at 0472a46" + last_modified: 2026-08-15 + - id: chestct-progress + resource: https://github.com/openimagingdata/findingmodels/blob/0472a467/docs/cdestaging_ct_chest_batch_progress.md + title: "Chest CT conversion batch progress, findingmodels content/chestcts at 0472a46" + last_modified: 2026-08-15 + - id: fm-context + resource: https://github.com/openimagingdata/findingmodel/blob/1942b06a/CONTEXT.md + title: "Project vocabulary, CONTEXT.md, findingmodel feature/metadata-cleanup at 1942b06" + last_modified: 2026-06-23 + - id: fm-models + resource: https://github.com/openimagingdata/findingmodel/blob/1942b06a/packages/findingmodel/src/findingmodel/types/models.py + title: "Finding model classes carrying the metadata fields, findingmodel feature/metadata-cleanup at 1942b06; contrast finding_model.py on main at 75afd39" + last_modified: 2026-06-23 + - id: metadata-rewrite + resource: https://github.com/openimagingdata/findingmodel/blob/1942b06a/docs/canonical-structured-metadata-and-enrichment-rewrite.md + title: "Canonical Structured Metadata and Enrichment Rewrite, findingmodel feature/metadata-cleanup at 1942b06" + last_modified: 2026-06-23 + - id: metadata-fields-doc + resource: https://github.com/openimagingdata/findingmodel/blob/1942b06a/docs/metadata/subspecialties.md + title: "Subspecialty policy and field standards, findingmodel feature/metadata-cleanup at 1942b06" + last_modified: 2026-06-23 + - id: metadata-prompts + resource: https://github.com/openimagingdata/findingmodel/tree/1942b06a/packages/findingmodel-ai/src/findingmodel_ai/metadata/prompts + title: "Metadata assignment prompts, findingmodel feature/metadata-cleanup at 1942b06" + last_modified: 2026-06-23 + - id: adr-0002 + resource: https://github.com/openimagingdata/findingmodel/blob/1942b06a/docs/adr/0002-split-agent-assignment-architecture.md + title: "ADR 0002, split agent assignment architecture, findingmodel feature/metadata-cleanup at 1942b06" + last_modified: 2026-06-23 + - id: human-review + resource: https://github.com/openimagingdata/findingmodel/blob/1942b06a/docs/metadata/enrichment/human-review-and-writeback.md + title: "Human review and writeback, findingmodel feature/metadata-cleanup at 1942b06" + last_modified: 2026-06-23 + - id: staging-readme + resource: https://github.com/openimagingdata/CDEStaging/blob/b814a102655054ac08b3c118cb1977a387655a8b/README.md + title: "CDEStaging README at b814a10" + last_modified: 2025-12-01 + - id: staging-extraction + resource: https://github.com/openimagingdata/CDEStaging/blob/b814a102655054ac08b3c118cb1977a387655a8b/docs/report_extraction_process.md + title: "Report extraction process, CDEStaging at b814a10" + last_modified: 2025-12-01 + - id: staging-catalogs + resource: https://github.com/openimagingdata/CDEStaging/tree/b814a102655054ac08b3c118cb1977a387655a8b/report_representation + title: "Negative statements, uncovered findings, and missing attributes catalogs, CDEStaging at b814a10" + last_modified: 2025-12-01 + - id: board-role-tagging + resource: internal project board, not published + title: "Open Imaging Data Model project board (internal), undated; schema idea only" + - id: status-deck-2026-01 + resource: https://gamma.app/docs/Open-Imaging-Data-Model-2026-Status-Update:-Realizing-Object-Oriented-Imaging-Results-yfxzx4q9zssafal + title: "Open Imaging Data Model 2026 Status Update, January 2026, extract" + last_modified: 2026-01-01 + - id: ipl-webinar + resource: https://oidm-public.t3.tigrisfiles.io/oidm-knowledge-sources/IPL%20Webinar%20Deck.html + title: "The Imaging Problem List as an Accelerator for Radiology AI Applications, SIIM Enterprise Imaging webinar, 15 July 2026" + last_modified: 2026-07-15 +--- + +# The project's position + +The project lead ruled on 2026-09-22, in the working notes both drafting sessions share: + +> "A 'CDE' and a 'Finding Model' are the same thing, but they're in different repos. Open Imaging Finding Models are in the OIDM-maintained repo, and are intended to be very INCLUSIVE, can almost be drafts. Common Data Elements live in the ACR/RSNA repository, and are intended to be WELL-REVIEWED. They're more like something published. They BOTH should soon be using the schema and classes being defined in the CDE schema re-write, with FindingClass, DataElement, Measurement, etc."[^joint-notes] + +And, in the same set of decisions: + +> "OIFMs VERY soon need to get re-organized around the graph-based approach we're developing in the next-gen-schema effort in CDEs. They're currently document-oriented and we need to fix that SOON."[^joint-notes] + +The common model is explained once here. Inclusive and well-reviewed describe *collections*, not items: nothing here says a given [finding model](../glossary/finding-model.md) is a draft, or a given [CDE set](../glossary/cde-set.md) well reviewed. Both the shared schema and the reorganization are stated intent, the latter a change of organization rather than added fields, with no migration done. + +# The common graph + +Both collections are meant to converge on the next-generation CDE vocabulary on the `next-gen-2026` branch of `ACR-RSNA-CDEs`, at commit `44836c1` of 2026-09-15. These structures "capture our working ideas and prototype choices, not a settled model," integration with the external reviewer's foundation still open.[^cde-03] The decision record marks provenance; two labels are carried here. **OWNER**: the project lead stated it, quoted verbatim. **CLAUDE DEFAULT**: an assistant chose it, unreviewed.[^cde-10] + +## Node types + +| Node type | What it is, and its status in the source | +|---|---| +| [FindingClass](../glossary/finding-class.md) | the named thing a report describes, carrying an `entity_type`; working proposal, exercised as graph data | +| Diagnosis | a separate node type (external reviewer, 2026-08-25); that only which relationships it can source distinguishes it is an assistant observation, not a decision | +| Grouping | nodes such as `renal abnormality` parenting findings and diagnoses; a separate type is an OWNER inclination, the narrowing to negative-only an unobjected assistant proposal | +| [DataElement](../glossary/data-element.md) | a categorical descriptor with an explicitly ordered or unordered value set | +| [Measurement](../glossary/measurement.md) | a quantitative descriptor with quantity type, units, optional method; a distinct type (OWNER) | +| [AssessmentScheme](../glossary/assessment-scheme.md) | a scheme whose dimensions are linked DataElements (OWNER) | + +Values are first-class, their ids derived from their element; [anatomic locations](../glossary/anatomic-location.md) are keyed by RadLex identity; standard clinical metadata values are shared concept nodes (OWNER).[^cde-03][^cde-10] + +## Edges are the content + +The draft heads its edge section "Edges — the actual content of the model."[^cde-03] An [element binding](../glossary/element-binding.md) runs from a FindingClass, or directly from an AnatomicLocation, to a DataElement, and may restrict that use to a subset of the element's values without changing the shared element (OWNER), a restriction on meaning, not presentation. There are no required elements: OWNER, "THERE IS NO SUCH THING AS A REQUIRED ELEMENT."[^cde-10] Reuse is in-degree, and a location binding elements directly (OWNER) lets normal anatomy be described with no FindingClass.[^cde-03][^cde-01] Modality is three statements, not one: where a finding can be seen, where a descriptor applies in a given binding, and a descriptor's intrinsic limits, the last a hard limit rather than an adjustable default. An omitted constraint means no information, neither applicability everywhere nor exclusion (OWNER, encoding open).[^cde-10][^cde-context] + +An Open Imaging Data Model project board approaches reuse from the consuming side, proposing **role tagging**: tag each element definition with a SNOMED or RadLex code naming its role — presence, location, size in its several measures such as diameters, volumes and segmentation data, modality-specific measures such as radiodensity, echogenicity and MR signal, and contrast behavior — so a consuming system finds the right element across CDE sets by role, looking up the element carrying the SNOMED code for volume measurement rather than hard-coding set-specific identifiers. A working proposal, undated, no implementation cited.[^board-role-tagging] The next-generation graph reaches reuse another way, one shared DataElement node bound by many classes;[^cde-03] no source says the two were coordinated. + +## Anatomic scope, not location + +**Anatomic scope** is the project lead's agreed term of 2026-09-10 for "the statement of where a kind of finding belongs, which may be a place (kidney) or a kind of structure (muscle, not otherwise specified)."[^cde-10][^cde-context] "Location" is the wrong word, the requirements document argues, because the statement ranges over three kinds of thing and only two are spatial: a named structure checked by identity or descent, a region checked by containment, and a structure type such as tendons checked taxonomically, "not spatial at all." Its strength varies too.[^cde-01] A class is scoped to the unsided organ while a specific [Observation](../glossary/observation.md) sits in a sided one, the is-a relation satisfying the scope; a plain list of targets matches any one, explicit combinations several together (both OWNER, encoding open).[^cde-10] Two scope families, tissue types and structure types, are to be developed (OWNER); the taxonomic kind waits on an is-a relation the data lacks.[^cde-11] + +## The relationship family and the derived differential + +A catalog called "tentative, explicitly non-comprehensive" proposes seven relationship pairs plus a catch-all: subtype, component, causation, manifestation, co-occurrence, progression, assessment. Manifestation and causation stay apart — a striated nephrogram *is* pyelonephritis appearing on imaging, a renal abscess is a second entity it produced — tested by whether a clinician would say the source "got better" or "a complication resolved." Manifestation edges take two optional properties: a typicality scale adopted verbatim from the HPO and Orphanet frequency scale, and a three-value specificity scale omitted when uninformative, absence meaning no judgment recorded. The differential is a derived view, not an edge type: the diagnoses reachable over the manifestation inverse, on the Gamuts ontology's precedent.[^cde-07] Whether the causal pair takes typicality is a CLAUDE DEFAULT; an `expected` property on causal edges, a CLAUDE INVENTION.[^cde-10][^cde-08] + +The finding-model side proposes the same mechanism differently: an April 2026 source-schema draft has a model store only the assertions authored on it, tooling deriving inverse and symmetric views from a registry of relationship types.[^oifm-v2-draft] Verified on 2026-09-01, that registry exists only in the draft, the live corpus "implements no relationship mechanism at all."[^cde-07] + +## Assessments, components, and measurements + +A scoring system is a valid definition but a different one from what it scores: a nodule model captures what the nodule looks like and a Lung-RADS model the risk category, because different radiologists can describe one nodule identically and assign different categories.[^oifm-prompts] That is an `assessment` value in the metadata entity-type enumeration today;[^metadata-prompts] in the next-generation design it is its own definition type with edges to ordinary DataElements (OWNER).[^cde-10][^cde-07] + +An independence test separates components from associated findings. An **associated finding** has its own lifecycle — pneumonia and pleural effusion each occur alone — and is one multichoice attribute, presence-level only, its values naming finding models. A **component** is an intrinsic part, such as the solid component of a mixed nodule, extracted into its own model.[^oifm-prompts] The chest CT content branch forbids an associated-findings attribute outright, contradicting that rule.[^chestct-spec] The next-generation design carries one component relationship with counts, plus the terms **component-of scope** and **lesion family** (OWNER, September 2026).[^cde-10][^cde-context] + +Measurement, method, and interpretation are three things. "Peak systolic velocity is 350 cm/s" and "this represents hemodynamically significant stenosis" have different truth conditions, and the reason given for separating them is durability: thresholds move while measurands do not, so a stored interpretation becomes wrong when criteria are revised. Confidence belongs to the interpretation, not the measurement; a separate ruling puts it on the report-plane assertion, for findings as much as diagnoses (OWNER).[^cde-01][^cde-10] + +## What the graph should carry for a finding + +Three sources say what a definition carries beyond its elements: + +| Source, dated | What it says | +|---|---| +| Next-generation vocabulary, OWNER term of 2026-09-10 | **Standard clinical metadata**, seven facts on a class: modality, body region, subspecialty, sex, age, time course, etiology — edges to shared concept nodes, three of them RadLex nodes and the rest on provisional codes (OWNER)[^cde-10][^cde-03] | +| SIIM Enterprise Imaging webinar, 15 July 2026 | Four dimensions that let an agent judge whether a finding *should still be there* on a new exam: where it is anatomically, what type it is, how long it lasts, whether it is transient or permanent — "the forward, AI-populated schema, not yet carried by the published definitions"[^ipl-webinar] | +| Metadata rewrite in `findingmodel`, metadata branch | Eight optional fields — body regions, subspecialties, etiologies, entity type, applicable modalities, expected time course, age profile, sex specificity — typed on the model classes, making metadata "canonical `FindingModel` state rather than disposable enrichment output"[^metadata-rewrite] | + +# The two collections today + +## The two formats + +A finding model is one JSON document: identifier, name, description, and attributes, plus optional synonyms, tags, contributors, and index codes. An attribute is either a choice attribute, whose values each carry their own code, or a numeric attribute with bounds and a unit.[^oifm-schema] Identifiers carry provenance — `OIFM_{ORG}_{six digits}` for a model, `OIFMA_{ORG}_{six digits}` for an attribute — the middle segment naming the contributing organization, so institutions mint independently.[^oifm-metadata-fields][^ids-json] The published [CDE set](../glossary/cde-set.md) is the corresponding container: an `RDES` identifier, descriptive and governance fields, and its elements; a [CDE element](../glossary/cde-element.md) carries an `RDE` identifier, its parent set, a definition and question, and either an enumerated value set or a numeric range.[^cde-schema] + +The published finding model is lean: the eight metadata fields above are typed on the development and metadata branches, absent from the released one.[^fm-models] They are specified by the near-miss they exclude: subspecialty is which service would *read and report* the finding, not which orders the study,[^metadata-fields-doc] and expected time course is the imaging-observable window, with "the clinical duration of the underlying disease" named as the thing to avoid.[^fm-context] An [index code](../glossary/index-code.md) must be an exact match or clinically substitutable near-equivalent for the whole model concept — policy carried by prompts and review, enforced nowhere at runtime.[^metadata-rewrite] + +## How they correspond + +By design: a finding model to a CDE set, an attribute to an element, choice values to a value set, index codes the join. In practice it runs one way: 115 of 2,382 finding models carry the `CDE` organization code, with a contributor record naming the ACR/RSNA project and a RadElement index code pointing at their set.[^ids-json] + +The January 2026 status deck calls this "OIFM: the CDE workbench," whose exploratory metadata "can graduate to standards."[^status-deck-2026-01] The CDE branch states the other half: the finding model effort "is roughly one iteration ahead," its models "can be treated as drafts for this project's FindingClasses," and bringing them over "is a review step, not a bulk import." How the crossover works is open between a shared identity space and a maintained crosswalk, and the document chooses neither.[^cde-00] + +Coverage is measured by running real reports against the definitions. The staging repository calls itself "a staging area for definitions ... prior to their entering the review pipeline," its extraction note working one report into mini-observations.[^staging-readme][^staging-extraction] Three catalogs record what the definitions could not carry — composite negative statements, uncovered findings, missing attributes — dated 2024 to 2025, undisposed.[^staging-catalogs] + +# What the inclusive collection holds, and where it is going + +The corpus merges uneven provenance streams. From the identifier registry, 2,382 models come from five sources: 1,933 derived from the Radiology Gamuts Ontology, 256 authored by the project, 115 from ACR and RSNA common data elements, 47 from an institutional contributor, 31 from a vendor.[^ids-json] The cleanup plan traces nine defect classes to specific streams and notes that some Gamuts-derived entries are differential patterns, not findings.[^cleanup-plan] + +The **MGB exam-oriented sub-taxonomies** are the immediate content direction: six per-exam finding hierarchies — chest radiograph, musculoskeletal radiograph, head CT, chest/abdomen/pelvis CT, mammography, spine MRI — 3,789 rows, each naming its parent, with "Parents are generic, children add specificity." They double as a coverage ledger: an identifier is filled only where a row matched an existing model by exact name, and "Nothing was minted here." 1,028 rows matched, unevenly — 305 of 403 for chest radiographs against 5 of 198 for mammography — and "Blank rows are the ones needing triage."[^lists-readme] The project lead stated on 2026-09-21: "the immediate direction for all of the content, probably replacing a lot of the Gamuts-based models."[^build-plan] Converting an outside set is a merge with a fixed direction, incoming definitions merging into the corpus and never the reverse, guarded against matching a specific incoming term to a general model.[^chestct-spec] One of twenty-one chunks is converted, six new models beside four matched, review still pending.[^chestct-progress] The content effort also feeds requirements upstream, a proposals document sizing each entry to one issue on an evidence base of a fourteen-model test batch.[^upstream-proposals] + +# Authoring and review + +Operational definitions live in prompt fragments and skill files.[^oifm-prompts][^oifm-skills] + +| Principle | What the sources say | +|---|---| +| What counts as a finding | Would a radiologist write "there is [X]" or "no [X]" as a standalone statement? Devices, postsurgical states, variants and diagnoses count; a state of a finding, normal anatomy and radiographic signs do not, though a generic descriptor becomes a finding when anatomic context makes it reportable alone. | +| Description and diagnosis both count | "Do not question whether a diagnosis 'should' be a finding." Three representations coexist: a `finding_type` column,[^lists-readme] an `entity_type` enumeration,[^metadata-prompts] and a separate Diagnosis node type, its taxonomy rule unsettled.[^cde-10] | +| Specificity and splitting | Compound names split when one part can be present without the other; needing different attributes signals that a subtype earns its own model, and a combined phrase with its own clinical meaning also qualifies. | +| Negative assertion, presence, change | Broad scoped findings exist so absence can be asserted against something, scoped by what the exam assesses; presence and change from prior are every model's first two attributes. | +| Synonyms | Collection is aggressive, but each must mean the same thing at the same specificity: "a bad synonym doesn't just fail to match — it matches the *wrong thing*." | +| Naming | Lowercase with spaces, acronyms expanded and kept as synonyms, eponyms minimized, brand names replaced, and a real anatomic anchor, though some findings are appropriately broad without one. | +| Stubs, then iteration | Names come from an ontology, from experts, and from a model reading report text; each becomes a stub, gets an identifier at once, improved later. | +| Triage before create | Two or three complementary searches run per candidate; the agent judges the pooled results and reports an exact match, no match, or true ambiguity. "Do not forward raw result lists to the user." | +| Review in three tiers, with context isolation | A deterministic linter, then a language-model review applying a checklist the linter deliberately does not attempt, then mandatory human sign-off, with "each finding drafted and reviewed by a fresh sub-agent with no exposure to its neighbors."[^oifm-skills] | +| Prompts as loadable fragments | Skill files are "pure orchestration." The case for sizing them surveys outside research rather than reporting a local experiment: instruction-following degrades as instructions accumulate, and prompt middles get less attention than either end. The note counts the team's own review agent at about forty checklist items, infers it is "deep in degradation territory," and recommends measuring the local effect.[^prompt-research] | +| Focused assignment | Seven narrow agents assign metadata under an orchestrator that never decides a field value; search agents propose, assignment agents dispose. A final pass audits rather than enforces, and null is legitimate.[^adr-0002] | +| Human review is the only authority | Metadata enrichment decisions reach the corpus only through approved records, with a separate field-limited rule permitting display-only repairs to existing index codes. Sub-agent triage is not authority, and generated diffs are not gold.[^human-review] | + +[^joint-notes]: Restructure joint working notes, the project lead's decisions of 2026-09-22 +[^build-plan]: Knowledgebase build plan, the project lead's content direction of 2026-09-21 +[^cde-00]: Next-Generation CDE Schema: Current Understanding, ACR-RSNA-CDEs next-gen-2026 at 44836c1 +[^cde-01]: What the Vocabulary Must Express, ACR-RSNA-CDEs next-gen-2026 at 44836c1 +[^cde-03]: Draft Structures for Worked Examples, ACR-RSNA-CDEs next-gen-2026 at 44836c1 +[^cde-07]: The Finding and Diagnosis Relationship Family, ACR-RSNA-CDEs next-gen-2026 at 44836c1 +[^cde-08]: Worked Examples, ACR-RSNA-CDEs next-gen-2026 at 44836c1 +[^cde-10]: Decision Record, 2 to 15 September 2026, ACR-RSNA-CDEs next-gen-2026 at 44836c1 +[^cde-11]: The Anatomy Axis, Current State, ACR-RSNA-CDEs next-gen-2026 at 44836c1 +[^cde-context]: CDE vocabulary, CONTEXT.md, ACR-RSNA-CDEs next-gen-2026 at 44836c1 +[^cde-schema]: cde.schema.json, ACR-RSNA-CDEs at 44836c1 +[^oifm-metadata-fields]: Finding Model Structured Metadata Fields, ACR-RSNA-CDEs next-gen-2026 at 44836c1 +[^oifm-v2-draft]: FindingModel Source Schema v2 Draft, April 2026, copied on ACR-RSNA-CDEs next-gen-2026 at 44836c1 +[^oifm-schema]: Finding Model Schema, findingmodels taxonomy-export-2026-08-15 at a30c3c9 +[^ids-json]: ids.json, findingmodels taxonomy-export-2026-08-15 at a30c3c9 +[^lists-readme]: Exam-oriented finding taxonomies README, findingmodels taxonomy-export-2026-08-15 at a30c3c9 +[^cleanup-plan]: Definition Cleanup Plan, findingmodels taxonomy-export-2026-08-15 at a30c3c9 +[^upstream-proposals]: Candidate upstream issues for the findingmodel library, findingmodels at a30c3c9 +[^oifm-prompts]: Authoring prompt fragments, findingmodels taxonomy-export-2026-08-15 at a30c3c9 +[^oifm-skills]: finding-author, finding-batch, and finding-review skill files, findingmodels at a30c3c9 +[^prompt-research]: Prompt Length and Instruction Complexity, 2026-03-22, findingmodels at a30c3c9 +[^chestct-spec]: Chest CT conversion project specification, findingmodels content/chestcts at 0472a46 +[^chestct-progress]: Chest CT conversion batch progress, findingmodels content/chestcts at 0472a46 +[^fm-context]: Project vocabulary, CONTEXT.md, findingmodel feature/metadata-cleanup at 1942b06 +[^fm-models]: Finding model classes carrying the metadata fields, findingmodel feature/metadata-cleanup at 1942b06 +[^metadata-rewrite]: Canonical Structured Metadata and Enrichment Rewrite, findingmodel feature/metadata-cleanup at 1942b06 +[^metadata-fields-doc]: Subspecialty policy and field standards, findingmodel feature/metadata-cleanup at 1942b06 +[^metadata-prompts]: Metadata assignment prompts, findingmodel feature/metadata-cleanup at 1942b06 +[^adr-0002]: ADR 0002, split agent assignment architecture, findingmodel feature/metadata-cleanup at 1942b06 +[^human-review]: Human review and writeback, findingmodel feature/metadata-cleanup at 1942b06 +[^staging-readme]: CDEStaging README at b814a10 +[^staging-extraction]: Report extraction process, CDEStaging at b814a10 +[^staging-catalogs]: Negative statements, uncovered findings, and missing attributes catalogs, CDEStaging at b814a10 +[^board-role-tagging]: Open Imaging Data Model project board (internal), undated; schema idea only +[^status-deck-2026-01]: Open Imaging Data Model 2026 Status Update, January 2026 +[^ipl-webinar]: SIIM Enterprise Imaging webinar, 15 July 2026 diff --git a/knowledge/drafts/foundation-context.md b/knowledge/drafts/foundation-context.md new file mode 100644 index 0000000..d6fc076 --- /dev/null +++ b/knowledge/drafts/foundation-context.md @@ -0,0 +1,51 @@ +--- +type: Overview +title: Foundation Context +description: "The shared, curated clinical knowledge that every patient's imaging data is woven into: three axes over existing standards, the relationships among them, and the citations they rest on." +tags: [foundation-context, finding-models, cdes, anatomic-locations, exam-types] +status: draft +generated: { by: claude-fable-5-1/2026-09-24-restructure, at: 2026-09-24T21:50:00Z } +sources: + - id: lead-2026-09-24 + resource: docs/plans/2026-09-22-layout-plan.md + title: The project lead's statements of 2026-09-22 to 2026-09-24 on the pillars, the two collections, the next-generation schema, and the wording of this page (recorded verbatim in the layout plan) + - id: siim-2026 + resource: https://oidm-public.t3.tigrisfiles.io/oidm-knowledge-sources/SIIM%202026%20Reports-of-the-Future.pptx + title: "Structured Results and Context for Next-Generation Imaging Resulting Tools, SIIM 2026 annual meeting talk, June 2026, Mass General Brigham" + - id: build-plan + resource: knowledge/plans/2026-09-20-knowledgebase-build-plan.md + title: Knowledgebase build plan, the project lead's stated goals (2026-09-20) and the decisions of 2026-09-21 and 2026-09-22 +--- + +# Foundation Context + +Foundation Context is the shared, curated knowledge that every patient's imaging data is woven into. It is one layer for everyone: definitions of what can be found, where things are in the body, how exams see them, the relationships among all of these, and citations out to the standards and references the definitions rest on. It is open-source, general clinical knowledge, authored by the imaging informatics community in the open. It covers both the schema that definitions take and the work of building the content.[^siim-2026][^lead-2026-09-24] + +It has three axes. Each is a curated layer over a standard that already exists, adding imaging-specific knowledge rather than reinventing it.[^siim-2026] + +[![The three axes of Foundation Context: finding/diagnosis definitions, anatomic locations, exam types, each layered over an existing standard](./three-axes.svg)](./three-axes.svg) + +**Finding/diagnosis definitions: what was found.** One kind of content, held today in two collections: the Open Imaging Finding Models, inclusive and fast-moving, and the ACR/RSNA Common Data Elements, well-reviewed and closer to published. Both are moving onto a single graph-based schema being developed in the CDE project, which applications will use across both collections at once.[^lead-2026-09-24] + +**Anatomic locations: where it is.** A curated index of anatomic entities anchored in RadLex, with containment, part-of, and laterality made explicit, now being incorporated into RadLex itself.[^build-plan][^siim-2026] + +**Exam types: how it was seen.** Content to come: preferred exam families over the LOINC/RSNA Radiology Playbook, each connected to the anatomy it covers.[^build-plan][^siim-2026] + +The axes are not independent. A definition says which anatomy it applies to and which modalities can show it. An exam type says which anatomy it covers. Definitions relate to one another as subtype and supertype, cause and effect, diagnosis and the findings it manifests as, things confused with each other, things that occur together. These relationships, with the citations out to Radiopaedia, Wikipedia, SNOMED CT, RadLex, LOINC, FMA, ICD, and CPT, are what turn a flat dictionary into something an application can reason over.[^siim-2026] + +[![A mini-network of Foundation Context: finding/diagnosis definitions, anatomic locations, and exam types, with relationships within and between them](./foundation-network.svg)](./foundation-network.svg) + +(click the image for full size) + +# In this section + +- Finding/diagnosis definitions: finding models and CDEs, with the OIFM content, the definition formats, and the identifiers +- The next-generation schema, with the relationship family and standard clinical metadata +- Authoring and review +- [Anatomic locations](./anatomic-locations.md) +- [Exam types](./exam-types.md) +- [Standards the foundation layers over and cites](./standards.md) + +[^lead-2026-09-24]: The project lead, 2026-09-22 to 2026-09-24: the two collections ruling, the shared next-generation schema for both, the RadLex migration, and the wording of the opening paragraph; recorded verbatim in the layout plan. +[^siim-2026]: SIIM 2026 annual meeting talk, June 2026, Mass General Brigham; slides 6, 7, 8, 10, 11, and 12. +[^build-plan]: Knowledgebase build plan: the project lead's stated goals on anatomic locations and exam types (2026-09-20). diff --git a/knowledge/drafts/foundation-network.excalidraw b/knowledge/drafts/foundation-network.excalidraw new file mode 100644 index 0000000..58a769b --- /dev/null +++ b/knowledge/drafts/foundation-network.excalidraw @@ -0,0 +1,6256 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "oidm-knowledge/tools/diagrams", + "elements": [ + { + "type": "text", + "id": "maintitle", + "x": 0, + "y": 8, + "width": 394.4, + "height": 25.0, + "strokeColor": "#1e40af", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1001, + "version": 1, + "versionNonce": 1002, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Foundation Context: a mini-network", + "originalText": "Foundation Context: a mini-network", + "fontSize": 20, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "subtitle", + "x": 0, + "y": 34, + "width": 550.42, + "height": 16.25, + "strokeColor": "#3b82f6", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1003, + "version": 1, + "versionNonce": 1004, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "three sectors of shared, curated knowledge \u2014 illustrative, not exhaustive", + "originalText": "three sectors of shared, curated knowledge \u2014 illustrative, not exhaustive", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "rA", + "x": 0, + "y": 70, + "width": 935, + "height": 300, + "strokeColor": "#e2e8f0", + "backgroundColor": "#f8fafc", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1005, + "version": 1, + "versionNonce": 1006, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "rA_title", + "x": 14, + "y": 80, + "width": 365.4, + "height": 18.75, + "strokeColor": "#1e40af", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1007, + "version": 1, + "versionNonce": 1008, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Sector 1 \u2014 Finding / diagnosis definitions", + "originalText": "Sector 1 \u2014 Finding / diagnosis definitions", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "rB", + "x": 0, + "y": 440, + "width": 935, + "height": 370, + "strokeColor": "#e2e8f0", + "backgroundColor": "#f8fafc", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1009, + "version": 1, + "versionNonce": 1010, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "rB_title", + "x": 54, + "y": 450, + "width": 252.29999999999998, + "height": 18.75, + "strokeColor": "#1e40af", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1011, + "version": 1, + "versionNonce": 1012, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Sector 2 \u2014 Anatomic locations", + "originalText": "Sector 2 \u2014 Anatomic locations", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "rC", + "x": 0, + "y": 880, + "width": 935, + "height": 300, + "strokeColor": "#e2e8f0", + "backgroundColor": "#f8fafc", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1013, + "version": 1, + "versionNonce": 1014, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "rC_title", + "x": 14, + "y": 890, + "width": 182.7, + "height": 18.75, + "strokeColor": "#1e40af", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1015, + "version": 1, + "versionNonce": 1016, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Sector 3 \u2014 Exam types", + "originalText": "Sector 3 \u2014 Exam types", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "rC_tag", + "x": 14, + "y": 910, + "width": 128.17999999999998, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1017, + "version": 1, + "versionNonce": 1018, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "(content to come)", + "originalText": "(content to come)", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "rL", + "x": 0, + "y": 1210, + "width": 935, + "height": 190, + "strokeColor": "#e2e8f0", + "backgroundColor": "#f8fafc", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1019, + "version": 1, + "versionNonce": 1020, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "rL_title", + "x": 14, + "y": 1220, + "width": 52.199999999999996, + "height": 18.75, + "strokeColor": "#1e40af", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1021, + "version": 1, + "versionNonce": 1022, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Legend", + "originalText": "Legend", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "lung_cancer", + "x": 20, + "y": 110, + "width": 140, + "height": 42, + "strokeColor": "#059669", + "backgroundColor": "#6ee7b7", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1023, + "version": 1, + "versionNonce": 1024, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "lung_cancer_t", + "type": "text" + }, + { + "id": "e_manifest", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "lung_cancer_t", + "x": 30, + "y": 120, + "width": 120, + "height": 22, + "strokeColor": "#064e3b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1025, + "version": 1, + "versionNonce": 1026, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "lung cancer", + "originalText": "lung cancer", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "lung_cancer", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "pulm_nodule", + "x": 272, + "y": 100, + "width": 146, + "height": 54, + "strokeColor": "#059669", + "backgroundColor": "#d1fae5", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1027, + "version": 1, + "versionNonce": 1028, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "pulm_nodule_t", + "type": "text" + }, + { + "id": "e_solid_sub", + "type": "arrow" + }, + { + "id": "e_partsolid_sub", + "type": "arrow" + }, + { + "id": "e_nonsolid_sub", + "type": "arrow" + }, + { + "id": "e_manifest", + "type": "arrow" + }, + { + "id": "e_assessed", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "pulm_nodule_t", + "x": 282, + "y": 110, + "width": 126, + "height": 34, + "strokeColor": "#064e3b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1029, + "version": 1, + "versionNonce": 1030, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "pulmonary\nnodule", + "originalText": "pulmonary\nnodule", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "pulm_nodule", + "lineHeight": 1.25 + }, + { + "type": "ellipse", + "id": "lungrads", + "x": 492, + "y": 95, + "width": 125, + "height": 75, + "strokeColor": "#7e22ce", + "backgroundColor": "#e9d5ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1031, + "version": 1, + "versionNonce": 1032, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "lungrads_t", + "type": "text" + }, + { + "id": "e_assessed", + "type": "arrow" + } + ], + "link": null, + "locked": false + }, + { + "type": "text", + "id": "lungrads_t", + "x": 517.0, + "y": 119.0, + "width": 75.0, + "height": 27.0, + "strokeColor": "#4c1d95", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1033, + "version": 1, + "versionNonce": 1034, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Lung-RADS", + "originalText": "Lung-RADS", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "lungrads", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "pleural_effusion", + "x": 637, + "y": 110, + "width": 142, + "height": 42, + "strokeColor": "#059669", + "backgroundColor": "#d1fae5", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1035, + "version": 1, + "versionNonce": 1036, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "pleural_effusion_t", + "type": "text" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "pleural_effusion_t", + "x": 647, + "y": 120, + "width": 122, + "height": 22, + "strokeColor": "#064e3b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1037, + "version": 1, + "versionNonce": 1038, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "pleural effusion", + "originalText": "pleural effusion", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "pleural_effusion", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "solid_nodule", + "x": 120, + "y": 210, + "width": 105, + "height": 70, + "strokeColor": "#059669", + "backgroundColor": "#d1fae5", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1039, + "version": 1, + "versionNonce": 1040, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "solid_nodule_t", + "type": "text" + }, + { + "id": "e_solid_sub", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "solid_nodule_t", + "x": 130, + "y": 220, + "width": 85, + "height": 50, + "strokeColor": "#064e3b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1041, + "version": 1, + "versionNonce": 1042, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "solid\npulmonary\nnodule", + "originalText": "solid\npulmonary\nnodule", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "solid_nodule", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "partsolid_nodule", + "x": 235, + "y": 210, + "width": 100, + "height": 70, + "strokeColor": "#059669", + "backgroundColor": "#d1fae5", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1043, + "version": 1, + "versionNonce": 1044, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "partsolid_nodule_t", + "type": "text" + }, + { + "id": "e_partsolid_sub", + "type": "arrow" + }, + { + "id": "e_partsolid_comp", + "type": "arrow" + }, + { + "id": "e_progress", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "partsolid_nodule_t", + "x": 245, + "y": 220, + "width": 80, + "height": 50, + "strokeColor": "#064e3b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1045, + "version": 1, + "versionNonce": 1046, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "part-solid\npulmonary\nnodule", + "originalText": "part-solid\npulmonary\nnodule", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "partsolid_nodule", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "nonsolid_nodule", + "x": 530, + "y": 210, + "width": 100, + "height": 70, + "strokeColor": "#059669", + "backgroundColor": "#d1fae5", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1047, + "version": 1, + "versionNonce": 1048, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "nonsolid_nodule_t", + "type": "text" + }, + { + "id": "e_nonsolid_sub", + "type": "arrow" + }, + { + "id": "e_progress", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "nonsolid_nodule_t", + "x": 540, + "y": 220, + "width": 80, + "height": 50, + "strokeColor": "#064e3b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1049, + "version": 1, + "versionNonce": 1050, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "non-solid\npulmonary\nnodule", + "originalText": "non-solid\npulmonary\nnodule", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "nonsolid_nodule", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "solid_component", + "x": 365, + "y": 295, + "width": 118, + "height": 38, + "strokeColor": "#059669", + "backgroundColor": "#d1fae5", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1051, + "version": 1, + "versionNonce": 1052, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "solid_component_t", + "type": "text" + }, + { + "id": "e_partsolid_comp", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "solid_component_t", + "x": 375, + "y": 305, + "width": 98, + "height": 18, + "strokeColor": "#064e3b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1053, + "version": 1, + "versionNonce": 1054, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "solid component", + "originalText": "solid component", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "solid_component", + "lineHeight": 1.25 + }, + { + "type": "ellipse", + "id": "gA1", + "x": 35, + "y": 220, + "width": 30, + "height": 30, + "strokeColor": "#9ca3af", + "backgroundColor": "#e5e7eb", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1055, + "version": 1, + "versionNonce": 1056, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "ellipse", + "id": "gA2", + "x": 62, + "y": 257, + "width": 26, + "height": 26, + "strokeColor": "#9ca3af", + "backgroundColor": "#e5e7eb", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1057, + "version": 1, + "versionNonce": 1058, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "ellipse", + "id": "gA3", + "x": 43, + "y": 283, + "width": 24, + "height": 24, + "strokeColor": "#9ca3af", + "backgroundColor": "#e5e7eb", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1059, + "version": 1, + "versionNonce": 1060, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "arrow", + "id": "fA_12", + "x": 50, + "y": 235, + "width": 25, + "height": 35, + "strokeColor": "#9ca3af", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 40, + "angle": 0, + "seed": 1061, + "version": 1, + "versionNonce": 1062, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 25, + 35 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "arrow", + "id": "fA_13", + "x": 50, + "y": 235, + "width": 5, + "height": 60, + "strokeColor": "#9ca3af", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 40, + "angle": 0, + "seed": 1063, + "version": 1, + "versionNonce": 1064, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 5, + 60 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "arrow", + "id": "fA_into", + "x": 75, + "y": 270, + "width": 45, + "height": -25, + "strokeColor": "#9ca3af", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 40, + "angle": 0, + "seed": 1065, + "version": 1, + "versionNonce": 1066, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 45, + -25 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "arrow", + "id": "e_solid_sub", + "x": 172.5, + "y": 210, + "width": 121.39999999999998, + "height": -56, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1067, + "version": 1, + "versionNonce": 1068, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 121.39999999999998, + -56 + ] + ], + "startBinding": { + "elementId": "solid_nodule", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "pulm_nodule", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_solid_sub_h", + "x": 293.9, + "y": 154, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1069, + "version": 1, + "versionNonce": 1070, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + -6.48348502073145, + 9.818575354192205 + ], + [ + -11.677453639093187, + -1.4412066148991016 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_partsolid_sub", + "x": 275.0, + "y": 210, + "width": 70.0, + "height": -56, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1071, + "version": 1, + "versionNonce": 1072, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 70.0, + -56 + ] + ], + "startBinding": { + "elementId": "partsolid_nodule", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "pulm_nodule", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_partsolid_sub_h", + "x": 345.0, + "y": 154, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1073, + "version": 1, + "versionNonce": 1074, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + -3.935578799592861, + 11.088337094091031 + ], + [ + -11.681797389267729, + 1.4055638569974747 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_nonsolid_sub", + "x": 550.0, + "y": 210, + "width": -146.60000000000002, + "height": -56, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1075, + "version": 1, + "versionNonce": 1076, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -146.60000000000002, + -56 + ] + ], + "startBinding": { + "elementId": "nonsolid_nodule", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "pulm_nodule", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_nonsolid_sub_h", + "x": 403.4, + "y": 154, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1077, + "version": 1, + "versionNonce": 1078, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + 11.554070614725333, + -2.223387557296462 + ], + [ + 7.129215863531158, + 9.360250059222551 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "l_solid_sub_bg", + "x": 170.0, + "y": 177.875, + "width": 70.0, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#f8fafc", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1079, + "version": 1, + "versionNonce": 1080, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "text", + "id": "l_solid_sub_t", + "x": 175.0, + "y": 180.875, + "width": 60.0, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1081, + "version": 1, + "versionNonce": 1082, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "subtype of", + "originalText": "subtype of", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_partsolid_sub_bg", + "x": 255.0, + "y": 177.875, + "width": 70.0, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#f8fafc", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1083, + "version": 1, + "versionNonce": 1084, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "text", + "id": "l_partsolid_sub_t", + "x": 260.0, + "y": 180.875, + "width": 60.0, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1085, + "version": 1, + "versionNonce": 1086, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "subtype of", + "originalText": "subtype of", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_nonsolid_sub_bg", + "x": 429.0, + "y": 157.875, + "width": 70.0, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#f8fafc", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1087, + "version": 1, + "versionNonce": 1088, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "text", + "id": "l_nonsolid_sub_t", + "x": 434.0, + "y": 160.875, + "width": 60.0, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1089, + "version": 1, + "versionNonce": 1090, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "subtype of", + "originalText": "subtype of", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "e_partsolid_comp", + "x": 295.0, + "y": 280, + "width": 105.39999999999998, + "height": 15, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1091, + "version": 1, + "versionNonce": 1092, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 105.39999999999998, + 15 + ] + ], + "startBinding": { + "elementId": "partsolid_nodule", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "solid_component", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "text", + "id": "e_partsolid_comp_l", + "x": 358.69, + "y": 265.5, + "width": 98.02, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1093, + "version": 1, + "versionNonce": 1094, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "has component", + "originalText": "has component", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "e_partsolid_comp_h", + "x": 400.4, + "y": 295, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1095, + "version": 1, + "versionNonce": 1096, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + -10.773796008606894, + 4.729198617622842 + ], + [ + -9.026693953157121, + -7.547105158670888 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_manifest", + "x": 160, + "y": 126.8, + "width": 112, + "height": -7.8999999999999915, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1097, + "version": 1, + "versionNonce": 1098, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 112, + -7.8999999999999915 + ] + ], + "startBinding": { + "elementId": "lung_cancer", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "pulm_nodule", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "text", + "id": "e_manifest_l", + "x": 159.45, + "y": 96.85, + "width": 113.1, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1099, + "version": 1, + "versionNonce": 1100, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "may manifest as", + "originalText": "may manifest as", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "e_manifest_h", + "x": 272, + "y": 118.9, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1101, + "version": 1, + "versionNonce": 1102, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + -9.538978435942965, + 6.888242910831082 + ], + [ + -10.411453578876774, + -5.481024938357194 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_progress", + "x": 530, + "y": 245.0, + "width": -195, + "height": 0.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1103, + "version": 1, + "versionNonce": 1104, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -195, + 0.0 + ] + ], + "startBinding": { + "elementId": "nonsolid_nodule", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "partsolid_nodule", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "text", + "id": "e_progress_l", + "x": 375.95, + "y": 221.0, + "width": 113.1, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1105, + "version": 1, + "versionNonce": 1106, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "may progress to", + "originalText": "may progress to", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "e_progress_h", + "x": 335, + "y": 245.0, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1107, + "version": 1, + "versionNonce": 1108, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 10.0, + -6.199999999999989 + ], + [ + 10.0, + 6.199999999999989 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_assessed", + "x": 418, + "y": 113.5, + "width": 74, + "height": 19.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1109, + "version": 1, + "versionNonce": 1110, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 74, + 19.0 + ] + ], + "startBinding": { + "elementId": "pulm_nodule", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "lungrads", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "text", + "id": "e_assessed_l", + "x": 419.53, + "y": 93.0, + "width": 82.94, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1111, + "version": 1, + "versionNonce": 1112, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "assessed by", + "originalText": "assessed by", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "e_assessed_h", + "x": 492, + "y": 132.5, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1113, + "version": 1, + "versionNonce": 1114, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + -11.227710220076972, + 3.518312552059541 + ], + [ + -8.143951152869988, + -8.492117499167563 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "thorax", + "x": 160, + "y": 480, + "width": 110, + "height": 42, + "strokeColor": "#1d4ed8", + "backgroundColor": "#bfdbfe", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1115, + "version": 1, + "versionNonce": 1116, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "thorax_t", + "type": "text" + }, + { + "id": "e_pspace_thorax", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "thorax_t", + "x": 170, + "y": 490, + "width": 90, + "height": 22, + "strokeColor": "#1e3a8a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1117, + "version": 1, + "versionNonce": 1118, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "thorax", + "originalText": "thorax", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "thorax", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "pleural_space", + "x": 654, + "y": 480, + "width": 108, + "height": 44, + "strokeColor": "#1d4ed8", + "backgroundColor": "#bfdbfe", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1119, + "version": 1, + "versionNonce": 1120, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "pleural_space_t", + "type": "text" + }, + { + "id": "e_pspace_thorax", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "pleural_space_t", + "x": 664, + "y": 490, + "width": 88, + "height": 24, + "strokeColor": "#1e3a8a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1121, + "version": 1, + "versionNonce": 1122, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "pleural\nspace", + "originalText": "pleural\nspace", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "pleural_space", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "upper_abdomen", + "x": 777, + "y": 480, + "width": 115, + "height": 42, + "strokeColor": "#9ca3af", + "backgroundColor": "#e5e7eb", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1123, + "version": 1, + "versionNonce": 1124, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "upper_abdomen_t", + "type": "text" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "upper_abdomen_t", + "x": 787, + "y": 490, + "width": 95, + "height": 22, + "strokeColor": "#4b5563", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1125, + "version": 1, + "versionNonce": 1126, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "upper abdomen", + "originalText": "upper abdomen", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "upper_abdomen", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "right_lung", + "x": 150, + "y": 550, + "width": 105, + "height": 40, + "strokeColor": "#1d4ed8", + "backgroundColor": "#bfdbfe", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1127, + "version": 1, + "versionNonce": 1128, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "right_lung_t", + "type": "text" + }, + { + "id": "e_rlung_lung", + "type": "arrow" + }, + { + "id": "e_ulobe_rlung", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "right_lung_t", + "x": 160, + "y": 560, + "width": 85, + "height": 20, + "strokeColor": "#1e3a8a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1129, + "version": 1, + "versionNonce": 1130, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "right lung", + "originalText": "right lung", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "right_lung", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "lung", + "x": 280, + "y": 550, + "width": 130, + "height": 42, + "strokeColor": "#1d4ed8", + "backgroundColor": "#bfdbfe", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1131, + "version": 1, + "versionNonce": 1132, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "lung_t", + "type": "text" + }, + { + "id": "e_rlung_lung", + "type": "arrow" + }, + { + "id": "e_llung_lung", + "type": "arrow" + }, + { + "id": "e_parenchyma_lung", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "lung_t", + "x": 290, + "y": 560, + "width": 110, + "height": 22, + "strokeColor": "#1e3a8a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1133, + "version": 1, + "versionNonce": 1134, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "lung", + "originalText": "lung", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "lung", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "left_lung", + "x": 435, + "y": 550, + "width": 105, + "height": 40, + "strokeColor": "#1d4ed8", + "backgroundColor": "#bfdbfe", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1135, + "version": 1, + "versionNonce": 1136, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "left_lung_t", + "type": "text" + }, + { + "id": "e_llung_lung", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "left_lung_t", + "x": 445, + "y": 560, + "width": 85, + "height": 20, + "strokeColor": "#1e3a8a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1137, + "version": 1, + "versionNonce": 1138, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "left lung", + "originalText": "left lung", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "left_lung", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "upper_lobe", + "x": 140, + "y": 660, + "width": 138, + "height": 42, + "strokeColor": "#1d4ed8", + "backgroundColor": "#bfdbfe", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1139, + "version": 1, + "versionNonce": 1140, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "upper_lobe_t", + "type": "text" + }, + { + "id": "e_ulobe_rlung", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "upper_lobe_t", + "x": 150, + "y": 670, + "width": 118, + "height": 22, + "strokeColor": "#1e3a8a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1141, + "version": 1, + "versionNonce": 1142, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "upper lobe of\nright lung", + "originalText": "upper lobe of\nright lung", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "upper_lobe", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "lung_parenchyma", + "x": 310, + "y": 660, + "width": 120, + "height": 44, + "strokeColor": "#1d4ed8", + "backgroundColor": "#bfdbfe", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1143, + "version": 1, + "versionNonce": 1144, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "lung_parenchyma_t", + "type": "text" + }, + { + "id": "e_parenchyma_lung", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "lung_parenchyma_t", + "x": 320, + "y": 670, + "width": 100, + "height": 24, + "strokeColor": "#1e3a8a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1145, + "version": 1, + "versionNonce": 1146, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "lung\nparenchyma", + "originalText": "lung\nparenchyma", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "lung_parenchyma", + "lineHeight": 1.25 + }, + { + "type": "ellipse", + "id": "gB1", + "x": 35, + "y": 675, + "width": 30, + "height": 30, + "strokeColor": "#9ca3af", + "backgroundColor": "#e5e7eb", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1147, + "version": 1, + "versionNonce": 1148, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "ellipse", + "id": "gB2", + "x": 62, + "y": 712, + "width": 26, + "height": 26, + "strokeColor": "#9ca3af", + "backgroundColor": "#e5e7eb", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1149, + "version": 1, + "versionNonce": 1150, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "ellipse", + "id": "gB3", + "x": 43, + "y": 738, + "width": 24, + "height": 24, + "strokeColor": "#9ca3af", + "backgroundColor": "#e5e7eb", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1151, + "version": 1, + "versionNonce": 1152, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "arrow", + "id": "fB_12", + "x": 50, + "y": 690, + "width": 25, + "height": 35, + "strokeColor": "#9ca3af", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 40, + "angle": 0, + "seed": 1153, + "version": 1, + "versionNonce": 1154, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 25, + 35 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "arrow", + "id": "fB_13", + "x": 50, + "y": 690, + "width": 5, + "height": 60, + "strokeColor": "#9ca3af", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 40, + "angle": 0, + "seed": 1155, + "version": 1, + "versionNonce": 1156, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 5, + 60 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "arrow", + "id": "fB_into", + "x": 75, + "y": 725, + "width": 65, + "height": -40, + "strokeColor": "#9ca3af", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 40, + "angle": 0, + "seed": 1157, + "version": 1, + "versionNonce": 1158, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 65, + -40 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "arrow", + "id": "e_rlung_lung", + "x": 255, + "y": 570.0, + "width": 25, + "height": -7.399999999999977, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1159, + "version": 1, + "versionNonce": 1160, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 25, + -7.399999999999977 + ] + ], + "startBinding": { + "elementId": "right_lung", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "lung", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_rlung_lung_h", + "x": 280, + "y": 562.6, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1161, + "version": 1, + "versionNonce": 1162, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + -7.82902639099558, + 8.783299253076507 + ], + [ + -11.34848289519772, + -3.1067565043632612 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_llung_lung", + "x": 435, + "y": 570.0, + "width": -25, + "height": 9.399999999999977, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1163, + "version": 1, + "versionNonce": 1164, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -25, + 9.399999999999977 + ] + ], + "startBinding": { + "elementId": "left_lung", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "lung", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_llung_lung_h", + "x": 410, + "y": 579.4, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1165, + "version": 1, + "versionNonce": 1166, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 7.178158496674996, + -9.322770006634983 + ], + [ + 11.54226320339535, + 2.2838914474086778 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_ulobe_rlung", + "x": 195.2, + "y": 660, + "width": -3.1999999999999886, + "height": -70, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1167, + "version": 1, + "versionNonce": 1168, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -3.1999999999999886, + -70 + ] + ], + "startBinding": { + "elementId": "upper_lobe", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "right_lung", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_ulobe_rlung_h", + "x": 192.0, + "y": 590, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1169, + "version": 1, + "versionNonce": 1170, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + 6.650197705725532, + 9.706434488253763 + ], + [ + -5.736865831977809, + 10.272700249977333 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_parenchyma_lung", + "x": 394.0, + "y": 660, + "width": 0.39999999999997726, + "height": -68, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1171, + "version": 1, + "versionNonce": 1172, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.39999999999997726, + -68 + ] + ], + "startBinding": { + "elementId": "lung_parenchyma", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "lung", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_parenchyma_lung_h", + "x": 394.4, + "y": 592, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1173, + "version": 1, + "versionNonce": 1174, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + 6.141070224617636, + 10.036296951381814 + ], + [ + -6.258715248077749, + 9.963357036836555 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_pspace_thorax", + "x": 654, + "y": 502.0, + "width": -384, + "height": -1.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1175, + "version": 1, + "versionNonce": 1176, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -384, + -1.0 + ] + ], + "startBinding": { + "elementId": "pleural_space", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "thorax", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_pspace_thorax_h", + "x": 270, + "y": 501.0, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1177, + "version": 1, + "versionNonce": 1178, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 10.016111870337966, + -6.173937398522469 + ], + [ + 9.983820313166632, + 6.226020555250386 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "l_ulobe_rlung_bg", + "x": 155.15, + "y": 600.875, + "width": 83.7, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#f8fafc", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1179, + "version": 1, + "versionNonce": 1180, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "text", + "id": "l_ulobe_rlung_t", + "x": 160.15, + "y": 603.875, + "width": 73.7, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1181, + "version": 1, + "versionNonce": 1182, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "contained by", + "originalText": "contained by", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_laterality_bg", + "x": 315.8, + "y": 600.875, + "width": 58.4, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#f8fafc", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1183, + "version": 1, + "versionNonce": 1184, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "text", + "id": "l_laterality_t", + "x": 320.8, + "y": 603.875, + "width": 48.4, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1185, + "version": 1, + "versionNonce": 1186, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "laterality", + "originalText": "laterality", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_parenchyma_lung_bg", + "x": 463.55, + "y": 600.875, + "width": 46.9, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#f8fafc", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1187, + "version": 1, + "versionNonce": 1188, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "text", + "id": "l_parenchyma_lung_t", + "x": 468.55, + "y": 603.875, + "width": 36.9, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1189, + "version": 1, + "versionNonce": 1190, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "part of", + "originalText": "part of", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_pspace_thorax_bg", + "x": 438.15, + "y": 483.875, + "width": 83.7, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#f8fafc", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1191, + "version": 1, + "versionNonce": 1192, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "text", + "id": "l_pspace_thorax_t", + "x": 443.15, + "y": 486.875, + "width": 73.7, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1193, + "version": 1, + "versionNonce": 1194, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "contained by", + "originalText": "contained by", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "ct_chest", + "x": 285, + "y": 920, + "width": 230, + "height": 60, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1195, + "version": 1, + "versionNonce": 1196, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "ct_chest_t", + "type": "text" + }, + { + "id": "e_wo_family", + "type": "arrow" + }, + { + "id": "e_w_family", + "type": "arrow" + }, + { + "id": "e_wo_w_family", + "type": "arrow" + }, + { + "id": "e_cta_family", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "ct_chest_t", + "x": 295, + "y": 930, + "width": 210, + "height": 40, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1197, + "version": 1, + "versionNonce": 1198, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "CT Chest\npreferred (to come)", + "originalText": "CT Chest\npreferred (to come)", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "ct_chest", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "ct_wo", + "x": 90, + "y": 1010, + "width": 152, + "height": 70, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1199, + "version": 1, + "versionNonce": 1200, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "ct_wo_t", + "type": "text" + }, + { + "id": "e_wo_family", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "ct_wo_t", + "x": 100, + "y": 1020, + "width": 132, + "height": 50, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1201, + "version": 1, + "versionNonce": 1202, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "CT Chest WO contrast\n29252-4", + "originalText": "CT Chest WO contrast\n29252-4", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "ct_wo", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "ct_w", + "x": 250, + "y": 1010, + "width": 158, + "height": 70, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1203, + "version": 1, + "versionNonce": 1204, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "ct_w_t", + "type": "text" + }, + { + "id": "e_w_family", + "type": "arrow" + }, + { + "id": "e_w_regionimaged", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "ct_w_t", + "x": 260, + "y": 1020, + "width": 138, + "height": 50, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1205, + "version": 1, + "versionNonce": 1206, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "CT Chest W contrast IV\n24628-0", + "originalText": "CT Chest W contrast IV\n24628-0", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "ct_w", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "ct_wo_w", + "x": 416, + "y": 1010, + "width": 209, + "height": 70, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1207, + "version": 1, + "versionNonce": 1208, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "ct_wo_w_t", + "type": "text" + }, + { + "id": "e_wo_w_family", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "ct_wo_w_t", + "x": 426, + "y": 1020, + "width": 189, + "height": 50, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1209, + "version": 1, + "versionNonce": 1210, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "CT Chest WO and W contrast IV\n30598-7", + "originalText": "CT Chest WO and W contrast IV\n30598-7", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "ct_wo_w", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "ct_cta", + "x": 633, + "y": 1010, + "width": 151, + "height": 70, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1211, + "version": 1, + "versionNonce": 1212, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "ct_cta_t", + "type": "text" + }, + { + "id": "e_cta_family", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "ct_cta_t", + "x": 643, + "y": 1020, + "width": 131, + "height": 50, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1213, + "version": 1, + "versionNonce": 1214, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "CTA Chest vessels\nWO and W contrast IV\n30804-9", + "originalText": "CTA Chest vessels\nWO and W contrast IV\n30804-9", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "ct_cta", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "ct_thoracic_spine", + "x": 792, + "y": 1010, + "width": 126, + "height": 70, + "strokeColor": "#9ca3af", + "backgroundColor": "#e5e7eb", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1215, + "version": 1, + "versionNonce": 1216, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "ct_thoracic_spine_t", + "type": "text" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "ct_thoracic_spine_t", + "x": 802, + "y": 1020, + "width": 106, + "height": 50, + "strokeColor": "#4b5563", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1217, + "version": 1, + "versionNonce": 1218, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "CT Thoracic spine\nW contrast IV\n24979-7", + "originalText": "CT Thoracic spine\nW contrast IV\n24979-7", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "ct_thoracic_spine", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "region_imaged", + "x": 266, + "y": 1100, + "width": 126, + "height": 40, + "strokeColor": "#9ca3af", + "backgroundColor": "#e5e7eb", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1219, + "version": 1, + "versionNonce": 1220, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "region_imaged_t", + "type": "text" + }, + { + "id": "e_w_regionimaged", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "region_imaged_t", + "x": 276, + "y": 1110, + "width": 106, + "height": 20, + "strokeColor": "#4b5563", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1221, + "version": 1, + "versionNonce": 1222, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Region imaged:\nThorax (RID1243)", + "originalText": "Region imaged:\nThorax (RID1243)", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "region_imaged", + "lineHeight": 1.25 + }, + { + "type": "ellipse", + "id": "gC1", + "x": 28, + "y": 1031, + "width": 28, + "height": 28, + "strokeColor": "#9ca3af", + "backgroundColor": "#e5e7eb", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1223, + "version": 1, + "versionNonce": 1224, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "ellipse", + "id": "gC2", + "x": 52, + "y": 1066, + "width": 24, + "height": 24, + "strokeColor": "#9ca3af", + "backgroundColor": "#e5e7eb", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1225, + "version": 1, + "versionNonce": 1226, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "arrow", + "id": "fC_12", + "x": 42, + "y": 1045, + "width": 22, + "height": 33, + "strokeColor": "#9ca3af", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 40, + "angle": 0, + "seed": 1227, + "version": 1, + "versionNonce": 1228, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 22, + 33 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "arrow", + "id": "fC_into", + "x": 42, + "y": 1045, + "width": 48, + "height": 0, + "strokeColor": "#9ca3af", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 40, + "angle": 0, + "seed": 1229, + "version": 1, + "versionNonce": 1230, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 48, + 0 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "arrow", + "id": "e_wo_family", + "x": 166.0, + "y": 1010, + "width": 142.0, + "height": -30, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1231, + "version": 1, + "versionNonce": 1232, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 142.0, + -30 + ] + ], + "startBinding": { + "elementId": "ct_wo", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "ct_chest", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "text", + "id": "e_wo_family_l", + "x": 161.68, + "y": 975.0, + "width": 120.63999999999999, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1233, + "version": 1, + "versionNonce": 1234, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "member of family", + "originalText": "member of family", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "e_wo_family_h", + "x": 308.0, + "y": 980, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1235, + "version": 1, + "versionNonce": 1236, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + -8.502462724935015, + 8.133149919378639 + ], + [ + -11.06560383812456, + -3.999051349718229 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_w_family", + "x": 329.0, + "y": 1010, + "width": 36.5, + "height": -30, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1237, + "version": 1, + "versionNonce": 1238, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 36.5, + -30 + ] + ], + "startBinding": { + "elementId": "ct_w", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "ct_chest", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_w_family_h", + "x": 365.5, + "y": 980, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1239, + "version": 1, + "versionNonce": 1240, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + -3.7886249515367467, + 11.13940397761894 + ], + [ + -11.662191889925964, + 1.559897535912114 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_wo_w_family", + "x": 520.5, + "y": 1010, + "width": -86.0, + "height": -30, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1241, + "version": 1, + "versionNonce": 1242, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -86.0, + -30 + ] + ], + "startBinding": { + "elementId": "ct_wo_w", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "ct_chest", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_wo_w_family_h", + "x": 434.5, + "y": 980, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1243, + "version": 1, + "versionNonce": 1244, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + 11.484109183631176, + -2.5603195617809433 + ], + [ + 7.399894445284303, + 9.147762688146713 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_cta_family", + "x": 678.3, + "y": 1010, + "width": -186.29999999999995, + "height": -30, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1245, + "version": 1, + "versionNonce": 1246, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -186.29999999999995, + -30 + ] + ], + "startBinding": { + "elementId": "ct_cta", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "ct_chest", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_cta_family_h", + "x": 492.0, + "y": 980, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1247, + "version": 1, + "versionNonce": 1248, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + 10.85850556438794, + -4.531319554848892 + ], + [ + 8.887122416534169, + 7.710969793322761 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_w_regionimaged", + "x": 329.0, + "y": 1080, + "width": 0.0, + "height": 20, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1249, + "version": 1, + "versionNonce": 1250, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.0, + 20 + ] + ], + "startBinding": { + "elementId": "ct_w", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "region_imaged", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "text", + "id": "e_w_regionimaged_l", + "x": 386.99, + "y": 1090.0, + "width": 98.02, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1251, + "version": 1, + "versionNonce": 1252, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Playbook part", + "originalText": "Playbook part", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "e_w_regionimaged_h", + "x": 329.0, + "y": 1100, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1253, + "version": 1, + "versionNonce": 1254, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + -6.199999999999989, + -10.0 + ], + [ + 6.199999999999989, + -10.0 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "cx_pn_lung", + "x": 345.0, + "y": 154, + "width": 0.0, + "height": 396, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 3, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1255, + "version": 1, + "versionNonce": 1256, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + 0.0, + 396 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "cx_pn_lung_h", + "x": 345.0, + "y": 550, + "width": 0, + "height": 0, + "strokeColor": "#be123c", + "backgroundColor": "#be123c", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1257, + "version": 1, + "versionNonce": 1258, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + -8.060000000000002, + -13.0 + ], + [ + 8.060000000000002, + -13.0 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "cx_pn_lung_bg", + "x": 358.8, + "y": 393, + "width": 66.4, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1259, + "version": 1, + "versionNonce": 1260, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "text", + "id": "cx_pn_lung_l", + "x": 363.8, + "y": 396, + "width": 56.4, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1261, + "version": 1, + "versionNonce": 1262, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "scoped to", + "originalText": "scoped to", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "cx_lc_lung", + "x": 90.0, + "y": 152, + "width": 209.5, + "height": 398, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 3, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1263, + "version": 1, + "versionNonce": 1264, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + 0.0, + 253 + ], + [ + 210.0, + 253 + ], + [ + 209.5, + 398 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "cx_lc_lung_h", + "x": 299.5, + "y": 550, + "width": 0, + "height": 0, + "strokeColor": "#be123c", + "backgroundColor": "#be123c", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1265, + "version": 1, + "versionNonce": 1266, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + -8.0151247615878, + -13.02771564995885 + ], + [ + 8.104779400979169, + -12.972129773536267 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "cx_lc_lung_bg", + "x": 161.8, + "y": 390, + "width": 66.4, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1267, + "version": 1, + "versionNonce": 1268, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "text", + "id": "cx_lc_lung_l", + "x": 166.8, + "y": 393, + "width": 56.4, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1269, + "version": 1, + "versionNonce": 1270, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "scoped to", + "originalText": "scoped to", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "cx_pe_pspace", + "x": 708.0, + "y": 152, + "width": 0.0, + "height": 328, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 3, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1271, + "version": 1, + "versionNonce": 1272, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + 0.0, + 328 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "cx_pe_pspace_h", + "x": 708.0, + "y": 480, + "width": 0, + "height": 0, + "strokeColor": "#be123c", + "backgroundColor": "#be123c", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1273, + "version": 1, + "versionNonce": 1274, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + -8.059999999999945, + -13.0 + ], + [ + 8.059999999999945, + -13.0 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "cx_pe_pspace_bg", + "x": 714.8, + "y": 283, + "width": 66.4, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#f8fafc", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1275, + "version": 1, + "versionNonce": 1276, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "text", + "id": "cx_pe_pspace_l", + "x": 719.8, + "y": 286, + "width": 56.4, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1277, + "version": 1, + "versionNonce": 1278, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "scoped to", + "originalText": "scoped to", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "cx_ctchest_thorax", + "x": 319.5, + "y": 920, + "width": -159.5, + "height": -419.0, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 3, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1279, + "version": 1, + "versionNonce": 1280, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + 0.0, + -74 + ], + [ + -219.5, + -74 + ], + [ + -219.5, + -419 + ], + [ + -159.5, + -419.0 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "cx_ctchest_thorax_h", + "x": 160, + "y": 501.0, + "width": 0, + "height": 0, + "strokeColor": "#be123c", + "backgroundColor": "#be123c", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1281, + "version": 1, + "versionNonce": 1282, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + -13.0, + 8.060000000000002 + ], + [ + -13.0, + -8.060000000000002 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "cx_ctchest_thorax_bg", + "x": 41.85, + "y": 811, + "width": 48.3, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1283, + "version": 1, + "versionNonce": 1284, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "text", + "id": "cx_ctchest_thorax_l", + "x": 46.85, + "y": 814, + "width": 38.3, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1285, + "version": 1, + "versionNonce": 1286, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "covers", + "originalText": "covers", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "cx_ctchest_lung", + "x": 354.0, + "y": 920, + "width": -59.69999999999999, + "height": -328, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 3, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1287, + "version": 1, + "versionNonce": 1288, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + 0.0, + -52 + ], + [ + -236.0, + -52 + ], + [ + -236.0, + -190 + ], + [ + -60.0, + -190 + ], + [ + -59.69999999999999, + -328 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "cx_ctchest_lung_h", + "x": 294.3, + "y": 592, + "width": 0, + "height": 0, + "strokeColor": "#be123c", + "backgroundColor": "#be123c", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1289, + "version": 1, + "versionNonce": 1290, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + 8.031720151912396, + 13.017490979500053 + ], + [ + -8.08824175748532, + 12.982447584044849 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "cx_ctchest_lung_bg", + "x": 130.8, + "y": 811, + "width": 58.4, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1291, + "version": 1, + "versionNonce": 1292, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "text", + "id": "cx_ctchest_lung_l", + "x": 135.8, + "y": 814, + "width": 48.4, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1293, + "version": 1, + "versionNonce": 1294, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "included", + "originalText": "included", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "cx_ctchest_abdomen", + "x": 480.5, + "y": 920, + "width": 354.0, + "height": -398, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1295, + "version": 1, + "versionNonce": 1296, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + 0.0, + -74 + ], + [ + 354.0, + -74 + ], + [ + 354.0, + -398 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "cx_ctchest_abdomen_h", + "x": 834.5, + "y": 522, + "width": 0, + "height": 0, + "strokeColor": "#be123c", + "backgroundColor": "#be123c", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1297, + "version": 1, + "versionNonce": 1298, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + 8.059999999999945, + 13.0 + ], + [ + -8.059999999999945, + 13.0 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "cx_ctchest_abdomen_bg", + "x": 788.65, + "y": 680, + "width": 91.7, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#f8fafc", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1299, + "version": 1, + "versionNonce": 1300, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "text", + "id": "cx_ctchest_abdomen_l", + "x": 793.65, + "y": 683, + "width": 81.7, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1301, + "version": 1, + "versionNonce": 1302, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "edge (usually)", + "originalText": "edge (usually)", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "cx_pn_ctchest", + "x": 272, + "y": 154.0, + "width": 13, + "height": 796.0, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 3, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1303, + "version": 1, + "versionNonce": 1304, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 0, + 12.0 + ], + [ + -264, + 12.0 + ], + [ + -264, + 796.0 + ], + [ + 13, + 796.0 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "cx_pn_ctchest_h", + "x": 285, + "y": 950.0, + "width": 0, + "height": 0, + "strokeColor": "#be123c", + "backgroundColor": "#be123c", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1305, + "version": 1, + "versionNonce": 1306, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + -13.0, + 8.059999999999945 + ], + [ + -13.0, + -8.059999999999945 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "cx_pn_ctchest_bg", + "x": 19.85, + "y": 589, + "width": 56.3, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#f8fafc", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1307, + "version": 1, + "versionNonce": 1308, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "text", + "id": "cx_pn_ctchest_l", + "x": 24.85, + "y": 592, + "width": 46.3, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1309, + "version": 1, + "versionNonce": 1310, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "seen on", + "originalText": "seen on", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "cx_pn_ctspine", + "x": 418, + "y": 154.0, + "width": 437.0, + "height": 856.0, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1311, + "version": 1, + "versionNonce": 1312, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 0, + 36.0 + ], + [ + 494, + 36.0 + ], + [ + 494, + 796.0 + ], + [ + 437, + 796.0 + ], + [ + 437.0, + 856.0 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "cx_pn_ctspine_h", + "x": 855.0, + "y": 1010, + "width": 0, + "height": 0, + "strokeColor": "#be123c", + "backgroundColor": "#be123c", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1313, + "version": 1, + "versionNonce": 1314, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + -8.059999999999945, + -13.0 + ], + [ + 8.059999999999945, + -13.0 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "cx_pn_ctspine_bg", + "x": 818.6, + "y": 389, + "width": 106.8, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1315, + "version": 1, + "versionNonce": 1316, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "text", + "id": "cx_pn_ctspine_l", + "x": 823.6, + "y": 392, + "width": 96.8, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1317, + "version": 1, + "versionNonce": 1318, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "possibly seen on", + "originalText": "possibly seen on", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "legA0", + "x": 24, + "y": 1244, + "width": 22, + "height": 16, + "strokeColor": "#059669", + "backgroundColor": "#d1fae5", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1319, + "version": 1, + "versionNonce": 1320, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "legA0_l", + "x": 56, + "y": 1243, + "width": 340, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1321, + "version": 1, + "versionNonce": 1322, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "finding", + "originalText": "finding", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "legA1", + "x": 24, + "y": 1272, + "width": 22, + "height": 16, + "strokeColor": "#059669", + "backgroundColor": "#6ee7b7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1323, + "version": 1, + "versionNonce": 1324, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "legA1_l", + "x": 56, + "y": 1271, + "width": 340, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1325, + "version": 1, + "versionNonce": 1326, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "diagnosis", + "originalText": "diagnosis", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "ellipse", + "id": "legA2", + "x": 24, + "y": 1299, + "width": 24, + "height": 18, + "strokeColor": "#7e22ce", + "backgroundColor": "#e9d5ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1327, + "version": 1, + "versionNonce": 1328, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "text", + "id": "legA2_l", + "x": 56, + "y": 1299, + "width": 340, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1329, + "version": 1, + "versionNonce": 1330, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "assessment scheme", + "originalText": "assessment scheme", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "legA3", + "x": 24, + "y": 1328, + "width": 22, + "height": 16, + "strokeColor": "#1d4ed8", + "backgroundColor": "#bfdbfe", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1331, + "version": 1, + "versionNonce": 1332, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "legA3_l", + "x": 56, + "y": 1327, + "width": 340, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1333, + "version": 1, + "versionNonce": 1334, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "anatomic location", + "originalText": "anatomic location", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "legA4", + "x": 24, + "y": 1356, + "width": 22, + "height": 16, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1335, + "version": 1, + "versionNonce": 1336, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "legA4_l", + "x": 56, + "y": 1355, + "width": 340, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1337, + "version": 1, + "versionNonce": 1338, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "exam type", + "originalText": "exam type", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "ellipse", + "id": "legB0", + "x": 479, + "y": 1243, + "width": 18, + "height": 18, + "strokeColor": "#9ca3af", + "backgroundColor": "#e5e7eb", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1339, + "version": 1, + "versionNonce": 1340, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "text", + "id": "legB0_l", + "x": 517, + "y": 1243, + "width": 340, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1341, + "version": 1, + "versionNonce": 1342, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "unlabeled grey = further nodes not shown", + "originalText": "unlabeled grey = further nodes not shown", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "legB1", + "x": 477, + "y": 1280, + "width": 30, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1343, + "version": 1, + "versionNonce": 1344, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 30, + 0 + ] + ] + }, + { + "type": "text", + "id": "legB1_l", + "x": 517, + "y": 1271, + "width": 340, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1345, + "version": 1, + "versionNonce": 1346, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "solid edge = within-sector relationship", + "originalText": "solid edge = within-sector relationship", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "legB2", + "x": 477, + "y": 1308, + "width": 30, + "height": 0, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 3, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1347, + "version": 1, + "versionNonce": 1348, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 30, + 0 + ] + ] + }, + { + "type": "text", + "id": "legB2_l", + "x": 517, + "y": 1299, + "width": 340, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1349, + "version": 1, + "versionNonce": 1350, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "colored thick edge = cross-sector relationship", + "originalText": "colored thick edge = cross-sector relationship", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "legB3", + "x": 477, + "y": 1336, + "width": 30, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1351, + "version": 1, + "versionNonce": 1352, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 30, + 0 + ] + ] + }, + { + "type": "text", + "id": "legB3_l", + "x": 517, + "y": 1327, + "width": 340, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1353, + "version": 1, + "versionNonce": 1354, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "dashed = possible or planned", + "originalText": "dashed = possible or planned", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + } + ], + "appState": { + "viewBackgroundColor": "#ffffff", + "gridSize": null + }, + "files": {} +} \ No newline at end of file diff --git a/knowledge/drafts/foundation-network.svg b/knowledge/drafts/foundation-network.svg new file mode 100644 index 0000000..3fed815 --- /dev/null +++ b/knowledge/drafts/foundation-network.svg @@ -0,0 +1,2 @@ +Foundation Context: a mini-networkthree sectors of shared, curated knowledge — illustrative, not exhaustiveSector 1 — Finding / diagnosis definitionsSector 2 — Anatomic locationsSector 3 — Exam types(content to come)Legendlung cancerpulmonarynoduleLung-RADSpleural effusionsolidpulmonarynodulepart-solidpulmonarynodulenon-solidpulmonarynodulesolid componentsubtype ofsubtype ofsubtype ofhas componentmay manifest asmay progress toassessed bythoraxpleuralspaceupper abdomenright lunglungleft lungupper lobe ofright lunglungparenchymacontained bylateralitypart ofcontained byCT Chestpreferred (to come)CT Chest WO contrast29252-4CT Chest W contrast IV24628-0CT Chest WO and W contrast IV30598-7CTA Chest vesselsWO and W contrast IV30804-9CT Thoracic spineW contrast IV24979-7Region imaged:Thorax (RID1243)member of familyPlaybook partscoped toscoped toscoped tocoversincludededge (usually)seen onpossibly seen onfindingdiagnosisassessment schemeanatomic locationexam typeunlabeled grey = further nodes not shownsolid edge = within-sector relationshipcolored thick edge = cross-sector relationshipdashed = possible or planned \ No newline at end of file diff --git a/knowledge/drafts/index.md b/knowledge/drafts/index.md new file mode 100644 index 0000000..f93f7df --- /dev/null +++ b/knowledge/drafts/index.md @@ -0,0 +1,20 @@ +# Drafts: the restructured pages + +Staging area for the restructure agreed on 2026-09-22 (see `docs/plans/restructure-joint-notes.md`). Each pillar's anchor page is drafted here beside the current pages, which stay in place until cross-review. After review, each anchor becomes the `index.md` of its own pillar directory with child sections beside it, and this directory is removed. + +Planned files, each session adding its link line when the file exists: + +* [Introduction](./introduction.md) - What the Open Imaging Data Model is, the two contexts it distinguishes, the five pillars of the work, and how the project expects agreement to happen. +* [Foundation Context](./foundation-context.md) - The shared, curated clinical knowledge that every patient's imaging data is woven into: three axes over existing standards, the relationships among them, and the citations they rest on. +* [Finding Models and Common Data Elements](./finding-models-and-cdes-hub.md) - Definitions of findings and diagnoses as the anchor for everything the project knows about them, held in two cross-linked collections: the beta channel and the release channel. +* [Finding models and CDEs](./finding-models-and-cdes.md) - One content in two collections - the common graph being drafted for both, the OIFM and RadElement formats that hold it today, what the inclusive collection contains, and the authoring and review principles behind it. +* [Anatomic locations](./anatomic-locations.md) - The curated anatomic location index as a reference layer - identity, containment, part-of, laterality, synthetic terms, curation rules, the RadLex overlay, and the two dated implementations. +* [Exam types](./exam-types.md) - A stated goal with no artifact - preferred high-level exam entries over the LOINC/RSNA Radiology Playbook, the Playbook properties they would expose, and the anatomy coverage edges in the project lead's two dated phrasings. +* [The next-generation schema](./next-generation-schema.md) - The graph-based schema being developed in the ACR/RSNA CDE project that both collections of finding/diagnosis definitions will move onto: its node types, its edges, and the relationships among definitions. +* [Relationships among definitions](./relationships.md) - The typed relationships among finding/diagnosis definitions: manifestation and causation, associated findings and components, how strongly a relationship holds, deriving the differential, assessment schemes, and a proposal for role tagging. +* [Standards the foundation layers over](./standards.md) - Which existing standard each Foundation Context axis layers over, the role each terminology plays, the external citations the deck names, and search recall as the gate. +* [SDKs](./sdks.md) - The tools that wrap the data structures and resolve their codes into Foundation Context, plus the libraries that help author that context. +* [Data Structures](./data-structures.md) - Observations connect a patient's imaging results to shared definitions and to one another across reports and examinations. +* [Use Cases](./use-cases.md) - Proposed reporting assistance, longitudinal care, outcome tracking, and information products built on OIDM context and structures. +* [Sample Applications](./sample-applications.md) - Applications that author shared definitions, display imaging histories, extract and review findings, and demonstrate structured exchange. +* [Overview](./overview.md) - What the Open Imaging Data Model is for, the two contexts it separates, its core pieces, what it is used for, what has been built, and where it stands. diff --git a/knowledge/drafts/introduction.md b/knowledge/drafts/introduction.md new file mode 100644 index 0000000..8f2d4db --- /dev/null +++ b/knowledge/drafts/introduction.md @@ -0,0 +1,110 @@ +--- +type: Overview +title: Introduction +description: What the Open Imaging Data Model is, the two contexts it distinguishes, the five pillars of the work, and how the project expects agreement to happen. +tags: [overview, orientation, foundation-context, patient-context] +status: draft +generated: { by: claude-opus-5/2026-09-22-restructure/draft-intro, at: 2026-09-22T12:53:46Z } +sources: + - id: owner-notes + resource: Project lead's notes on the revised Imaging Problem List manuscript, 2026-09-19, sources/email/2026-09-19-ipl-manuscript-notes.md + title: Structures versus transport, and what OIDM defines, 2026-09-19 + - id: siim-deck + resource: https://oidm-public.t3.tigrisfiles.io/oidm-knowledge-sources/SIIM%202026%20Reports-of-the-Future.pptx + title: "Structured Results and Context for Next-Generation Imaging Resulting Tools, SIIM 2026 annual meeting talk, June 2026, Mass General Brigham" + - id: cde-two-planes + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/docs/next-gen-schema/03-draft-structures.md + title: "Next-generation Common Data Element draft structures, section 5, two planes, snapshot 2026-09-15" + - id: jan-deck + resource: https://gamma.app/docs/Open-Imaging-Data-Model-2026-Status-Update:-Realizing-Object-Oriented-Imaging-Results-yfxzx4q9zssafal + title: Open Imaging Data Model 2026 Status Update, January 2026 + - id: site-about + resource: https://www.openimagingdata.org/ + title: openimagingdata.org, project site and tagline + - id: site-findings + resource: https://www.openimagingdata.org/findings-cdes-and-observations/ + title: "Findings, CDEs, and Observations, 2023-06-24" + - id: site-data-model + resource: https://www.openimagingdata.org/data-model-structure-and-function/ + title: "Data Model: Structure and Function, 2024-01-25" + - id: site-benchmarking + resource: https://www.openimagingdata.org/benchmarking-a-vision/ + title: "Benchmarking a Vision, 2024-07-01" + - id: joint-notes + resource: docs/plans/restructure-joint-notes.md + title: Restructure joint working notes, the project lead's decisions of 2026-09-22 + - id: build-plan + resource: knowledge/plans/2026-09-20-knowledgebase-build-plan.md + title: Knowledgebase build plan, decisions added 2026-09-21 +--- + +# What OIDM is + +The Open Imaging Data Model (OIDM) defines, in the project lead's words of 2026-09-19, "a system of defined data structures for representing imaging exam result information", "intended to be used within applications to both read and create result data".[^owner-notes] The project site states the purpose as "defining unified data structures to integrate new functionality into imaging informatics platforms". The January 2026 status update titles the goal "Realizing Object-Oriented Imaging Results" and calls it "standardizing the DNA of imaging IT".[^site-about][^jan-deck] + +The June 2026 talk states why the result should be data. A finished report "is where the value should begin": a report's findings are written for a human reader, then locked in narrative text. Structuring them makes them reusable in two directions — forward to clinicians, "driving treatment decisions, follow-up, and care coordination", and forward to the next radiologist reading the subsequent exam, "what was there before, where, and whether it changed".[^siim-deck] + +That talk was given from Mass General Brigham. The finding definitions the model points at exist in two collections: the inclusive collection the Open Imaging Data Model organization maintains on GitHub, and the well-reviewed Common Data Element collection of the American College of Radiology and the Radiological Society of North America. The January 2026 update describes the first as a "workbench", a "proving ground before ACR/RSNA CDE adoption".[^jan-deck][^joint-notes] + +# The two contexts + +The June 2026 talk names the two halves that next-generation tools need: "the structured result, and the knowledge to interpret it."[^siim-deck] + +| | Patient Context | Foundation Context | +|---|---|---| +| Scope | One per patient | One layer shared by every patient | +| Contents | Observations, Exam Finding List, Imaging Problem List | Definitions, relationships, citations | +| How it changes | With the patient's clinical evolution | By open authoring and versioning | +| Privacy | Protected health information | Open, not patient-specific | +| Example | "8 mm nodule, RUL, new" | "what a pulmonary nodule is" | + +The two are joined by their codes. The talk presents Foundation Context as three curated axes — what was found, where it is, how it was seen — and states the join: "A code on an Observation is a pointer into one of these axes — the axes also point to each other, and out to external references."[^siim-deck] (The deck's tentative name for the first axis is "Observation Type"; its notes say the ACR/RSNA elements "may carry" that name later.) The relationships on each side are different in kind. Between definitions, a relationship is a standing possibility, as in the talk's worked figure where a radiodense urinary calculus "may cause" hydronephrosis.[^siim-deck] Between observations, a relationship is what this radiologist asserted about these particular observations on this exam. The next-generation Common Data Element draft states that separation, and the project lead recorded it as a decision on 2026-09-02: "consistent with" is "radiologist-talk for 'I'm putting THESE findings together as THIS diagnosis'", and "it's NOT the same relationship" the abstract ideas hold in definition space.[^cde-two-planes] [Data Structures](./data-structures.md) explains the two graphs and how they work together; this page only previews them. + +# What a structured Observation cannot answer + +The talk's pivot is that "the structures identify — but they don't explain." A structured Observation, "pulmonary nodule, present", says it exists, where, and on what exam. It does not say:[^siim-deck] + +- How does it associate with other findings? +- How is it potentially precancerous? +- Which prior exams could show it? +- What are the implications? +- What else could it be? + +"Answering these needs background knowledge of anatomy, pathology, and imaging technique — knowledge that isn't in the patient's record."[^siim-deck] That is the stated motivation for Foundation Context. + +# The five pillars + +The project lead named five parts of the work on 2026-09-22, to be used by name.[^joint-notes] + +- **[Foundation Context](./foundation-context.md)**, the semantic layer, "includes both the schema/meta-definitions as well as the efforts to build out content." +- **[Data Structures](./data-structures.md)**, "most ESPECIALLY in the Observation layer, and how there are two graphs and they work together." +- **[SDKs](./sdks.md)**, "the tools that wrap the data structures and enable developers working in the application layer to manipulate instances in real-world applications (and some around helping with definition of the foundation context, obviously)." +- **[Use Cases](./use-cases.md)**, "Imaging all the different kinds of applications/tools/plugins/output products we could create using an ecosystem built around this foundation." +- **[Sample Applications](./sample-applications.md)**, "ACTUAL sample applications we've created to try to illustrate some of these ideas." + +# Structure first, transport after + +The structures are defined for use inside applications, and are not a transport definition. The project lead's 2026-09-19 notes state that they are "NOT a transport definition (not FHIR, not DICOM)", that they may eventually need FHIR expressions to travel, and that designing for that possibility is "completely separate from the definition of the structures applications manipulate". The stated reason to agree on the structures is that agreed structures make it easier to agree on what must be conveyed between systems, and that they guide the design of the FHIR profiles and related artifacts that inter-process communication will need.[^owner-notes] The January 2026 call to action puts the same ordering as "structure-first (then FHIR etc.)".[^jan-deck] + +Earlier project statements describe the relationship to FHIR in their own terms, set out here by date rather than reconciled. The founding site post of 2023-06-24 represents a finding as a FHIR Observation labeled with Common Data Element identifiers.[^site-findings] The 2024-01-25 post proposes structures over FHIR definitions for programmatic access and distinguishes the two by analogy: "the relationship between OIDM and FHIR might be that between the browser's DOM and HTML."[^site-data-model] The 2024-07-01 post announces a manuscript describing a CDE-encoded FHIR Observation framework, and states its claim that "CDE-labeled Observations should be the universal representation for exchanging and consuming content in radiology reports".[^site-benchmarking] [Data Structures](./data-structures.md) carries the current mapping status. + +# Nothing is formally defined yet + +The project is in a coalescing phase, and nothing is formally defined. This knowledgebase presents each source's current version of a structure beside the others, dated and attributed, and states disagreements without resolving them. No source here is called the specification or the canonical model.[^build-plan] + +How agreement is meant to happen is itself a proposal. The January 2026 call to action names an ACR-OIDM Structured Imaging Results Working Group, co-hosted with the American College of Radiology, "vendor-driven", with next steps to "host/moderate academic-vendor big tent; use-case pipeline -> CDE group; standardize the result". It names ACR priorities as recommendation tracking, AI validation, quality metrics, and *-RADS support.[^jan-deck] No source read records the working group as convened. + +# The ask + +The June 2026 talk closes with three requests: contribute or propose finding definitions (the talk's wording is "Observation Type definitions"); review AI-generated content and connections; build against the SDKs.[^siim-deck] + +[^owner-notes]: The project lead, 2026-09-19, points 3, 4, and 5 of the notes on the revised Imaging Problem List manuscript. Held in the local source collection. +[^siim-deck]: SIIM 2026 annual meeting talk, June 2026, Mass General Brigham; slides 1, 3, 6, 7, 8, 12, 14, and 15 with their speaker notes. +[^cde-two-planes]: [Draft structures, section 5](https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/docs/next-gen-schema/03-draft-structures.md#5-two-planes-reports-point-into-the-vocabulary), snapshot 2026-09-15, with row S21 of the [decision record of 2026-09-02](https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/docs/next-gen-schema/10-decision-record-2026-09-02.md), which records the quoted wording as the project lead's. +[^jan-deck]: Open Imaging Data Model 2026 Status Update, January 2026: executive summary, strategic pillars, the CDE workbench section, and the call to action. +[^site-about]: openimagingdata.org, project site tagline, read 2026-09-21. +[^site-findings]: "Findings, CDEs, and Observations", openimagingdata.org, 2023-06-24. +[^site-data-model]: "Data Model: Structure and Function", openimagingdata.org, 2024-01-25. +[^site-benchmarking]: "Benchmarking a Vision", openimagingdata.org, 2024-07-01. +[^joint-notes]: Restructure joint working notes, "Decisions of 2026-09-22", items 1 and 2, quoting the project lead. +[^build-plan]: Knowledgebase build plan, "Decisions added 2026-09-21", the "No specification exists" row. diff --git a/knowledge/drafts/next-gen-findingclass-neighborhood.svg b/knowledge/drafts/next-gen-findingclass-neighborhood.svg new file mode 100644 index 0000000..1038928 --- /dev/null +++ b/knowledge/drafts/next-gen-findingclass-neighborhood.svg @@ -0,0 +1 @@ +FINDING CLASSpulmonary noduleA rounded or oval opacity within the lung parenchyma measuring less than 30 mm.synonyms: lung nodule · SPN (abbreviation) · pulmonary node (deprecated)RDE2_000123 · v1 · proposed · 2026-08-19entity_type: findingSUBTYPE_OF — is anoduleFindingClassSCOPED_TO — anatomic scopelungAnatomicLocation · RID1301structure · requiredHAS_ELEMENT — characterized by · ×4presence→ existing element RDE2_000001 · shared · categoricalpresentpossibleabsentindeterminateunknownattenuationdefined here as RDE2_000015 · DataElement · categoricalAttenuation class of the nodule on CT, per Fleischner usage.drives managementsolidpart-solidground-glasssize (mean diameter)→ existing element RDE2_000014 · shared · lengthmargindefined here as RDE2_000031 · DataElement · categoricalCharacter of the nodule's interface with surrounding lung.smoothlobulatedspiculatedill-definedMAY_REPRESENT — may representlung cancerFindingClass · diagnosisASSESSED_BY — assessed byFleischner recommendationFindingClass · assessment - incidentalLung-RADS categoryFindingClass · assessment - screeningMAY_HAVE_COMPONENT — may have componentsolid componentFindingClass · finding - sub-finding of a part-solid nodule, with its own sizeCONTEXT — discoverability edgesneoplastic : benignHAS_ETIOLOGY · Etiologyneoplastic : malignantHAS_ETIOLOGY · Etiologyinflammatory : infectiousHAS_ETIOLOGY · EtiologycongenitalHAS_ETIOLOGY · EtiologyCTSEEN_ON · ModalityXRSEEN_ON · ModalitychestIN_REGION · BodyRegionchest radiologyIN_SUBSPECIALTY · Subspecialtysex-neutralSEX · SexSpecificityall agesAGE_APPLICABILITY · AgeProfileyears - progressive or stableTIME_COURSE · ExpectedTimeCourseMAPPINGS — skos:exactMatch / closeMatchpulmonary noduleRADLEX RID50149 · skos:exactMatchSolitary nodule of lung (finding)SNOMEDCT 427359005 · skos:exactMatch diff --git a/knowledge/drafts/next-generation-schema.md b/knowledge/drafts/next-generation-schema.md new file mode 100644 index 0000000..2225dc2 --- /dev/null +++ b/knowledge/drafts/next-generation-schema.md @@ -0,0 +1,160 @@ +--- +type: Concept +title: The next-generation schema +description: "The graph-based schema being developed in the ACR/RSNA CDE project that both collections of finding/diagnosis definitions will move onto: its node types, its edges, and the relationships among definitions." +tags: [foundation-context, next-gen-schema, finding-models, cdes, relationships, graph] +status: draft +generated: { by: claude-opus-5/2026-09-30-restructure/schema-page, at: 2026-09-30T13:51:40Z } +sources: + - id: lead-schema + resource: docs/plans/2026-09-22-layout-plan.md + title: The project lead's statements of 2026-09-29 and 2026-09-30 on this page - the two collections moving onto one schema, the common SDK, the "defines" wording for each node type, the Concept note, the anatomic scope sentence, the Edges paragraph, the kinds of quantity a Measurement indicates, and the whole Evolution section (recorded verbatim in the layout plan) + last_modified: 2026-09-30 + - id: lead-2026-09-22 + resource: docs/plans/restructure-joint-notes.md + title: The project lead's decisions of 2026-09-22 - a Common Data Element and a finding model are the same content, both collections soon using the classes being defined in the CDE schema rewrite, and the urgent move off document orientation (quoted in the restructure joint notes) + last_modified: 2026-09-22 + - id: cde-branch + resource: https://github.com/RSNA/ACR-RSNA-CDEs/tree/b541b74c22a33b64834309244569a60d06de79e4 + title: The ACR/RSNA CDE schema repository, next-gen-2026 branch at b541b74 - the branch of record for the next-generation schema work, read at this commit on 2026-09-30 + last_modified: 2026-09-23 + - id: table-check + resource: https://github.com/RSNA/ACR-RSNA-CDEs/tree/b541b74c22a33b64834309244569a60d06de79e4/docs/next-gen-schema + title: The next-generation schema working directory, ACR-RSNA-CDEs next-gen-2026 at b541b74 - the relationship type declarations and the example edges checked one by one for the table on this page + last_modified: 2026-09-23 + - id: cde-understanding + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/b541b74c22a33b64834309244569a60d06de79e4/docs/next-gen-schema/00-current-understanding.md + title: "Next-Generation CDE Schema: Current Understanding, ACR-RSNA-CDEs next-gen-2026 at b541b74 - the knowledge graph rather than a document tree as the internal representation" + last_modified: 2026-09-15 + - id: cde-requirements + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/b541b74c22a33b64834309244569a60d06de79e4/docs/next-gen-schema/01-what-the-vocabulary-must-express.md + title: What the Vocabulary Must Express, ACR-RSNA-CDEs next-gen-2026 at b541b74 - what a FindingClass is, anatomic scope, and measurement versus interpretation + last_modified: 2026-09-15 + - id: cde-structures + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/b541b74c22a33b64834309244569a60d06de79e4/docs/next-gen-schema/03-draft-structures.md + title: Draft Structures for Worked Examples, ACR-RSNA-CDEs next-gen-2026 at b541b74 - the node type table, the edge catalog, and the object view of a FindingClass as its gathered edges + last_modified: 2026-09-15 + - id: cde-relationships + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/b541b74c22a33b64834309244569a60d06de79e4/docs/next-gen-schema/07-relationship-family.md + title: The Finding and Diagnosis Relationship Family, ACR-RSNA-CDEs next-gen-2026 at b541b74 - the catalog of relationships with their domains, ranges, inverses, symmetry, and the typicality and specificity properties + last_modified: 2026-09-09 + - id: cde-worked-examples + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/b541b74c22a33b64834309244569a60d06de79e4/docs/next-gen-schema/08-worked-examples.md + title: Worked Examples, Acute Pyelonephritis, Pleural Effusion, and One Report, ACR-RSNA-CDEs next-gen-2026 at b541b74 + last_modified: 2026-09-09 + - id: cde-decisions + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/b541b74c22a33b64834309244569a60d06de79e4/docs/next-gen-schema/10-decision-record-2026-09-02.md + title: The decision record, ACR-RSNA-CDEs next-gen-2026 at b541b74 - every structural decision with a provenance mark, OWNER for what the project lead stated and CLAUDE DEFAULT for what an assistant chose to keep moving and the project lead has not reviewed + last_modified: 2026-09-23 + - id: cde-anatomy + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/b541b74c22a33b64834309244569a60d06de79e4/docs/next-gen-schema/11-anatomy-axis.md + title: The Anatomy Axis, Current State, ACR-RSNA-CDEs next-gen-2026 at b541b74 - the anatomic locations data as the substrate, keyed by RadLex id, and what it lacks + last_modified: 2026-09-15 + - id: cde-graph + resource: https://github.com/RSNA/ACR-RSNA-CDEs/tree/b541b74c22a33b64834309244569a60d06de79e4/docs/next-gen-schema/graph + title: "The vocabulary written as JSON Lines, ACR-RSNA-CDEs next-gen-2026 at b541b74: core.jsonl declares each relationship type with its inverse, symmetry, domain, and range; pyelonephritis.jsonl and pleural-effusion.jsonl hold the two worked families" + last_modified: 2026-09-09 + - id: cde-alpha-graph + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/b541b74c22a33b64834309244569a60d06de79e4/docs/next-gen-schema/alpha/graph/definition-graph.json + title: "The reviewer's alpha definition graph, ACR-RSNA-CDEs next-gen-2026 at b541b74: 45 FindingClass, 25 Diagnosis, 36 DataElement, 16 Measurement, 5 AssessmentScheme and 28 AnatomicLocation nodes with their typed edges, the implementation approach the project lead adopted as the basis going forward" + last_modified: 2026-09-14 + - id: cde-alpha-shape + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/b541b74c22a33b64834309244569a60d06de79e4/docs/next-gen-schema/alpha/SHAPE.md + title: "The alpha's generated node and edge documentation, ACR-RSNA-CDEs next-gen-2026 at b541b74: §4 tabulates each edge's signature and states that signatures are the endpoint types observed in the build, not everything the edge is permitted to take" + last_modified: 2026-09-14 + - id: cde-alpha-readme + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/b541b74c22a33b64834309244569a60d06de79e4/docs/next-gen-schema/alpha/README.md + title: "The alpha's own README, ACR-RSNA-CDEs next-gen-2026 at b541b74: the anatomy architecture that treats RadLex as the single source of truth, the list of generated artifacts, and the reasoner regression suite" + last_modified: 2026-09-14 + - id: cde-libraries-plan + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/b541b74c22a33b64834309244569a60d06de79e4/docs/plans/2026-09-13-definition-libraries.md + title: "Plan: typed definition libraries (Python, then TypeScript) over a PostgreSQL copy of the graph, ACR-RSNA-CDEs next-gen-2026 at b541b74 - proposed 2026-09-13, with a note of 2026-09-15 reconciling it toward the alpha" + last_modified: 2026-09-15 + - id: cde-fc-diagram + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/b541b74c22a33b64834309244569a60d06de79e4/docs/next-gen-schema/diagrams/fc-neighborhood.svg + title: The pulmonary nodule FindingClass and its typed edges, ACR-RSNA-CDEs next-gen-2026 at b541b74 - reused here with the project lead's agreement + last_modified: 2026-09-03 + - id: cde-fc-diagram-input + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/b541b74c22a33b64834309244569a60d06de79e4/docs/next-gen-schema/examples/pulmonary-nodule.neighborhood.json + title: The pulmonary nodule neighborhood example, ACR-RSNA-CDEs next-gen-2026 at b541b74 - the input the figure above is rendered from by the repository's tools/render_neighborhood.py at the same commit + last_modified: 2026-09-03 + - id: cde-schema + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/b541b74c22a33b64834309244569a60d06de79e4/cde.schema.json + title: The current Common Data Element schema, ACR-RSNA-CDEs next-gen-2026 at b541b74 - a JSON Schema whose root is a nested element_set document + last_modified: 2024-11-19 + - id: oifm-repo + resource: https://github.com/openimagingdata/findingmodels/tree/4475ac1bcb591f1a0951b2082b59208def173a5d + title: "Open Imaging Finding Models repository, main at 4475ac1 (snapshot of 2026-04-28): the JSON Schema for a single self-contained finding model and the 2,382 per-definition files under defs/" + last_modified: 2026-04-28 + - id: siim-2026 + resource: https://oidm-public.t3.tigrisfiles.io/oidm-knowledge-sources/SIIM%202026%20Reports-of-the-Future.pptx + title: Structured Results and Context for Next-Generation Imaging Resulting Tools, SIIM 2026 annual meeting talk, June 2026, Mass General Brigham - slide 12 on relationships and external citations + last_modified: 2026-06-11 +--- + +# The next-generation schema + +Both Open Imaging Finding Models and ACR/RSNA Common Data Elements are moving onto one schema, being developed in the [ACR/RSNA CDE schema repository](https://github.com/RSNA/ACR-RSNA-CDEs/tree/next-gen-2026) on its next-gen-2026 branch, as a graph of interconnected concepts rather than a set of documents.[^lead-schema][^lead-2026-09-22][^cde-understanding] Applications will be able to use either or both collections at once via a common SDK based on the new schema.[^lead-schema][^cde-libraries-plan] What follows is the design as it stands on that branch, dated to the commit read.[^cde-branch] It is working material, and it carries the project's own provenance labels: decisions the project lead made, and defaults an assistant chose to keep moving that remain unreviewed.[^cde-decisions] + +# Node types + +- **FindingClass** defines the properties of the items described in imaging reports.[^lead-schema][^cde-structures][^cde-requirements] +- **Diagnosis** is a separate, closely related node type, distinguished by a different set of possible relationships.[^lead-schema][^cde-structures][^cde-relationships] +- **Grouping** defines broad classes of findings/diagnoses such as "renal abnormality", usually intended to be used in the negative.[^lead-schema][^cde-decisions][^cde-structures] +- **DataElement** defines a categorical descriptor: a value set, ordered or unordered, whose values are themselves shared nodes.[^cde-decisions][^cde-structures] +- **Measurement** defines a quantitative descriptor by the kind of quantity, such as length or CT density, with the unit family following from the kind.[^lead-schema][^cde-decisions][^cde-alpha-graph] +- **AssessmentScheme** definitions lay out the systems, such as Lung-RADS, via which a constellation of other findings is evaluated.[^lead-schema][^cde-decisions][^cde-structures] +- **AnatomicLocation** nodes are the entries of the anatomic locations index, keyed by their RadLex identity.[^cde-anatomy][^cde-decisions] + +Beyond these, shared **Concept** nodes hold the standard clinical metadata a definition can carry: modality, body region, subspecialty, sex, age, time course, etiology.[^lead-schema][^cde-decisions][^cde-structures] And the anatomic scope property of each FindingClass, Diagnosis, Grouping, DataElement, and Measurement indicates the locations and/or structures in which they may be localized (e.g., "lung parenchyma" for a pulmonary nodule).[^lead-schema][^cde-decisions][^cde-alpha-graph][^cde-anatomy] + +# Edges + +Edges integrate the nodes into a rich fabric of interrelated concepts, enabling reliable, reproducible inference.[^lead-schema][^cde-understanding][^cde-alpha-readme] Edges bind FindingClass and Diagnosis definitions to their anatomic scope and to the DataElements and Measurements used to specify their attributes.[^lead-schema][^cde-alpha-graph][^cde-structures] The edges themselves may contain properties that provide additional detail about the relationships between nodes: a binding may, for example, restrict a shared DataElement to a subset of its values for one FindingClass without changing the element itself.[^lead-schema][^cde-decisions][^cde-structures] No element is required by any definition.[^cde-decisions][^cde-structures][^table-check] + +| Relationship | From → to | Example | +|---|---|---| +| SUBTYPE_OF | each of FindingClass, Diagnosis, Grouping and AnatomicLocation → a node of its own kind | part-solid pulmonary nodule → pulmonary nodule | +| HAS_COMPONENT | FindingClass → FindingClass | part-solid pulmonary nodule → solid component | +| MAY_MANIFEST_AS | Diagnosis → FindingClass or Diagnosis | acute pyelonephritis → striated nephrogram | +| MAY_CAUSE | FindingClass or Diagnosis → FindingClass or Diagnosis | urinary calculus → hydronephrosis | +| MAY_PROGRESS_TO | FindingClass or Diagnosis → FindingClass or Diagnosis | parapneumonic effusion → empyema | +| OCCURS_WITH | FindingClass or Diagnosis ↔ FindingClass or Diagnosis | pleural effusion ↔ atelectasis | +| ASSESSED_BY | FindingClass or Diagnosis → AssessmentScheme | pulmonary nodule → Lung-RADS | +| SCOPED_TO | FindingClass, Diagnosis or Grouping → AnatomicLocation | pulmonary nodule → lung | +| SEEN_ON | FindingClass, Diagnosis or Grouping → Modality concept | pulmonary nodule → CT | +| HAS_DATA_ELEMENT, HAS_MEASUREMENT | FindingClass or Diagnosis → DataElement or Measurement | pulmonary nodule → presence; pulmonary nodule → mean diameter | + +[![The pulmonary nodule FindingClass and the typed edges it gathers: its parent class, its anatomic scope, the data elements that characterize it, the diagnosis it may represent, the assessment schemes that apply, its component, and its standard clinical metadata. Rendered from the pulmonary nodule neighborhood example in the ACR/RSNA CDE schema repository, next-gen-2026 at b541b74.](./next-gen-findingclass-neighborhood.svg)](./next-gen-findingclass-neighborhood.svg) + +(click the image for full size) + +*The diagram dates from 2026-09-03 and predates the separation of Measurement and AssessmentScheme into their own node types, so it still renders Lung-RADS and mean diameter as a FindingClass and a DataElement, and still writes the older edge names `HAS_ELEMENT` and `MAY_HAVE_COMPONENT`.*[^cde-fc-diagram][^cde-fc-diagram-input] + +The full family, with each relationship's inverse, symmetry, and provenance, is on the relationships page.[^cde-relationships][^cde-graph] + +# Evolution of CDEs and Finding Models + +Both CDEs and existing Open Imaging Finding Models will have to migrate from their current JSON document-based organization to a new graph-oriented format, likely using RDF/OWL as an underlying storage format.[^lead-schema][^lead-2026-09-22][^cde-schema][^oifm-repo][^cde-decisions] More ergonomic data structures will also be developed for use in SDKs and via an API.[^lead-schema][^cde-decisions][^cde-libraries-plan] + +[^lead-schema]: The project lead, 2026-09-29 and 2026-09-30, recorded verbatim in the layout plan. On this page: "Both Open Imaging FInding Models and RSNA/ACR Common Data Elements are moving..."; "Show a link to the ACR/RSNA CDE schema repository, on the next-gen-2026 branch"; "...as a graph of interconnected concepts rather than a set of documents."; "Applications will be able to use either or both collections at once via a common SDK based on the new schema."; the node-type wording, with the instruction that "For most of these node class definitions, we want to use 'defines' rather than 'is a' (this is a very tricky but important semantic distinction)"; "'AssessmentScheme' definitions layout the systems such as Lung-RADS via which a constellation of other findings is evaluated."; "The anatomic scope property of each other node indicates the locations and/or structures in which they may be localized (e.g., 'lung parenchyma' for a pulmonary nodule)."; "Edges integrate the notes into a rich fabric of interrelated concepts, enabling reliable, reproducible inference."; "Edges bind FindingClass and Diagnosis definitions to their anatomic scope and to the DataElements and Measurements used to specify their attributes. The edges themselves may contain properties that provide additional detail about the relationships between nodes."; "Concept nodes as a note below the list, introducing the paragraph that also talks about anatomic scope."; "Use the actual table of relationship types as examples."; and the whole Evolution section. On Measurements, 2026-09-29: "Measurements don't have EXPLICIT units, they indicate what KIND of thing they are: length (with appropriate length units, which could be mm, cm, whatever), CT density (HU), or count (unitless), ratio (unitless), velocity (m/s, cm/s), volume (cc, mL, mm^3..., L)". Two sentences on this page rest on this statement for what they actually promise. The repository has a proposed design for typed libraries and a query API, but nothing in it states that one SDK will consume both collections together, which is the project lead's own commitment.[^cde-libraries-plan] The repository puts inference in scope and has a reasoner regression suite, but neither establishes that inference over the vocabulary is reliable and reproducible today, which is the project lead's claim for the design.[^cde-understanding][^cde-alpha-readme] +[^lead-2026-09-22]: The project lead, 2026-09-22, quoted in the restructure joint notes: both collections "BOTH should soon be using the schema and classes being defined in the CDE schema re-write, with FindingClass, DataElement, Measurement, etc.", and "OIFMs VERY soon need to get re-organized around the graph-based approach we're developing in the next-gen-schema effort in CDEs. They're currently document-oriented and we need to fix that SOON." +[^cde-branch]: The ACR/RSNA CDE schema repository, next-gen-2026 branch, read on 2026-09-30 at commit b541b74 of 2026-09-23. Every statement below that is attributed to the repository is taken from files committed at that commit; the branch had uncommitted working-tree changes on that date, which were not read. Two sentences on this page rest on the project lead's statement alone and are identified as such in the note on that statement. +[^cde-understanding]: "Next-Generation CDE Schema: Current Understanding" §2.2: "The authoritative internal representation is a knowledge graph, not a document tree", following the committee's own move to "a graph model, where findings point to canonical attribute objects". §2.3 puts inference in scope as a first-class concern: "Subsumption, typed relations, ontology binding, and inference are in scope as first-class concerns rather than as things layered on afterwards." That is the intent, not a demonstration. The document's own open issues qualify it: Issue A asks what inference `is-a` licenses and notes that the negation sweep over a grouping is sound only under genuine transitive subsumption and a closed-world assumption that the radiologist assessed everything beneath the class; Issue B leaves undecided whether finding classes are OWL classes or SKOS-style individuals, where the second choice "has no inference semantics - surrendering exactly what Issue A wants"; Issue C asks "What reasoning do we actually need, and who owns the formal layer?" and is unanswered. +[^cde-requirements]: "What the Vocabulary Must Express" sets out what a FindingClass has to be able to carry, what is reported on (an imaging observation, a physiologic quantity, a device, the image itself), and the separation of a measured quantity from its interpretation and from any method that produced it. +[^cde-structures]: "Draft Structures for Worked Examples" §1 is the node-type table: FindingClass with its identity, definition, typed synonyms and `entity_type`; Diagnosis "as FindingClass, without `entity_type`", where "what still distinguishes Diagnosis from FindingClass is only which relationship types it can source, `MAY_MANIFEST_AS` above all"; Grouping as "the negative-only nodes (`renal abnormality`) that sit above findings and diagnoses alike"; DataElement with its "explicit ordered/unordered value-set distinction"; Measurement with "quantity type, permitted units, optional method (unspecified by default)"; AssessmentScheme, whose "descriptive dimensions are linked ordinary DataElements"; Value as a first-class node whose id derives from its element; AnatomicLocation; and the Concept nodes for the metadata vocabularies. §2 is the edge catalog and the properties edges carry, including the value-subset restriction and the removal of the `required` flag. §3, "The object view: a FindingClass is its gathered edges", is the source of the figure above. +[^cde-relationships]: "The Finding and Diagnosis Relationship Family" is the catalog: seven pairs and one catch-all, each with its domain, range, inverse or symmetry, character and meaning, plus the typicality and specificity properties that manifestation edges carry, the rules that keep manifestation, causation, subsumption and progression apart, and the differential as a derived view rather than a stored edge. Its §7 lists the questions still open for review. The relationships page of this knowledgebase is where that family belongs in full. +[^cde-worked-examples]: "Worked Examples, Acute Pyelonephritis, Pleural Effusion, and One Report" describes the two families written into the graph and warns, before any of their content is used: "Read the provenance before trusting a number. The owner chose the two examples and the effusion's cause list. Every typicality and specificity value, every `expected` hint, the subtype trees, the element choices, and the close-versus-exact code matches are Claude's clinical and terminological estimates, unreviewed." +[^cde-decisions]: The decision record carries a provenance column on every row. **OWNER** means "The owner stated it. The quotation is verbatim from the session. This is the decision."; **CLAUDE DEFAULT** means "Claude chose it to keep moving and recorded the choice. The owner has not reviewed it. Reversible."; **CLAUDE INVENTION** means content "that no one has checked. Treat as unverified." A second caution applies to every row from S49 onward: S49 records the project lead's own ruling that "nothing is 'settled'" by the project's internal discussion, so a decision the project lead and an assistant reached together is a proposal to put to the external reviewer, not a jointly adopted design. The rows used here, with the later ones that qualify them. S8, Grouping as a narrow node type, the negative-only nodes, OWNER inclination with the narrowing NOT OBJECTED. S9, "THERE IS NO SUCH THING AS A REQUIRED ELEMENT", OWNER. S10 and S11, standard clinical metadata as its own node class, with modality, body region and subspecialty as RadLex nodes and provisional codes for etiology, sex, age and time course, OWNER. S12, S37 and S53, an anatomic location's only id is its RID and the substrate is the anatomic locations overlay pointed to at a pinned commit, whose compound sided ids are used as they stand until RadLex mints real ones, OWNER. S31, the agreed terms **anatomic scope** ("it might not be a PLACE, it may be something like 'muscle' (NOS)") and **standard clinical metadata**, OWNER. S33 gave one `HAS_COMPONENT` relationship with inverse `COMPONENT_OF` carrying a count, PROPOSED and ACCEPTED, **and S58 withdraws that form**: the disposition is the reviewer's two distinct edges, the whole must have the part and the part occurs only in that whole, with a minimum count proposed on the first; the alpha's own documentation describes them as two separate assertions rather than one relationship read in two directions, and S34's lesion-family rule is unchanged.[^cde-alpha-shape] S3 and S13 held that `SUBTYPE_OF` propagates nothing, **and S55 moves the project lead's position**: the disposition is the reviewer's approach, under which a subtype carries every element and edge its parent declares, may add elements and narrow inherited values, and cannot drop an inherited element, with a standing requirement that authoring show the blast radius of a change to a parent. S36, "I think we're going to do JSON and OWL", with official TypeScript and Python access libraries wanted, OWNER. S38, the reviewer's implementation approach as the basis going forward, OWNER, who noted that selecting it "does not automatically accept every structural choice in the alpha". S39, Measurement distinct from DataElement and value sets explicitly ordered or unordered, PROPOSED and ACCEPTED with OWNER clarifications. S40 and S41, AssessmentScheme a separate definition type whose linked descriptors are ordinary DataElements, OWNER. S42, a binding "Takes this element, but only this subset of values", OWNER, **qualified by S64 and S65**: S64 makes the narrowing an annotation on the binding with enforcement left to tooling and proposes a strength so it can shade between a hint and an absolute restriction, the "restriction on meaning" reading of S42 becoming that absolute end; S65 proposes two further capabilities to put alongside it, that a binding may add permitted values for one use and may give context-specific language for values, neither changing the shared element. S43, anatomic locations bound directly to data elements and measurements, OWNER, **restated by S62 in the reviewer's form**: the descriptor is created in the CDE repository and points at the RadLex anatomy node, carrying the anatomic scope itself, and no edge is written on the anatomy node. S57, a diagnosis is never a subtype of a finding, with paired FindingClass and Diagnosis nodes for parent and grouping terms joined by a manifestation edge, superseding the cross-label taxonomy of S1. Examples of the weaker mark: S14, non-imaging causes as Diagnosis nodes with no elements, and S18, that the causal pair takes typicality, are both CLAUDE DEFAULT, recorded because the project lead never answered the question. +[^cde-anatomy]: "The Anatomy Axis, Current State" §1: the substrate is "the anatomic locations data behind the owner's published `anatomic-locations` Python package: 2,926 locations, each keyed by its RadLex id, with containment, part-of, left, right, and unsided variants, a body region, SNOMED and other codes, synonyms, and some definitions", pointed to at a pinned commit rather than copied, and settled by the project lead as "an overlay on RadLex, not a replacement and not the sole source"; S53 keeps that overlay as the reviewer's configured anatomy source, using its compound sided ids as they stand until RadLex mints real ones.[^cde-decisions] §2 records that the file lacks a lung parenchyma entry; it is on the running node request list to be fed upstream. §5 records the two anatomic scope families still to be developed, tissue types and structure types, which is why scope may name a kind of structure and not only a place. That is one representation. The alpha states a different one and the two are cited separately here: in its own README, "RadLex is the single source of truth for anatomy", `AnatomicLocation` is a role type whose occupants are native RadLex classes under RID3 keeping their native RID and IRI, the generated ontology imports the configured RadLex directly and leaves its native predicates (`Contained_In`, `Part_Of`, `Regional_Part_Of` and the rest) distinct and unchanged, and `scripts/anatomy.json` is a generated read-only index of the full native anatomy branch that consumers join against rather than copying into the definition graph.[^cde-alpha-readme] +[^cde-graph]: The vocabulary written as JSON Lines. `core.jsonl` declares each relationship type as its own node recording "its inverse, symmetry, formal name, domain and range, and the properties it may carry". `pyelonephritis.jsonl` and `pleural-effusion.jsonl` hold the two worked families. The directory README states the rule these files were authored under: "Every edge is explicit. In particular, `SUBTYPE_OF` does not copy or imply `HAS_ELEMENT`, `SCOPED_TO`, context, or any other outgoing edge on the subtype." That rule is the historical representation, not the current direction. S55 moves the project lead's position to the reviewer's approach, and the alpha's own documentation describes `SUBTYPE_OF` as carrying strict monotonic inheritance.[^cde-decisions][^cde-alpha-shape] +[^cde-alpha-graph]: The reviewer's alpha definition graph, a single JSON file of nodes and edges: 45 FindingClass, 25 Diagnosis, 36 DataElement, 155 Value, 16 Measurement, 5 AssessmentScheme, 28 AnatomicLocation and the metadata concept nodes, joined by 170 `HAS_DATA_ELEMENT`, 71 `SCOPED_TO`, 41 `HAS_MEASUREMENT`, 38 `MAY_MANIFEST_AS`, 10 `MAY_CAUSE`, 10 `SUBTYPE_OF`, 5 `ASSESSED_BY`, 4 `OCCURS_WITH` and single `HAS_COMPONENT` and `MAY_PROGRESS_TO` edges, among others. The project lead selected this implementation approach as the basis going forward on 2026-09-14, while noting that "Selecting the implementation approach does not automatically accept every structural choice in the alpha". This JSON file is the export inspected here; the same alpha model is also committed as `alpha/radcde-alpha.ttl` and `alpha/rdfxml/radcde-alpha.rdf`, which carry the same Measurement and AssessmentScheme individuals, MS-000001 and AS-000001 among them. Across these representations the alpha is where Measurement and AssessmentScheme exist as actual nodes rather than as decisions on paper, and where the anatomic scope edge runs from a DataElement or a Measurement as well as from a definition.[^cde-alpha-readme] +[^cde-alpha-readme]: The alpha's own README. On anatomy, it states that "RadLex is the single source of truth", that the generated ontology imports the configured RadLex release directly, and that `scripts/anatomy.json` is a generated read-only index of the native anatomy branch. Under "Reasoner regression" it records the testing done toward repeatable inference: the shipped alpha imports the complete configured RadLex ontology, full HermiT classification of that world "can be slow", so the suite uses "reduced fixtures containing the unchanged generated CDE ontology plus only the exact native RadLex axioms exercised by the tests", verified against the RadLex index before serialization, with `test_reason.py` and `test_probes.py` run against them and a companion file of "deliberate reasoning probes". The README is explicit that "The reduced fixtures are testing infrastructure only." This is evidence of work toward reasoning that can be repeated and checked; it does not establish that inference over the whole vocabulary is reliable, and the formal layer remains an open question in the baseline document.[^cde-understanding] +[^cde-alpha-shape]: The alpha's generated node and edge documentation. §4 tabulates every edge with its signature, count and properties, and opens with the caveat this page relies on: "Signatures are the tail and head types observed in the build, not everything the edge is permitted to take." It is also where the two component edges are described as separate assertions, `HAS_COMPONENT` as "The whole must have this sub-part" and `COMPONENT_OF` as "This sub-part belongs only to that whole; says nothing about whether the whole has one", and where `SUBTYPE_OF` is glossed as "Taxonomy, more to less specific. Strict monotonic inheritance." +[^cde-libraries-plan]: "Plan: typed definition libraries (Python, then TypeScript) over a PostgreSQL copy of the graph", written 2026-09-13 at the project lead's request and marked "proposed; nothing below is done". It sets out the library direction cited here: Pydantic models mirroring the graph node types, a loader and store, a query API with the operations the documents already perform, and generated TypeScript types so that "a TypeScript consumer of the export is typed from day one", under the rule that "Nothing is resolved only in a library or a loader." Its note of 2026-09-15 reconciles it toward the reviewer's implementation under S38: the plan's models, loader and query API "must be reconciled with that specification rather than built beside it", and its five open decisions stay open. It is a proposed design for libraries over the CDE graph; it does not itself establish that one SDK will serve both collections at once. +[^cde-fc-diagram-input]: The pulmonary nodule neighborhood example, the JSON view the figure is rendered from. Its own description is the figure's alt text at source: "The pulmonary nodule FindingClass node and its typed edges to shared nodes: data elements, values, anatomic location, related classes, and metadata concepts." It records the anatomic scope as lung, RID1301, "structure - required", the elements bound or defined in place, and the related classes over `SUBTYPE_OF`, `MAY_REPRESENT`, `ASSESSED_BY` and `MAY_HAVE_COMPONENT`. The structures document describes this view as generated rather than drawn, and the example files as interim, to be replaced once the renderer reads the graph directly.[^cde-structures] +[^cde-fc-diagram]: The pulmonary nodule FindingClass diagram, committed 2026-09-03. Its own description: "The pulmonary nodule FindingClass node and its typed edges to shared nodes: data elements, values, anatomic location, related classes, and metadata concepts." The project lead cleared its reuse here; the file embedded on this page is byte-for-byte the committed one. Its input is a specific artifact, not either of the graph exports this page uses to check the table: at this commit `tools/render_neighborhood.py` reads `examples/pulmonary-nodule.neighborhood.json` and emits the card, and rendering that example with that pinned script reproduces the figure exactly.[^cde-fc-diagram-input] It is not generated from the alpha definition graph or from the JSON Lines graph. It predates the decisions of 2026-09-14 that made Measurement and AssessmentScheme separate node types, so it labels Lung-RADS and Fleischner as FindingClasses and size (mean diameter) as a DataElement, and it predates the later edge names; the repository notes that the older rendered artifacts were not regenerated. It is kept here as a historical illustration of the object view, which is what its caption dates. +[^cde-schema]: The current Common Data Element schema, `cde.schema.json`, last changed 2024-11-19: a draft-07 JSON Schema whose root is `element_set`, a nested document whose required properties include an `elements` array. This is the document form the ACR/RSNA collection takes today. +[^oifm-repo]: Open Imaging Finding Models repository, main at 4475ac1, a snapshot of 2026-04-28. Its schema is a JSON Schema for a single self-contained finding model, and the corpus is 2,382 individual files under `defs/`, one per definition. This is the document form the OIFM collection takes today. +[^siim-2026]: SIIM 2026 annual meeting talk, June 2026, Mass General Brigham, slide 12, "Relationships and external citations". Its notes: "The relationships turn a flat dictionary into something an app can reason over - differentials, associations, and 'what else could it be.' Example shown: a radiodense urinary calculus may cause hydronephrosis." Read from the project's text extraction of the deck, `sources/bucket/text/siim2026-reports-of-the-future.md`; the presentation file records a modification date of 2026-06-11. +[^table-check]: How each row was checked, at ACR-RSNA-CDEs next-gen-2026 b541b74. Two different kinds of evidence are in play and the table does not merge them. **Declared** domains and ranges come from `graph/core.jsonl`, where each relationship type is a node recording its own domain, range, inverse and symmetry.[^cde-graph] **Observed** endpoints come from the alpha definition graph, whose own generated documentation states the limit plainly: its signatures are "the tail and head types observed in the build, not everything the edge is permitted to take".[^cde-alpha-shape][^cde-alpha-graph] Example edges cannot establish an exhaustive domain, and the alpha contains no Grouping nodes at all, so nothing in it can settle whether a Grouping may source the newer binding names. Rows whose relationship `core.jsonl` declares follow that declaration; `HAS_COMPONENT`, `HAS_DATA_ELEMENT`, `HAS_MEASUREMENT` and the AssessmentScheme range of `ASSESSED_BY` are not declared there, since that file still carries the earlier `MAY_HAVE_COMPONENT` and a single `HAS_ELEMENT`, so those follow the alpha together with the decisions that renamed them.[^cde-decisions] Four rows where the sources disagree, left as differences rather than combined: **SCOPED_TO** is declared from FindingClass, Diagnosis and Grouping, and the row says so; the alpha additionally runs it from a DataElement and from a Measurement, which is the direction S62 takes, and it is the descriptor that carries the scope edge in that form.[^cde-decisions][^cde-alpha-shape] **The binding row** excludes AnatomicLocation as a source: S62 records that a descriptor for a normal structure points at the RadLex anatomy node and no edge is written on the anatomy node itself, so what can be said about a structure is a query over what is scoped to it. The earlier representation is the one to read `core.jsonl` and S43 for, where an AnatomicLocation sources a `HAS_ELEMENT` edge directly; neither anatomy binding occurs in the alpha.[^cde-decisions][^cde-structures][^cde-graph] **MAY_PROGRESS_TO** is declared between either node type at either end, and the row follows that declaration; the relationship catalog states the narrower rule, FindingClass to FindingClass or Diagnosis to Diagnosis, and the alpha's one progression edge runs Diagnosis to Diagnosis.[^cde-graph][^cde-relationships][^cde-alpha-shape] **SUBTYPE_OF** is version-sensitive: `core.jsonl` and the relationship catalog both permit a taxonomy that crosses the finding and diagnosis labels, on S1, while S57 moves the project lead's position to a rule under which a diagnosis is never a subtype of a finding and a parent term such as "renal lesion" exists as a paired FindingClass and Diagnosis joined by a manifestation edge. The row follows S57 and stays within a label; the worked families were written under S1 and are to be re-authored.[^cde-graph][^cde-relationships][^cde-decisions] Each **Example** is an edge that exists in the graph at that commit: the part-solid nodule's parent and component, the pulmonary nodule's Lung-RADS assessment, its CT modality, its presence element, its mean diameter measurement, the pleural effusion and atelectasis association, and the parapneumonic effusion progressing to empyema are all in the alpha definition graph; acute pyelonephritis manifesting as a striated nephrogram is in both that graph and `graph/pyelonephritis.jsonl`.[^cde-alpha-graph][^cde-graph][^cde-worked-examples] None of these checks establishes that the example content is clinically validated, which the worked examples document is explicit about. Three examples the project lead gave were adjusted against the branch and are flagged for review. The anatomic scope of a pulmonary nodule is recorded as **lung** (RadLex RID1301), not lung parenchyma; the anatomy file has no lung parenchyma entry, and adding one is on the project's own node request list.[^cde-anatomy] The measurement bound to a pulmonary nodule is **mean diameter**, one of three quantitative descriptors it binds; length is the kind of quantity, not the name of the measurement.[^cde-alpha-graph] No progression edge runs from a non-solid to a part-solid pulmonary nodule; the example shown is the only progression edge that appears in both graph forms.[^cde-alpha-graph][^cde-graph] The causal example is the one the project lead gave and is the only row not drawn from the graph: no urinary calculus node exists in either authored graph at this commit, though the imported RadLex artifacts carry renal calculus as RID38586, and the edge itself comes from the SIIM 2026 deck.[^siim-2026][^cde-alpha-readme] One row carries a relationship type whose name is still unsettled in the repository: the anatomy is-a edge is written `SUBTYPE_OF` in the graph while the reviewer's viewer writes `IS_A`, and the names are on the project's own list to settle.[^cde-anatomy][^cde-decisions] diff --git a/knowledge/drafts/nodule-neighborhood.excalidraw b/knowledge/drafts/nodule-neighborhood.excalidraw new file mode 100644 index 0000000..e1cbdf0 --- /dev/null +++ b/knowledge/drafts/nodule-neighborhood.excalidraw @@ -0,0 +1,6015 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "oidm-knowledge/tools/diagrams", + "elements": [ + { + "type": "rectangle", + "id": "fc", + "x": 400, + "y": 270, + "width": 240, + "height": 80, + "strokeColor": "#059669", + "backgroundColor": "#d1fae5", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1001, + "version": 1, + "versionNonce": 1002, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "e_gr_fc", + "type": "arrow" + }, + { + "id": "e_mma_gn", + "type": "arrow" + }, + { + "id": "e_mma_neo", + "type": "arrow" + }, + { + "id": "e_st1", + "type": "arrow" + }, + { + "id": "e_st2", + "type": "arrow" + }, + { + "id": "e_st3", + "type": "arrow" + }, + { + "id": "e_de0", + "type": "arrow" + }, + { + "id": "e_de1", + "type": "arrow" + }, + { + "id": "e_de2", + "type": "arrow" + }, + { + "id": "e_de3", + "type": "arrow" + }, + { + "id": "e_de4", + "type": "arrow" + }, + { + "id": "e_ms0", + "type": "arrow" + }, + { + "id": "e_ms1", + "type": "arrow" + }, + { + "id": "e_sc", + "type": "arrow" + }, + { + "id": "e_sp", + "type": "arrow" + }, + { + "id": "e_sn0", + "type": "arrow" + }, + { + "id": "e_sn1", + "type": "arrow" + }, + { + "id": "e_sn2", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "fc_n", + "x": 408, + "y": 291.0, + "width": 224, + "height": 21.25, + "strokeColor": "#064e3b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1003, + "version": 1, + "versionNonce": 1004, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "pulmonary nodule", + "originalText": "pulmonary nodule", + "fontSize": 17, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "fc_k", + "x": 408, + "y": 315.25, + "width": 224, + "height": 13.75, + "strokeColor": "#047857", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1005, + "version": 1, + "versionNonce": 1006, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "FindingClass", + "originalText": "FindingClass", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "gr", + "x": 320, + "y": 25, + "width": 250, + "height": 70, + "strokeColor": "#10b981", + "backgroundColor": "#ecfdf5", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1007, + "version": 1, + "versionNonce": 1008, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "e_gr_fc", + "type": "arrow" + }, + { + "id": "e_gr_gn", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "gr_n", + "x": 328, + "y": 42.875, + "width": 234, + "height": 17.5, + "strokeColor": "#065f46", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1009, + "version": 1, + "versionNonce": 1010, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "pulmonary parenchymal abnormality", + "originalText": "pulmonary parenchymal abnormality", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "gr_k", + "x": 328, + "y": 63.375, + "width": 234, + "height": 13.75, + "strokeColor": "#059669", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1011, + "version": 1, + "versionNonce": 1012, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Grouping", + "originalText": "Grouping", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "dx_gran", + "x": 20, + "y": 30, + "width": 165, + "height": 62, + "strokeColor": "#059669", + "backgroundColor": "#6ee7b7", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1013, + "version": 1, + "versionNonce": 1014, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "e_gr_gn", + "type": "arrow" + }, + { + "id": "e_mma_gn", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "dx_gran_n", + "x": 28, + "y": 43.875, + "width": 149, + "height": 17.5, + "strokeColor": "#064e3b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1015, + "version": 1, + "versionNonce": 1016, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "pulmonary granuloma", + "originalText": "pulmonary granuloma", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "dx_gran_k", + "x": 28, + "y": 64.375, + "width": 149, + "height": 13.75, + "strokeColor": "#047857", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1017, + "version": 1, + "versionNonce": 1018, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Diagnosis", + "originalText": "Diagnosis", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "dx_neo", + "x": 20, + "y": 140, + "width": 165, + "height": 62, + "strokeColor": "#059669", + "backgroundColor": "#6ee7b7", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1019, + "version": 1, + "versionNonce": 1020, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "e_mma_neo", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "dx_neo_n", + "x": 28, + "y": 153.875, + "width": 149, + "height": 17.5, + "strokeColor": "#064e3b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1021, + "version": 1, + "versionNonce": 1022, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "pulmonary neoplasm", + "originalText": "pulmonary neoplasm", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "dx_neo_k", + "x": 28, + "y": 174.375, + "width": 149, + "height": 13.75, + "strokeColor": "#047857", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1023, + "version": 1, + "versionNonce": 1024, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Diagnosis", + "originalText": "Diagnosis", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "ellipse", + "id": "as_lr", + "x": 600, + "y": 14, + "width": 190, + "height": 92, + "strokeColor": "#7e22ce", + "backgroundColor": "#e9d5ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1025, + "version": 1, + "versionNonce": 1026, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "text", + "id": "as_lr_n", + "x": 626.6, + "y": 42.875, + "width": 136.79999999999998, + "height": 17.5, + "strokeColor": "#4c1d95", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1027, + "version": 1, + "versionNonce": 1028, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Lung-RADS", + "originalText": "Lung-RADS", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "as_lr_k", + "x": 626.6, + "y": 63.375, + "width": 136.79999999999998, + "height": 13.75, + "strokeColor": "#7e22ce", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1029, + "version": 1, + "versionNonce": 1030, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "AssessmentScheme", + "originalText": "AssessmentScheme", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "ellipse", + "id": "as_fl", + "x": 845, + "y": 14, + "width": 190, + "height": 92, + "strokeColor": "#7e22ce", + "backgroundColor": "#e9d5ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1031, + "version": 1, + "versionNonce": 1032, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "text", + "id": "as_fl_n", + "x": 871.6, + "y": 42.875, + "width": 136.79999999999998, + "height": 17.5, + "strokeColor": "#4c1d95", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1033, + "version": 1, + "versionNonce": 1034, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Fleischner criteria", + "originalText": "Fleischner criteria", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "as_fl_k", + "x": 871.6, + "y": 63.375, + "width": 136.79999999999998, + "height": 13.75, + "strokeColor": "#7e22ce", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1035, + "version": 1, + "versionNonce": 1036, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "AssessmentScheme", + "originalText": "AssessmentScheme", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "s1", + "x": 300, + "y": 500, + "width": 140, + "height": 80, + "strokeColor": "#059669", + "backgroundColor": "#d1fae5", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1037, + "version": 1, + "versionNonce": 1038, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "e_st1", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "s1_n", + "x": 308, + "y": 515.375, + "width": 124, + "height": 32.5, + "strokeColor": "#064e3b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1039, + "version": 1, + "versionNonce": 1040, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "solid\npulmonary nodule", + "originalText": "solid\npulmonary nodule", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "s1_k", + "x": 308, + "y": 550.875, + "width": 124, + "height": 13.75, + "strokeColor": "#047857", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1041, + "version": 1, + "versionNonce": 1042, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "FindingClass", + "originalText": "FindingClass", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "s2", + "x": 450, + "y": 500, + "width": 140, + "height": 80, + "strokeColor": "#059669", + "backgroundColor": "#d1fae5", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1043, + "version": 1, + "versionNonce": 1044, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "e_st2", + "type": "arrow" + }, + { + "id": "e_hc", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "s2_n", + "x": 458, + "y": 515.375, + "width": 124, + "height": 32.5, + "strokeColor": "#064e3b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1045, + "version": 1, + "versionNonce": 1046, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "part-solid\npulmonary nodule", + "originalText": "part-solid\npulmonary nodule", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "s2_k", + "x": 458, + "y": 550.875, + "width": 124, + "height": 13.75, + "strokeColor": "#047857", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1047, + "version": 1, + "versionNonce": 1048, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "FindingClass", + "originalText": "FindingClass", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "s3", + "x": 600, + "y": 500, + "width": 140, + "height": 80, + "strokeColor": "#059669", + "backgroundColor": "#d1fae5", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1049, + "version": 1, + "versionNonce": 1050, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "e_st3", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "s3_n", + "x": 608, + "y": 515.375, + "width": 124, + "height": 32.5, + "strokeColor": "#064e3b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1051, + "version": 1, + "versionNonce": 1052, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "ground glass\nnodule", + "originalText": "ground glass\nnodule", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "s3_k", + "x": 608, + "y": 550.875, + "width": 124, + "height": 13.75, + "strokeColor": "#047857", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1053, + "version": 1, + "versionNonce": 1054, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "FindingClass", + "originalText": "FindingClass", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "sc", + "x": 400, + "y": 630, + "width": 240, + "height": 70, + "strokeColor": "#059669", + "backgroundColor": "#d1fae5", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1055, + "version": 1, + "versionNonce": 1056, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "e_hc", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "sc_n", + "x": 408, + "y": 640.375, + "width": 224, + "height": 32.5, + "strokeColor": "#064e3b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1057, + "version": 1, + "versionNonce": 1058, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "solid component of\npart-solid pulmonary nodule", + "originalText": "solid component of\npart-solid pulmonary nodule", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "sc_k", + "x": 408, + "y": 675.875, + "width": 224, + "height": 13.75, + "strokeColor": "#047857", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1059, + "version": 1, + "versionNonce": 1060, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "FindingClass", + "originalText": "FindingClass", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "an", + "x": 60, + "y": 290, + "width": 140, + "height": 60, + "strokeColor": "#1d4ed8", + "backgroundColor": "#bfdbfe", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1061, + "version": 1, + "versionNonce": 1062, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "e_sc", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "an_n", + "x": 68, + "y": 302.875, + "width": 124, + "height": 17.5, + "strokeColor": "#1e3a8a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1063, + "version": 1, + "versionNonce": 1064, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "lung", + "originalText": "lung", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "an_k", + "x": 68, + "y": 323.375, + "width": 124, + "height": 13.75, + "strokeColor": "#1d4ed8", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1065, + "version": 1, + "versionNonce": 1066, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "AnatomicLocation", + "originalText": "AnatomicLocation", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "sp", + "x": 40, + "y": 370, + "width": 170, + "height": 60, + "strokeColor": "#78748f", + "backgroundColor": "#e5e3ee", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1067, + "version": 1, + "versionNonce": 1068, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "e_sp", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "sp_n", + "x": 48, + "y": 382.875, + "width": 154, + "height": 17.5, + "strokeColor": "#3c3a52", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1069, + "version": 1, + "versionNonce": 1070, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "chest radiology", + "originalText": "chest radiology", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "sp_k", + "x": 48, + "y": 403.375, + "width": 154, + "height": 13.75, + "strokeColor": "#5d5a78", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1071, + "version": 1, + "versionNonce": 1072, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Subspecialty", + "originalText": "Subspecialty", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "md_ct", + "x": 55, + "y": 480, + "width": 90, + "height": 38, + "strokeColor": "#6b7280", + "backgroundColor": "#e5e7eb", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1073, + "version": 1, + "versionNonce": 1074, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "e_sn0", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "md_ct_n", + "x": 63, + "y": 483.75, + "width": 74, + "height": 16.25, + "strokeColor": "#374151", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1075, + "version": 1, + "versionNonce": 1076, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "CT", + "originalText": "CT", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "md_ct_k", + "x": 63, + "y": 503.0, + "width": 74, + "height": 11.25, + "strokeColor": "#4b5563", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1077, + "version": 1, + "versionNonce": 1078, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Modality", + "originalText": "Modality", + "fontSize": 9, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "md_xr", + "x": 55, + "y": 528, + "width": 90, + "height": 38, + "strokeColor": "#6b7280", + "backgroundColor": "#e5e7eb", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1079, + "version": 1, + "versionNonce": 1080, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "e_sn1", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "md_xr_n", + "x": 63, + "y": 531.75, + "width": 74, + "height": 16.25, + "strokeColor": "#374151", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1081, + "version": 1, + "versionNonce": 1082, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "XR", + "originalText": "XR", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "md_xr_k", + "x": 63, + "y": 551.0, + "width": 74, + "height": 11.25, + "strokeColor": "#4b5563", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1083, + "version": 1, + "versionNonce": 1084, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Modality", + "originalText": "Modality", + "fontSize": 9, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "md_mr", + "x": 55, + "y": 576, + "width": 90, + "height": 38, + "strokeColor": "#6b7280", + "backgroundColor": "#e5e7eb", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1085, + "version": 1, + "versionNonce": 1086, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "e_sn2", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "md_mr_n", + "x": 63, + "y": 579.75, + "width": 74, + "height": 16.25, + "strokeColor": "#374151", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1087, + "version": 1, + "versionNonce": 1088, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "MR", + "originalText": "MR", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "md_mr_k", + "x": 63, + "y": 599.0, + "width": 74, + "height": 11.25, + "strokeColor": "#4b5563", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1089, + "version": 1, + "versionNonce": 1090, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Modality", + "originalText": "Modality", + "fontSize": 9, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "de0", + "x": 845, + "y": 150, + "width": 190, + "height": 48, + "strokeColor": "#be123c", + "backgroundColor": "#ffe4e6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1091, + "version": 1, + "versionNonce": 1092, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "e_de0", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "de0_n", + "x": 853, + "y": 156.875, + "width": 174, + "height": 17.5, + "strokeColor": "#881337", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1093, + "version": 1, + "versionNonce": 1094, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "presence", + "originalText": "presence", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "de0_k", + "x": 853, + "y": 177.375, + "width": 174, + "height": 13.75, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1095, + "version": 1, + "versionNonce": 1096, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "DataElement", + "originalText": "DataElement", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "de1", + "x": 845, + "y": 216, + "width": 190, + "height": 48, + "strokeColor": "#be123c", + "backgroundColor": "#ffe4e6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1097, + "version": 1, + "versionNonce": 1098, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "e_de1", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "de1_n", + "x": 853, + "y": 222.875, + "width": 174, + "height": 17.5, + "strokeColor": "#881337", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1099, + "version": 1, + "versionNonce": 1100, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "composition", + "originalText": "composition", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "de1_k", + "x": 853, + "y": 243.375, + "width": 174, + "height": 13.75, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1101, + "version": 1, + "versionNonce": 1102, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "DataElement", + "originalText": "DataElement", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "de2", + "x": 845, + "y": 282, + "width": 190, + "height": 48, + "strokeColor": "#be123c", + "backgroundColor": "#ffe4e6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1103, + "version": 1, + "versionNonce": 1104, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "e_de2", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "de2_n", + "x": 853, + "y": 288.875, + "width": 174, + "height": 17.5, + "strokeColor": "#881337", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1105, + "version": 1, + "versionNonce": 1106, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "margin", + "originalText": "margin", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "de2_k", + "x": 853, + "y": 309.375, + "width": 174, + "height": 13.75, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1107, + "version": 1, + "versionNonce": 1108, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "DataElement", + "originalText": "DataElement", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "de3", + "x": 845, + "y": 348, + "width": 190, + "height": 48, + "strokeColor": "#be123c", + "backgroundColor": "#ffe4e6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1109, + "version": 1, + "versionNonce": 1110, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "e_de3", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "de3_n", + "x": 853, + "y": 354.875, + "width": 174, + "height": 17.5, + "strokeColor": "#881337", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1111, + "version": 1, + "versionNonce": 1112, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "calcification", + "originalText": "calcification", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "de3_k", + "x": 853, + "y": 375.375, + "width": 174, + "height": 13.75, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1113, + "version": 1, + "versionNonce": 1114, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "DataElement", + "originalText": "DataElement", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "de4", + "x": 845, + "y": 414, + "width": 190, + "height": 48, + "strokeColor": "#be123c", + "backgroundColor": "#ffe4e6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1115, + "version": 1, + "versionNonce": 1116, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "e_de4", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "de4_n", + "x": 853, + "y": 420.875, + "width": 174, + "height": 17.5, + "strokeColor": "#881337", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1117, + "version": 1, + "versionNonce": 1118, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "interval change", + "originalText": "interval change", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "de4_k", + "x": 853, + "y": 441.375, + "width": 174, + "height": 13.75, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1119, + "version": 1, + "versionNonce": 1120, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "DataElement", + "originalText": "DataElement", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "ms0", + "x": 845, + "y": 510, + "width": 190, + "height": 48, + "strokeColor": "#6d28d9", + "backgroundColor": "#ede9fe", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1121, + "version": 1, + "versionNonce": 1122, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "e_ms0", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "ms0_n", + "x": 853, + "y": 516.875, + "width": 174, + "height": 17.5, + "strokeColor": "#4c1d95", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1123, + "version": 1, + "versionNonce": 1124, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "mean diameter", + "originalText": "mean diameter", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "ms0_k", + "x": 853, + "y": 537.375, + "width": 174, + "height": 13.75, + "strokeColor": "#6d28d9", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1125, + "version": 1, + "versionNonce": 1126, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Measurement", + "originalText": "Measurement", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "ms1", + "x": 845, + "y": 576, + "width": 190, + "height": 48, + "strokeColor": "#6d28d9", + "backgroundColor": "#ede9fe", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1127, + "version": 1, + "versionNonce": 1128, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "e_ms1", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "ms1_n", + "x": 853, + "y": 582.875, + "width": 174, + "height": 17.5, + "strokeColor": "#4c1d95", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1129, + "version": 1, + "versionNonce": 1130, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "long-axis diameter", + "originalText": "long-axis diameter", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "ms1_k", + "x": 853, + "y": 603.375, + "width": 174, + "height": 13.75, + "strokeColor": "#6d28d9", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1131, + "version": 1, + "versionNonce": 1132, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Measurement", + "originalText": "Measurement", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "e_gr_fc", + "x": 520.0, + "y": 270, + "width": 0.0, + "height": -175, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1133, + "version": 1, + "versionNonce": 1134, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.0, + -175 + ] + ], + "startBinding": { + "elementId": "fc", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "gr", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_gr_fc_h", + "x": 520.0, + "y": 95, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1135, + "version": 1, + "versionNonce": 1136, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + 6.2000000000000455, + 10.0 + ], + [ + -6.2000000000000455, + 10.0 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_gr_gn", + "x": 185, + "y": 61.0, + "width": 135, + "height": -1.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1137, + "version": 1, + "versionNonce": 1138, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 135, + -1.0 + ] + ], + "startBinding": { + "elementId": "dx_gran", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "gr", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_gr_gn_h", + "x": 320, + "y": 60.0, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1139, + "version": 1, + "versionNonce": 1140, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + -9.953800996859798, + 6.2739019529247315 + ], + [ + -10.045650328874274, + -6.125757869030409 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_mma_gn", + "x": 185, + "y": 83.94, + "width": 215, + "height": 198.06, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1141, + "version": 1, + "versionNonce": 1142, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 215, + 198.06 + ] + ], + "startBinding": { + "elementId": "dx_gran", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "fc", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_mma_gn_h", + "x": 400, + "y": 282.0, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1143, + "version": 1, + "versionNonce": 1144, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + -11.555613006793124, + -2.215357315927804 + ], + [ + -3.1541406350992247, + -11.335404573900973 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_mma_neo", + "x": 185, + "y": 171.0, + "width": 215, + "height": 143.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1145, + "version": 1, + "versionNonce": 1146, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 215, + 143.0 + ] + ], + "startBinding": { + "elementId": "dx_neo", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "fc", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_mma_neo_h", + "x": 400, + "y": 314.0, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1147, + "version": 1, + "versionNonce": 1148, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + -11.76005444388511, + -0.37565872392042365 + ], + [ + -4.892858059805235, + -10.70046447620848 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_asb_lr", + "x": 548.8, + "y": 270, + "width": 112.71064285388809, + "height": -161.896272225147, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1149, + "version": 1, + "versionNonce": 1150, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 112.71064285388809, + -161.896272225147 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_asb_lr_h", + "x": 664.6531347457569, + "y": 103.58988853208655, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1151, + "version": 1, + "versionNonce": 1152, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + -0.6252937479156344, + 11.749425846772994 + ], + [ + -10.801949495243775, + 4.6645350360141435 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_asb_fl", + "x": 592.0, + "y": 270, + "width": 283.8362978722794, + "height": -171.28052457809966, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1153, + "version": 1, + "versionNonce": 1154, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 283.8362978722794, + -171.28052457809966 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_asb_fl_h", + "x": 880.5453300081402, + "y": 95.87781809853604, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1155, + "version": 1, + "versionNonce": 1156, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + -5.358553809772729, + 10.475013177450933 + ], + [ + -11.76519941153947, + -0.1417138197625718 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_st1", + "x": 370.0, + "y": 500, + "width": 114.0, + "height": -150, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1157, + "version": 1, + "versionNonce": 1158, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 114.0, + -150 + ] + ], + "startBinding": { + "elementId": "s1", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "fc", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_st1_h", + "x": 484.0, + "y": 350, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1159, + "version": 1, + "versionNonce": 1160, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + -1.114627071772361, + 11.713138199939124 + ], + [ + -10.987038278898808, + 4.210105682522965 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_st2", + "x": 520.0, + "y": 500, + "width": 0.0, + "height": -150, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1161, + "version": 1, + "versionNonce": 1162, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.0, + -150 + ] + ], + "startBinding": { + "elementId": "s2", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "fc", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_st2_h", + "x": 520.0, + "y": 350, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1163, + "version": 1, + "versionNonce": 1164, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + 6.2000000000000455, + 10.0 + ], + [ + -6.2000000000000455, + 10.0 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_st3", + "x": 670.0, + "y": 500, + "width": -97.20000000000005, + "height": -150, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1165, + "version": 1, + "versionNonce": 1166, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -97.20000000000005, + -150 + ] + ], + "startBinding": { + "elementId": "s3", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "fc", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_st3_h", + "x": 572.8, + "y": 350, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1167, + "version": 1, + "versionNonce": 1168, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + 10.641179331118224, + 5.020488267388146 + ], + [ + 0.23497872340010417, + 11.763706261189554 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_hc", + "x": 520.0, + "y": 580, + "width": 0.0, + "height": 50, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1169, + "version": 1, + "versionNonce": 1170, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.0, + 50 + ] + ], + "startBinding": { + "elementId": "s2", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "sc", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_hc_h", + "x": 520.0, + "y": 630, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1171, + "version": 1, + "versionNonce": 1172, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + -6.2000000000000455, + -10.0 + ], + [ + 6.2000000000000455, + -10.0 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_de0", + "x": 640, + "y": 278.0, + "width": 205, + "height": -104.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1173, + "version": 1, + "versionNonce": 1174, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 205, + -104.0 + ] + ], + "startBinding": { + "elementId": "fc", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "de0", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_de0_h", + "x": 845, + "y": 174.0, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1175, + "version": 1, + "versionNonce": 1176, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + -6.112975105396686, + 10.053434008377423 + ], + [ + -11.723060997739253, + -1.0049083755669415 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_de1", + "x": 640, + "y": 290.0, + "width": 205, + "height": -50.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1177, + "version": 1, + "versionNonce": 1178, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 205, + -50.0 + ] + ], + "startBinding": { + "elementId": "fc", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "de1", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_de1_h", + "x": 845, + "y": 240.0, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1179, + "version": 1, + "versionNonce": 1180, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + -8.246075070646953, + 8.392987902365462 + ], + [ + -11.184331705015552, + -3.6538642985453293 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_de2", + "x": 640, + "y": 302.0, + "width": 205, + "height": 4.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1181, + "version": 1, + "versionNonce": 1182, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 205, + 4.0 + ] + ], + "startBinding": { + "elementId": "fc", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "de2", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_de2_h", + "x": 845, + "y": 306.0, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1183, + "version": 1, + "versionNonce": 1184, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + -10.119049501670133, + 6.003735269209528 + ], + [ + -9.877144327541146, + -6.393904904901433 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_de3", + "x": 640, + "y": 314.0, + "width": 205, + "height": 58.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1185, + "version": 1, + "versionNonce": 1186, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 205, + 58.0 + ] + ], + "startBinding": { + "elementId": "fc", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "de3", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_de3_h", + "x": 845, + "y": 372.0, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1187, + "version": 1, + "versionNonce": 1188, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + -11.310183398971162, + 3.243416637072187 + ], + [ + -7.934401567737837, + -8.688226042287397 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_de4", + "x": 640, + "y": 326.0, + "width": 205, + "height": 112.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1189, + "version": 1, + "versionNonce": 1190, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 205, + 112.0 + ] + ], + "startBinding": { + "elementId": "fc", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "de4", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_de4_h", + "x": 845, + "y": 438.0, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1191, + "version": 1, + "versionNonce": 1192, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + -11.748283365385305, + 0.6464038726763874 + ], + [ + -5.803080064901678, + -10.235441454101533 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_ms0", + "x": 640, + "y": 338.0, + "width": 205, + "height": 196.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1193, + "version": 1, + "versionNonce": 1194, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 205, + 196.0 + ] + ], + "startBinding": { + "elementId": "fc", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "ms0", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_ms0_h", + "x": 845, + "y": 534.0, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1195, + "version": 1, + "versionNonce": 1196, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + -11.512537487962504, + -2.429296315449619 + ], + [ + -2.9433622121006238, + -11.391954129488795 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_ms1", + "x": 640, + "y": 346.0, + "width": 205, + "height": 254.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1197, + "version": 1, + "versionNonce": 1198, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 205, + 254.0 + ] + ], + "startBinding": { + "elementId": "fc", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "ms1", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_ms1_h", + "x": 845, + "y": 600.0, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1199, + "version": 1, + "versionNonce": 1200, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + -11.105181598440822, + -3.8877939330229765 + ], + [ + -1.4558547493872993, + -11.67563646867643 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_sc", + "x": 400, + "y": 340.0, + "width": -200, + "height": -20.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1201, + "version": 1, + "versionNonce": 1202, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -200, + -20.0 + ] + ], + "startBinding": { + "elementId": "fc", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "an", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_sc_h", + "x": 200, + "y": 320.0, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1203, + "version": 1, + "versionNonce": 1204, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 10.567294960030097, + -5.174193389091954 + ], + [ + 9.333448844169709, + 7.164267769511923 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_sp", + "x": 412.0, + "y": 350, + "width": -202.0, + "height": 50.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1205, + "version": 1, + "versionNonce": 1206, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -202.0, + 50.0 + ] + ], + "startBinding": { + "elementId": "fc", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "sp", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_sp_h", + "x": 210.0, + "y": 400.0, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1207, + "version": 1, + "versionNonce": 1208, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 8.217356019995549, + -8.421108005520637 + ], + [ + 11.196748261163549, + 3.615636648798045 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_sn0", + "x": 424.0, + "y": 350, + "width": -279.0, + "height": 149.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1209, + "version": 1, + "versionNonce": 1210, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -279.0, + 149.0 + ] + ], + "startBinding": { + "elementId": "fc", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "md_ct", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_sn0_h", + "x": 145.0, + "y": 499.0, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1211, + "version": 1, + "versionNonce": 1212, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 5.9002036567105165, + -10.179764084169165 + ], + [ + 11.741601296908925, + 0.7581549870749313 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_sn1", + "x": 443.2, + "y": 350, + "width": -298.2, + "height": 197.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1213, + "version": 1, + "versionNonce": 1214, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -298.2, + 197.0 + ] + ], + "startBinding": { + "elementId": "fc", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "md_xr", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_sn1_h", + "x": 145.0, + "y": 547.0, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1215, + "version": 1, + "versionNonce": 1216, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 4.926181777142375, + -10.68516415870863 + ], + [ + 11.761168057503227, + -0.3390072612282893 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "arrow", + "id": "e_sn2", + "x": 462.4, + "y": 350, + "width": -317.4, + "height": 245.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1217, + "version": 1, + "versionNonce": 1218, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -317.4, + 245.0 + ] + ], + "startBinding": { + "elementId": "fc", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "md_mr", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_sn2_h", + "x": 145.0, + "y": 595.0, + "width": 0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "#64748b", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1219, + "version": 1, + "versionNonce": 1220, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 4.127608686525235, + -11.018295990348065 + ], + [ + 11.704451701427757, + -1.2024185498172528 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "l_gr_fc", + "x": 471.0, + "y": 167.875, + "width": 98.0, + "height": 24.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1221, + "version": 1, + "versionNonce": 1222, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_gr_fc_t", + "x": 477.0, + "y": 171.875, + "width": 86.0, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1223, + "version": 1, + "versionNonce": 1224, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "SUBTYPE_OF", + "originalText": "SUBTYPE_OF", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_gr_gn", + "x": 203.0, + "y": 47.875, + "width": 98.0, + "height": 24.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1225, + "version": 1, + "versionNonce": 1226, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_gr_gn_t", + "x": 209.0, + "y": 51.875, + "width": 86.0, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1227, + "version": 1, + "versionNonce": 1228, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "SUBTYPE_OF", + "originalText": "SUBTYPE_OF", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_mma_gn", + "x": 223.65, + "y": 170.875, + "width": 136.7, + "height": 24.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1229, + "version": 1, + "versionNonce": 1230, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_mma_gn_t", + "x": 229.65, + "y": 174.875, + "width": 124.7, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1231, + "version": 1, + "versionNonce": 1232, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "MAY_MANIFEST_AS", + "originalText": "MAY_MANIFEST_AS", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_mma_neo", + "x": 223.65, + "y": 229.875, + "width": 136.7, + "height": 24.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1233, + "version": 1, + "versionNonce": 1234, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_mma_neo_t", + "x": 229.65, + "y": 233.875, + "width": 124.7, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1235, + "version": 1, + "versionNonce": 1236, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "MAY_MANIFEST_AS", + "originalText": "MAY_MANIFEST_AS", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_e_asb_lr", + "x": 534.8400658135573, + "y": 201.29556210090942, + "width": 106.7, + "height": 24.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1237, + "version": 1, + "versionNonce": 1238, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_e_asb_lr_t", + "x": 540.8400658135573, + "y": 205.29556210090942, + "width": 94.7, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1239, + "version": 1, + "versionNonce": 1240, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "ASSESSED_BY", + "originalText": "ASSESSED_BY", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_e_asb_fl", + "x": 729.0899178053726, + "y": 142.9543599450338, + "width": 106.7, + "height": 24.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1241, + "version": 1, + "versionNonce": 1242, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_e_asb_fl_t", + "x": 735.0899178053726, + "y": 146.9543599450338, + "width": 94.7, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1243, + "version": 1, + "versionNonce": 1244, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "ASSESSED_BY", + "originalText": "ASSESSED_BY", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_st1", + "x": 361.0, + "y": 435.875, + "width": 98.0, + "height": 24.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1245, + "version": 1, + "versionNonce": 1246, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_st1_t", + "x": 367.0, + "y": 439.875, + "width": 86.0, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1247, + "version": 1, + "versionNonce": 1248, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "SUBTYPE_OF", + "originalText": "SUBTYPE_OF", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_st2", + "x": 471.0, + "y": 412.875, + "width": 98.0, + "height": 24.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1249, + "version": 1, + "versionNonce": 1250, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_st2_t", + "x": 477.0, + "y": 416.875, + "width": 86.0, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1251, + "version": 1, + "versionNonce": 1252, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "SUBTYPE_OF", + "originalText": "SUBTYPE_OF", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_st3", + "x": 543.0, + "y": 367.875, + "width": 98.0, + "height": 24.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1253, + "version": 1, + "versionNonce": 1254, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_st3_t", + "x": 549.0, + "y": 371.875, + "width": 86.0, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1255, + "version": 1, + "versionNonce": 1256, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "SUBTYPE_OF", + "originalText": "SUBTYPE_OF", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_hc", + "x": 559.75, + "y": 592.875, + "width": 130.5, + "height": 24.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1257, + "version": 1, + "versionNonce": 1258, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_hc_t", + "x": 565.75, + "y": 596.875, + "width": 118.5, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1259, + "version": 1, + "versionNonce": 1260, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "HAS_COMPONENT", + "originalText": "HAS_COMPONENT", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_de0", + "x": 668.35, + "y": 213.875, + "width": 147.3, + "height": 24.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1261, + "version": 1, + "versionNonce": 1262, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_de0_t", + "x": 674.35, + "y": 217.875, + "width": 135.3, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1263, + "version": 1, + "versionNonce": 1264, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "HAS_DATA_ELEMENT", + "originalText": "HAS_DATA_ELEMENT", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_de1", + "x": 668.35, + "y": 252.875, + "width": 147.3, + "height": 24.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1265, + "version": 1, + "versionNonce": 1266, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_de1_t", + "x": 674.35, + "y": 256.875, + "width": 135.3, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1267, + "version": 1, + "versionNonce": 1268, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "HAS_DATA_ELEMENT", + "originalText": "HAS_DATA_ELEMENT", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_de2", + "x": 668.35, + "y": 291.875, + "width": 147.3, + "height": 24.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1269, + "version": 1, + "versionNonce": 1270, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_de2_t", + "x": 674.35, + "y": 295.875, + "width": 135.3, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1271, + "version": 1, + "versionNonce": 1272, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "HAS_DATA_ELEMENT", + "originalText": "HAS_DATA_ELEMENT", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_de3", + "x": 668.35, + "y": 330.875, + "width": 147.3, + "height": 24.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1273, + "version": 1, + "versionNonce": 1274, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_de3_t", + "x": 674.35, + "y": 334.875, + "width": 135.3, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1275, + "version": 1, + "versionNonce": 1276, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "HAS_DATA_ELEMENT", + "originalText": "HAS_DATA_ELEMENT", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_de4", + "x": 668.35, + "y": 369.875, + "width": 147.3, + "height": 24.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1277, + "version": 1, + "versionNonce": 1278, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_de4_t", + "x": 674.35, + "y": 373.875, + "width": 135.3, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1279, + "version": 1, + "versionNonce": 1280, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "HAS_DATA_ELEMENT", + "originalText": "HAS_DATA_ELEMENT", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_ms0", + "x": 653.45, + "y": 408.875, + "width": 147.1, + "height": 24.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1281, + "version": 1, + "versionNonce": 1282, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_ms0_t", + "x": 659.45, + "y": 412.875, + "width": 135.1, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1283, + "version": 1, + "versionNonce": 1284, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "HAS_MEASUREMENT", + "originalText": "HAS_MEASUREMENT", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_ms1", + "x": 658.45, + "y": 447.875, + "width": 147.1, + "height": 24.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1285, + "version": 1, + "versionNonce": 1286, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_ms1_t", + "x": 664.45, + "y": 451.875, + "width": 135.1, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1287, + "version": 1, + "versionNonce": 1288, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "HAS_MEASUREMENT", + "originalText": "HAS_MEASUREMENT", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_sc", + "x": 254.05, + "y": 317.875, + "width": 91.9, + "height": 24.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1289, + "version": 1, + "versionNonce": 1290, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_sc_t", + "x": 260.05, + "y": 321.875, + "width": 79.9, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1291, + "version": 1, + "versionNonce": 1292, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "SCOPED_TO", + "originalText": "SCOPED_TO", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_sp", + "x": 246.25, + "y": 362.875, + "width": 129.5, + "height": 24.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1293, + "version": 1, + "versionNonce": 1294, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_sp_t", + "x": 252.25, + "y": 366.875, + "width": 117.5, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1295, + "version": 1, + "versionNonce": 1296, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "IN_SUBSPECIALTY", + "originalText": "IN_SUBSPECIALTY", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_sn0", + "x": 269.77, + "y": 400.455, + "width": 74.1, + "height": 24.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1297, + "version": 1, + "versionNonce": 1298, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_sn0_t", + "x": 275.77, + "y": 404.455, + "width": 62.1, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1299, + "version": 1, + "versionNonce": 1300, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "SEEN_ON", + "originalText": "SEEN_ON", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_sn1", + "x": 257.05, + "y": 436.375, + "width": 74.1, + "height": 24.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1301, + "version": 1, + "versionNonce": 1302, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_sn1_t", + "x": 263.05, + "y": 440.375, + "width": 62.1, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1303, + "version": 1, + "versionNonce": 1304, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "SEEN_ON", + "originalText": "SEEN_ON", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "l_sn2", + "x": 209.51799999999997, + "y": 504.475, + "width": 74.1, + "height": 24.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1305, + "version": 1, + "versionNonce": 1306, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_sn2_t", + "x": 215.51799999999997, + "y": 508.475, + "width": 62.1, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1307, + "version": 1, + "versionNonce": 1308, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "SEEN_ON", + "originalText": "SEEN_ON", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "leg", + "x": 15, + "y": 735, + "width": 1020, + "height": 52, + "strokeColor": "#e2e8f0", + "backgroundColor": "#f8fafc", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1309, + "version": 1, + "versionNonce": 1310, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "lg0", + "x": 32, + "y": 753, + "width": 22, + "height": 16, + "strokeColor": "#059669", + "backgroundColor": "#d1fae5", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1311, + "version": 1, + "versionNonce": 1312, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "lg0_t", + "x": 62, + "y": 754, + "width": 63.6, + "height": 13.75, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1313, + "version": 1, + "versionNonce": 1314, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "FindingClass", + "originalText": "FindingClass", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "lg1", + "x": 141.6, + "y": 753, + "width": 22, + "height": 16, + "strokeColor": "#10b981", + "backgroundColor": "#ecfdf5", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1315, + "version": 1, + "versionNonce": 1316, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "lg1_t", + "x": 171.6, + "y": 754, + "width": 45.3, + "height": 13.75, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1317, + "version": 1, + "versionNonce": 1318, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Grouping", + "originalText": "Grouping", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "lg2", + "x": 232.89999999999998, + "y": 753, + "width": 22, + "height": 16, + "strokeColor": "#059669", + "backgroundColor": "#6ee7b7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1319, + "version": 1, + "versionNonce": 1320, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "lg2_t", + "x": 262.9, + "y": 754, + "width": 48.3, + "height": 13.75, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1321, + "version": 1, + "versionNonce": 1322, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Diagnosis", + "originalText": "Diagnosis", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "ellipse", + "id": "lg3", + "x": 326.2, + "y": 752, + "width": 26, + "height": 18, + "strokeColor": "#7e22ce", + "backgroundColor": "#e9d5ff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1323, + "version": 1, + "versionNonce": 1324, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "text", + "id": "lg3_t", + "x": 361.2, + "y": 754, + "width": 100.3, + "height": 13.75, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1325, + "version": 1, + "versionNonce": 1326, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "AssessmentScheme", + "originalText": "AssessmentScheme", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "lg4", + "x": 477.5, + "y": 753, + "width": 22, + "height": 16, + "strokeColor": "#1d4ed8", + "backgroundColor": "#bfdbfe", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1327, + "version": 1, + "versionNonce": 1328, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "lg4_t", + "x": 507.5, + "y": 754, + "width": 87.4, + "height": 13.75, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1329, + "version": 1, + "versionNonce": 1330, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "AnatomicLocation", + "originalText": "AnatomicLocation", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "lg5", + "x": 610.9, + "y": 753, + "width": 22, + "height": 16, + "strokeColor": "#6b7280", + "backgroundColor": "#e5e7eb", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1331, + "version": 1, + "versionNonce": 1332, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "lg5_t", + "x": 640.9, + "y": 754, + "width": 41.0, + "height": 13.75, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1333, + "version": 1, + "versionNonce": 1334, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Modality", + "originalText": "Modality", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "lg6", + "x": 697.9, + "y": 753, + "width": 22, + "height": 16, + "strokeColor": "#be123c", + "backgroundColor": "#ffe4e6", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1335, + "version": 1, + "versionNonce": 1336, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "lg6_t", + "x": 727.9, + "y": 754, + "width": 63.6, + "height": 13.75, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1337, + "version": 1, + "versionNonce": 1338, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "DataElement", + "originalText": "DataElement", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "lg7", + "x": 807.5, + "y": 753, + "width": 22, + "height": 16, + "strokeColor": "#6d28d9", + "backgroundColor": "#ede9fe", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1339, + "version": 1, + "versionNonce": 1340, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "lg7_t", + "x": 837.5, + "y": 754, + "width": 67.3, + "height": 13.75, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1341, + "version": 1, + "versionNonce": 1342, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Measurement", + "originalText": "Measurement", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "lg8", + "x": 920.8, + "y": 753, + "width": 22, + "height": 16, + "strokeColor": "#78748f", + "backgroundColor": "#e5e3ee", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1343, + "version": 1, + "versionNonce": 1344, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "lg8_t", + "x": 950.8, + "y": 754, + "width": 62.4, + "height": 13.75, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1345, + "version": 1, + "versionNonce": 1346, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Subspecialty", + "originalText": "Subspecialty", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "cap", + "x": 225.0, + "y": 799, + "width": 600, + "height": 13.75, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1347, + "version": 1, + "versionNonce": 1348, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "illustrative: reflects pending updates to the CDE graph", + "originalText": "illustrative: reflects pending updates to the CDE graph", + "fontSize": 11, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + } + ], + "appState": { + "viewBackgroundColor": "#ffffff", + "gridSize": null + }, + "files": {} +} \ No newline at end of file diff --git a/knowledge/drafts/nodule-neighborhood.svg b/knowledge/drafts/nodule-neighborhood.svg new file mode 100644 index 0000000..a1e1e76 --- /dev/null +++ b/knowledge/drafts/nodule-neighborhood.svg @@ -0,0 +1,2 @@ +pulmonary noduleFindingClasspulmonary parenchymal abnormalityGroupingpulmonary granulomaDiagnosispulmonary neoplasmDiagnosisLung-RADSAssessmentSchemeFleischner criteriaAssessmentSchemesolidpulmonary noduleFindingClasspart-solidpulmonary noduleFindingClassground glassnoduleFindingClasssolid component ofpart-solid pulmonary noduleFindingClasslungAnatomicLocationchest radiologySubspecialtyCTModalityXRModalityMRModalitypresenceDataElementcompositionDataElementmarginDataElementcalcificationDataElementinterval changeDataElementmean diameterMeasurementlong-axis diameterMeasurementSUBTYPE_OFSUBTYPE_OFMAY_MANIFEST_ASMAY_MANIFEST_ASASSESSED_BYASSESSED_BYSUBTYPE_OFSUBTYPE_OFSUBTYPE_OFHAS_COMPONENTHAS_DATA_ELEMENTHAS_DATA_ELEMENTHAS_DATA_ELEMENTHAS_DATA_ELEMENTHAS_DATA_ELEMENTHAS_MEASUREMENTHAS_MEASUREMENTSCOPED_TOIN_SUBSPECIALTYSEEN_ONSEEN_ONSEEN_ONFindingClassGroupingDiagnosisAssessmentSchemeAnatomicLocationModalityDataElementMeasurementSubspecialtyillustrative: reflects pending updates to the CDE graph \ No newline at end of file diff --git a/knowledge/drafts/overview.md b/knowledge/drafts/overview.md new file mode 100644 index 0000000..0caa189 --- /dev/null +++ b/knowledge/drafts/overview.md @@ -0,0 +1,117 @@ +--- +type: Overview +title: Open Imaging Data Model +description: What the Open Imaging Data Model is for, the two contexts it separates, its core pieces, what it is used for, what has been built, and where it stands. +tags: [overview, foundation-context, patient-context, data-structures, sdks] +status: draft +generated: { by: claude-fable-5-1/2026-09-24-restructure, at: 2026-09-24T00:00:00Z } +sources: + - id: lead-2026-09-24 + resource: docs/plans/2026-09-22-layout-plan.md + title: The project lead's statements of 2026-09-24 on the scope of OIDM, the Imaging Persona, and the two graphs (recorded verbatim in the layout plan) + - id: lead-2026-09-19 + resource: knowledge/plans/2026-09-20-knowledgebase-build-plan.md + title: "The project lead's notes of 2026-09-19 on data structures versus transport, recorded in the build plan's decisions of 2026-09-21 (\"Data structures versus transport\")" + - id: siim-2026 + resource: https://oidm-public.t3.tigrisfiles.io/oidm-knowledge-sources/SIIM%202026%20Reports-of-the-Future.pptx + title: "Structured Results and Context for Next-Generation Imaging Resulting Tools, SIIM 2026 annual meeting talk, June 2026, Mass General Brigham" + - id: status-2026-01 + resource: https://gamma.app/docs/Open-Imaging-Data-Model-2026-Status-Update:-Realizing-Object-Oriented-Imaging-Results-yfxzx4q9zssafal + title: Open Imaging Data Model 2026 Status Update, January 2026 + - id: webinar-2026-07 + resource: https://oidm-public.t3.tigrisfiles.io/oidm-knowledge-sources/IPL%20Webinar%20Deck.html + title: "The Imaging Problem List as an Accelerator for Radiology AI Applications, SIIM Enterprise Imaging webinar, 15 July 2026" + - id: build-plan + resource: knowledge/plans/2026-09-20-knowledgebase-build-plan.md + title: Knowledgebase build plan, the project lead's stated goals and the decisions of 2026-09-21 + - id: use-cases-index + resource: https://github.com/openimagingdata/UseCases/blob/71a90d2/Index.md + title: Use case catalog index, UseCases repository, including the ACR GRID registry submission case + - id: forge-docs + resource: https://github.com/openimagingdata/FindingModelForge/blob/dev/docs/finding-model-creation-workflow.md + title: Finding Model Forge, finding model creation workflow, dev branch + - id: catalog-site + resource: https://github.com/openimagingdata/finding-models-site + title: finding-models-site repository, the static catalog reader + - id: fm-cli + resource: https://github.com/openimagingdata/findingmodel/blob/main/README.md + title: findingmodel README, the finding model and anatomic locations command-line tools + - id: ipl-readme + resource: https://github.com/openimagingdata/imaging-problem-list/blob/dev/README.md + title: imaging-problem-list README, dev branch, the extraction and coding platform and the viewers + - id: site-2023-06 + resource: https://www.openimagingdata.org/siim-update/ + title: "SIIM update, openimagingdata.org, June 2023 (the rendering hackathon)" + - id: site-2024-01 + resource: https://www.openimagingdata.org/2024-new-year-update/ + title: "2024 New Year Update, openimagingdata.org, January 2024 (assisted-reporting and AI in Practice demonstrations)" + - id: site-2024-07 + resource: https://www.openimagingdata.org/siim-2024-update-hackathon-edition/ + title: "SIIM 2024 update, hackathon edition, openimagingdata.org, July 2024 (the ontology-search hackathon)" +--- + +# Open Imaging Data Model + +The Open Imaging Data Model (OIDM) is an effort to model the context of imaging work across its whole lifecycle, from ordering through acquisition, interpretation, reporting, and follow-up, so that the medical imaging ecosystem has a common platform on which to build tools that assist radiologists, technologists, ordering providers, and back-office staff.[^lead-2026-09-24] + +The current focus is one part of that: data structures and semantics for representing imaging results. That means results from the current exam and from prior exams, produced by radiologists, technologists, AI, or the modalities themselves, and integrated across time so that a finding has a history rather than a series of disconnected mentions. Later work will model the broader patient context, integrating imaging results into the larger fabric of the patient's history and linking them to the patient's other diagnoses, procedures, and issues.[^lead-2026-09-24] + +OIDM defines data structures for use inside applications, to both read and create data. It is not a transport format. FHIR and DICOM expressions of the structures are designed separately and are guided by them.[^lead-2026-09-19] + +# Why results as data + +Today the findings in a radiology report are written for a human reader and then locked in narrative text. Represented as data, once, each finding becomes reusable in two directions: forward to clinicians, to drive treatment decisions, follow-up, and care coordination; and forward to the next radiologist reading the subsequent exam, who needs to know what was there before, where, and whether it changed.[^siim-2026] + +# The two contexts + +A structured finding, say "pulmonary nodule, present, right upper lobe, 8 mm, new", says what exists, where, and on what exam. It does not say how a nodule associates with other findings, how it might be precancerous, which prior exams could show it, what the implications are, or what else it could be. That knowledge is not in the patient's record. It is background knowledge of anatomy, pathology, and imaging technique.[^siim-2026] + +OIDM therefore separates two things. **Patient Context** is this patient's results and clinical context: one per patient, protected health information, changing as the patient's condition evolves. **Foundation Context** is a single shared layer of definitions, relationships, and citations: what a pulmonary nodule is, where it can occur, what it can cause, what it can be confused with. It is open, not patient-specific, authored and versioned in the open.[^siim-2026] The two are deeply interconnected: every contingent fact about this patient, this nodule on this exam, is attached to the baseline clinical knowledge about what such a thing is, so that an application reading the patient's record has the knowledge to interpret it.[^lead-2026-09-24] + +[![Two planes: a patient's exam and findings in Patient Context, attached to the exam type, the finding definitions, and the anatomic locations in Foundation Context](./two-planes.svg)](./two-planes.svg) + +(click the image for full size) + +# The core pieces + +**[Foundation Context](./foundation-context.md).** The shared semantic layer. It has three axes, each a curated layer over an existing standard: what was found (finding/diagnosis definitions, held as Open Imaging Finding Models and as ACR/RSNA Common Data Elements), where it is (anatomic locations anchored in RadLex), and how it was seen (exam types over the LOINC/RSNA Radiology Playbook). The axes relate to each other and cite external references. This pillar covers both the shape a definition takes and the work of building the content.[^siim-2026][^build-plan] + +**[Data Structures](./data-structures.md).** The patient-side structures. The Observation is the atomic unit: one finding or diagnosis, its presence, its change from prior, its location, its characterizing attributes, and its ties into Foundation Context. Observations can come from a radiologist, a technologist, an AI, or the modality itself. An Exam Finding List holds all the Observations from one exam. An Imaging Problem List reorganizes a patient's Observations by finding, across exams, so that each finding has a history. The Imaging Persona is the proposal that goes furthest: the imaging results integrated into a single larger graph of the patient's history, with the patient's other diagnoses, procedures, and issues, the whole of it underpinned by Foundation Context. Patient-side data forms one graph and Foundation Context forms another, and the patient graph is woven into the foundation graph at every finding, diagnosis, location, and exam type.[^siim-2026][^lead-2026-09-24] + +**[SDKs](./sdks.md).** The tools that wrap these structures so that developers can create, read, and manipulate instances in real applications, and that attach the shared knowledge to a patient's data the same way every time. Some SDK capabilities also support the authoring of Foundation Context itself.[^build-plan][^siim-2026] + +# Use cases + +With structured results and shared context, the same machinery serves many purposes: reporting assistance that knows what a finding is; longitudinal tracking of findings across exams; decision support, follow-up management, and care coordination; quality surveillance; registry submission and research extraction; and grounding for generative tools, which get a citable shared context instead of inventing one.[^webinar-2026-07][^siim-2026][^use-cases-index] The [Use Cases](./use-cases.md) section lists every purpose the project has written down, with a page for each one worked out in detail. + +# Sample applications + +The project has built demonstrations to make the ideas concrete. Each is listed in [Sample Applications](./sample-applications.md) with the idea it illustrates. + +- [Finding Model Forge](https://fmf.oidm.org), for authoring and reviewing finding/diagnosis definitions.[^forge-docs] +- The [finding models catalog](https://openimagingdata.github.io/finding-models-site/), for browsing the definitions.[^catalog-site] +- Command-line tools for finding models and for anatomic locations.[^fm-cli] +- Two Imaging Problem List viewers: [the first](https://imaging-problem-list.pages.dev), and [the second](https://main.ipl-anatomy.pages.dev), organized by anatomy.[^webinar-2026-07][^ipl-readme] +- A report extraction and coding platform that turns report text into Observations.[^ipl-readme] +- Public demonstrations of rendering a coded finding as prose (2023), ontology search (2024), and assisted reporting (2024).[^site-2023-06][^site-2024-07][^site-2024-01] + +# Where things stand + +Nothing here is formally specified. The project is coalescing, and its structures exist in several dated versions: in code, in manuscripts under review, in talks, and in working documents. This knowledgebase presents each version beside the others, attributed and dated, and states disagreements without resolving them.[^build-plan] + +The project asks three things: contribute or propose finding/diagnosis definitions; review AI-generated content and connections; build against the SDKs.[^siim-2026] + +[^lead-2026-09-24]: The project lead, 2026-09-24, on the scope of OIDM, the Imaging Persona, and the interconnection of the two graphs; recorded verbatim in the layout plan. +[^lead-2026-09-19]: The project lead, 2026-09-19, notes on the revised Imaging Problem List manuscript: data structures for use within applications, not a transport definition. +[^siim-2026]: SIIM 2026 annual meeting talk, June 2026, Mass General Brigham; slides 3, 4, 5, 6, 7, 8, 14, and 15. +[^status-2026-01]: Open Imaging Data Model 2026 Status Update, January 2026. +[^webinar-2026-07]: SIIM Enterprise Imaging webinar, 15 July 2026, the six application families and the two live-prototype slides. +[^use-cases-index]: Use case catalog index, UseCases repository, commit 71a90d2: "Add information to ACR GRID registry". +[^forge-docs]: Finding Model Forge, finding model creation workflow document, dev branch. +[^catalog-site]: finding-models-site repository. +[^fm-cli]: findingmodel README, main branch, command-line tools. +[^ipl-readme]: imaging-problem-list README, dev branch. +[^site-2023-06]: "SIIM update", openimagingdata.org, June 2023. +[^site-2024-01]: "2024 New Year Update", openimagingdata.org, January 2024. +[^site-2024-07]: "SIIM 2024 update, hackathon edition", openimagingdata.org, July 2024. +[^build-plan]: Knowledgebase build plan, the project lead's stated goals (2026-09-20) and "No specification exists" (2026-09-21). diff --git a/knowledge/drafts/pillars-a.excalidraw b/knowledge/drafts/pillars-a.excalidraw new file mode 100644 index 0000000..3efda21 --- /dev/null +++ b/knowledge/drafts/pillars-a.excalidraw @@ -0,0 +1,2317 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "oidm-knowledge/tools/diagrams", + "elements": [ + { + "type": "rectangle", + "id": "band53", + "x": 0, + "y": 437.05, + "width": 880, + "height": 247.49999999999994, + "strokeColor": "#b45309", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1105, + "version": 1, + "versionNonce": 1106, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "band33", + "x": 0, + "y": 187.3, + "width": 880, + "height": 189.75, + "strokeColor": "#0f766e", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1065, + "version": 1, + "versionNonce": 1066, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "band15", + "x": 0, + "y": 91.65, + "width": 880, + "height": 71.65, + "strokeColor": "#6d28d9", + "backgroundColor": "#ede9fe", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1029, + "version": 1, + "versionNonce": 1030, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "panel1", + "x": 0, + "y": 0, + "width": 388.0, + "height": 67.65, + "strokeColor": "#be123c", + "backgroundColor": "#ffe4e6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1001, + "version": 1, + "versionNonce": 1002, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "panel2", + "x": 492.0, + "y": 0, + "width": 388.0, + "height": 67.65, + "strokeColor": "#15803d", + "backgroundColor": "#dcfce7", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1003, + "version": 1, + "versionNonce": 1004, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "bicon3", + "x": 18, + "y": 12.0, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1005, + "version": 1, + "versionNonce": 1006, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon3", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle4", + "x": 58, + "y": 14, + "width": 93.96, + "height": 22.5, + "strokeColor": "#881337", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1007, + "version": 1, + "versionNonce": 1008, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Use Cases", + "originalText": "Use Cases", + "fontSize": 18, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub5", + "x": 58, + "y": 37.400000000000006, + "width": 211.11999999999998, + "height": 16.25, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1009, + "version": 1, + "versionNonce": 1010, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "what the project wants built", + "originalText": "what the project wants built", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon6", + "x": 510.0, + "y": 12.0, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1011, + "version": 1, + "versionNonce": 1012, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon6", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle7", + "x": 550.0, + "y": 14, + "width": 198.35999999999999, + "height": 22.5, + "strokeColor": "#14532d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1013, + "version": 1, + "versionNonce": 1014, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Sample Applications", + "originalText": "Sample Applications", + "fontSize": 18, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub8", + "x": 550.0, + "y": 37.400000000000006, + "width": 143.26, + "height": 16.25, + "strokeColor": "#15803d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1015, + "version": 1, + "versionNonce": 1016, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "what has been built", + "originalText": "what has been built", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "conn9", + "x": 390.0, + "y": 33.825, + "width": 100.0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1017, + "version": 1, + "versionNonce": 1018, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 100.0, + 0 + ] + ] + }, + { + "type": "rectangle", + "id": "chip10", + "x": 389.53, + "y": 4.575000000000003, + "width": 100.94, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1019, + "version": 1, + "versionNonce": 1020, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "chipt11", + "x": 398.53, + "y": 7.575000000000003, + "width": 82.94, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1021, + "version": 1, + "versionNonce": 1022, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "illustrates", + "originalText": "illustrates", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon12", + "x": 18, + "y": 105.65, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1023, + "version": 1, + "versionNonce": 1024, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon12", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle13", + "x": 58, + "y": 107.65, + "width": 41.76, + "height": 22.5, + "strokeColor": "#4c1d95", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1025, + "version": 1, + "versionNonce": 1026, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "SDKs", + "originalText": "SDKs", + "fontSize": 18, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub14", + "x": 58, + "y": 131.05, + "width": 520.26, + "height": 16.25, + "strokeColor": "#6d28d9", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1027, + "version": 1, + "versionNonce": 1028, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "wrap the structures \u00b7 attach the shared knowledge \u00b7 support authoring", + "originalText": "wrap the structures \u00b7 attach the shared knowledge \u00b7 support authoring", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon16", + "x": 18, + "y": 203.3, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1031, + "version": 1, + "versionNonce": 1032, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon16", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle17", + "x": 58, + "y": 205.3, + "width": 174.0, + "height": 25.0, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1033, + "version": 1, + "versionNonce": 1034, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Data Structures", + "originalText": "Data Structures", + "fontSize": 20, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub18", + "x": 58, + "y": 231.3, + "width": 226.2, + "height": 16.25, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1035, + "version": 1, + "versionNonce": 1036, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "this patient \u00b7 Patient Context", + "originalText": "this patient \u00b7 Patient Context", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk19", + "x": 20.0, + "y": 261.55, + "width": 195.0, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1037, + "version": 1, + "versionNonce": 1038, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki20", + "x": 103.5, + "y": 281.925, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1039, + "version": 1, + "versionNonce": 1040, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki20", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt21", + "x": 26.0, + "y": 315.925, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1041, + "version": 1, + "versionNonce": 1042, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Observation", + "originalText": "Observation", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk22", + "x": 235.0, + "y": 261.55, + "width": 195.0, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1043, + "version": 1, + "versionNonce": 1044, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki23", + "x": 318.5, + "y": 272.55, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1045, + "version": 1, + "versionNonce": 1046, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki23", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt24", + "x": 241.0, + "y": 306.55, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1047, + "version": 1, + "versionNonce": 1048, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Exam Finding", + "originalText": "Exam Finding", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkt25", + "x": 241.0, + "y": 325.3, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1049, + "version": 1, + "versionNonce": 1050, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "List", + "originalText": "List", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk26", + "x": 450.0, + "y": 261.55, + "width": 195.0, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1051, + "version": 1, + "versionNonce": 1052, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki27", + "x": 533.5, + "y": 272.55, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1053, + "version": 1, + "versionNonce": 1054, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki27", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt28", + "x": 456.0, + "y": 306.55, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1055, + "version": 1, + "versionNonce": 1056, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Imaging Problem", + "originalText": "Imaging Problem", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkt29", + "x": 456.0, + "y": 325.3, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1057, + "version": 1, + "versionNonce": 1058, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "List", + "originalText": "List", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk30", + "x": 665.0, + "y": 261.55, + "width": 195.0, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1059, + "version": 1, + "versionNonce": 1060, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki31", + "x": 746.5, + "y": 279.925, + "width": 32, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1061, + "version": 1, + "versionNonce": 1062, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki31", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt32", + "x": 671.0, + "y": 315.925, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1063, + "version": 1, + "versionNonce": 1064, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Imaging Persona", + "originalText": "Imaging Persona", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon34", + "x": 18, + "y": 481.05, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1067, + "version": 1, + "versionNonce": 1068, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon34", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle35", + "x": 58, + "y": 483.05, + "width": 208.79999999999998, + "height": 25.0, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1069, + "version": 1, + "versionNonce": 1070, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Foundation Context", + "originalText": "Foundation Context", + "fontSize": 20, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub36", + "x": 58, + "y": 509.05, + "width": 188.5, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1071, + "version": 1, + "versionNonce": 1072, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "shared, curated knowledge", + "originalText": "shared, curated knowledge", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "chip37", + "x": 381.99, + "y": 537.3, + "width": 116.02, + "height": 22.25, + "strokeColor": "#b45309", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1073, + "version": 1, + "versionNonce": 1074, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "chipt38", + "x": 390.99, + "y": 540.3, + "width": 98.02, + "height": 16.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1075, + "version": 1, + "versionNonce": 1076, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "relationships", + "originalText": "relationships", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk39", + "x": 20.0, + "y": 569.55, + "width": 237.33333333333334, + "height": 95.0, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1077, + "version": 1, + "versionNonce": 1078, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki40", + "x": 124.66666666666669, + "y": 580.55, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1079, + "version": 1, + "versionNonce": 1080, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki40", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt41", + "x": 26.0, + "y": 614.55, + "width": 225.33333333333334, + "height": 18.75, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1081, + "version": 1, + "versionNonce": 1082, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Finding/diagnosis definitions", + "originalText": "Finding/diagnosis definitions", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkd42", + "x": 26.0, + "y": 635.3, + "width": 225.33333333333334, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1083, + "version": 1, + "versionNonce": 1084, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "finding models \u00b7 CDEs", + "originalText": "finding models \u00b7 CDEs", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk43", + "x": 321.33333333333337, + "y": 569.55, + "width": 237.33333333333334, + "height": 95.0, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1085, + "version": 1, + "versionNonce": 1086, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki44", + "x": 424.00000000000006, + "y": 578.55, + "width": 32, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1087, + "version": 1, + "versionNonce": 1088, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki44", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt45", + "x": 327.33333333333337, + "y": 614.55, + "width": 225.33333333333334, + "height": 18.75, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1089, + "version": 1, + "versionNonce": 1090, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Anatomic locations", + "originalText": "Anatomic locations", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkd46", + "x": 327.33333333333337, + "y": 635.3, + "width": 225.33333333333334, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1091, + "version": 1, + "versionNonce": 1092, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "anchored in RadLex", + "originalText": "anchored in RadLex", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk47", + "x": 622.6666666666667, + "y": 569.55, + "width": 237.33333333333334, + "height": 95.0, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1093, + "version": 1, + "versionNonce": 1094, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki48", + "x": 725.3333333333334, + "y": 578.55, + "width": 32, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1095, + "version": 1, + "versionNonce": 1096, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki48", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt49", + "x": 628.6666666666667, + "y": 614.55, + "width": 225.33333333333334, + "height": 18.75, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1097, + "version": 1, + "versionNonce": 1098, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Exam types", + "originalText": "Exam types", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkd50", + "x": 628.6666666666667, + "y": 635.3, + "width": 225.33333333333334, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1099, + "version": 1, + "versionNonce": 1100, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "LOINC/RSNA Playbook", + "originalText": "LOINC/RSNA Playbook", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "conn51", + "x": 263.33333333333337, + "y": 617.05, + "width": 52.0, + "height": 0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1101, + "version": 1, + "versionNonce": 1102, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 52.0, + 0 + ] + ], + "startArrowhead": "arrow", + "endArrowhead": "arrow" + }, + { + "type": "arrow", + "id": "conn52", + "x": 564.6666666666667, + "y": 617.05, + "width": 52.0, + "height": 0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1103, + "version": 1, + "versionNonce": 1104, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 52.0, + 0 + ] + ], + "startArrowhead": "arrow", + "endArrowhead": "arrow" + }, + { + "type": "line", + "id": "ln54", + "x": 62.9, + "y": 357.05, + "width": 9.9866666666667, + "height": 57.75, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 75, + "angle": 0, + "seed": 1107, + "version": 1, + "versionNonce": 1108, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 9.9866666666667, + 57.75 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln55", + "x": 117.5, + "y": 357.05, + "width": 264.26000000000005, + "height": 57.75, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 75, + "angle": 0, + "seed": 1109, + "version": 1, + "versionNonce": 1110, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 264.26000000000005, + 57.75 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln56", + "x": 172.1, + "y": 357.05, + "width": 499.6833333333334, + "height": 57.75, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 75, + "angle": 0, + "seed": 1111, + "version": 1, + "versionNonce": 1112, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 499.6833333333334, + 57.75 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln57", + "x": 332.5, + "y": 357.05, + "width": 448.22333333333336, + "height": 57.75, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 75, + "angle": 0, + "seed": 1113, + "version": 1, + "versionNonce": 1114, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 448.22333333333336, + 57.75 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln58", + "x": 518.25, + "y": 357.05, + "width": 351.50333333333333, + "height": 57.75, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 75, + "angle": 0, + "seed": 1115, + "version": 1, + "versionNonce": 1116, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + -351.50333333333333, + 57.75 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln59", + "x": 576.75, + "y": 357.05, + "width": 86.04999999999995, + "height": 57.75, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 75, + "angle": 0, + "seed": 1117, + "version": 1, + "versionNonce": 1118, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + -86.04999999999995, + 57.75 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "plate60", + "x": 50.8066666666667, + "y": 414.8, + "width": 44.16, + "height": 22.25, + "strokeColor": "#b45309", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1119, + "version": 1, + "versionNonce": 1120, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "platet61", + "x": 57.8066666666667, + "y": 417.8, + "width": 30.159999999999997, + "height": 16.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1121, + "version": 1, + "versionNonce": 1122, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "is a", + "originalText": "is a", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "plate62", + "x": 337.06000000000006, + "y": 414.8, + "width": 89.39999999999999, + "height": 22.25, + "strokeColor": "#b45309", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1123, + "version": 1, + "versionNonce": 1124, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "platet63", + "x": 344.06000000000006, + "y": 417.8, + "width": 75.39999999999999, + "height": 16.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1125, + "version": 1, + "versionNonce": 1126, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "located at", + "originalText": "located at", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "plate64", + "x": 638.3933333333334, + "y": 414.8, + "width": 66.78, + "height": 22.25, + "strokeColor": "#b45309", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1127, + "version": 1, + "versionNonce": 1128, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "platet65", + "x": 645.3933333333334, + "y": 417.8, + "width": 52.78, + "height": 16.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1129, + "version": 1, + "versionNonce": 1130, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "seen on", + "originalText": "seen on", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "plate66", + "x": 717.1733333333334, + "y": 414.8, + "width": 127.1, + "height": 22.25, + "strokeColor": "#b45309", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1131, + "version": 1, + "versionNonce": 1132, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "platet67", + "x": 724.1733333333334, + "y": 417.8, + "width": 113.1, + "height": 16.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1133, + "version": 1, + "versionNonce": 1134, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "of an exam type", + "originalText": "of an exam type", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "plate68", + "x": 106.96666666666667, + "y": 414.8, + "width": 119.55999999999999, + "height": 22.25, + "strokeColor": "#b45309", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1135, + "version": 1, + "versionNonce": 1136, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "platet69", + "x": 113.96666666666667, + "y": 417.8, + "width": 105.55999999999999, + "height": 16.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1137, + "version": 1, + "versionNonce": 1138, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "per definition", + "originalText": "per definition", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "plate70", + "x": 438.46000000000004, + "y": 414.8, + "width": 104.47999999999999, + "height": 22.25, + "strokeColor": "#b45309", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1139, + "version": 1, + "versionNonce": 1140, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "platet71", + "x": 445.46000000000004, + "y": 417.8, + "width": 90.47999999999999, + "height": 16.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1141, + "version": 1, + "versionNonce": 1142, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "per location", + "originalText": "per location", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "seaml72", + "x": 0, + "y": 450.05, + "width": 880, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1143, + "version": 1, + "versionNonce": 1144, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "interconnected at every finding, diagnosis, location, and exam type", + "originalText": "interconnected at every finding, diagnosis, location, and exam type", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + } + ], + "appState": { + "viewBackgroundColor": "#ffffff", + "gridSize": null + }, + "files": { + "img_bicon3": { + "mimeType": "image/svg+xml", + "id": "img_bicon3", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiNiZTEyM2MiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTE1IDE0Yy4yLTEgLjctMS43IDEuNS0yLjUgMS0uOSAxLjUtMi4yIDEuNS0zLjVBNiA2IDAgMCAwIDYgOGMwIDEgLjIgMi4yIDEuNSAzLjUuNy43IDEuMyAxLjUgMS41IDIuNSIgLz4KICA8cGF0aCBkPSJNOSAxOGg2IiAvPgogIDxwYXRoIGQ9Ik0xMCAyMmg0IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_bicon6": { + "mimeType": "image/svg+xml", + "id": "img_bicon6", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMxNTgwM2QiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHJlY3QgeD0iMiIgeT0iNCIgd2lkdGg9IjIwIiBoZWlnaHQ9IjE2IiByeD0iMiIgLz4KICA8cGF0aCBkPSJNMTAgNHY0IiAvPgogIDxwYXRoIGQ9Ik0yIDhoMjAiIC8+CiAgPHBhdGggZD0iTTYgNHY0IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_bicon12": { + "mimeType": "image/svg+xml", + "id": "img_bicon12", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiM2ZDI4ZDkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTExIDIxLjczYTIgMiAwIDAgMCAyIDBsNy00QTIgMiAwIDAgMCAyMSAxNlY4YTIgMiAwIDAgMC0xLTEuNzNsLTctNGEyIDIgMCAwIDAtMiAwbC03IDRBMiAyIDAgMCAwIDMgOHY4YTIgMiAwIDAgMCAxIDEuNzN6IiAvPgogIDxwYXRoIGQ9Ik0xMiAyMlYxMiIgLz4KICA8cG9seWxpbmUgcG9pbnRzPSIzLjI5IDcgMTIgMTIgMjAuNzEgNyIgLz4KICA8cGF0aCBkPSJtNy41IDQuMjcgOSA1LjE1IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_bicon16": { + "mimeType": "image/svg+xml", + "id": "img_bicon16", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyLjgzIDIuMThhMiAyIDAgMCAwLTEuNjYgMEwyLjYgNi4wOGExIDEgMCAwIDAgMCAxLjgzbDguNTggMy45MWEyIDIgMCAwIDAgMS42NiAwbDguNTgtMy45YTEgMSAwIDAgMCAwLTEuODN6IiAvPgogIDxwYXRoIGQ9Ik0yIDEyYTEgMSAwIDAgMCAuNTguOTFsOC42IDMuOTFhMiAyIDAgMCAwIDEuNjUgMGw4LjU4LTMuOUExIDEgMCAwIDAgMjIgMTIiIC8+CiAgPHBhdGggZD0iTTIgMTdhMSAxIDAgMCAwIC41OC45MWw4LjYgMy45MWEyIDIgMCAwIDAgMS42NSAwbDguNTgtMy45QTEgMSAwIDAgMCAyMiAxNyIgLz4KPC9zdmc+Cg==", + "created": 1700000000000 + }, + "img_blki20": { + "mimeType": "image/svg+xml", + "id": "img_blki20", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHJlY3Qgd2lkdGg9IjgiIGhlaWdodD0iNCIgeD0iOCIgeT0iMiIgcng9IjEiIHJ5PSIxIiAvPgogIDxwYXRoIGQ9Ik0xNiA0aDJhMiAyIDAgMCAxIDIgMnYxNGEyIDIgMCAwIDEtMiAySDZhMiAyIDAgMCAxLTItMlY2YTIgMiAwIDAgMSAyLTJoMiIgLz4KPC9zdmc+Cg==", + "created": 1700000000000 + }, + "img_blki23": { + "mimeType": "image/svg+xml", + "id": "img_blki23", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHJlY3Qgd2lkdGg9IjgiIGhlaWdodD0iNCIgeD0iOCIgeT0iMiIgcng9IjEiIHJ5PSIxIiAvPgogIDxwYXRoIGQ9Ik0xNiA0aDJhMiAyIDAgMCAxIDIgMnYxNGEyIDIgMCAwIDEtMiAySDZhMiAyIDAgMCAxLTItMlY2YTIgMiAwIDAgMSAyLTJoMiIgLz4KICA8cGF0aCBkPSJNMTIgMTFoNCIgLz4KICA8cGF0aCBkPSJNMTIgMTZoNCIgLz4KICA8cGF0aCBkPSJNOCAxMWguMDEiIC8+CiAgPHBhdGggZD0iTTggMTZoLjAxIiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki27": { + "mimeType": "image/svg+xml", + "id": "img_blki27", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTMgNWguMDEiIC8+CiAgPHBhdGggZD0iTTMgMTJoLjAxIiAvPgogIDxwYXRoIGQ9Ik0zIDE5aC4wMSIgLz4KICA8cGF0aCBkPSJNOCA1aDEzIiAvPgogIDxwYXRoIGQ9Ik04IDEyaDEzIiAvPgogIDxwYXRoIGQ9Ik04IDE5aDEzIiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki31": { + "mimeType": "image/svg+xml", + "id": "img_blki31", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yNCAyNEMyOC40MjA0IDI0IDMyIDIwLjQyMDQgMzIgMTZDMzIgMTEuNTc5NiAyOC40MjA0IDggMjQgOEMxOS41Nzk2IDggMTYgMTEuNTc5NiAxNiAxNkMxNiAyMC40MjA0IDE5LjU3OTYgMjQgMjQgMjRaTTM0IDE2QzM0IDIxLjUyNSAyOS41MjUgMjYgMjQgMjZDMTguNDc1IDI2IDE0IDIxLjUyNSAxNCAxNkMxNCAxMC40NzUgMTguNDc1IDYgMjQgNkMyOS41MjUgNiAzNCAxMC40NzUgMzQgMTZaIiBmaWxsPSIjMGY3NjZlIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNOS4yMjM0OCAzNC4yMTE5QzguMjIwMzggMzUuMDIxMSA4IDM1LjYyOTEgOCAzNlY0MEg0MFYzNkM0MCAzNS42MjkxIDM5Ljc3OTYgMzUuMDIxMSAzOC43NzY1IDM0LjIxMTlDMzcuNzk1OCAzMy40MjA3IDM2LjMzNDEgMzIuNjY2OSAzNC41NjIyIDMyLjAxNUMzMS4wMTk5IDMwLjcxMTcgMjYuNzUzMiAzMCAyNCAzMEMyMS4yNDY4IDMwIDE2Ljk4MDEgMzAuNzExNyAxMy40Mzc4IDMyLjAxNUMxMS42NjU5IDMyLjY2NjkgMTAuMjA0MiAzMy40MjA3IDkuMjIzNDggMzQuMjExOVpNMjQgMjhDMTcuOTkyNSAyOCA2IDMxLjAzNDcgNiAzNlY0Mkg0MlYzNkM0MiAzMS4wMzQ3IDMwLjAwNzUgMjggMjQgMjhaIiBmaWxsPSIjMGY3NjZlIi8+Cjwvc3ZnPgo=", + "created": 1700000000000 + }, + "img_bicon34": { + "mimeType": "image/svg+xml", + "id": "img_bicon34", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiNiNDUzMDkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyIDV2MTYiIC8+CiAgPHBhdGggZD0iTTIwLjAwMSAxOUEyIDIgMCAwMDIyIDE3VjVhMiAyIDAgMDAtMS45OTktMkwxNiAzLjAwMkE1IDUgMCAwMDEyIDVhNSA1IDAgMDAtNC0ySDRhMiAyIDAgMDAtMiAydjEyYTIgMiAwIDAwMS45OTkgMkg4YTUgNSAwIDAxNCAyIDUgNSAwIDAxNC0yeiIgLz4KPC9zdmc+Cg==", + "created": 1700000000000 + }, + "img_blki40": { + "mimeType": "image/svg+xml", + "id": "img_blki40", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiNiNDUzMDkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyLjU4NiAyLjU4NkEyIDIgMCAwIDAgMTEuMTcyIDJINGEyIDIgMCAwIDAtMiAydjcuMTcyYTIgMiAwIDAgMCAuNTg2IDEuNDE0bDguNzA0IDguNzA0YTIuNDI2IDIuNDI2IDAgMCAwIDMuNDIgMGw2LjU4LTYuNThhMi40MjYgMi40MjYgMCAwIDAgMC0zLjQyeiIgLz4KICA8Y2lyY2xlIGN4PSI3LjUiIGN5PSI3LjUiIHI9Ii41IiBmaWxsPSIjYjQ1MzA5IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki44": { + "mimeType": "image/svg+xml", + "id": "img_blki44", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yMyA2LjAwMDEzQzIzIDYuMDAwMDQgMjMgNiAyNCA2SDI0LjE3NjFDMjQuMjUzMyA2IDI0LjMyMzMgNiAyNC4zODY4IDZDMjUgNi4wMDAwMSAyNSA2LjAwMDA1IDI1IDYuMDAwMTNWMjAuNUMyNSAyMS44OTc3IDI1LjU2NDEgMjIuNDQyMSAyNi4wMDM5IDIyLjY5ODdDMjYuMDUzIDIyLjcyNzMgMjYuMTAyNCAyMi43NTMzIDI2LjE1MTYgMjIuNzc3QzI2LjE1MDYgMjIuNjU2OCAyNi4xNDkzIDIyLjUzMTYgMjYuMTQ3OSAyMi40MDE5TDI2LjE0NzkgMjIuNDAwM0MyNi4xMTAxIDE4Ljg3MTYgMjYuMDM2NSAxMS45OTk3IDMxLjQ3NTMgMTEuOTk5N0MzOC45MjU5IDExLjk5OTcgNDQuMjQ3OCAzOC4wMDYyIDQxLjA1NDcgNDAuNjU5OUMzNy44NjE1IDQzLjMxMzYgMzEuNDc1MyA0MS43MjE0IDI4LjI4MjIgMzguNTM2OUMyNS43MDQyIDM1Ljk2NTkgMjUuOTI3MiAyOS45NTgzIDI2LjA4NzMgMjUuNjQ1N0wyNi4wODc0IDI1LjY0NDNDMjYuMDk3MSAyNS4zODE5IDI2LjEwNjcgMjUuMTI1OCAyNi4xMTUzIDI0Ljg3NzFDMjUuNzkgMjQuNzk2MiAyNS4zOTU5IDI0LjY1OTUgMjQuOTk2MiAyNC40MjYzQzI0LjYzOTggMjQuMjE4NCAyNC4yOTc1IDIzLjk0NDIgMjQgMjMuNTkxOUMyMy43MDI2IDIzLjk0NDIgMjMuMzYwMyAyNC4yMTg0IDIzLjAwMzkgMjQuNDI2M0MyMi42MDQxIDI0LjY1OTUgMjIuMjEwMSAyNC43OTYyIDIxLjg4NDggMjQuODc3MUMyMS44OTM0IDI1LjEyNjEgMjEuOTAyOSAyNS4zODI2IDIxLjkxMjcgMjUuNjQ1M0MyMi4wNzI4IDI5Ljk1NzkgMjIuMjk1OSAzNS45NjYyIDE5LjcxNzkgMzguNTM3MkMxNi41MjQ3IDQxLjcyMTcgMTAuMTM4NSA0My4zMTM5IDYuOTQ1MzYgNDAuNjYwMkMzLjc1MjIyIDM4LjAwNjUgOS4wNzQxMyAxMiAxNi41MjQ3IDEyQzIxLjk2MzYgMTIgMjEuODkgMTguODcxNyAyMS44NTIyIDIyLjQwMDNDMjEuODUyIDIyLjQxNjYgMjEuODUxOCAyMi40MzI4IDIxLjg1MTYgMjIuNDQ4OUMyMS44NTA0IDIyLjU2MTkgMjEuODQ5MyAyMi42NzE0IDIxLjg0ODQgMjIuNzc3QzIxLjg5NzcgMjIuNzUzNCAyMS45NDcxIDIyLjcyNzQgMjEuOTk2MiAyMi42OTg3QzIyLjQzNiAyMi40NDIxIDIzIDIxLjg5NzcgMjMgMjAuNVY2LjAwMDEzWk0zMS40NzUzIDEzLjk5OTdDMzAuNTIxMiAxMy45OTk3IDI5Ljk4NDMgMTQuMzAwMiAyOS42MDg2IDE0LjY4NjlDMjkuMTc1MiAxNS4xMzMxIDI4LjgxMzIgMTUuODUwNyAyOC41NTkgMTYuODY0NkMyOC4xMTQxIDE4LjYzOTUgMjguMTMzIDIwLjY4MTkgMjguMTQ4MyAyMi4zMjkzQzI4LjE1MDkgMjIuNjE0MiAyOC4xNTM0IDIyLjg4NzQgMjguMTUzNCAyMy4xNDUzQzI4LjE1MzQgMjMuOTA1MyAyOC4xMTk2IDI0LjgxNTMgMjguMDg0NSAyNS43NjIxQzI4LjA3MDcgMjYuMTM0OSAyOC4wNTY2IDI2LjUxMzMgMjguMDQ0MyAyNi44OTA1QzI3Ljk5OTYgMjguMjY1NyAyNy45NzQxIDI5LjcwNTUgMjguMDQwNSAzMS4wOTgyQzI4LjEwNzIgMzIuNDk4NSAyOC4yNjQyIDMzLjc4MzUgMjguNTU3MyAzNC44NTk2QzI4Ljg1MzggMzUuOTQ4MyAyOS4yNTA5IDM2LjY3ODQgMjkuNjk0NCAzNy4xMjA4QzMwLjk3MjYgMzguMzk1NCAzMi45OTA4IDM5LjQyNTEgMzUuMDQ5MiAzOS44MjQzQzM3LjA4NDIgNDAuMjE4OSAzOC43MjI0IDM5LjkyNjkgMzkuNjgxOCAzOS4xOTY5QzM5LjY4NjggMzkuMTg1NyAzOS42OTIzIDM5LjE3MjYgMzkuNjk4NCAzOS4xNTc0QzM5Ljc1NzYgMzkuMDA5NSAzOS44Mjk0IDM4Ljc1NTQgMzkuODg3OCAzOC4zNjgzQzQwLjAwNDcgMzcuNTkzMyA0MC4wMzUgMzYuNTEyMiAzOS45NTYyIDM1LjE4MDNDMzkuNzk5NSAzMi41MzA1IDM5LjIyODYgMjkuMTY4OSAzOC4zMjY4IDI1Ljg2MDZDMzcuNDIxNiAyMi41Mzk2IDM2LjIxNzMgMTkuMzk5OCAzNC44NTIxIDE3LjEzODNDMzQuMTY4OCAxNi4wMDYyIDMzLjQ5NTEgMTUuMTc4NiAzMi44NzAzIDE0LjY1MzVDMzIuMjUxOCAxNC4xMzM3IDMxLjc5MzUgMTMuOTk5NyAzMS40NzUzIDEzLjk5OTdaTTE2LjUyNDcgMTRDMTcuNDc4OCAxNCAxOC4wMTU4IDE0LjMwMDUgMTguMzkxNCAxNC42ODcyQzE4LjgyNDggMTUuMTMzNCAxOS4xODY4IDE1Ljg1MSAxOS40NDEgMTYuODY0OUMxOS44ODU5IDE4LjYzOTkgMTkuODY3IDIwLjY4MjIgMTkuODUxOCAyMi4zMjk2QzE5Ljg0OTEgMjIuNjE0NiAxOS44NDY2IDIyLjg4NzcgMTkuODQ2NiAyMy4xNDU2QzE5Ljg0NjYgMjMuOTA1NiAxOS44ODA0IDI0LjgxNTYgMTkuOTE1NSAyNS43NjI0QzE5LjkyOTQgMjYuMTM1IDE5Ljk0MzQgMjYuNTEzOCAxOS45NTU3IDI2Ljg5MDhDMjAuMDAwNSAyOC4yNjYgMjAuMDI1OSAyOS43MDU4IDE5Ljk1OTYgMzEuMDk4NUMxOS44OTI5IDMyLjQ5ODggMTkuNzM1OSAzMy43ODM4IDE5LjQ0MjcgMzQuODU5OUMxOS4xNDYyIDM1Ljk0ODYgMTguNzQ5MiAzNi42Nzg3IDE4LjMwNTYgMzcuMTIxMUMxNy4wMjc1IDM4LjM5NTcgMTUuMDA5MyAzOS40MjU0IDEyLjk1MDkgMzkuODI0NkMxMC45MTU5IDQwLjIxOTIgOS4yNzc2OCAzOS45MjcyIDguMzE4MjMgMzkuMTk3MkM4LjMxMzI2IDM5LjE4NiA4LjMwNzcgMzkuMTcyOSA4LjMwMTYyIDM5LjE1NzdDOC4yNDI0MSAzOS4wMDk4IDguMTcwNjEgMzguNzU1NyA4LjExMjI0IDM4LjM2ODZDNy45OTUzOSAzNy41OTM2IDcuOTY1IDM2LjUxMjUgOC4wNDM4IDM1LjE4MDZDOC4yMDA1NiAzMi41MzA4IDguNzcxNDcgMjkuMTY5MiA5LjY3MzI0IDI1Ljg2MDlDMTAuNTc4NSAyMi41Mzk5IDExLjc4MjcgMTkuNDAwMSAxMy4xNDc5IDE3LjEzODZDMTMuODMxMyAxNi4wMDY1IDE0LjUwNDkgMTUuMTc4OSAxNS4xMjk4IDE0LjY1MzhDMTUuNzQ4MiAxNC4xMzQgMTYuMjA2NSAxNCAxNi41MjQ3IDE0WiIgZmlsbD0iI2I0NTMwOSIvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki48": { + "mimeType": "image/svg+xml", + "id": "img_blki48", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yOSA5QzI5IDExLjc2MTQgMjYuNzYxNCAxNCAyNCAxNEMyMS4yMzg2IDE0IDE5IDExLjc2MTQgMTkgOUMxOSA2LjIzODU4IDIxLjIzODYgNCAyNCA0QzI2Ljc2MTQgNCAyOSA2LjIzODU4IDI5IDlaTTI3IDlDMjcgMTAuNjU2OSAyNS42NTY5IDEyIDI0IDEyQzIyLjM0MzEgMTIgMjEgMTAuNjU2OSAyMSA5QzIxIDcuMzQzMTUgMjIuMzQzMSA2IDI0IDZDMjUuNjU2OSA2IDI3IDcuMzQzMTUgMjcgOVoiIGZpbGw9IiNiNDUzMDkiLz4KPHBhdGggZD0iTTE2Ljk5OTggNDFWMzRIMTguOTk5OFY0MUMxOC45OTk4IDQxLjU1MjMgMTkuNDQ3NSA0MiAxOS45OTk4IDQySDIwLjA4NjVDMjAuNjAzNyA0MiAyMS4wMzU2IDQxLjYwNTYgMjEuMDgyNCA0MS4wOTA1TDIxLjcyNyAzNEgyMy43MzUzTDIzLjA3NDIgNDEuMjcxNkMyMy4wNjkgNDEuMzI4OCAyMy4wNjIyIDQxLjM4NTYgMjMuMDUzOSA0MS40NDE3QzIzLjAzNTcgNDEuNTY0NyAyMy4wMTAxIDQxLjY4NTEgMjIuOTc3NiA0MS44MDI1QzIyLjYyNDIgNDMuMDc5OCAyMS40NTQ5IDQ0IDIwLjA4NjUgNDRIMTkuOTk5OEMxOC4zNDI5IDQ0IDE2Ljk5OTggNDIuNjU2OSAxNi45OTk4IDQxWiIgZmlsbD0iI2I0NTMwOSIvPgo8cGF0aCBkPSJNMjYuOTE3MSA0MS4wOTA1TDI2LjI3MjUgMzRIMjQuMjY0MkwyNC45MjUzIDQxLjI3MTZDMjQuOTMwNSA0MS4zMjg4IDI0LjkzNzMgNDEuMzg1NiAyNC45NDU2IDQxLjQ0MTdDMjQuOTYzOCA0MS41NjQ3IDI0Ljk4OTQgNDEuNjg1MSAyNS4wMjE5IDQxLjgwMjVDMjUuMzc1MyA0My4wNzk4IDI2LjU0NDYgNDQgMjcuOTEzIDQ0SDI3Ljk5OThDMjkuNjU2NiA0NCAzMC45OTk4IDQyLjY1NjkgMzAuOTk5OCA0MVYzNEgyOC45OTk4VjQxQzI4Ljk5OTggNDEuNTUyMyAyOC41NTIgNDIgMjcuOTk5OCA0MkgyNy45MTNDMjcuMzk1OCA0MiAyNi45NjM5IDQxLjYwNTYgMjYuOTE3MSA0MS4wOTA1WiIgZmlsbD0iI2I0NTMwOSIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTExIDE1QzEwLjQ0NzcgMTUgMTAgMTUuNDQ3NyAxMCAxNlYzMUMxMCAzMS41NTIzIDEwLjQ0NzcgMzIgMTEgMzJIMzdDMzcuNTUyMyAzMiAzOCAzMS41NTIzIDM4IDMxVjE2QzM4IDE1LjQ0NzcgMzcuNTUyMyAxNSAzNyAxNUgxMVpNMTIgMTdWMzBIMTkuNUMxOS41IDI5LjQ0MjQgMTkuNzU5MSAyOC45NTcyIDIwLjAyNzYgMjguNjAwNkMyMC4zMDg2IDI4LjIyNzYgMjAuNjc5NiAyNy44ODgzIDIxLjA3OTQgMjcuNjAxNkMyMS42MjUyIDI3LjIxMDMgMjIuMjk4NiAyNi44NjUgMjMgMjYuNjY3OFYyNC41SDIyLjJDMjEuNTk3MyAyNC41IDIwLjc1MzUgMjQuODY0MiAxOS45NDMzIDI1LjM1NTJDMTkuNTYzOCAyNS41ODUyIDE5LjIzMzcgMjUuODE2NyAxOC45OTg0IDI1Ljk5MTFDMTguODgxMiAyNi4wNzc4IDE4Ljc4ODggMjYuMTQ5NSAxOC43MjcgMjYuMTk4NEMxOC42OTYxIDI2LjIyMjggMTguNjczIDI2LjI0MTUgMTguNjU4MiAyNi4yNTM1TDE4LjY0MjYgMjYuMjY2M0wxOC42Mzk5IDI2LjI2ODRDMTguNjM5OSAyNi4yNjg0IDE4LjY0MDIgMjYuMjY4MiAxOCAyNS41QzE3LjM1OTggMjQuNzMxOCAxNy4zNjAxIDI0LjczMTUgMTcuMzYwMSAyNC43MzE1TDE3LjM2MTQgMjQuNzMwNUwxNy4zNjM4IDI0LjcyODVMMTcuMzcxMyAyNC43MjIzTDE3LjM5NjYgMjQuNzAxNkMxNy40MTc5IDI0LjY4NDMgMTcuNDQ4IDI0LjY2IDE3LjQ4NjMgMjQuNjI5N0MxNy41NjI3IDI0LjU2OTMgMTcuNjcxOSAyNC40ODQ3IDE3LjgwNzkgMjQuMzgzOUMxOC4wNzg4IDI0LjE4MzMgMTguNDYxMiAyMy45MTQ4IDE4LjkwNjcgMjMuNjQ0OEMxOS43NDY1IDIzLjEzNTggMjEuMDAyNyAyMi41IDIyLjIgMjIuNUgyM1YyMC41SDIyLjVDMjEuOTMwOSAyMC41IDIxLjE5MDkgMjAuNjk5MiAyMC41MjkyIDIwLjkzOThDMjAuMjEyIDIxLjA1NTIgMTkuOTM3IDIxLjE3MDkgMTkuNzQyMSAyMS4yNTc2QzE5LjY0NDkgMjEuMzAwNyAxOS41Njg1IDIxLjMzNjMgMTkuNTE3NiAyMS4zNjA1QzE5LjQ5MjIgMjEuMzcyNSAxOS40NzMyIDIxLjM4MTcgMTkuNDYxMyAyMS4zODc1TDE5LjQ0ODcgMjEuMzkzN0wxOS40NDcgMjEuMzk0NUMxOS40NDcgMjEuMzk0NSAxOS40NDcyIDIxLjM5NDQgMTkgMjAuNUMxOC41NTI4IDE5LjYwNTYgMTguNTUzMSAxOS42MDU0IDE4LjU1MzEgMTkuNjA1NEwxOC41NTY0IDE5LjYwMzhMMTguNTYyOSAxOS42MDA2TDE4LjU4NDQgMTkuNTlDMTguNjAyNSAxOS41ODEyIDE4LjYyNzkgMTkuNTY4OSAxOC42NjAxIDE5LjU1MzZDMTguNzI0NSAxOS41MjMxIDE4LjgxNiAxOS40ODA1IDE4LjkyOTggMTkuNDI5OUMxOS4xNTY3IDE5LjMyOTEgMTkuNDc1NSAxOS4xOTQ4IDE5Ljg0NTggMTkuMDYwMkMyMC41NTkxIDE4LjgwMDggMjEuNTY5MSAxOC41IDIyLjUgMTguNUgyM1YxN0gxMlpNMjUgMjQuNUgyNi4xQzI2Ljg0ODkgMjQuNSAyNy42MTg2IDI0Ljg2NjMgMjguMjYzMSAyNS4zMTg2QzI4LjU3MzUgMjUuNTM2NCAyOC44Mjg1IDI1Ljc1NTYgMjkuMDA0OCAyNS45MTk3QzI5LjA5MjUgMjYuMDAxMiAyOS4xNTk0IDI2LjA2NzkgMjkuMjAyNiAyNi4xMTIyQzI5LjIyNDEgMjYuMTM0MyAyOS4yMzk3IDI2LjE1MDcgMjkuMjQ4OCAyNi4xNjA1TDI5LjI1NzQgMjYuMTY5N0MyOS4yNTc0IDI2LjE2OTcgMjkuMjU2NyAyNi4xNjkgMzAgMjUuNUMzMC43NDMzIDI0LjgzMSAzMC43NDI5IDI0LjgzMDYgMzAuNzQyOSAyNC44MzA2TDMwLjc0MTQgMjQuODI5TDMwLjczODkgMjQuODI2MkwzMC43MzE4IDI0LjgxODRMMzAuNzA5NyAyNC43OTQ2QzMwLjY5MTUgMjQuNzc1MSAzMC42NjYzIDI0Ljc0ODUgMzAuNjM0NiAyNC43MTZDMzAuNTcxMSAyNC42NTA5IDMwLjQ4MDkgMjQuNTYxMyAzMC4zNjcgMjQuNDU1M0MzMC4xNDAzIDI0LjI0NDQgMjkuODE0IDIzLjk2MzYgMjkuNDExOSAyMy42ODE0QzI4LjYzMTQgMjMuMTMzNyAyNy40NTExIDIyLjUgMjYuMSAyMi41SDI1VjIwLjVIMjUuNzVDMjYuNDQ0MyAyMC41IDI3LjExOTMgMjAuNzAxMSAyNy42NDMyIDIwLjkyMTZDMjcuOTAwMyAyMS4wMjk5IDI4LjEwOTIgMjEuMTM3OCAyOC4yNTA5IDIxLjIxNjlDMjguMzIxNSAyMS4yNTY0IDI4LjM3NDcgMjEuMjg4MiAyOC40MDggMjEuMzA4N0MyOC40MjQ3IDIxLjMxODkgMjguNDM2MyAyMS4zMjYzIDI4LjQ0MjcgMjEuMzMwNEwyOC40NDU3IDIxLjMzMjNDMjguNDQ1NyAyMS4zMzIzIDI4LjQ0NTMgMjEuMzMyMSAyOSAyMC41QzI5LjU1NDcgMTkuNjY3OSAyOS41NTQyIDE5LjY2NzYgMjkuNTU0MiAxOS42Njc2TDI5LjU1MjcgMTkuNjY2NkwyOS41NTAxIDE5LjY2NDlMMjkuNTQzMiAxOS42NjA0TDI5LjUyMjggMTkuNjQ3MkMyOS41MDYzIDE5LjYzNjYgMjkuNDg0IDE5LjYyMjUgMjkuNDU2MiAxOS42MDU0QzI5LjQwMDcgMTkuNTcxMiAyOS4zMjMgMTkuNTI0OSAyOS4yMjU2IDE5LjQ3MDZDMjkuMDMxNSAxOS4zNjIyIDI4Ljc1NTkgMTkuMjIwMSAyOC40MTkzIDE5LjA3ODRDMjcuNzU1NyAxOC43OTg5IDI2LjgwNTcgMTguNSAyNS43NSAxOC41SDI1VjE3SDM2VjMwSDI4LjVDMjguNSAyOS40Mzc5IDI4LjIzMjQgMjguOTQ1MiAyNy45NjQxIDI4LjU4NzVDMjcuNjgwMyAyOC4yMDkyIDI3LjMwNTQgMjcuODYwNiAyNi45MDA3IDI3LjU2NjNDMjYuMzY3NSAyNy4xNzg1IDI1LjY5ODkgMjYuODI1NyAyNSAyNi42MzkxVjI0LjVaTTI2LjQ5MjkgMzBDMjYuNDc5NyAyOS45NjcgMjYuNDQ1NyAyOS44OTY0IDI2LjM2NDEgMjkuNzg3NUMyNi4yMjU5IDI5LjYwMzMgMjYuMDA3MSAyOS4zODk0IDI1LjcyNDMgMjkuMTgzN0MyNS4xNDc4IDI4Ljc2NDUgMjQuNDkzNyAyOC41MTE3IDI0LjAzMiAyOC41MDA0QzIzLjQ4NzcgMjguNTQ2NCAyMi44MDUyIDI4LjgyNTIgMjIuMjQ0OSAyOS4yMjdDMjEuOTY1NyAyOS40MjcyIDIxLjc1NTYgMjkuNjMwNyAyMS42MjUyIDI5LjgwMzhDMjEuNTQ5NiAyOS45MDQzIDIxLjUxODQgMjkuOTY5NCAyMS41MDYzIDMwSDI2LjQ5MjlaIiBmaWxsPSIjYjQ1MzA5Ii8+Cjwvc3ZnPgo=", + "created": 1700000000000 + } + } +} \ No newline at end of file diff --git a/knowledge/drafts/pillars-b.excalidraw b/knowledge/drafts/pillars-b.excalidraw new file mode 100644 index 0000000..6a37f7f --- /dev/null +++ b/knowledge/drafts/pillars-b.excalidraw @@ -0,0 +1,2564 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "oidm-knowledge/tools/diagrams", + "elements": [ + { + "type": "rectangle", + "id": "band53", + "x": 0, + "y": 377.05, + "width": 880, + "height": 253.49999999999994, + "strokeColor": "#b45309", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1105, + "version": 1, + "versionNonce": 1106, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "fill58", + "x": -1, + "y": 377.05, + "width": 33, + "height": 32.0, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1115, + "version": 1, + "versionNonce": 1116, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill59", + "x": 848, + "y": 377.05, + "width": 33, + "height": 32.0, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1117, + "version": 1, + "versionNonce": 1118, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "line", + "id": "ln60", + "x": 0, + "y": 377.05, + "width": 0, + "height": 32.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1119, + "version": 1, + "versionNonce": 1120, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln61", + "x": 880, + "y": 377.05, + "width": 0, + "height": 32.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1121, + "version": 1, + "versionNonce": 1122, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "band33", + "x": 0, + "y": 187.3, + "width": 880, + "height": 189.75, + "strokeColor": "#0f766e", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1065, + "version": 1, + "versionNonce": 1066, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "fill54", + "x": -1, + "y": 345.05, + "width": 33, + "height": 32.0, + "strokeColor": "transparent", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1107, + "version": 1, + "versionNonce": 1108, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill55", + "x": 848, + "y": 345.05, + "width": 33, + "height": 32.0, + "strokeColor": "transparent", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1109, + "version": 1, + "versionNonce": 1110, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "line", + "id": "ln56", + "x": 0, + "y": 345.05, + "width": 0, + "height": 32.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1111, + "version": 1, + "versionNonce": 1112, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln57", + "x": 880, + "y": 345.05, + "width": 0, + "height": 32.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1113, + "version": 1, + "versionNonce": 1114, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "band15", + "x": 0, + "y": 91.65, + "width": 880, + "height": 71.65, + "strokeColor": "#6d28d9", + "backgroundColor": "#ede9fe", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1029, + "version": 1, + "versionNonce": 1030, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "panel1", + "x": 0, + "y": 0, + "width": 388.0, + "height": 67.65, + "strokeColor": "#be123c", + "backgroundColor": "#ffe4e6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1001, + "version": 1, + "versionNonce": 1002, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "panel2", + "x": 492.0, + "y": 0, + "width": 388.0, + "height": 67.65, + "strokeColor": "#15803d", + "backgroundColor": "#dcfce7", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1003, + "version": 1, + "versionNonce": 1004, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "bicon3", + "x": 18, + "y": 12.0, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1005, + "version": 1, + "versionNonce": 1006, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon3", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle4", + "x": 58, + "y": 14, + "width": 93.96, + "height": 22.5, + "strokeColor": "#881337", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1007, + "version": 1, + "versionNonce": 1008, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Use Cases", + "originalText": "Use Cases", + "fontSize": 18, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub5", + "x": 58, + "y": 37.400000000000006, + "width": 211.11999999999998, + "height": 16.25, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1009, + "version": 1, + "versionNonce": 1010, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "what the project wants built", + "originalText": "what the project wants built", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon6", + "x": 510.0, + "y": 12.0, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1011, + "version": 1, + "versionNonce": 1012, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon6", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle7", + "x": 550.0, + "y": 14, + "width": 198.35999999999999, + "height": 22.5, + "strokeColor": "#14532d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1013, + "version": 1, + "versionNonce": 1014, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Sample Applications", + "originalText": "Sample Applications", + "fontSize": 18, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub8", + "x": 550.0, + "y": 37.400000000000006, + "width": 143.26, + "height": 16.25, + "strokeColor": "#15803d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1015, + "version": 1, + "versionNonce": 1016, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "what has been built", + "originalText": "what has been built", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "conn9", + "x": 390.0, + "y": 33.825, + "width": 100.0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1017, + "version": 1, + "versionNonce": 1018, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 100.0, + 0 + ] + ] + }, + { + "type": "rectangle", + "id": "chip10", + "x": 389.53, + "y": 4.575000000000003, + "width": 100.94, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1019, + "version": 1, + "versionNonce": 1020, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "chipt11", + "x": 398.53, + "y": 7.575000000000003, + "width": 82.94, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1021, + "version": 1, + "versionNonce": 1022, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "illustrates", + "originalText": "illustrates", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon12", + "x": 18, + "y": 105.65, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1023, + "version": 1, + "versionNonce": 1024, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon12", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle13", + "x": 58, + "y": 107.65, + "width": 41.76, + "height": 22.5, + "strokeColor": "#4c1d95", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1025, + "version": 1, + "versionNonce": 1026, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "SDKs", + "originalText": "SDKs", + "fontSize": 18, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub14", + "x": 58, + "y": 131.05, + "width": 520.26, + "height": 16.25, + "strokeColor": "#6d28d9", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1027, + "version": 1, + "versionNonce": 1028, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "wrap the structures \u00b7 attach the shared knowledge \u00b7 support authoring", + "originalText": "wrap the structures \u00b7 attach the shared knowledge \u00b7 support authoring", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon16", + "x": 18, + "y": 203.3, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1031, + "version": 1, + "versionNonce": 1032, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon16", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle17", + "x": 58, + "y": 205.3, + "width": 174.0, + "height": 25.0, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1033, + "version": 1, + "versionNonce": 1034, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Data Structures", + "originalText": "Data Structures", + "fontSize": 20, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub18", + "x": 58, + "y": 231.3, + "width": 226.2, + "height": 16.25, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1035, + "version": 1, + "versionNonce": 1036, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "this patient \u00b7 Patient Context", + "originalText": "this patient \u00b7 Patient Context", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk19", + "x": 20.0, + "y": 261.55, + "width": 195.0, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1037, + "version": 1, + "versionNonce": 1038, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki20", + "x": 103.5, + "y": 281.925, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1039, + "version": 1, + "versionNonce": 1040, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki20", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt21", + "x": 26.0, + "y": 315.925, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1041, + "version": 1, + "versionNonce": 1042, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Observation", + "originalText": "Observation", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk22", + "x": 235.0, + "y": 261.55, + "width": 195.0, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1043, + "version": 1, + "versionNonce": 1044, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki23", + "x": 318.5, + "y": 272.55, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1045, + "version": 1, + "versionNonce": 1046, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki23", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt24", + "x": 241.0, + "y": 306.55, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1047, + "version": 1, + "versionNonce": 1048, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Exam Finding", + "originalText": "Exam Finding", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkt25", + "x": 241.0, + "y": 325.3, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1049, + "version": 1, + "versionNonce": 1050, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "List", + "originalText": "List", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk26", + "x": 450.0, + "y": 261.55, + "width": 195.0, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1051, + "version": 1, + "versionNonce": 1052, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki27", + "x": 533.5, + "y": 272.55, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1053, + "version": 1, + "versionNonce": 1054, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki27", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt28", + "x": 456.0, + "y": 306.55, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1055, + "version": 1, + "versionNonce": 1056, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Imaging Problem", + "originalText": "Imaging Problem", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkt29", + "x": 456.0, + "y": 325.3, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1057, + "version": 1, + "versionNonce": 1058, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "List", + "originalText": "List", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk30", + "x": 665.0, + "y": 261.55, + "width": 195.0, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1059, + "version": 1, + "versionNonce": 1060, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki31", + "x": 746.5, + "y": 279.925, + "width": 32, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1061, + "version": 1, + "versionNonce": 1062, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki31", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt32", + "x": 671.0, + "y": 315.925, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1063, + "version": 1, + "versionNonce": 1064, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Imaging Persona", + "originalText": "Imaging Persona", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon34", + "x": 18, + "y": 427.05, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1067, + "version": 1, + "versionNonce": 1068, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon34", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle35", + "x": 58, + "y": 429.05, + "width": 208.79999999999998, + "height": 25.0, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1069, + "version": 1, + "versionNonce": 1070, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Foundation Context", + "originalText": "Foundation Context", + "fontSize": 20, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub36", + "x": 58, + "y": 455.05, + "width": 188.5, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1071, + "version": 1, + "versionNonce": 1072, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "shared, curated knowledge", + "originalText": "shared, curated knowledge", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "chip37", + "x": 381.99, + "y": 483.3, + "width": 116.02, + "height": 22.25, + "strokeColor": "#b45309", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1073, + "version": 1, + "versionNonce": 1074, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "chipt38", + "x": 390.99, + "y": 486.3, + "width": 98.02, + "height": 16.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1075, + "version": 1, + "versionNonce": 1076, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "relationships", + "originalText": "relationships", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk39", + "x": 20.0, + "y": 515.55, + "width": 237.33333333333334, + "height": 95.0, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1077, + "version": 1, + "versionNonce": 1078, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki40", + "x": 124.66666666666669, + "y": 526.55, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1079, + "version": 1, + "versionNonce": 1080, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki40", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt41", + "x": 26.0, + "y": 560.55, + "width": 225.33333333333334, + "height": 18.75, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1081, + "version": 1, + "versionNonce": 1082, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Finding/diagnosis definitions", + "originalText": "Finding/diagnosis definitions", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkd42", + "x": 26.0, + "y": 581.3, + "width": 225.33333333333334, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1083, + "version": 1, + "versionNonce": 1084, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "finding models \u00b7 CDEs", + "originalText": "finding models \u00b7 CDEs", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk43", + "x": 321.33333333333337, + "y": 515.55, + "width": 237.33333333333334, + "height": 95.0, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1085, + "version": 1, + "versionNonce": 1086, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki44", + "x": 424.00000000000006, + "y": 524.55, + "width": 32, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1087, + "version": 1, + "versionNonce": 1088, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki44", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt45", + "x": 327.33333333333337, + "y": 560.55, + "width": 225.33333333333334, + "height": 18.75, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1089, + "version": 1, + "versionNonce": 1090, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Anatomic locations", + "originalText": "Anatomic locations", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkd46", + "x": 327.33333333333337, + "y": 581.3, + "width": 225.33333333333334, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1091, + "version": 1, + "versionNonce": 1092, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "anchored in RadLex", + "originalText": "anchored in RadLex", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk47", + "x": 622.6666666666667, + "y": 515.55, + "width": 237.33333333333334, + "height": 95.0, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1093, + "version": 1, + "versionNonce": 1094, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki48", + "x": 725.3333333333334, + "y": 524.55, + "width": 32, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1095, + "version": 1, + "versionNonce": 1096, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki48", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt49", + "x": 628.6666666666667, + "y": 560.55, + "width": 225.33333333333334, + "height": 18.75, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1097, + "version": 1, + "versionNonce": 1098, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Exam types", + "originalText": "Exam types", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkd50", + "x": 628.6666666666667, + "y": 581.3, + "width": 225.33333333333334, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1099, + "version": 1, + "versionNonce": 1100, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "LOINC/RSNA Playbook", + "originalText": "LOINC/RSNA Playbook", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "conn51", + "x": 263.33333333333337, + "y": 563.05, + "width": 52.0, + "height": 0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1101, + "version": 1, + "versionNonce": 1102, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 52.0, + 0 + ] + ], + "startArrowhead": "arrow", + "endArrowhead": "arrow" + }, + { + "type": "arrow", + "id": "conn52", + "x": 564.6666666666667, + "y": 563.05, + "width": 52.0, + "height": 0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1103, + "version": 1, + "versionNonce": 1104, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 52.0, + 0 + ] + ], + "startArrowhead": "arrow", + "endArrowhead": "arrow" + }, + { + "type": "line", + "id": "ln62", + "x": 0, + "y": 377.05, + "width": 880, + "height": 0.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1123, + "version": 1, + "versionNonce": 1124, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 880, + 0.0 + ] + ], + "roundness": null + }, + { + "type": "text", + "id": "bl63", + "x": 20, + "y": 385.925, + "width": 180.95999999999998, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1125, + "version": 1, + "versionNonce": 1126, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "woven together at every:", + "originalText": "woven together at every:", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "fill64", + "x": 222.95999999999998, + "y": 365.05, + "width": 120.0, + "height": 46.0, + "strokeColor": "transparent", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1127, + "version": 1, + "versionNonce": 1128, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "line", + "id": "ln65", + "x": 222.95999999999998, + "y": 370.05, + "width": 120.0, + "height": 41.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1129, + "version": 1, + "versionNonce": 1130, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 30.0 + ], + [ + 0.8373251423758461, + 34.209517756016 + ], + [ + 3.2218254069479713, + 37.77817459305203 + ], + [ + 6.790482243984002, + 40.162674857624154 + ], + [ + 11.0, + 41.0 + ], + [ + 109.0, + 41.0 + ], + [ + 113.209517756016, + 40.162674857624154 + ], + [ + 116.77817459305203, + 37.77817459305203 + ], + [ + 119.16267485762415, + 34.209517756016 + ], + [ + 120.0, + 30.0 + ], + [ + 120.0, + 0.0 + ] + ], + "roundness": null + }, + { + "type": "text", + "id": "bw66", + "x": 222.95999999999998, + "y": 385.925, + "width": 120.0, + "height": 16.25, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1131, + "version": 1, + "versionNonce": 1132, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "finding", + "originalText": "finding", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "fill67", + "x": 381.9733333333333, + "y": 365.05, + "width": 120.0, + "height": 46.0, + "strokeColor": "transparent", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1133, + "version": 1, + "versionNonce": 1134, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "line", + "id": "ln68", + "x": 381.9733333333333, + "y": 370.05, + "width": 120.0, + "height": 41.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1135, + "version": 1, + "versionNonce": 1136, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 30.0 + ], + [ + 0.8373251423758461, + 34.209517756016 + ], + [ + 3.2218254069479713, + 37.77817459305203 + ], + [ + 6.790482243984002, + 40.162674857624154 + ], + [ + 11.0, + 41.0 + ], + [ + 109.0, + 41.0 + ], + [ + 113.209517756016, + 40.162674857624154 + ], + [ + 116.77817459305203, + 37.77817459305203 + ], + [ + 119.16267485762415, + 34.209517756016 + ], + [ + 120.0, + 30.0 + ], + [ + 120.0, + 0.0 + ] + ], + "roundness": null + }, + { + "type": "text", + "id": "bw69", + "x": 381.9733333333333, + "y": 385.925, + "width": 120.0, + "height": 16.25, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1137, + "version": 1, + "versionNonce": 1138, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "diagnosis", + "originalText": "diagnosis", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "fill70", + "x": 540.9866666666667, + "y": 365.05, + "width": 120.0, + "height": 46.0, + "strokeColor": "transparent", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1139, + "version": 1, + "versionNonce": 1140, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "line", + "id": "ln71", + "x": 540.9866666666667, + "y": 370.05, + "width": 120.0, + "height": 41.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1141, + "version": 1, + "versionNonce": 1142, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 30.0 + ], + [ + 0.8373251423759029, + 34.209517756016 + ], + [ + 3.221825406948028, + 37.77817459305203 + ], + [ + 6.790482243984002, + 40.162674857624154 + ], + [ + 11.0, + 41.0 + ], + [ + 109.0, + 41.0 + ], + [ + 113.209517756016, + 40.162674857624154 + ], + [ + 116.77817459305197, + 37.77817459305203 + ], + [ + 119.1626748576241, + 34.209517756016 + ], + [ + 120.0, + 30.0 + ], + [ + 120.0, + 0.0 + ] + ], + "roundness": null + }, + { + "type": "text", + "id": "bw72", + "x": 540.9866666666667, + "y": 385.925, + "width": 120.0, + "height": 16.25, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1143, + "version": 1, + "versionNonce": 1144, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "location", + "originalText": "location", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "fill73", + "x": 700.0, + "y": 365.05, + "width": 120.0, + "height": 46.0, + "strokeColor": "transparent", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1145, + "version": 1, + "versionNonce": 1146, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "line", + "id": "ln74", + "x": 700.0, + "y": 370.05, + "width": 120.0, + "height": 41.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1147, + "version": 1, + "versionNonce": 1148, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 30.0 + ], + [ + 0.8373251423759029, + 34.209517756016 + ], + [ + 3.221825406948028, + 37.77817459305203 + ], + [ + 6.790482243984002, + 40.162674857624154 + ], + [ + 11.0, + 41.0 + ], + [ + 109.0, + 41.0 + ], + [ + 113.209517756016, + 40.162674857624154 + ], + [ + 116.77817459305197, + 37.77817459305203 + ], + [ + 119.1626748576241, + 34.209517756016 + ], + [ + 120.0, + 30.0 + ], + [ + 120.0, + 0.0 + ] + ], + "roundness": null + }, + { + "type": "text", + "id": "bw75", + "x": 700.0, + "y": 385.925, + "width": 120.0, + "height": 16.25, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1149, + "version": 1, + "versionNonce": 1150, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "exam type", + "originalText": "exam type", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + } + ], + "appState": { + "viewBackgroundColor": "#ffffff", + "gridSize": null + }, + "files": { + "img_bicon3": { + "mimeType": "image/svg+xml", + "id": "img_bicon3", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiNiZTEyM2MiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTE1IDE0Yy4yLTEgLjctMS43IDEuNS0yLjUgMS0uOSAxLjUtMi4yIDEuNS0zLjVBNiA2IDAgMCAwIDYgOGMwIDEgLjIgMi4yIDEuNSAzLjUuNy43IDEuMyAxLjUgMS41IDIuNSIgLz4KICA8cGF0aCBkPSJNOSAxOGg2IiAvPgogIDxwYXRoIGQ9Ik0xMCAyMmg0IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_bicon6": { + "mimeType": "image/svg+xml", + "id": "img_bicon6", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMxNTgwM2QiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHJlY3QgeD0iMiIgeT0iNCIgd2lkdGg9IjIwIiBoZWlnaHQ9IjE2IiByeD0iMiIgLz4KICA8cGF0aCBkPSJNMTAgNHY0IiAvPgogIDxwYXRoIGQ9Ik0yIDhoMjAiIC8+CiAgPHBhdGggZD0iTTYgNHY0IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_bicon12": { + "mimeType": "image/svg+xml", + "id": "img_bicon12", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiM2ZDI4ZDkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTExIDIxLjczYTIgMiAwIDAgMCAyIDBsNy00QTIgMiAwIDAgMCAyMSAxNlY4YTIgMiAwIDAgMC0xLTEuNzNsLTctNGEyIDIgMCAwIDAtMiAwbC03IDRBMiAyIDAgMCAwIDMgOHY4YTIgMiAwIDAgMCAxIDEuNzN6IiAvPgogIDxwYXRoIGQ9Ik0xMiAyMlYxMiIgLz4KICA8cG9seWxpbmUgcG9pbnRzPSIzLjI5IDcgMTIgMTIgMjAuNzEgNyIgLz4KICA8cGF0aCBkPSJtNy41IDQuMjcgOSA1LjE1IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_bicon16": { + "mimeType": "image/svg+xml", + "id": "img_bicon16", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyLjgzIDIuMThhMiAyIDAgMCAwLTEuNjYgMEwyLjYgNi4wOGExIDEgMCAwIDAgMCAxLjgzbDguNTggMy45MWEyIDIgMCAwIDAgMS42NiAwbDguNTgtMy45YTEgMSAwIDAgMCAwLTEuODN6IiAvPgogIDxwYXRoIGQ9Ik0yIDEyYTEgMSAwIDAgMCAuNTguOTFsOC42IDMuOTFhMiAyIDAgMCAwIDEuNjUgMGw4LjU4LTMuOUExIDEgMCAwIDAgMjIgMTIiIC8+CiAgPHBhdGggZD0iTTIgMTdhMSAxIDAgMCAwIC41OC45MWw4LjYgMy45MWEyIDIgMCAwIDAgMS42NSAwbDguNTgtMy45QTEgMSAwIDAgMCAyMiAxNyIgLz4KPC9zdmc+Cg==", + "created": 1700000000000 + }, + "img_blki20": { + "mimeType": "image/svg+xml", + "id": "img_blki20", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHJlY3Qgd2lkdGg9IjgiIGhlaWdodD0iNCIgeD0iOCIgeT0iMiIgcng9IjEiIHJ5PSIxIiAvPgogIDxwYXRoIGQ9Ik0xNiA0aDJhMiAyIDAgMCAxIDIgMnYxNGEyIDIgMCAwIDEtMiAySDZhMiAyIDAgMCAxLTItMlY2YTIgMiAwIDAgMSAyLTJoMiIgLz4KPC9zdmc+Cg==", + "created": 1700000000000 + }, + "img_blki23": { + "mimeType": "image/svg+xml", + "id": "img_blki23", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHJlY3Qgd2lkdGg9IjgiIGhlaWdodD0iNCIgeD0iOCIgeT0iMiIgcng9IjEiIHJ5PSIxIiAvPgogIDxwYXRoIGQ9Ik0xNiA0aDJhMiAyIDAgMCAxIDIgMnYxNGEyIDIgMCAwIDEtMiAySDZhMiAyIDAgMCAxLTItMlY2YTIgMiAwIDAgMSAyLTJoMiIgLz4KICA8cGF0aCBkPSJNMTIgMTFoNCIgLz4KICA8cGF0aCBkPSJNMTIgMTZoNCIgLz4KICA8cGF0aCBkPSJNOCAxMWguMDEiIC8+CiAgPHBhdGggZD0iTTggMTZoLjAxIiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki27": { + "mimeType": "image/svg+xml", + "id": "img_blki27", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTMgNWguMDEiIC8+CiAgPHBhdGggZD0iTTMgMTJoLjAxIiAvPgogIDxwYXRoIGQ9Ik0zIDE5aC4wMSIgLz4KICA8cGF0aCBkPSJNOCA1aDEzIiAvPgogIDxwYXRoIGQ9Ik04IDEyaDEzIiAvPgogIDxwYXRoIGQ9Ik04IDE5aDEzIiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki31": { + "mimeType": "image/svg+xml", + "id": "img_blki31", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yNCAyNEMyOC40MjA0IDI0IDMyIDIwLjQyMDQgMzIgMTZDMzIgMTEuNTc5NiAyOC40MjA0IDggMjQgOEMxOS41Nzk2IDggMTYgMTEuNTc5NiAxNiAxNkMxNiAyMC40MjA0IDE5LjU3OTYgMjQgMjQgMjRaTTM0IDE2QzM0IDIxLjUyNSAyOS41MjUgMjYgMjQgMjZDMTguNDc1IDI2IDE0IDIxLjUyNSAxNCAxNkMxNCAxMC40NzUgMTguNDc1IDYgMjQgNkMyOS41MjUgNiAzNCAxMC40NzUgMzQgMTZaIiBmaWxsPSIjMGY3NjZlIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNOS4yMjM0OCAzNC4yMTE5QzguMjIwMzggMzUuMDIxMSA4IDM1LjYyOTEgOCAzNlY0MEg0MFYzNkM0MCAzNS42MjkxIDM5Ljc3OTYgMzUuMDIxMSAzOC43NzY1IDM0LjIxMTlDMzcuNzk1OCAzMy40MjA3IDM2LjMzNDEgMzIuNjY2OSAzNC41NjIyIDMyLjAxNUMzMS4wMTk5IDMwLjcxMTcgMjYuNzUzMiAzMCAyNCAzMEMyMS4yNDY4IDMwIDE2Ljk4MDEgMzAuNzExNyAxMy40Mzc4IDMyLjAxNUMxMS42NjU5IDMyLjY2NjkgMTAuMjA0MiAzMy40MjA3IDkuMjIzNDggMzQuMjExOVpNMjQgMjhDMTcuOTkyNSAyOCA2IDMxLjAzNDcgNiAzNlY0Mkg0MlYzNkM0MiAzMS4wMzQ3IDMwLjAwNzUgMjggMjQgMjhaIiBmaWxsPSIjMGY3NjZlIi8+Cjwvc3ZnPgo=", + "created": 1700000000000 + }, + "img_bicon34": { + "mimeType": "image/svg+xml", + "id": "img_bicon34", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiNiNDUzMDkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyIDV2MTYiIC8+CiAgPHBhdGggZD0iTTIwLjAwMSAxOUEyIDIgMCAwMDIyIDE3VjVhMiAyIDAgMDAtMS45OTktMkwxNiAzLjAwMkE1IDUgMCAwMDEyIDVhNSA1IDAgMDAtNC0ySDRhMiAyIDAgMDAtMiAydjEyYTIgMiAwIDAwMS45OTkgMkg4YTUgNSAwIDAxNCAyIDUgNSAwIDAxNC0yeiIgLz4KPC9zdmc+Cg==", + "created": 1700000000000 + }, + "img_blki40": { + "mimeType": "image/svg+xml", + "id": "img_blki40", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiNiNDUzMDkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyLjU4NiAyLjU4NkEyIDIgMCAwIDAgMTEuMTcyIDJINGEyIDIgMCAwIDAtMiAydjcuMTcyYTIgMiAwIDAgMCAuNTg2IDEuNDE0bDguNzA0IDguNzA0YTIuNDI2IDIuNDI2IDAgMCAwIDMuNDIgMGw2LjU4LTYuNThhMi40MjYgMi40MjYgMCAwIDAgMC0zLjQyeiIgLz4KICA8Y2lyY2xlIGN4PSI3LjUiIGN5PSI3LjUiIHI9Ii41IiBmaWxsPSIjYjQ1MzA5IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki44": { + "mimeType": "image/svg+xml", + "id": "img_blki44", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yMyA2LjAwMDEzQzIzIDYuMDAwMDQgMjMgNiAyNCA2SDI0LjE3NjFDMjQuMjUzMyA2IDI0LjMyMzMgNiAyNC4zODY4IDZDMjUgNi4wMDAwMSAyNSA2LjAwMDA1IDI1IDYuMDAwMTNWMjAuNUMyNSAyMS44OTc3IDI1LjU2NDEgMjIuNDQyMSAyNi4wMDM5IDIyLjY5ODdDMjYuMDUzIDIyLjcyNzMgMjYuMTAyNCAyMi43NTMzIDI2LjE1MTYgMjIuNzc3QzI2LjE1MDYgMjIuNjU2OCAyNi4xNDkzIDIyLjUzMTYgMjYuMTQ3OSAyMi40MDE5TDI2LjE0NzkgMjIuNDAwM0MyNi4xMTAxIDE4Ljg3MTYgMjYuMDM2NSAxMS45OTk3IDMxLjQ3NTMgMTEuOTk5N0MzOC45MjU5IDExLjk5OTcgNDQuMjQ3OCAzOC4wMDYyIDQxLjA1NDcgNDAuNjU5OUMzNy44NjE1IDQzLjMxMzYgMzEuNDc1MyA0MS43MjE0IDI4LjI4MjIgMzguNTM2OUMyNS43MDQyIDM1Ljk2NTkgMjUuOTI3MiAyOS45NTgzIDI2LjA4NzMgMjUuNjQ1N0wyNi4wODc0IDI1LjY0NDNDMjYuMDk3MSAyNS4zODE5IDI2LjEwNjcgMjUuMTI1OCAyNi4xMTUzIDI0Ljg3NzFDMjUuNzkgMjQuNzk2MiAyNS4zOTU5IDI0LjY1OTUgMjQuOTk2MiAyNC40MjYzQzI0LjYzOTggMjQuMjE4NCAyNC4yOTc1IDIzLjk0NDIgMjQgMjMuNTkxOUMyMy43MDI2IDIzLjk0NDIgMjMuMzYwMyAyNC4yMTg0IDIzLjAwMzkgMjQuNDI2M0MyMi42MDQxIDI0LjY1OTUgMjIuMjEwMSAyNC43OTYyIDIxLjg4NDggMjQuODc3MUMyMS44OTM0IDI1LjEyNjEgMjEuOTAyOSAyNS4zODI2IDIxLjkxMjcgMjUuNjQ1M0MyMi4wNzI4IDI5Ljk1NzkgMjIuMjk1OSAzNS45NjYyIDE5LjcxNzkgMzguNTM3MkMxNi41MjQ3IDQxLjcyMTcgMTAuMTM4NSA0My4zMTM5IDYuOTQ1MzYgNDAuNjYwMkMzLjc1MjIyIDM4LjAwNjUgOS4wNzQxMyAxMiAxNi41MjQ3IDEyQzIxLjk2MzYgMTIgMjEuODkgMTguODcxNyAyMS44NTIyIDIyLjQwMDNDMjEuODUyIDIyLjQxNjYgMjEuODUxOCAyMi40MzI4IDIxLjg1MTYgMjIuNDQ4OUMyMS44NTA0IDIyLjU2MTkgMjEuODQ5MyAyMi42NzE0IDIxLjg0ODQgMjIuNzc3QzIxLjg5NzcgMjIuNzUzNCAyMS45NDcxIDIyLjcyNzQgMjEuOTk2MiAyMi42OTg3QzIyLjQzNiAyMi40NDIxIDIzIDIxLjg5NzcgMjMgMjAuNVY2LjAwMDEzWk0zMS40NzUzIDEzLjk5OTdDMzAuNTIxMiAxMy45OTk3IDI5Ljk4NDMgMTQuMzAwMiAyOS42MDg2IDE0LjY4NjlDMjkuMTc1MiAxNS4xMzMxIDI4LjgxMzIgMTUuODUwNyAyOC41NTkgMTYuODY0NkMyOC4xMTQxIDE4LjYzOTUgMjguMTMzIDIwLjY4MTkgMjguMTQ4MyAyMi4zMjkzQzI4LjE1MDkgMjIuNjE0MiAyOC4xNTM0IDIyLjg4NzQgMjguMTUzNCAyMy4xNDUzQzI4LjE1MzQgMjMuOTA1MyAyOC4xMTk2IDI0LjgxNTMgMjguMDg0NSAyNS43NjIxQzI4LjA3MDcgMjYuMTM0OSAyOC4wNTY2IDI2LjUxMzMgMjguMDQ0MyAyNi44OTA1QzI3Ljk5OTYgMjguMjY1NyAyNy45NzQxIDI5LjcwNTUgMjguMDQwNSAzMS4wOTgyQzI4LjEwNzIgMzIuNDk4NSAyOC4yNjQyIDMzLjc4MzUgMjguNTU3MyAzNC44NTk2QzI4Ljg1MzggMzUuOTQ4MyAyOS4yNTA5IDM2LjY3ODQgMjkuNjk0NCAzNy4xMjA4QzMwLjk3MjYgMzguMzk1NCAzMi45OTA4IDM5LjQyNTEgMzUuMDQ5MiAzOS44MjQzQzM3LjA4NDIgNDAuMjE4OSAzOC43MjI0IDM5LjkyNjkgMzkuNjgxOCAzOS4xOTY5QzM5LjY4NjggMzkuMTg1NyAzOS42OTIzIDM5LjE3MjYgMzkuNjk4NCAzOS4xNTc0QzM5Ljc1NzYgMzkuMDA5NSAzOS44Mjk0IDM4Ljc1NTQgMzkuODg3OCAzOC4zNjgzQzQwLjAwNDcgMzcuNTkzMyA0MC4wMzUgMzYuNTEyMiAzOS45NTYyIDM1LjE4MDNDMzkuNzk5NSAzMi41MzA1IDM5LjIyODYgMjkuMTY4OSAzOC4zMjY4IDI1Ljg2MDZDMzcuNDIxNiAyMi41Mzk2IDM2LjIxNzMgMTkuMzk5OCAzNC44NTIxIDE3LjEzODNDMzQuMTY4OCAxNi4wMDYyIDMzLjQ5NTEgMTUuMTc4NiAzMi44NzAzIDE0LjY1MzVDMzIuMjUxOCAxNC4xMzM3IDMxLjc5MzUgMTMuOTk5NyAzMS40NzUzIDEzLjk5OTdaTTE2LjUyNDcgMTRDMTcuNDc4OCAxNCAxOC4wMTU4IDE0LjMwMDUgMTguMzkxNCAxNC42ODcyQzE4LjgyNDggMTUuMTMzNCAxOS4xODY4IDE1Ljg1MSAxOS40NDEgMTYuODY0OUMxOS44ODU5IDE4LjYzOTkgMTkuODY3IDIwLjY4MjIgMTkuODUxOCAyMi4zMjk2QzE5Ljg0OTEgMjIuNjE0NiAxOS44NDY2IDIyLjg4NzcgMTkuODQ2NiAyMy4xNDU2QzE5Ljg0NjYgMjMuOTA1NiAxOS44ODA0IDI0LjgxNTYgMTkuOTE1NSAyNS43NjI0QzE5LjkyOTQgMjYuMTM1IDE5Ljk0MzQgMjYuNTEzOCAxOS45NTU3IDI2Ljg5MDhDMjAuMDAwNSAyOC4yNjYgMjAuMDI1OSAyOS43MDU4IDE5Ljk1OTYgMzEuMDk4NUMxOS44OTI5IDMyLjQ5ODggMTkuNzM1OSAzMy43ODM4IDE5LjQ0MjcgMzQuODU5OUMxOS4xNDYyIDM1Ljk0ODYgMTguNzQ5MiAzNi42Nzg3IDE4LjMwNTYgMzcuMTIxMUMxNy4wMjc1IDM4LjM5NTcgMTUuMDA5MyAzOS40MjU0IDEyLjk1MDkgMzkuODI0NkMxMC45MTU5IDQwLjIxOTIgOS4yNzc2OCAzOS45MjcyIDguMzE4MjMgMzkuMTk3MkM4LjMxMzI2IDM5LjE4NiA4LjMwNzcgMzkuMTcyOSA4LjMwMTYyIDM5LjE1NzdDOC4yNDI0MSAzOS4wMDk4IDguMTcwNjEgMzguNzU1NyA4LjExMjI0IDM4LjM2ODZDNy45OTUzOSAzNy41OTM2IDcuOTY1IDM2LjUxMjUgOC4wNDM4IDM1LjE4MDZDOC4yMDA1NiAzMi41MzA4IDguNzcxNDcgMjkuMTY5MiA5LjY3MzI0IDI1Ljg2MDlDMTAuNTc4NSAyMi41Mzk5IDExLjc4MjcgMTkuNDAwMSAxMy4xNDc5IDE3LjEzODZDMTMuODMxMyAxNi4wMDY1IDE0LjUwNDkgMTUuMTc4OSAxNS4xMjk4IDE0LjY1MzhDMTUuNzQ4MiAxNC4xMzQgMTYuMjA2NSAxNCAxNi41MjQ3IDE0WiIgZmlsbD0iI2I0NTMwOSIvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki48": { + "mimeType": "image/svg+xml", + "id": "img_blki48", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yOSA5QzI5IDExLjc2MTQgMjYuNzYxNCAxNCAyNCAxNEMyMS4yMzg2IDE0IDE5IDExLjc2MTQgMTkgOUMxOSA2LjIzODU4IDIxLjIzODYgNCAyNCA0QzI2Ljc2MTQgNCAyOSA2LjIzODU4IDI5IDlaTTI3IDlDMjcgMTAuNjU2OSAyNS42NTY5IDEyIDI0IDEyQzIyLjM0MzEgMTIgMjEgMTAuNjU2OSAyMSA5QzIxIDcuMzQzMTUgMjIuMzQzMSA2IDI0IDZDMjUuNjU2OSA2IDI3IDcuMzQzMTUgMjcgOVoiIGZpbGw9IiNiNDUzMDkiLz4KPHBhdGggZD0iTTE2Ljk5OTggNDFWMzRIMTguOTk5OFY0MUMxOC45OTk4IDQxLjU1MjMgMTkuNDQ3NSA0MiAxOS45OTk4IDQySDIwLjA4NjVDMjAuNjAzNyA0MiAyMS4wMzU2IDQxLjYwNTYgMjEuMDgyNCA0MS4wOTA1TDIxLjcyNyAzNEgyMy43MzUzTDIzLjA3NDIgNDEuMjcxNkMyMy4wNjkgNDEuMzI4OCAyMy4wNjIyIDQxLjM4NTYgMjMuMDUzOSA0MS40NDE3QzIzLjAzNTcgNDEuNTY0NyAyMy4wMTAxIDQxLjY4NTEgMjIuOTc3NiA0MS44MDI1QzIyLjYyNDIgNDMuMDc5OCAyMS40NTQ5IDQ0IDIwLjA4NjUgNDRIMTkuOTk5OEMxOC4zNDI5IDQ0IDE2Ljk5OTggNDIuNjU2OSAxNi45OTk4IDQxWiIgZmlsbD0iI2I0NTMwOSIvPgo8cGF0aCBkPSJNMjYuOTE3MSA0MS4wOTA1TDI2LjI3MjUgMzRIMjQuMjY0MkwyNC45MjUzIDQxLjI3MTZDMjQuOTMwNSA0MS4zMjg4IDI0LjkzNzMgNDEuMzg1NiAyNC45NDU2IDQxLjQ0MTdDMjQuOTYzOCA0MS41NjQ3IDI0Ljk4OTQgNDEuNjg1MSAyNS4wMjE5IDQxLjgwMjVDMjUuMzc1MyA0My4wNzk4IDI2LjU0NDYgNDQgMjcuOTEzIDQ0SDI3Ljk5OThDMjkuNjU2NiA0NCAzMC45OTk4IDQyLjY1NjkgMzAuOTk5OCA0MVYzNEgyOC45OTk4VjQxQzI4Ljk5OTggNDEuNTUyMyAyOC41NTIgNDIgMjcuOTk5OCA0MkgyNy45MTNDMjcuMzk1OCA0MiAyNi45NjM5IDQxLjYwNTYgMjYuOTE3MSA0MS4wOTA1WiIgZmlsbD0iI2I0NTMwOSIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTExIDE1QzEwLjQ0NzcgMTUgMTAgMTUuNDQ3NyAxMCAxNlYzMUMxMCAzMS41NTIzIDEwLjQ0NzcgMzIgMTEgMzJIMzdDMzcuNTUyMyAzMiAzOCAzMS41NTIzIDM4IDMxVjE2QzM4IDE1LjQ0NzcgMzcuNTUyMyAxNSAzNyAxNUgxMVpNMTIgMTdWMzBIMTkuNUMxOS41IDI5LjQ0MjQgMTkuNzU5MSAyOC45NTcyIDIwLjAyNzYgMjguNjAwNkMyMC4zMDg2IDI4LjIyNzYgMjAuNjc5NiAyNy44ODgzIDIxLjA3OTQgMjcuNjAxNkMyMS42MjUyIDI3LjIxMDMgMjIuMjk4NiAyNi44NjUgMjMgMjYuNjY3OFYyNC41SDIyLjJDMjEuNTk3MyAyNC41IDIwLjc1MzUgMjQuODY0MiAxOS45NDMzIDI1LjM1NTJDMTkuNTYzOCAyNS41ODUyIDE5LjIzMzcgMjUuODE2NyAxOC45OTg0IDI1Ljk5MTFDMTguODgxMiAyNi4wNzc4IDE4Ljc4ODggMjYuMTQ5NSAxOC43MjcgMjYuMTk4NEMxOC42OTYxIDI2LjIyMjggMTguNjczIDI2LjI0MTUgMTguNjU4MiAyNi4yNTM1TDE4LjY0MjYgMjYuMjY2M0wxOC42Mzk5IDI2LjI2ODRDMTguNjM5OSAyNi4yNjg0IDE4LjY0MDIgMjYuMjY4MiAxOCAyNS41QzE3LjM1OTggMjQuNzMxOCAxNy4zNjAxIDI0LjczMTUgMTcuMzYwMSAyNC43MzE1TDE3LjM2MTQgMjQuNzMwNUwxNy4zNjM4IDI0LjcyODVMMTcuMzcxMyAyNC43MjIzTDE3LjM5NjYgMjQuNzAxNkMxNy40MTc5IDI0LjY4NDMgMTcuNDQ4IDI0LjY2IDE3LjQ4NjMgMjQuNjI5N0MxNy41NjI3IDI0LjU2OTMgMTcuNjcxOSAyNC40ODQ3IDE3LjgwNzkgMjQuMzgzOUMxOC4wNzg4IDI0LjE4MzMgMTguNDYxMiAyMy45MTQ4IDE4LjkwNjcgMjMuNjQ0OEMxOS43NDY1IDIzLjEzNTggMjEuMDAyNyAyMi41IDIyLjIgMjIuNUgyM1YyMC41SDIyLjVDMjEuOTMwOSAyMC41IDIxLjE5MDkgMjAuNjk5MiAyMC41MjkyIDIwLjkzOThDMjAuMjEyIDIxLjA1NTIgMTkuOTM3IDIxLjE3MDkgMTkuNzQyMSAyMS4yNTc2QzE5LjY0NDkgMjEuMzAwNyAxOS41Njg1IDIxLjMzNjMgMTkuNTE3NiAyMS4zNjA1QzE5LjQ5MjIgMjEuMzcyNSAxOS40NzMyIDIxLjM4MTcgMTkuNDYxMyAyMS4zODc1TDE5LjQ0ODcgMjEuMzkzN0wxOS40NDcgMjEuMzk0NUMxOS40NDcgMjEuMzk0NSAxOS40NDcyIDIxLjM5NDQgMTkgMjAuNUMxOC41NTI4IDE5LjYwNTYgMTguNTUzMSAxOS42MDU0IDE4LjU1MzEgMTkuNjA1NEwxOC41NTY0IDE5LjYwMzhMMTguNTYyOSAxOS42MDA2TDE4LjU4NDQgMTkuNTlDMTguNjAyNSAxOS41ODEyIDE4LjYyNzkgMTkuNTY4OSAxOC42NjAxIDE5LjU1MzZDMTguNzI0NSAxOS41MjMxIDE4LjgxNiAxOS40ODA1IDE4LjkyOTggMTkuNDI5OUMxOS4xNTY3IDE5LjMyOTEgMTkuNDc1NSAxOS4xOTQ4IDE5Ljg0NTggMTkuMDYwMkMyMC41NTkxIDE4LjgwMDggMjEuNTY5MSAxOC41IDIyLjUgMTguNUgyM1YxN0gxMlpNMjUgMjQuNUgyNi4xQzI2Ljg0ODkgMjQuNSAyNy42MTg2IDI0Ljg2NjMgMjguMjYzMSAyNS4zMTg2QzI4LjU3MzUgMjUuNTM2NCAyOC44Mjg1IDI1Ljc1NTYgMjkuMDA0OCAyNS45MTk3QzI5LjA5MjUgMjYuMDAxMiAyOS4xNTk0IDI2LjA2NzkgMjkuMjAyNiAyNi4xMTIyQzI5LjIyNDEgMjYuMTM0MyAyOS4yMzk3IDI2LjE1MDcgMjkuMjQ4OCAyNi4xNjA1TDI5LjI1NzQgMjYuMTY5N0MyOS4yNTc0IDI2LjE2OTcgMjkuMjU2NyAyNi4xNjkgMzAgMjUuNUMzMC43NDMzIDI0LjgzMSAzMC43NDI5IDI0LjgzMDYgMzAuNzQyOSAyNC44MzA2TDMwLjc0MTQgMjQuODI5TDMwLjczODkgMjQuODI2MkwzMC43MzE4IDI0LjgxODRMMzAuNzA5NyAyNC43OTQ2QzMwLjY5MTUgMjQuNzc1MSAzMC42NjYzIDI0Ljc0ODUgMzAuNjM0NiAyNC43MTZDMzAuNTcxMSAyNC42NTA5IDMwLjQ4MDkgMjQuNTYxMyAzMC4zNjcgMjQuNDU1M0MzMC4xNDAzIDI0LjI0NDQgMjkuODE0IDIzLjk2MzYgMjkuNDExOSAyMy42ODE0QzI4LjYzMTQgMjMuMTMzNyAyNy40NTExIDIyLjUgMjYuMSAyMi41SDI1VjIwLjVIMjUuNzVDMjYuNDQ0MyAyMC41IDI3LjExOTMgMjAuNzAxMSAyNy42NDMyIDIwLjkyMTZDMjcuOTAwMyAyMS4wMjk5IDI4LjEwOTIgMjEuMTM3OCAyOC4yNTA5IDIxLjIxNjlDMjguMzIxNSAyMS4yNTY0IDI4LjM3NDcgMjEuMjg4MiAyOC40MDggMjEuMzA4N0MyOC40MjQ3IDIxLjMxODkgMjguNDM2MyAyMS4zMjYzIDI4LjQ0MjcgMjEuMzMwNEwyOC40NDU3IDIxLjMzMjNDMjguNDQ1NyAyMS4zMzIzIDI4LjQ0NTMgMjEuMzMyMSAyOSAyMC41QzI5LjU1NDcgMTkuNjY3OSAyOS41NTQyIDE5LjY2NzYgMjkuNTU0MiAxOS42Njc2TDI5LjU1MjcgMTkuNjY2NkwyOS41NTAxIDE5LjY2NDlMMjkuNTQzMiAxOS42NjA0TDI5LjUyMjggMTkuNjQ3MkMyOS41MDYzIDE5LjYzNjYgMjkuNDg0IDE5LjYyMjUgMjkuNDU2MiAxOS42MDU0QzI5LjQwMDcgMTkuNTcxMiAyOS4zMjMgMTkuNTI0OSAyOS4yMjU2IDE5LjQ3MDZDMjkuMDMxNSAxOS4zNjIyIDI4Ljc1NTkgMTkuMjIwMSAyOC40MTkzIDE5LjA3ODRDMjcuNzU1NyAxOC43OTg5IDI2LjgwNTcgMTguNSAyNS43NSAxOC41SDI1VjE3SDM2VjMwSDI4LjVDMjguNSAyOS40Mzc5IDI4LjIzMjQgMjguOTQ1MiAyNy45NjQxIDI4LjU4NzVDMjcuNjgwMyAyOC4yMDkyIDI3LjMwNTQgMjcuODYwNiAyNi45MDA3IDI3LjU2NjNDMjYuMzY3NSAyNy4xNzg1IDI1LjY5ODkgMjYuODI1NyAyNSAyNi42MzkxVjI0LjVaTTI2LjQ5MjkgMzBDMjYuNDc5NyAyOS45NjcgMjYuNDQ1NyAyOS44OTY0IDI2LjM2NDEgMjkuNzg3NUMyNi4yMjU5IDI5LjYwMzMgMjYuMDA3MSAyOS4zODk0IDI1LjcyNDMgMjkuMTgzN0MyNS4xNDc4IDI4Ljc2NDUgMjQuNDkzNyAyOC41MTE3IDI0LjAzMiAyOC41MDA0QzIzLjQ4NzcgMjguNTQ2NCAyMi44MDUyIDI4LjgyNTIgMjIuMjQ0OSAyOS4yMjdDMjEuOTY1NyAyOS40MjcyIDIxLjc1NTYgMjkuNjMwNyAyMS42MjUyIDI5LjgwMzhDMjEuNTQ5NiAyOS45MDQzIDIxLjUxODQgMjkuOTY5NCAyMS41MDYzIDMwSDI2LjQ5MjlaIiBmaWxsPSIjYjQ1MzA5Ii8+Cjwvc3ZnPgo=", + "created": 1700000000000 + } + } +} \ No newline at end of file diff --git a/knowledge/drafts/pillars-b1.excalidraw b/knowledge/drafts/pillars-b1.excalidraw new file mode 100644 index 0000000..4547574 --- /dev/null +++ b/knowledge/drafts/pillars-b1.excalidraw @@ -0,0 +1,2044 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "oidm-knowledge/tools/diagrams", + "elements": [ + { + "type": "rectangle", + "id": "band49", + "x": 0, + "y": 395.05, + "width": 880, + "height": 221.24999999999994, + "strokeColor": "#b45309", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1097, + "version": 1, + "versionNonce": 1098, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "band33", + "x": 0, + "y": 187.3, + "width": 880, + "height": 247.75, + "strokeColor": "#0f766e", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1065, + "version": 1, + "versionNonce": 1066, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "band15", + "x": 0, + "y": 91.65, + "width": 880, + "height": 71.65, + "strokeColor": "#6d28d9", + "backgroundColor": "#ede9fe", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1029, + "version": 1, + "versionNonce": 1030, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "panel1", + "x": 0, + "y": 0, + "width": 388.0, + "height": 67.65, + "strokeColor": "#be123c", + "backgroundColor": "#ffe4e6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1001, + "version": 1, + "versionNonce": 1002, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "panel2", + "x": 492.0, + "y": 0, + "width": 388.0, + "height": 67.65, + "strokeColor": "#15803d", + "backgroundColor": "#dcfce7", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1003, + "version": 1, + "versionNonce": 1004, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "bicon3", + "x": 18, + "y": 12.0, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1005, + "version": 1, + "versionNonce": 1006, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon3", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle4", + "x": 58, + "y": 14, + "width": 93.96, + "height": 22.5, + "strokeColor": "#881337", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1007, + "version": 1, + "versionNonce": 1008, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Use Cases", + "originalText": "Use Cases", + "fontSize": 18, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub5", + "x": 58, + "y": 37.400000000000006, + "width": 211.11999999999998, + "height": 16.25, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1009, + "version": 1, + "versionNonce": 1010, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "what the project wants built", + "originalText": "what the project wants built", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon6", + "x": 510.0, + "y": 12.0, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1011, + "version": 1, + "versionNonce": 1012, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon6", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle7", + "x": 550.0, + "y": 14, + "width": 198.35999999999999, + "height": 22.5, + "strokeColor": "#14532d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1013, + "version": 1, + "versionNonce": 1014, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Sample Applications", + "originalText": "Sample Applications", + "fontSize": 18, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub8", + "x": 550.0, + "y": 37.400000000000006, + "width": 143.26, + "height": 16.25, + "strokeColor": "#15803d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1015, + "version": 1, + "versionNonce": 1016, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "what has been built", + "originalText": "what has been built", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "conn9", + "x": 390.0, + "y": 33.825, + "width": 100.0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1017, + "version": 1, + "versionNonce": 1018, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 100.0, + 0 + ] + ] + }, + { + "type": "rectangle", + "id": "chip10", + "x": 389.53, + "y": 4.575000000000003, + "width": 100.94, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1019, + "version": 1, + "versionNonce": 1020, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "chipt11", + "x": 398.53, + "y": 7.575000000000003, + "width": 82.94, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1021, + "version": 1, + "versionNonce": 1022, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "illustrates", + "originalText": "illustrates", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon12", + "x": 18, + "y": 105.65, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1023, + "version": 1, + "versionNonce": 1024, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon12", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle13", + "x": 58, + "y": 107.65, + "width": 41.76, + "height": 22.5, + "strokeColor": "#4c1d95", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1025, + "version": 1, + "versionNonce": 1026, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "SDKs", + "originalText": "SDKs", + "fontSize": 18, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub14", + "x": 58, + "y": 131.05, + "width": 520.26, + "height": 16.25, + "strokeColor": "#6d28d9", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1027, + "version": 1, + "versionNonce": 1028, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "wrap the structures \u00b7 attach the shared knowledge \u00b7 support authoring", + "originalText": "wrap the structures \u00b7 attach the shared knowledge \u00b7 support authoring", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon16", + "x": 18, + "y": 203.3, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1031, + "version": 1, + "versionNonce": 1032, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon16", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle17", + "x": 58, + "y": 205.3, + "width": 174.0, + "height": 25.0, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1033, + "version": 1, + "versionNonce": 1034, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Data Structures", + "originalText": "Data Structures", + "fontSize": 20, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub18", + "x": 58, + "y": 231.3, + "width": 226.2, + "height": 16.25, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1035, + "version": 1, + "versionNonce": 1036, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "this patient \u00b7 Patient Context", + "originalText": "this patient \u00b7 Patient Context", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk19", + "x": 20.0, + "y": 261.55, + "width": 195.0, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1037, + "version": 1, + "versionNonce": 1038, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki20", + "x": 103.5, + "y": 281.925, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1039, + "version": 1, + "versionNonce": 1040, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki20", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt21", + "x": 26.0, + "y": 315.925, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1041, + "version": 1, + "versionNonce": 1042, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Observation", + "originalText": "Observation", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk22", + "x": 235.0, + "y": 261.55, + "width": 195.0, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1043, + "version": 1, + "versionNonce": 1044, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki23", + "x": 318.5, + "y": 272.55, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1045, + "version": 1, + "versionNonce": 1046, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki23", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt24", + "x": 241.0, + "y": 306.55, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1047, + "version": 1, + "versionNonce": 1048, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Exam Finding", + "originalText": "Exam Finding", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkt25", + "x": 241.0, + "y": 325.3, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1049, + "version": 1, + "versionNonce": 1050, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "List", + "originalText": "List", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk26", + "x": 450.0, + "y": 261.55, + "width": 195.0, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1051, + "version": 1, + "versionNonce": 1052, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki27", + "x": 533.5, + "y": 272.55, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1053, + "version": 1, + "versionNonce": 1054, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki27", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt28", + "x": 456.0, + "y": 306.55, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1055, + "version": 1, + "versionNonce": 1056, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Imaging Problem", + "originalText": "Imaging Problem", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkt29", + "x": 456.0, + "y": 325.3, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1057, + "version": 1, + "versionNonce": 1058, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "List", + "originalText": "List", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk30", + "x": 665.0, + "y": 261.55, + "width": 195.0, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1059, + "version": 1, + "versionNonce": 1060, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki31", + "x": 746.5, + "y": 279.925, + "width": 32, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1061, + "version": 1, + "versionNonce": 1062, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki31", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt32", + "x": 671.0, + "y": 315.925, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1063, + "version": 1, + "versionNonce": 1064, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Imaging Persona", + "originalText": "Imaging Persona", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon34", + "x": 18, + "y": 447.05, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1067, + "version": 1, + "versionNonce": 1068, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon34", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle35", + "x": 58, + "y": 449.05, + "width": 208.79999999999998, + "height": 25.0, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1069, + "version": 1, + "versionNonce": 1070, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Foundation Context", + "originalText": "Foundation Context", + "fontSize": 20, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub36", + "x": 58, + "y": 475.05, + "width": 188.5, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1071, + "version": 1, + "versionNonce": 1072, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "shared, curated knowledge", + "originalText": "shared, curated knowledge", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk37", + "x": 20.0, + "y": 501.3, + "width": 264.0, + "height": 95.0, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1073, + "version": 1, + "versionNonce": 1074, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki38", + "x": 138.0, + "y": 512.3, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1075, + "version": 1, + "versionNonce": 1076, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki38", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt39", + "x": 26.0, + "y": 546.3, + "width": 252.0, + "height": 18.75, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1077, + "version": 1, + "versionNonce": 1078, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Finding/diagnosis definitions", + "originalText": "Finding/diagnosis definitions", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkd40", + "x": 26.0, + "y": 567.05, + "width": 252.0, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1079, + "version": 1, + "versionNonce": 1080, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "finding models \u00b7 CDEs", + "originalText": "finding models \u00b7 CDEs", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk41", + "x": 308.0, + "y": 501.3, + "width": 264.0, + "height": 95.0, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1081, + "version": 1, + "versionNonce": 1082, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki42", + "x": 424.0, + "y": 510.29999999999995, + "width": 32, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1083, + "version": 1, + "versionNonce": 1084, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki42", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt43", + "x": 314.0, + "y": 546.3, + "width": 252.0, + "height": 18.75, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1085, + "version": 1, + "versionNonce": 1086, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Anatomic locations", + "originalText": "Anatomic locations", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkd44", + "x": 314.0, + "y": 567.05, + "width": 252.0, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1087, + "version": 1, + "versionNonce": 1088, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "anchored in RadLex", + "originalText": "anchored in RadLex", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk45", + "x": 596.0, + "y": 501.3, + "width": 264.0, + "height": 95.0, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1089, + "version": 1, + "versionNonce": 1090, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki46", + "x": 712.0, + "y": 510.29999999999995, + "width": 32, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1091, + "version": 1, + "versionNonce": 1092, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki46", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt47", + "x": 602.0, + "y": 546.3, + "width": 252.0, + "height": 18.75, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1093, + "version": 1, + "versionNonce": 1094, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Exam types", + "originalText": "Exam types", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkd48", + "x": 602.0, + "y": 567.05, + "width": 252.0, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1095, + "version": 1, + "versionNonce": 1096, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "LOINC/RSNA Playbook", + "originalText": "LOINC/RSNA Playbook", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "fill50", + "x": 0.0, + "y": 395.05, + "width": 81.6, + "height": 43.0, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1099, + "version": 1, + "versionNonce": 1100, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill51", + "x": 199.6, + "y": 395.05, + "width": 81.6, + "height": 43.0, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1101, + "version": 1, + "versionNonce": 1102, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill52", + "x": 399.2, + "y": 395.05, + "width": 81.6, + "height": 43.0, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1103, + "version": 1, + "versionNonce": 1104, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill53", + "x": 598.8, + "y": 395.05, + "width": 81.6, + "height": 43.0, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1105, + "version": 1, + "versionNonce": 1106, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill54", + "x": 798.4, + "y": 395.05, + "width": 81.6, + "height": 43.0, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1107, + "version": 1, + "versionNonce": 1108, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "line", + "id": "ln55", + "x": 0.0, + "y": 395.05, + "width": 880.0, + "height": 40.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1109, + "version": 1, + "versionNonce": 1110, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 81.6, + 0.0 + ], + [ + 81.6, + 40.0 + ], + [ + 199.6, + 40.0 + ], + [ + 199.6, + 0.0 + ], + [ + 281.2, + 0.0 + ], + [ + 281.2, + 40.0 + ], + [ + 399.2, + 40.0 + ], + [ + 399.2, + 0.0 + ], + [ + 480.79999999999995, + 0.0 + ], + [ + 480.79999999999995, + 40.0 + ], + [ + 598.8, + 40.0 + ], + [ + 598.8, + 0.0 + ], + [ + 680.4, + 0.0 + ], + [ + 680.4, + 40.0 + ], + [ + 798.4, + 40.0 + ], + [ + 798.4, + 0.0 + ], + [ + 880.0, + 0.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln56", + "x": 0.0, + "y": 395.05, + "width": 0.0, + "height": 43.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1111, + "version": 1, + "versionNonce": 1112, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 43.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln57", + "x": 880, + "y": 395.05, + "width": 0, + "height": 43.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1113, + "version": 1, + "versionNonce": 1114, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 0, + 43.0 + ] + ], + "roundness": null + }, + { + "type": "text", + "id": "jw58", + "x": 81.6, + "y": 406.925, + "width": 118.0, + "height": 16.25, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1115, + "version": 1, + "versionNonce": 1116, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "finding", + "originalText": "finding", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "jw59", + "x": 281.2, + "y": 406.925, + "width": 118.0, + "height": 16.25, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1117, + "version": 1, + "versionNonce": 1118, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "diagnosis", + "originalText": "diagnosis", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "jw60", + "x": 480.79999999999995, + "y": 406.925, + "width": 118.0, + "height": 16.25, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1119, + "version": 1, + "versionNonce": 1120, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "location", + "originalText": "location", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "jw61", + "x": 680.4, + "y": 406.925, + "width": 118.0, + "height": 16.25, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1121, + "version": 1, + "versionNonce": 1122, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "exam type", + "originalText": "exam type", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "lead62", + "x": 0, + "y": 367.925, + "width": 880, + "height": 16.25, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1123, + "version": 1, + "versionNonce": 1124, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "woven together at every:", + "originalText": "woven together at every:", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + } + ], + "appState": { + "viewBackgroundColor": "#ffffff", + "gridSize": null + }, + "files": { + "img_bicon3": { + "mimeType": "image/svg+xml", + "id": "img_bicon3", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiNiZTEyM2MiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTE1IDE0Yy4yLTEgLjctMS43IDEuNS0yLjUgMS0uOSAxLjUtMi4yIDEuNS0zLjVBNiA2IDAgMCAwIDYgOGMwIDEgLjIgMi4yIDEuNSAzLjUuNy43IDEuMyAxLjUgMS41IDIuNSIgLz4KICA8cGF0aCBkPSJNOSAxOGg2IiAvPgogIDxwYXRoIGQ9Ik0xMCAyMmg0IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_bicon6": { + "mimeType": "image/svg+xml", + "id": "img_bicon6", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMxNTgwM2QiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHJlY3QgeD0iMiIgeT0iNCIgd2lkdGg9IjIwIiBoZWlnaHQ9IjE2IiByeD0iMiIgLz4KICA8cGF0aCBkPSJNMTAgNHY0IiAvPgogIDxwYXRoIGQ9Ik0yIDhoMjAiIC8+CiAgPHBhdGggZD0iTTYgNHY0IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_bicon12": { + "mimeType": "image/svg+xml", + "id": "img_bicon12", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiM2ZDI4ZDkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTExIDIxLjczYTIgMiAwIDAgMCAyIDBsNy00QTIgMiAwIDAgMCAyMSAxNlY4YTIgMiAwIDAgMC0xLTEuNzNsLTctNGEyIDIgMCAwIDAtMiAwbC03IDRBMiAyIDAgMCAwIDMgOHY4YTIgMiAwIDAgMCAxIDEuNzN6IiAvPgogIDxwYXRoIGQ9Ik0xMiAyMlYxMiIgLz4KICA8cG9seWxpbmUgcG9pbnRzPSIzLjI5IDcgMTIgMTIgMjAuNzEgNyIgLz4KICA8cGF0aCBkPSJtNy41IDQuMjcgOSA1LjE1IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_bicon16": { + "mimeType": "image/svg+xml", + "id": "img_bicon16", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyLjgzIDIuMThhMiAyIDAgMCAwLTEuNjYgMEwyLjYgNi4wOGExIDEgMCAwIDAgMCAxLjgzbDguNTggMy45MWEyIDIgMCAwIDAgMS42NiAwbDguNTgtMy45YTEgMSAwIDAgMCAwLTEuODN6IiAvPgogIDxwYXRoIGQ9Ik0yIDEyYTEgMSAwIDAgMCAuNTguOTFsOC42IDMuOTFhMiAyIDAgMCAwIDEuNjUgMGw4LjU4LTMuOUExIDEgMCAwIDAgMjIgMTIiIC8+CiAgPHBhdGggZD0iTTIgMTdhMSAxIDAgMCAwIC41OC45MWw4LjYgMy45MWEyIDIgMCAwIDAgMS42NSAwbDguNTgtMy45QTEgMSAwIDAgMCAyMiAxNyIgLz4KPC9zdmc+Cg==", + "created": 1700000000000 + }, + "img_blki20": { + "mimeType": "image/svg+xml", + "id": "img_blki20", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHJlY3Qgd2lkdGg9IjgiIGhlaWdodD0iNCIgeD0iOCIgeT0iMiIgcng9IjEiIHJ5PSIxIiAvPgogIDxwYXRoIGQ9Ik0xNiA0aDJhMiAyIDAgMCAxIDIgMnYxNGEyIDIgMCAwIDEtMiAySDZhMiAyIDAgMCAxLTItMlY2YTIgMiAwIDAgMSAyLTJoMiIgLz4KPC9zdmc+Cg==", + "created": 1700000000000 + }, + "img_blki23": { + "mimeType": "image/svg+xml", + "id": "img_blki23", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHJlY3Qgd2lkdGg9IjgiIGhlaWdodD0iNCIgeD0iOCIgeT0iMiIgcng9IjEiIHJ5PSIxIiAvPgogIDxwYXRoIGQ9Ik0xNiA0aDJhMiAyIDAgMCAxIDIgMnYxNGEyIDIgMCAwIDEtMiAySDZhMiAyIDAgMCAxLTItMlY2YTIgMiAwIDAgMSAyLTJoMiIgLz4KICA8cGF0aCBkPSJNMTIgMTFoNCIgLz4KICA8cGF0aCBkPSJNMTIgMTZoNCIgLz4KICA8cGF0aCBkPSJNOCAxMWguMDEiIC8+CiAgPHBhdGggZD0iTTggMTZoLjAxIiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki27": { + "mimeType": "image/svg+xml", + "id": "img_blki27", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTMgNWguMDEiIC8+CiAgPHBhdGggZD0iTTMgMTJoLjAxIiAvPgogIDxwYXRoIGQ9Ik0zIDE5aC4wMSIgLz4KICA8cGF0aCBkPSJNOCA1aDEzIiAvPgogIDxwYXRoIGQ9Ik04IDEyaDEzIiAvPgogIDxwYXRoIGQ9Ik04IDE5aDEzIiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki31": { + "mimeType": "image/svg+xml", + "id": "img_blki31", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yNCAyNEMyOC40MjA0IDI0IDMyIDIwLjQyMDQgMzIgMTZDMzIgMTEuNTc5NiAyOC40MjA0IDggMjQgOEMxOS41Nzk2IDggMTYgMTEuNTc5NiAxNiAxNkMxNiAyMC40MjA0IDE5LjU3OTYgMjQgMjQgMjRaTTM0IDE2QzM0IDIxLjUyNSAyOS41MjUgMjYgMjQgMjZDMTguNDc1IDI2IDE0IDIxLjUyNSAxNCAxNkMxNCAxMC40NzUgMTguNDc1IDYgMjQgNkMyOS41MjUgNiAzNCAxMC40NzUgMzQgMTZaIiBmaWxsPSIjMGY3NjZlIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNOS4yMjM0OCAzNC4yMTE5QzguMjIwMzggMzUuMDIxMSA4IDM1LjYyOTEgOCAzNlY0MEg0MFYzNkM0MCAzNS42MjkxIDM5Ljc3OTYgMzUuMDIxMSAzOC43NzY1IDM0LjIxMTlDMzcuNzk1OCAzMy40MjA3IDM2LjMzNDEgMzIuNjY2OSAzNC41NjIyIDMyLjAxNUMzMS4wMTk5IDMwLjcxMTcgMjYuNzUzMiAzMCAyNCAzMEMyMS4yNDY4IDMwIDE2Ljk4MDEgMzAuNzExNyAxMy40Mzc4IDMyLjAxNUMxMS42NjU5IDMyLjY2NjkgMTAuMjA0MiAzMy40MjA3IDkuMjIzNDggMzQuMjExOVpNMjQgMjhDMTcuOTkyNSAyOCA2IDMxLjAzNDcgNiAzNlY0Mkg0MlYzNkM0MiAzMS4wMzQ3IDMwLjAwNzUgMjggMjQgMjhaIiBmaWxsPSIjMGY3NjZlIi8+Cjwvc3ZnPgo=", + "created": 1700000000000 + }, + "img_bicon34": { + "mimeType": "image/svg+xml", + "id": "img_bicon34", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiNiNDUzMDkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyIDV2MTYiIC8+CiAgPHBhdGggZD0iTTIwLjAwMSAxOUEyIDIgMCAwMDIyIDE3VjVhMiAyIDAgMDAtMS45OTktMkwxNiAzLjAwMkE1IDUgMCAwMDEyIDVhNSA1IDAgMDAtNC0ySDRhMiAyIDAgMDAtMiAydjEyYTIgMiAwIDAwMS45OTkgMkg4YTUgNSAwIDAxNCAyIDUgNSAwIDAxNC0yeiIgLz4KPC9zdmc+Cg==", + "created": 1700000000000 + }, + "img_blki38": { + "mimeType": "image/svg+xml", + "id": "img_blki38", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiNiNDUzMDkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyLjU4NiAyLjU4NkEyIDIgMCAwIDAgMTEuMTcyIDJINGEyIDIgMCAwIDAtMiAydjcuMTcyYTIgMiAwIDAgMCAuNTg2IDEuNDE0bDguNzA0IDguNzA0YTIuNDI2IDIuNDI2IDAgMCAwIDMuNDIgMGw2LjU4LTYuNThhMi40MjYgMi40MjYgMCAwIDAgMC0zLjQyeiIgLz4KICA8Y2lyY2xlIGN4PSI3LjUiIGN5PSI3LjUiIHI9Ii41IiBmaWxsPSIjYjQ1MzA5IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki42": { + "mimeType": "image/svg+xml", + "id": "img_blki42", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yMyA2LjAwMDEzQzIzIDYuMDAwMDQgMjMgNiAyNCA2SDI0LjE3NjFDMjQuMjUzMyA2IDI0LjMyMzMgNiAyNC4zODY4IDZDMjUgNi4wMDAwMSAyNSA2LjAwMDA1IDI1IDYuMDAwMTNWMjAuNUMyNSAyMS44OTc3IDI1LjU2NDEgMjIuNDQyMSAyNi4wMDM5IDIyLjY5ODdDMjYuMDUzIDIyLjcyNzMgMjYuMTAyNCAyMi43NTMzIDI2LjE1MTYgMjIuNzc3QzI2LjE1MDYgMjIuNjU2OCAyNi4xNDkzIDIyLjUzMTYgMjYuMTQ3OSAyMi40MDE5TDI2LjE0NzkgMjIuNDAwM0MyNi4xMTAxIDE4Ljg3MTYgMjYuMDM2NSAxMS45OTk3IDMxLjQ3NTMgMTEuOTk5N0MzOC45MjU5IDExLjk5OTcgNDQuMjQ3OCAzOC4wMDYyIDQxLjA1NDcgNDAuNjU5OUMzNy44NjE1IDQzLjMxMzYgMzEuNDc1MyA0MS43MjE0IDI4LjI4MjIgMzguNTM2OUMyNS43MDQyIDM1Ljk2NTkgMjUuOTI3MiAyOS45NTgzIDI2LjA4NzMgMjUuNjQ1N0wyNi4wODc0IDI1LjY0NDNDMjYuMDk3MSAyNS4zODE5IDI2LjEwNjcgMjUuMTI1OCAyNi4xMTUzIDI0Ljg3NzFDMjUuNzkgMjQuNzk2MiAyNS4zOTU5IDI0LjY1OTUgMjQuOTk2MiAyNC40MjYzQzI0LjYzOTggMjQuMjE4NCAyNC4yOTc1IDIzLjk0NDIgMjQgMjMuNTkxOUMyMy43MDI2IDIzLjk0NDIgMjMuMzYwMyAyNC4yMTg0IDIzLjAwMzkgMjQuNDI2M0MyMi42MDQxIDI0LjY1OTUgMjIuMjEwMSAyNC43OTYyIDIxLjg4NDggMjQuODc3MUMyMS44OTM0IDI1LjEyNjEgMjEuOTAyOSAyNS4zODI2IDIxLjkxMjcgMjUuNjQ1M0MyMi4wNzI4IDI5Ljk1NzkgMjIuMjk1OSAzNS45NjYyIDE5LjcxNzkgMzguNTM3MkMxNi41MjQ3IDQxLjcyMTcgMTAuMTM4NSA0My4zMTM5IDYuOTQ1MzYgNDAuNjYwMkMzLjc1MjIyIDM4LjAwNjUgOS4wNzQxMyAxMiAxNi41MjQ3IDEyQzIxLjk2MzYgMTIgMjEuODkgMTguODcxNyAyMS44NTIyIDIyLjQwMDNDMjEuODUyIDIyLjQxNjYgMjEuODUxOCAyMi40MzI4IDIxLjg1MTYgMjIuNDQ4OUMyMS44NTA0IDIyLjU2MTkgMjEuODQ5MyAyMi42NzE0IDIxLjg0ODQgMjIuNzc3QzIxLjg5NzcgMjIuNzUzNCAyMS45NDcxIDIyLjcyNzQgMjEuOTk2MiAyMi42OTg3QzIyLjQzNiAyMi40NDIxIDIzIDIxLjg5NzcgMjMgMjAuNVY2LjAwMDEzWk0zMS40NzUzIDEzLjk5OTdDMzAuNTIxMiAxMy45OTk3IDI5Ljk4NDMgMTQuMzAwMiAyOS42MDg2IDE0LjY4NjlDMjkuMTc1MiAxNS4xMzMxIDI4LjgxMzIgMTUuODUwNyAyOC41NTkgMTYuODY0NkMyOC4xMTQxIDE4LjYzOTUgMjguMTMzIDIwLjY4MTkgMjguMTQ4MyAyMi4zMjkzQzI4LjE1MDkgMjIuNjE0MiAyOC4xNTM0IDIyLjg4NzQgMjguMTUzNCAyMy4xNDUzQzI4LjE1MzQgMjMuOTA1MyAyOC4xMTk2IDI0LjgxNTMgMjguMDg0NSAyNS43NjIxQzI4LjA3MDcgMjYuMTM0OSAyOC4wNTY2IDI2LjUxMzMgMjguMDQ0MyAyNi44OTA1QzI3Ljk5OTYgMjguMjY1NyAyNy45NzQxIDI5LjcwNTUgMjguMDQwNSAzMS4wOTgyQzI4LjEwNzIgMzIuNDk4NSAyOC4yNjQyIDMzLjc4MzUgMjguNTU3MyAzNC44NTk2QzI4Ljg1MzggMzUuOTQ4MyAyOS4yNTA5IDM2LjY3ODQgMjkuNjk0NCAzNy4xMjA4QzMwLjk3MjYgMzguMzk1NCAzMi45OTA4IDM5LjQyNTEgMzUuMDQ5MiAzOS44MjQzQzM3LjA4NDIgNDAuMjE4OSAzOC43MjI0IDM5LjkyNjkgMzkuNjgxOCAzOS4xOTY5QzM5LjY4NjggMzkuMTg1NyAzOS42OTIzIDM5LjE3MjYgMzkuNjk4NCAzOS4xNTc0QzM5Ljc1NzYgMzkuMDA5NSAzOS44Mjk0IDM4Ljc1NTQgMzkuODg3OCAzOC4zNjgzQzQwLjAwNDcgMzcuNTkzMyA0MC4wMzUgMzYuNTEyMiAzOS45NTYyIDM1LjE4MDNDMzkuNzk5NSAzMi41MzA1IDM5LjIyODYgMjkuMTY4OSAzOC4zMjY4IDI1Ljg2MDZDMzcuNDIxNiAyMi41Mzk2IDM2LjIxNzMgMTkuMzk5OCAzNC44NTIxIDE3LjEzODNDMzQuMTY4OCAxNi4wMDYyIDMzLjQ5NTEgMTUuMTc4NiAzMi44NzAzIDE0LjY1MzVDMzIuMjUxOCAxNC4xMzM3IDMxLjc5MzUgMTMuOTk5NyAzMS40NzUzIDEzLjk5OTdaTTE2LjUyNDcgMTRDMTcuNDc4OCAxNCAxOC4wMTU4IDE0LjMwMDUgMTguMzkxNCAxNC42ODcyQzE4LjgyNDggMTUuMTMzNCAxOS4xODY4IDE1Ljg1MSAxOS40NDEgMTYuODY0OUMxOS44ODU5IDE4LjYzOTkgMTkuODY3IDIwLjY4MjIgMTkuODUxOCAyMi4zMjk2QzE5Ljg0OTEgMjIuNjE0NiAxOS44NDY2IDIyLjg4NzcgMTkuODQ2NiAyMy4xNDU2QzE5Ljg0NjYgMjMuOTA1NiAxOS44ODA0IDI0LjgxNTYgMTkuOTE1NSAyNS43NjI0QzE5LjkyOTQgMjYuMTM1IDE5Ljk0MzQgMjYuNTEzOCAxOS45NTU3IDI2Ljg5MDhDMjAuMDAwNSAyOC4yNjYgMjAuMDI1OSAyOS43MDU4IDE5Ljk1OTYgMzEuMDk4NUMxOS44OTI5IDMyLjQ5ODggMTkuNzM1OSAzMy43ODM4IDE5LjQ0MjcgMzQuODU5OUMxOS4xNDYyIDM1Ljk0ODYgMTguNzQ5MiAzNi42Nzg3IDE4LjMwNTYgMzcuMTIxMUMxNy4wMjc1IDM4LjM5NTcgMTUuMDA5MyAzOS40MjU0IDEyLjk1MDkgMzkuODI0NkMxMC45MTU5IDQwLjIxOTIgOS4yNzc2OCAzOS45MjcyIDguMzE4MjMgMzkuMTk3MkM4LjMxMzI2IDM5LjE4NiA4LjMwNzcgMzkuMTcyOSA4LjMwMTYyIDM5LjE1NzdDOC4yNDI0MSAzOS4wMDk4IDguMTcwNjEgMzguNzU1NyA4LjExMjI0IDM4LjM2ODZDNy45OTUzOSAzNy41OTM2IDcuOTY1IDM2LjUxMjUgOC4wNDM4IDM1LjE4MDZDOC4yMDA1NiAzMi41MzA4IDguNzcxNDcgMjkuMTY5MiA5LjY3MzI0IDI1Ljg2MDlDMTAuNTc4NSAyMi41Mzk5IDExLjc4MjcgMTkuNDAwMSAxMy4xNDc5IDE3LjEzODZDMTMuODMxMyAxNi4wMDY1IDE0LjUwNDkgMTUuMTc4OSAxNS4xMjk4IDE0LjY1MzhDMTUuNzQ4MiAxNC4xMzQgMTYuMjA2NSAxNCAxNi41MjQ3IDE0WiIgZmlsbD0iI2I0NTMwOSIvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki46": { + "mimeType": "image/svg+xml", + "id": "img_blki46", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yOSA5QzI5IDExLjc2MTQgMjYuNzYxNCAxNCAyNCAxNEMyMS4yMzg2IDE0IDE5IDExLjc2MTQgMTkgOUMxOSA2LjIzODU4IDIxLjIzODYgNCAyNCA0QzI2Ljc2MTQgNCAyOSA2LjIzODU4IDI5IDlaTTI3IDlDMjcgMTAuNjU2OSAyNS42NTY5IDEyIDI0IDEyQzIyLjM0MzEgMTIgMjEgMTAuNjU2OSAyMSA5QzIxIDcuMzQzMTUgMjIuMzQzMSA2IDI0IDZDMjUuNjU2OSA2IDI3IDcuMzQzMTUgMjcgOVoiIGZpbGw9IiNiNDUzMDkiLz4KPHBhdGggZD0iTTE2Ljk5OTggNDFWMzRIMTguOTk5OFY0MUMxOC45OTk4IDQxLjU1MjMgMTkuNDQ3NSA0MiAxOS45OTk4IDQySDIwLjA4NjVDMjAuNjAzNyA0MiAyMS4wMzU2IDQxLjYwNTYgMjEuMDgyNCA0MS4wOTA1TDIxLjcyNyAzNEgyMy43MzUzTDIzLjA3NDIgNDEuMjcxNkMyMy4wNjkgNDEuMzI4OCAyMy4wNjIyIDQxLjM4NTYgMjMuMDUzOSA0MS40NDE3QzIzLjAzNTcgNDEuNTY0NyAyMy4wMTAxIDQxLjY4NTEgMjIuOTc3NiA0MS44MDI1QzIyLjYyNDIgNDMuMDc5OCAyMS40NTQ5IDQ0IDIwLjA4NjUgNDRIMTkuOTk5OEMxOC4zNDI5IDQ0IDE2Ljk5OTggNDIuNjU2OSAxNi45OTk4IDQxWiIgZmlsbD0iI2I0NTMwOSIvPgo8cGF0aCBkPSJNMjYuOTE3MSA0MS4wOTA1TDI2LjI3MjUgMzRIMjQuMjY0MkwyNC45MjUzIDQxLjI3MTZDMjQuOTMwNSA0MS4zMjg4IDI0LjkzNzMgNDEuMzg1NiAyNC45NDU2IDQxLjQ0MTdDMjQuOTYzOCA0MS41NjQ3IDI0Ljk4OTQgNDEuNjg1MSAyNS4wMjE5IDQxLjgwMjVDMjUuMzc1MyA0My4wNzk4IDI2LjU0NDYgNDQgMjcuOTEzIDQ0SDI3Ljk5OThDMjkuNjU2NiA0NCAzMC45OTk4IDQyLjY1NjkgMzAuOTk5OCA0MVYzNEgyOC45OTk4VjQxQzI4Ljk5OTggNDEuNTUyMyAyOC41NTIgNDIgMjcuOTk5OCA0MkgyNy45MTNDMjcuMzk1OCA0MiAyNi45NjM5IDQxLjYwNTYgMjYuOTE3MSA0MS4wOTA1WiIgZmlsbD0iI2I0NTMwOSIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTExIDE1QzEwLjQ0NzcgMTUgMTAgMTUuNDQ3NyAxMCAxNlYzMUMxMCAzMS41NTIzIDEwLjQ0NzcgMzIgMTEgMzJIMzdDMzcuNTUyMyAzMiAzOCAzMS41NTIzIDM4IDMxVjE2QzM4IDE1LjQ0NzcgMzcuNTUyMyAxNSAzNyAxNUgxMVpNMTIgMTdWMzBIMTkuNUMxOS41IDI5LjQ0MjQgMTkuNzU5MSAyOC45NTcyIDIwLjAyNzYgMjguNjAwNkMyMC4zMDg2IDI4LjIyNzYgMjAuNjc5NiAyNy44ODgzIDIxLjA3OTQgMjcuNjAxNkMyMS42MjUyIDI3LjIxMDMgMjIuMjk4NiAyNi44NjUgMjMgMjYuNjY3OFYyNC41SDIyLjJDMjEuNTk3MyAyNC41IDIwLjc1MzUgMjQuODY0MiAxOS45NDMzIDI1LjM1NTJDMTkuNTYzOCAyNS41ODUyIDE5LjIzMzcgMjUuODE2NyAxOC45OTg0IDI1Ljk5MTFDMTguODgxMiAyNi4wNzc4IDE4Ljc4ODggMjYuMTQ5NSAxOC43MjcgMjYuMTk4NEMxOC42OTYxIDI2LjIyMjggMTguNjczIDI2LjI0MTUgMTguNjU4MiAyNi4yNTM1TDE4LjY0MjYgMjYuMjY2M0wxOC42Mzk5IDI2LjI2ODRDMTguNjM5OSAyNi4yNjg0IDE4LjY0MDIgMjYuMjY4MiAxOCAyNS41QzE3LjM1OTggMjQuNzMxOCAxNy4zNjAxIDI0LjczMTUgMTcuMzYwMSAyNC43MzE1TDE3LjM2MTQgMjQuNzMwNUwxNy4zNjM4IDI0LjcyODVMMTcuMzcxMyAyNC43MjIzTDE3LjM5NjYgMjQuNzAxNkMxNy40MTc5IDI0LjY4NDMgMTcuNDQ4IDI0LjY2IDE3LjQ4NjMgMjQuNjI5N0MxNy41NjI3IDI0LjU2OTMgMTcuNjcxOSAyNC40ODQ3IDE3LjgwNzkgMjQuMzgzOUMxOC4wNzg4IDI0LjE4MzMgMTguNDYxMiAyMy45MTQ4IDE4LjkwNjcgMjMuNjQ0OEMxOS43NDY1IDIzLjEzNTggMjEuMDAyNyAyMi41IDIyLjIgMjIuNUgyM1YyMC41SDIyLjVDMjEuOTMwOSAyMC41IDIxLjE5MDkgMjAuNjk5MiAyMC41MjkyIDIwLjkzOThDMjAuMjEyIDIxLjA1NTIgMTkuOTM3IDIxLjE3MDkgMTkuNzQyMSAyMS4yNTc2QzE5LjY0NDkgMjEuMzAwNyAxOS41Njg1IDIxLjMzNjMgMTkuNTE3NiAyMS4zNjA1QzE5LjQ5MjIgMjEuMzcyNSAxOS40NzMyIDIxLjM4MTcgMTkuNDYxMyAyMS4zODc1TDE5LjQ0ODcgMjEuMzkzN0wxOS40NDcgMjEuMzk0NUMxOS40NDcgMjEuMzk0NSAxOS40NDcyIDIxLjM5NDQgMTkgMjAuNUMxOC41NTI4IDE5LjYwNTYgMTguNTUzMSAxOS42MDU0IDE4LjU1MzEgMTkuNjA1NEwxOC41NTY0IDE5LjYwMzhMMTguNTYyOSAxOS42MDA2TDE4LjU4NDQgMTkuNTlDMTguNjAyNSAxOS41ODEyIDE4LjYyNzkgMTkuNTY4OSAxOC42NjAxIDE5LjU1MzZDMTguNzI0NSAxOS41MjMxIDE4LjgxNiAxOS40ODA1IDE4LjkyOTggMTkuNDI5OUMxOS4xNTY3IDE5LjMyOTEgMTkuNDc1NSAxOS4xOTQ4IDE5Ljg0NTggMTkuMDYwMkMyMC41NTkxIDE4LjgwMDggMjEuNTY5MSAxOC41IDIyLjUgMTguNUgyM1YxN0gxMlpNMjUgMjQuNUgyNi4xQzI2Ljg0ODkgMjQuNSAyNy42MTg2IDI0Ljg2NjMgMjguMjYzMSAyNS4zMTg2QzI4LjU3MzUgMjUuNTM2NCAyOC44Mjg1IDI1Ljc1NTYgMjkuMDA0OCAyNS45MTk3QzI5LjA5MjUgMjYuMDAxMiAyOS4xNTk0IDI2LjA2NzkgMjkuMjAyNiAyNi4xMTIyQzI5LjIyNDEgMjYuMTM0MyAyOS4yMzk3IDI2LjE1MDcgMjkuMjQ4OCAyNi4xNjA1TDI5LjI1NzQgMjYuMTY5N0MyOS4yNTc0IDI2LjE2OTcgMjkuMjU2NyAyNi4xNjkgMzAgMjUuNUMzMC43NDMzIDI0LjgzMSAzMC43NDI5IDI0LjgzMDYgMzAuNzQyOSAyNC44MzA2TDMwLjc0MTQgMjQuODI5TDMwLjczODkgMjQuODI2MkwzMC43MzE4IDI0LjgxODRMMzAuNzA5NyAyNC43OTQ2QzMwLjY5MTUgMjQuNzc1MSAzMC42NjYzIDI0Ljc0ODUgMzAuNjM0NiAyNC43MTZDMzAuNTcxMSAyNC42NTA5IDMwLjQ4MDkgMjQuNTYxMyAzMC4zNjcgMjQuNDU1M0MzMC4xNDAzIDI0LjI0NDQgMjkuODE0IDIzLjk2MzYgMjkuNDExOSAyMy42ODE0QzI4LjYzMTQgMjMuMTMzNyAyNy40NTExIDIyLjUgMjYuMSAyMi41SDI1VjIwLjVIMjUuNzVDMjYuNDQ0MyAyMC41IDI3LjExOTMgMjAuNzAxMSAyNy42NDMyIDIwLjkyMTZDMjcuOTAwMyAyMS4wMjk5IDI4LjEwOTIgMjEuMTM3OCAyOC4yNTA5IDIxLjIxNjlDMjguMzIxNSAyMS4yNTY0IDI4LjM3NDcgMjEuMjg4MiAyOC40MDggMjEuMzA4N0MyOC40MjQ3IDIxLjMxODkgMjguNDM2MyAyMS4zMjYzIDI4LjQ0MjcgMjEuMzMwNEwyOC40NDU3IDIxLjMzMjNDMjguNDQ1NyAyMS4zMzIzIDI4LjQ0NTMgMjEuMzMyMSAyOSAyMC41QzI5LjU1NDcgMTkuNjY3OSAyOS41NTQyIDE5LjY2NzYgMjkuNTU0MiAxOS42Njc2TDI5LjU1MjcgMTkuNjY2NkwyOS41NTAxIDE5LjY2NDlMMjkuNTQzMiAxOS42NjA0TDI5LjUyMjggMTkuNjQ3MkMyOS41MDYzIDE5LjYzNjYgMjkuNDg0IDE5LjYyMjUgMjkuNDU2MiAxOS42MDU0QzI5LjQwMDcgMTkuNTcxMiAyOS4zMjMgMTkuNTI0OSAyOS4yMjU2IDE5LjQ3MDZDMjkuMDMxNSAxOS4zNjIyIDI4Ljc1NTkgMTkuMjIwMSAyOC40MTkzIDE5LjA3ODRDMjcuNzU1NyAxOC43OTg5IDI2LjgwNTcgMTguNSAyNS43NSAxOC41SDI1VjE3SDM2VjMwSDI4LjVDMjguNSAyOS40Mzc5IDI4LjIzMjQgMjguOTQ1MiAyNy45NjQxIDI4LjU4NzVDMjcuNjgwMyAyOC4yMDkyIDI3LjMwNTQgMjcuODYwNiAyNi45MDA3IDI3LjU2NjNDMjYuMzY3NSAyNy4xNzg1IDI1LjY5ODkgMjYuODI1NyAyNSAyNi42MzkxVjI0LjVaTTI2LjQ5MjkgMzBDMjYuNDc5NyAyOS45NjcgMjYuNDQ1NyAyOS44OTY0IDI2LjM2NDEgMjkuNzg3NUMyNi4yMjU5IDI5LjYwMzMgMjYuMDA3MSAyOS4zODk0IDI1LjcyNDMgMjkuMTgzN0MyNS4xNDc4IDI4Ljc2NDUgMjQuNDkzNyAyOC41MTE3IDI0LjAzMiAyOC41MDA0QzIzLjQ4NzcgMjguNTQ2NCAyMi44MDUyIDI4LjgyNTIgMjIuMjQ0OSAyOS4yMjdDMjEuOTY1NyAyOS40MjcyIDIxLjc1NTYgMjkuNjMwNyAyMS42MjUyIDI5LjgwMzhDMjEuNTQ5NiAyOS45MDQzIDIxLjUxODQgMjkuOTY5NCAyMS41MDYzIDMwSDI2LjQ5MjlaIiBmaWxsPSIjYjQ1MzA5Ii8+Cjwvc3ZnPgo=", + "created": 1700000000000 + } + } +} \ No newline at end of file diff --git a/knowledge/drafts/pillars-b2.excalidraw b/knowledge/drafts/pillars-b2.excalidraw new file mode 100644 index 0000000..0c52966 --- /dev/null +++ b/knowledge/drafts/pillars-b2.excalidraw @@ -0,0 +1,2960 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "oidm-knowledge/tools/diagrams", + "elements": [ + { + "type": "rectangle", + "id": "band50", + "x": 0, + "y": 377.05, + "width": 880, + "height": 150.99999999999994, + "strokeColor": "#b45309", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1099, + "version": 1, + "versionNonce": 1100, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "fill55", + "x": -1, + "y": 377.05, + "width": 33, + "height": 32.0, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1109, + "version": 1, + "versionNonce": 1110, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill56", + "x": 848, + "y": 377.05, + "width": 33, + "height": 32.0, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1111, + "version": 1, + "versionNonce": 1112, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "line", + "id": "ln57", + "x": 0, + "y": 377.05, + "width": 0, + "height": 32.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1113, + "version": 1, + "versionNonce": 1114, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln58", + "x": 880, + "y": 377.05, + "width": 0, + "height": 32.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1115, + "version": 1, + "versionNonce": 1116, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "band33", + "x": 0, + "y": 187.3, + "width": 880, + "height": 189.75, + "strokeColor": "#0f766e", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1065, + "version": 1, + "versionNonce": 1066, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "fill51", + "x": -1, + "y": 345.05, + "width": 33, + "height": 32.0, + "strokeColor": "transparent", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1101, + "version": 1, + "versionNonce": 1102, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill52", + "x": 848, + "y": 345.05, + "width": 33, + "height": 32.0, + "strokeColor": "transparent", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1103, + "version": 1, + "versionNonce": 1104, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "line", + "id": "ln53", + "x": 0, + "y": 345.05, + "width": 0, + "height": 32.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1105, + "version": 1, + "versionNonce": 1106, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln54", + "x": 880, + "y": 345.05, + "width": 0, + "height": 32.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1107, + "version": 1, + "versionNonce": 1108, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "band15", + "x": 0, + "y": 91.65, + "width": 880, + "height": 71.65, + "strokeColor": "#6d28d9", + "backgroundColor": "#ede9fe", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1029, + "version": 1, + "versionNonce": 1030, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "panel1", + "x": 0, + "y": 0, + "width": 388.0, + "height": 67.65, + "strokeColor": "#be123c", + "backgroundColor": "#ffe4e6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1001, + "version": 1, + "versionNonce": 1002, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "panel2", + "x": 492.0, + "y": 0, + "width": 388.0, + "height": 67.65, + "strokeColor": "#15803d", + "backgroundColor": "#dcfce7", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1003, + "version": 1, + "versionNonce": 1004, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "bicon3", + "x": 18, + "y": 12.0, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1005, + "version": 1, + "versionNonce": 1006, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon3", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle4", + "x": 58, + "y": 14, + "width": 93.96, + "height": 22.5, + "strokeColor": "#881337", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1007, + "version": 1, + "versionNonce": 1008, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Use Cases", + "originalText": "Use Cases", + "fontSize": 18, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub5", + "x": 58, + "y": 37.400000000000006, + "width": 211.11999999999998, + "height": 16.25, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1009, + "version": 1, + "versionNonce": 1010, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "what the project wants built", + "originalText": "what the project wants built", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon6", + "x": 510.0, + "y": 12.0, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1011, + "version": 1, + "versionNonce": 1012, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon6", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle7", + "x": 550.0, + "y": 14, + "width": 198.35999999999999, + "height": 22.5, + "strokeColor": "#14532d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1013, + "version": 1, + "versionNonce": 1014, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Sample Applications", + "originalText": "Sample Applications", + "fontSize": 18, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub8", + "x": 550.0, + "y": 37.400000000000006, + "width": 143.26, + "height": 16.25, + "strokeColor": "#15803d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1015, + "version": 1, + "versionNonce": 1016, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "what has been built", + "originalText": "what has been built", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "conn9", + "x": 390.0, + "y": 33.825, + "width": 100.0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1017, + "version": 1, + "versionNonce": 1018, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 100.0, + 0 + ] + ] + }, + { + "type": "rectangle", + "id": "chip10", + "x": 389.53, + "y": 4.575000000000003, + "width": 100.94, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1019, + "version": 1, + "versionNonce": 1020, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "chipt11", + "x": 398.53, + "y": 7.575000000000003, + "width": 82.94, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1021, + "version": 1, + "versionNonce": 1022, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "illustrates", + "originalText": "illustrates", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon12", + "x": 18, + "y": 105.65, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1023, + "version": 1, + "versionNonce": 1024, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon12", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle13", + "x": 58, + "y": 107.65, + "width": 41.76, + "height": 22.5, + "strokeColor": "#4c1d95", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1025, + "version": 1, + "versionNonce": 1026, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "SDKs", + "originalText": "SDKs", + "fontSize": 18, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub14", + "x": 58, + "y": 131.05, + "width": 520.26, + "height": 16.25, + "strokeColor": "#6d28d9", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1027, + "version": 1, + "versionNonce": 1028, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "wrap the structures \u00b7 attach the shared knowledge \u00b7 support authoring", + "originalText": "wrap the structures \u00b7 attach the shared knowledge \u00b7 support authoring", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon16", + "x": 18, + "y": 203.3, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1031, + "version": 1, + "versionNonce": 1032, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon16", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle17", + "x": 58, + "y": 205.3, + "width": 174.0, + "height": 25.0, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1033, + "version": 1, + "versionNonce": 1034, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Data Structures", + "originalText": "Data Structures", + "fontSize": 20, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub18", + "x": 58, + "y": 231.3, + "width": 226.2, + "height": 16.25, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1035, + "version": 1, + "versionNonce": 1036, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "this patient \u00b7 Patient Context", + "originalText": "this patient \u00b7 Patient Context", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk19", + "x": 20.0, + "y": 261.55, + "width": 195.0, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1037, + "version": 1, + "versionNonce": 1038, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki20", + "x": 103.5, + "y": 281.925, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1039, + "version": 1, + "versionNonce": 1040, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki20", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt21", + "x": 26.0, + "y": 315.925, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1041, + "version": 1, + "versionNonce": 1042, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Observation", + "originalText": "Observation", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk22", + "x": 235.0, + "y": 261.55, + "width": 195.0, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1043, + "version": 1, + "versionNonce": 1044, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki23", + "x": 318.5, + "y": 272.55, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1045, + "version": 1, + "versionNonce": 1046, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki23", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt24", + "x": 241.0, + "y": 306.55, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1047, + "version": 1, + "versionNonce": 1048, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Exam Finding", + "originalText": "Exam Finding", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkt25", + "x": 241.0, + "y": 325.3, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1049, + "version": 1, + "versionNonce": 1050, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "List", + "originalText": "List", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk26", + "x": 450.0, + "y": 261.55, + "width": 195.0, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1051, + "version": 1, + "versionNonce": 1052, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki27", + "x": 533.5, + "y": 272.55, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1053, + "version": 1, + "versionNonce": 1054, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki27", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt28", + "x": 456.0, + "y": 306.55, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1055, + "version": 1, + "versionNonce": 1056, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Imaging Problem", + "originalText": "Imaging Problem", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkt29", + "x": 456.0, + "y": 325.3, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1057, + "version": 1, + "versionNonce": 1058, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "List", + "originalText": "List", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk30", + "x": 665.0, + "y": 261.55, + "width": 195.0, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1059, + "version": 1, + "versionNonce": 1060, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki31", + "x": 746.5, + "y": 279.925, + "width": 32, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1061, + "version": 1, + "versionNonce": 1062, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki31", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt32", + "x": 671.0, + "y": 315.925, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1063, + "version": 1, + "versionNonce": 1064, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Imaging Persona", + "originalText": "Imaging Persona", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk34", + "x": 236.0, + "y": 377.05, + "width": 236.0, + "height": 125.0, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1067, + "version": 1, + "versionNonce": 1068, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki35", + "x": 340.0, + "y": 418.05, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1069, + "version": 1, + "versionNonce": 1070, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki35", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt36", + "x": 242.0, + "y": 452.05, + "width": 224.0, + "height": 18.75, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1071, + "version": 1, + "versionNonce": 1072, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Finding/diagnosis definitions", + "originalText": "Finding/diagnosis definitions", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkd37", + "x": 242.0, + "y": 472.8, + "width": 224.0, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1073, + "version": 1, + "versionNonce": 1074, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "finding models \u00b7 CDEs", + "originalText": "finding models \u00b7 CDEs", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk38", + "x": 492.0, + "y": 377.05, + "width": 174.0, + "height": 125.0, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1075, + "version": 1, + "versionNonce": 1076, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki39", + "x": 563.0, + "y": 416.05, + "width": 32, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1077, + "version": 1, + "versionNonce": 1078, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki39", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt40", + "x": 498.0, + "y": 452.05, + "width": 162.0, + "height": 18.75, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1079, + "version": 1, + "versionNonce": 1080, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Anatomic locations", + "originalText": "Anatomic locations", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkd41", + "x": 498.0, + "y": 472.8, + "width": 162.0, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1081, + "version": 1, + "versionNonce": 1082, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "anchored in RadLex", + "originalText": "anchored in RadLex", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk42", + "x": 686.0, + "y": 377.05, + "width": 174.0, + "height": 125.0, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1083, + "version": 1, + "versionNonce": 1084, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki43", + "x": 757.0, + "y": 416.05, + "width": 32, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1085, + "version": 1, + "versionNonce": 1086, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki43", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt44", + "x": 692.0, + "y": 452.05, + "width": 162.0, + "height": 18.75, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1087, + "version": 1, + "versionNonce": 1088, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Exam types", + "originalText": "Exam types", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkd45", + "x": 692.0, + "y": 472.8, + "width": 162.0, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1089, + "version": 1, + "versionNonce": 1090, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "LOINC/RSNA Playbook", + "originalText": "LOINC/RSNA Playbook", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon46", + "x": 20, + "y": 416.425, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1091, + "version": 1, + "versionNonce": 1092, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon46", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle47", + "x": 60, + "y": 418.425, + "width": 115.99999999999999, + "height": 25.0, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1093, + "version": 1, + "versionNonce": 1094, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Foundation", + "originalText": "Foundation", + "fontSize": 20, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "btitle48", + "x": 60, + "y": 444.425, + "width": 81.19999999999999, + "height": 25.0, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1095, + "version": 1, + "versionNonce": 1096, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Context", + "originalText": "Context", + "fontSize": 20, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub49", + "x": 60, + "y": 474.425, + "width": 188.5, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1097, + "version": 1, + "versionNonce": 1098, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "shared, curated knowledge", + "originalText": "shared, curated knowledge", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "fill59", + "x": 236.0, + "y": 377.05, + "width": 236.0, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1117, + "version": 1, + "versionNonce": 1118, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "line", + "id": "ln60", + "x": 236.0, + "y": 377.05, + "width": 0.0, + "height": 32.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1119, + "version": 1, + "versionNonce": 1120, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln61", + "x": 472.0, + "y": 377.05, + "width": 0.0, + "height": 32.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1121, + "version": 1, + "versionNonce": 1122, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "fill62", + "x": 492.0, + "y": 377.05, + "width": 174.0, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1123, + "version": 1, + "versionNonce": 1124, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "line", + "id": "ln63", + "x": 492.0, + "y": 377.05, + "width": 0.0, + "height": 32.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1125, + "version": 1, + "versionNonce": 1126, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln64", + "x": 666.0, + "y": 377.05, + "width": 0.0, + "height": 32.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1127, + "version": 1, + "versionNonce": 1128, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "fill65", + "x": 686.0, + "y": 377.05, + "width": 174.0, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1129, + "version": 1, + "versionNonce": 1130, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "line", + "id": "ln66", + "x": 686.0, + "y": 377.05, + "width": 0.0, + "height": 32.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1131, + "version": 1, + "versionNonce": 1132, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln67", + "x": 860.0, + "y": 377.05, + "width": 0.0, + "height": 32.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1133, + "version": 1, + "versionNonce": 1134, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln68", + "x": 236.0, + "y": 377.05, + "width": 236.0, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1135, + "version": 1, + "versionNonce": 1136, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 236.0, + 0.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln69", + "x": 492.0, + "y": 377.05, + "width": 174.0, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1137, + "version": 1, + "versionNonce": 1138, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 174.0, + 0.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln70", + "x": 686.0, + "y": 377.05, + "width": 174.0, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1139, + "version": 1, + "versionNonce": 1140, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 174.0, + 0.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln71", + "x": 0.0, + "y": 377.05, + "width": 236.0, + "height": 0.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1141, + "version": 1, + "versionNonce": 1142, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 236.0, + 0.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln72", + "x": 472.0, + "y": 377.05, + "width": 20.0, + "height": 0.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1143, + "version": 1, + "versionNonce": 1144, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 20.0, + 0.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln73", + "x": 666.0, + "y": 377.05, + "width": 20.0, + "height": 0.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1145, + "version": 1, + "versionNonce": 1146, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 20.0, + 0.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln74", + "x": 860.0, + "y": 377.05, + "width": 20.0, + "height": 0.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1147, + "version": 1, + "versionNonce": 1148, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 20.0, + 0.0 + ] + ], + "roundness": null + }, + { + "type": "text", + "id": "lead75", + "x": 20, + "y": 383.925, + "width": 180.95999999999998, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1149, + "version": 1, + "versionNonce": 1150, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "woven together at every:", + "originalText": "woven together at every:", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "fill76", + "x": 250.0, + "y": 363.05, + "width": 92.0, + "height": 44.0, + "strokeColor": "transparent", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1151, + "version": 1, + "versionNonce": 1152, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "line", + "id": "ln77", + "x": 250.0, + "y": 377.05, + "width": 92.0, + "height": 30.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1153, + "version": 1, + "versionNonce": 1154, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 20.0 + ], + [ + 0.7612046748871251, + 23.82683432365087 + ], + [ + 2.9289321881345245, + 27.071067811865476 + ], + [ + 6.173165676349129, + 29.238795325112847 + ], + [ + 10.0, + 30.0 + ], + [ + 82.0, + 30.0 + ], + [ + 85.82683432365087, + 29.238795325112847 + ], + [ + 89.07106781186548, + 27.071067811865476 + ], + [ + 91.23879532511285, + 23.82683432365087 + ], + [ + 92.0, + 20.0 + ], + [ + 92.0, + 0.0 + ] + ], + "roundness": null + }, + { + "type": "text", + "id": "tabw78", + "x": 250.0, + "y": 383.925, + "width": 92.0, + "height": 16.25, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1155, + "version": 1, + "versionNonce": 1156, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "finding", + "originalText": "finding", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "fill79", + "x": 366.0, + "y": 363.05, + "width": 92.0, + "height": 44.0, + "strokeColor": "transparent", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1157, + "version": 1, + "versionNonce": 1158, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "line", + "id": "ln80", + "x": 366.0, + "y": 377.05, + "width": 92.0, + "height": 30.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1159, + "version": 1, + "versionNonce": 1160, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 20.0 + ], + [ + 0.7612046748871535, + 23.82683432365087 + ], + [ + 2.9289321881345245, + 27.071067811865476 + ], + [ + 6.173165676349129, + 29.238795325112847 + ], + [ + 10.0, + 30.0 + ], + [ + 82.0, + 30.0 + ], + [ + 85.82683432365087, + 29.238795325112847 + ], + [ + 89.07106781186548, + 27.071067811865476 + ], + [ + 91.23879532511285, + 23.82683432365087 + ], + [ + 92.0, + 20.0 + ], + [ + 92.0, + 0.0 + ] + ], + "roundness": null + }, + { + "type": "text", + "id": "tabw81", + "x": 366.0, + "y": 383.925, + "width": 92.0, + "height": 16.25, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1161, + "version": 1, + "versionNonce": 1162, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "diagnosis", + "originalText": "diagnosis", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "fill82", + "x": 533.0, + "y": 363.05, + "width": 92.0, + "height": 44.0, + "strokeColor": "transparent", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1163, + "version": 1, + "versionNonce": 1164, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "line", + "id": "ln83", + "x": 533.0, + "y": 377.05, + "width": 92.0, + "height": 30.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1165, + "version": 1, + "versionNonce": 1166, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 20.0 + ], + [ + 0.7612046748871535, + 23.82683432365087 + ], + [ + 2.9289321881345813, + 27.071067811865476 + ], + [ + 6.173165676349072, + 29.238795325112847 + ], + [ + 10.0, + 30.0 + ], + [ + 82.0, + 30.0 + ], + [ + 85.82683432365093, + 29.238795325112847 + ], + [ + 89.07106781186553, + 27.071067811865476 + ], + [ + 91.23879532511285, + 23.82683432365087 + ], + [ + 92.0, + 20.0 + ], + [ + 92.0, + 0.0 + ] + ], + "roundness": null + }, + { + "type": "text", + "id": "tabw84", + "x": 533.0, + "y": 383.925, + "width": 92.0, + "height": 16.25, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1167, + "version": 1, + "versionNonce": 1168, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "location", + "originalText": "location", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "fill85", + "x": 727.0, + "y": 363.05, + "width": 92.0, + "height": 44.0, + "strokeColor": "transparent", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1169, + "version": 1, + "versionNonce": 1170, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "line", + "id": "ln86", + "x": 727.0, + "y": 377.05, + "width": 92.0, + "height": 30.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1171, + "version": 1, + "versionNonce": 1172, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 20.0 + ], + [ + 0.7612046748871535, + 23.82683432365087 + ], + [ + 2.9289321881345813, + 27.071067811865476 + ], + [ + 6.173165676349072, + 29.238795325112847 + ], + [ + 10.0, + 30.0 + ], + [ + 82.0, + 30.0 + ], + [ + 85.82683432365093, + 29.238795325112847 + ], + [ + 89.07106781186553, + 27.071067811865476 + ], + [ + 91.23879532511285, + 23.82683432365087 + ], + [ + 92.0, + 20.0 + ], + [ + 92.0, + 0.0 + ] + ], + "roundness": null + }, + { + "type": "text", + "id": "tabw87", + "x": 727.0, + "y": 383.925, + "width": 92.0, + "height": 16.25, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1173, + "version": 1, + "versionNonce": 1174, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "exam type", + "originalText": "exam type", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + } + ], + "appState": { + "viewBackgroundColor": "#ffffff", + "gridSize": null + }, + "files": { + "img_bicon3": { + "mimeType": "image/svg+xml", + "id": "img_bicon3", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiNiZTEyM2MiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTE1IDE0Yy4yLTEgLjctMS43IDEuNS0yLjUgMS0uOSAxLjUtMi4yIDEuNS0zLjVBNiA2IDAgMCAwIDYgOGMwIDEgLjIgMi4yIDEuNSAzLjUuNy43IDEuMyAxLjUgMS41IDIuNSIgLz4KICA8cGF0aCBkPSJNOSAxOGg2IiAvPgogIDxwYXRoIGQ9Ik0xMCAyMmg0IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_bicon6": { + "mimeType": "image/svg+xml", + "id": "img_bicon6", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMxNTgwM2QiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHJlY3QgeD0iMiIgeT0iNCIgd2lkdGg9IjIwIiBoZWlnaHQ9IjE2IiByeD0iMiIgLz4KICA8cGF0aCBkPSJNMTAgNHY0IiAvPgogIDxwYXRoIGQ9Ik0yIDhoMjAiIC8+CiAgPHBhdGggZD0iTTYgNHY0IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_bicon12": { + "mimeType": "image/svg+xml", + "id": "img_bicon12", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiM2ZDI4ZDkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTExIDIxLjczYTIgMiAwIDAgMCAyIDBsNy00QTIgMiAwIDAgMCAyMSAxNlY4YTIgMiAwIDAgMC0xLTEuNzNsLTctNGEyIDIgMCAwIDAtMiAwbC03IDRBMiAyIDAgMCAwIDMgOHY4YTIgMiAwIDAgMCAxIDEuNzN6IiAvPgogIDxwYXRoIGQ9Ik0xMiAyMlYxMiIgLz4KICA8cG9seWxpbmUgcG9pbnRzPSIzLjI5IDcgMTIgMTIgMjAuNzEgNyIgLz4KICA8cGF0aCBkPSJtNy41IDQuMjcgOSA1LjE1IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_bicon16": { + "mimeType": "image/svg+xml", + "id": "img_bicon16", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyLjgzIDIuMThhMiAyIDAgMCAwLTEuNjYgMEwyLjYgNi4wOGExIDEgMCAwIDAgMCAxLjgzbDguNTggMy45MWEyIDIgMCAwIDAgMS42NiAwbDguNTgtMy45YTEgMSAwIDAgMCAwLTEuODN6IiAvPgogIDxwYXRoIGQ9Ik0yIDEyYTEgMSAwIDAgMCAuNTguOTFsOC42IDMuOTFhMiAyIDAgMCAwIDEuNjUgMGw4LjU4LTMuOUExIDEgMCAwIDAgMjIgMTIiIC8+CiAgPHBhdGggZD0iTTIgMTdhMSAxIDAgMCAwIC41OC45MWw4LjYgMy45MWEyIDIgMCAwIDAgMS42NSAwbDguNTgtMy45QTEgMSAwIDAgMCAyMiAxNyIgLz4KPC9zdmc+Cg==", + "created": 1700000000000 + }, + "img_blki20": { + "mimeType": "image/svg+xml", + "id": "img_blki20", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHJlY3Qgd2lkdGg9IjgiIGhlaWdodD0iNCIgeD0iOCIgeT0iMiIgcng9IjEiIHJ5PSIxIiAvPgogIDxwYXRoIGQ9Ik0xNiA0aDJhMiAyIDAgMCAxIDIgMnYxNGEyIDIgMCAwIDEtMiAySDZhMiAyIDAgMCAxLTItMlY2YTIgMiAwIDAgMSAyLTJoMiIgLz4KPC9zdmc+Cg==", + "created": 1700000000000 + }, + "img_blki23": { + "mimeType": "image/svg+xml", + "id": "img_blki23", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHJlY3Qgd2lkdGg9IjgiIGhlaWdodD0iNCIgeD0iOCIgeT0iMiIgcng9IjEiIHJ5PSIxIiAvPgogIDxwYXRoIGQ9Ik0xNiA0aDJhMiAyIDAgMCAxIDIgMnYxNGEyIDIgMCAwIDEtMiAySDZhMiAyIDAgMCAxLTItMlY2YTIgMiAwIDAgMSAyLTJoMiIgLz4KICA8cGF0aCBkPSJNMTIgMTFoNCIgLz4KICA8cGF0aCBkPSJNMTIgMTZoNCIgLz4KICA8cGF0aCBkPSJNOCAxMWguMDEiIC8+CiAgPHBhdGggZD0iTTggMTZoLjAxIiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki27": { + "mimeType": "image/svg+xml", + "id": "img_blki27", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTMgNWguMDEiIC8+CiAgPHBhdGggZD0iTTMgMTJoLjAxIiAvPgogIDxwYXRoIGQ9Ik0zIDE5aC4wMSIgLz4KICA8cGF0aCBkPSJNOCA1aDEzIiAvPgogIDxwYXRoIGQ9Ik04IDEyaDEzIiAvPgogIDxwYXRoIGQ9Ik04IDE5aDEzIiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki31": { + "mimeType": "image/svg+xml", + "id": "img_blki31", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yNCAyNEMyOC40MjA0IDI0IDMyIDIwLjQyMDQgMzIgMTZDMzIgMTEuNTc5NiAyOC40MjA0IDggMjQgOEMxOS41Nzk2IDggMTYgMTEuNTc5NiAxNiAxNkMxNiAyMC40MjA0IDE5LjU3OTYgMjQgMjQgMjRaTTM0IDE2QzM0IDIxLjUyNSAyOS41MjUgMjYgMjQgMjZDMTguNDc1IDI2IDE0IDIxLjUyNSAxNCAxNkMxNCAxMC40NzUgMTguNDc1IDYgMjQgNkMyOS41MjUgNiAzNCAxMC40NzUgMzQgMTZaIiBmaWxsPSIjMGY3NjZlIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNOS4yMjM0OCAzNC4yMTE5QzguMjIwMzggMzUuMDIxMSA4IDM1LjYyOTEgOCAzNlY0MEg0MFYzNkM0MCAzNS42MjkxIDM5Ljc3OTYgMzUuMDIxMSAzOC43NzY1IDM0LjIxMTlDMzcuNzk1OCAzMy40MjA3IDM2LjMzNDEgMzIuNjY2OSAzNC41NjIyIDMyLjAxNUMzMS4wMTk5IDMwLjcxMTcgMjYuNzUzMiAzMCAyNCAzMEMyMS4yNDY4IDMwIDE2Ljk4MDEgMzAuNzExNyAxMy40Mzc4IDMyLjAxNUMxMS42NjU5IDMyLjY2NjkgMTAuMjA0MiAzMy40MjA3IDkuMjIzNDggMzQuMjExOVpNMjQgMjhDMTcuOTkyNSAyOCA2IDMxLjAzNDcgNiAzNlY0Mkg0MlYzNkM0MiAzMS4wMzQ3IDMwLjAwNzUgMjggMjQgMjhaIiBmaWxsPSIjMGY3NjZlIi8+Cjwvc3ZnPgo=", + "created": 1700000000000 + }, + "img_blki35": { + "mimeType": "image/svg+xml", + "id": "img_blki35", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiNiNDUzMDkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyLjU4NiAyLjU4NkEyIDIgMCAwIDAgMTEuMTcyIDJINGEyIDIgMCAwIDAtMiAydjcuMTcyYTIgMiAwIDAgMCAuNTg2IDEuNDE0bDguNzA0IDguNzA0YTIuNDI2IDIuNDI2IDAgMCAwIDMuNDIgMGw2LjU4LTYuNThhMi40MjYgMi40MjYgMCAwIDAgMC0zLjQyeiIgLz4KICA8Y2lyY2xlIGN4PSI3LjUiIGN5PSI3LjUiIHI9Ii41IiBmaWxsPSIjYjQ1MzA5IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki39": { + "mimeType": "image/svg+xml", + "id": "img_blki39", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yMyA2LjAwMDEzQzIzIDYuMDAwMDQgMjMgNiAyNCA2SDI0LjE3NjFDMjQuMjUzMyA2IDI0LjMyMzMgNiAyNC4zODY4IDZDMjUgNi4wMDAwMSAyNSA2LjAwMDA1IDI1IDYuMDAwMTNWMjAuNUMyNSAyMS44OTc3IDI1LjU2NDEgMjIuNDQyMSAyNi4wMDM5IDIyLjY5ODdDMjYuMDUzIDIyLjcyNzMgMjYuMTAyNCAyMi43NTMzIDI2LjE1MTYgMjIuNzc3QzI2LjE1MDYgMjIuNjU2OCAyNi4xNDkzIDIyLjUzMTYgMjYuMTQ3OSAyMi40MDE5TDI2LjE0NzkgMjIuNDAwM0MyNi4xMTAxIDE4Ljg3MTYgMjYuMDM2NSAxMS45OTk3IDMxLjQ3NTMgMTEuOTk5N0MzOC45MjU5IDExLjk5OTcgNDQuMjQ3OCAzOC4wMDYyIDQxLjA1NDcgNDAuNjU5OUMzNy44NjE1IDQzLjMxMzYgMzEuNDc1MyA0MS43MjE0IDI4LjI4MjIgMzguNTM2OUMyNS43MDQyIDM1Ljk2NTkgMjUuOTI3MiAyOS45NTgzIDI2LjA4NzMgMjUuNjQ1N0wyNi4wODc0IDI1LjY0NDNDMjYuMDk3MSAyNS4zODE5IDI2LjEwNjcgMjUuMTI1OCAyNi4xMTUzIDI0Ljg3NzFDMjUuNzkgMjQuNzk2MiAyNS4zOTU5IDI0LjY1OTUgMjQuOTk2MiAyNC40MjYzQzI0LjYzOTggMjQuMjE4NCAyNC4yOTc1IDIzLjk0NDIgMjQgMjMuNTkxOUMyMy43MDI2IDIzLjk0NDIgMjMuMzYwMyAyNC4yMTg0IDIzLjAwMzkgMjQuNDI2M0MyMi42MDQxIDI0LjY1OTUgMjIuMjEwMSAyNC43OTYyIDIxLjg4NDggMjQuODc3MUMyMS44OTM0IDI1LjEyNjEgMjEuOTAyOSAyNS4zODI2IDIxLjkxMjcgMjUuNjQ1M0MyMi4wNzI4IDI5Ljk1NzkgMjIuMjk1OSAzNS45NjYyIDE5LjcxNzkgMzguNTM3MkMxNi41MjQ3IDQxLjcyMTcgMTAuMTM4NSA0My4zMTM5IDYuOTQ1MzYgNDAuNjYwMkMzLjc1MjIyIDM4LjAwNjUgOS4wNzQxMyAxMiAxNi41MjQ3IDEyQzIxLjk2MzYgMTIgMjEuODkgMTguODcxNyAyMS44NTIyIDIyLjQwMDNDMjEuODUyIDIyLjQxNjYgMjEuODUxOCAyMi40MzI4IDIxLjg1MTYgMjIuNDQ4OUMyMS44NTA0IDIyLjU2MTkgMjEuODQ5MyAyMi42NzE0IDIxLjg0ODQgMjIuNzc3QzIxLjg5NzcgMjIuNzUzNCAyMS45NDcxIDIyLjcyNzQgMjEuOTk2MiAyMi42OTg3QzIyLjQzNiAyMi40NDIxIDIzIDIxLjg5NzcgMjMgMjAuNVY2LjAwMDEzWk0zMS40NzUzIDEzLjk5OTdDMzAuNTIxMiAxMy45OTk3IDI5Ljk4NDMgMTQuMzAwMiAyOS42MDg2IDE0LjY4NjlDMjkuMTc1MiAxNS4xMzMxIDI4LjgxMzIgMTUuODUwNyAyOC41NTkgMTYuODY0NkMyOC4xMTQxIDE4LjYzOTUgMjguMTMzIDIwLjY4MTkgMjguMTQ4MyAyMi4zMjkzQzI4LjE1MDkgMjIuNjE0MiAyOC4xNTM0IDIyLjg4NzQgMjguMTUzNCAyMy4xNDUzQzI4LjE1MzQgMjMuOTA1MyAyOC4xMTk2IDI0LjgxNTMgMjguMDg0NSAyNS43NjIxQzI4LjA3MDcgMjYuMTM0OSAyOC4wNTY2IDI2LjUxMzMgMjguMDQ0MyAyNi44OTA1QzI3Ljk5OTYgMjguMjY1NyAyNy45NzQxIDI5LjcwNTUgMjguMDQwNSAzMS4wOTgyQzI4LjEwNzIgMzIuNDk4NSAyOC4yNjQyIDMzLjc4MzUgMjguNTU3MyAzNC44NTk2QzI4Ljg1MzggMzUuOTQ4MyAyOS4yNTA5IDM2LjY3ODQgMjkuNjk0NCAzNy4xMjA4QzMwLjk3MjYgMzguMzk1NCAzMi45OTA4IDM5LjQyNTEgMzUuMDQ5MiAzOS44MjQzQzM3LjA4NDIgNDAuMjE4OSAzOC43MjI0IDM5LjkyNjkgMzkuNjgxOCAzOS4xOTY5QzM5LjY4NjggMzkuMTg1NyAzOS42OTIzIDM5LjE3MjYgMzkuNjk4NCAzOS4xNTc0QzM5Ljc1NzYgMzkuMDA5NSAzOS44Mjk0IDM4Ljc1NTQgMzkuODg3OCAzOC4zNjgzQzQwLjAwNDcgMzcuNTkzMyA0MC4wMzUgMzYuNTEyMiAzOS45NTYyIDM1LjE4MDNDMzkuNzk5NSAzMi41MzA1IDM5LjIyODYgMjkuMTY4OSAzOC4zMjY4IDI1Ljg2MDZDMzcuNDIxNiAyMi41Mzk2IDM2LjIxNzMgMTkuMzk5OCAzNC44NTIxIDE3LjEzODNDMzQuMTY4OCAxNi4wMDYyIDMzLjQ5NTEgMTUuMTc4NiAzMi44NzAzIDE0LjY1MzVDMzIuMjUxOCAxNC4xMzM3IDMxLjc5MzUgMTMuOTk5NyAzMS40NzUzIDEzLjk5OTdaTTE2LjUyNDcgMTRDMTcuNDc4OCAxNCAxOC4wMTU4IDE0LjMwMDUgMTguMzkxNCAxNC42ODcyQzE4LjgyNDggMTUuMTMzNCAxOS4xODY4IDE1Ljg1MSAxOS40NDEgMTYuODY0OUMxOS44ODU5IDE4LjYzOTkgMTkuODY3IDIwLjY4MjIgMTkuODUxOCAyMi4zMjk2QzE5Ljg0OTEgMjIuNjE0NiAxOS44NDY2IDIyLjg4NzcgMTkuODQ2NiAyMy4xNDU2QzE5Ljg0NjYgMjMuOTA1NiAxOS44ODA0IDI0LjgxNTYgMTkuOTE1NSAyNS43NjI0QzE5LjkyOTQgMjYuMTM1IDE5Ljk0MzQgMjYuNTEzOCAxOS45NTU3IDI2Ljg5MDhDMjAuMDAwNSAyOC4yNjYgMjAuMDI1OSAyOS43MDU4IDE5Ljk1OTYgMzEuMDk4NUMxOS44OTI5IDMyLjQ5ODggMTkuNzM1OSAzMy43ODM4IDE5LjQ0MjcgMzQuODU5OUMxOS4xNDYyIDM1Ljk0ODYgMTguNzQ5MiAzNi42Nzg3IDE4LjMwNTYgMzcuMTIxMUMxNy4wMjc1IDM4LjM5NTcgMTUuMDA5MyAzOS40MjU0IDEyLjk1MDkgMzkuODI0NkMxMC45MTU5IDQwLjIxOTIgOS4yNzc2OCAzOS45MjcyIDguMzE4MjMgMzkuMTk3MkM4LjMxMzI2IDM5LjE4NiA4LjMwNzcgMzkuMTcyOSA4LjMwMTYyIDM5LjE1NzdDOC4yNDI0MSAzOS4wMDk4IDguMTcwNjEgMzguNzU1NyA4LjExMjI0IDM4LjM2ODZDNy45OTUzOSAzNy41OTM2IDcuOTY1IDM2LjUxMjUgOC4wNDM4IDM1LjE4MDZDOC4yMDA1NiAzMi41MzA4IDguNzcxNDcgMjkuMTY5MiA5LjY3MzI0IDI1Ljg2MDlDMTAuNTc4NSAyMi41Mzk5IDExLjc4MjcgMTkuNDAwMSAxMy4xNDc5IDE3LjEzODZDMTMuODMxMyAxNi4wMDY1IDE0LjUwNDkgMTUuMTc4OSAxNS4xMjk4IDE0LjY1MzhDMTUuNzQ4MiAxNC4xMzQgMTYuMjA2NSAxNCAxNi41MjQ3IDE0WiIgZmlsbD0iI2I0NTMwOSIvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki43": { + "mimeType": "image/svg+xml", + "id": "img_blki43", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yOSA5QzI5IDExLjc2MTQgMjYuNzYxNCAxNCAyNCAxNEMyMS4yMzg2IDE0IDE5IDExLjc2MTQgMTkgOUMxOSA2LjIzODU4IDIxLjIzODYgNCAyNCA0QzI2Ljc2MTQgNCAyOSA2LjIzODU4IDI5IDlaTTI3IDlDMjcgMTAuNjU2OSAyNS42NTY5IDEyIDI0IDEyQzIyLjM0MzEgMTIgMjEgMTAuNjU2OSAyMSA5QzIxIDcuMzQzMTUgMjIuMzQzMSA2IDI0IDZDMjUuNjU2OSA2IDI3IDcuMzQzMTUgMjcgOVoiIGZpbGw9IiNiNDUzMDkiLz4KPHBhdGggZD0iTTE2Ljk5OTggNDFWMzRIMTguOTk5OFY0MUMxOC45OTk4IDQxLjU1MjMgMTkuNDQ3NSA0MiAxOS45OTk4IDQySDIwLjA4NjVDMjAuNjAzNyA0MiAyMS4wMzU2IDQxLjYwNTYgMjEuMDgyNCA0MS4wOTA1TDIxLjcyNyAzNEgyMy43MzUzTDIzLjA3NDIgNDEuMjcxNkMyMy4wNjkgNDEuMzI4OCAyMy4wNjIyIDQxLjM4NTYgMjMuMDUzOSA0MS40NDE3QzIzLjAzNTcgNDEuNTY0NyAyMy4wMTAxIDQxLjY4NTEgMjIuOTc3NiA0MS44MDI1QzIyLjYyNDIgNDMuMDc5OCAyMS40NTQ5IDQ0IDIwLjA4NjUgNDRIMTkuOTk5OEMxOC4zNDI5IDQ0IDE2Ljk5OTggNDIuNjU2OSAxNi45OTk4IDQxWiIgZmlsbD0iI2I0NTMwOSIvPgo8cGF0aCBkPSJNMjYuOTE3MSA0MS4wOTA1TDI2LjI3MjUgMzRIMjQuMjY0MkwyNC45MjUzIDQxLjI3MTZDMjQuOTMwNSA0MS4zMjg4IDI0LjkzNzMgNDEuMzg1NiAyNC45NDU2IDQxLjQ0MTdDMjQuOTYzOCA0MS41NjQ3IDI0Ljk4OTQgNDEuNjg1MSAyNS4wMjE5IDQxLjgwMjVDMjUuMzc1MyA0My4wNzk4IDI2LjU0NDYgNDQgMjcuOTEzIDQ0SDI3Ljk5OThDMjkuNjU2NiA0NCAzMC45OTk4IDQyLjY1NjkgMzAuOTk5OCA0MVYzNEgyOC45OTk4VjQxQzI4Ljk5OTggNDEuNTUyMyAyOC41NTIgNDIgMjcuOTk5OCA0MkgyNy45MTNDMjcuMzk1OCA0MiAyNi45NjM5IDQxLjYwNTYgMjYuOTE3MSA0MS4wOTA1WiIgZmlsbD0iI2I0NTMwOSIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTExIDE1QzEwLjQ0NzcgMTUgMTAgMTUuNDQ3NyAxMCAxNlYzMUMxMCAzMS41NTIzIDEwLjQ0NzcgMzIgMTEgMzJIMzdDMzcuNTUyMyAzMiAzOCAzMS41NTIzIDM4IDMxVjE2QzM4IDE1LjQ0NzcgMzcuNTUyMyAxNSAzNyAxNUgxMVpNMTIgMTdWMzBIMTkuNUMxOS41IDI5LjQ0MjQgMTkuNzU5MSAyOC45NTcyIDIwLjAyNzYgMjguNjAwNkMyMC4zMDg2IDI4LjIyNzYgMjAuNjc5NiAyNy44ODgzIDIxLjA3OTQgMjcuNjAxNkMyMS42MjUyIDI3LjIxMDMgMjIuMjk4NiAyNi44NjUgMjMgMjYuNjY3OFYyNC41SDIyLjJDMjEuNTk3MyAyNC41IDIwLjc1MzUgMjQuODY0MiAxOS45NDMzIDI1LjM1NTJDMTkuNTYzOCAyNS41ODUyIDE5LjIzMzcgMjUuODE2NyAxOC45OTg0IDI1Ljk5MTFDMTguODgxMiAyNi4wNzc4IDE4Ljc4ODggMjYuMTQ5NSAxOC43MjcgMjYuMTk4NEMxOC42OTYxIDI2LjIyMjggMTguNjczIDI2LjI0MTUgMTguNjU4MiAyNi4yNTM1TDE4LjY0MjYgMjYuMjY2M0wxOC42Mzk5IDI2LjI2ODRDMTguNjM5OSAyNi4yNjg0IDE4LjY0MDIgMjYuMjY4MiAxOCAyNS41QzE3LjM1OTggMjQuNzMxOCAxNy4zNjAxIDI0LjczMTUgMTcuMzYwMSAyNC43MzE1TDE3LjM2MTQgMjQuNzMwNUwxNy4zNjM4IDI0LjcyODVMMTcuMzcxMyAyNC43MjIzTDE3LjM5NjYgMjQuNzAxNkMxNy40MTc5IDI0LjY4NDMgMTcuNDQ4IDI0LjY2IDE3LjQ4NjMgMjQuNjI5N0MxNy41NjI3IDI0LjU2OTMgMTcuNjcxOSAyNC40ODQ3IDE3LjgwNzkgMjQuMzgzOUMxOC4wNzg4IDI0LjE4MzMgMTguNDYxMiAyMy45MTQ4IDE4LjkwNjcgMjMuNjQ0OEMxOS43NDY1IDIzLjEzNTggMjEuMDAyNyAyMi41IDIyLjIgMjIuNUgyM1YyMC41SDIyLjVDMjEuOTMwOSAyMC41IDIxLjE5MDkgMjAuNjk5MiAyMC41MjkyIDIwLjkzOThDMjAuMjEyIDIxLjA1NTIgMTkuOTM3IDIxLjE3MDkgMTkuNzQyMSAyMS4yNTc2QzE5LjY0NDkgMjEuMzAwNyAxOS41Njg1IDIxLjMzNjMgMTkuNTE3NiAyMS4zNjA1QzE5LjQ5MjIgMjEuMzcyNSAxOS40NzMyIDIxLjM4MTcgMTkuNDYxMyAyMS4zODc1TDE5LjQ0ODcgMjEuMzkzN0wxOS40NDcgMjEuMzk0NUMxOS40NDcgMjEuMzk0NSAxOS40NDcyIDIxLjM5NDQgMTkgMjAuNUMxOC41NTI4IDE5LjYwNTYgMTguNTUzMSAxOS42MDU0IDE4LjU1MzEgMTkuNjA1NEwxOC41NTY0IDE5LjYwMzhMMTguNTYyOSAxOS42MDA2TDE4LjU4NDQgMTkuNTlDMTguNjAyNSAxOS41ODEyIDE4LjYyNzkgMTkuNTY4OSAxOC42NjAxIDE5LjU1MzZDMTguNzI0NSAxOS41MjMxIDE4LjgxNiAxOS40ODA1IDE4LjkyOTggMTkuNDI5OUMxOS4xNTY3IDE5LjMyOTEgMTkuNDc1NSAxOS4xOTQ4IDE5Ljg0NTggMTkuMDYwMkMyMC41NTkxIDE4LjgwMDggMjEuNTY5MSAxOC41IDIyLjUgMTguNUgyM1YxN0gxMlpNMjUgMjQuNUgyNi4xQzI2Ljg0ODkgMjQuNSAyNy42MTg2IDI0Ljg2NjMgMjguMjYzMSAyNS4zMTg2QzI4LjU3MzUgMjUuNTM2NCAyOC44Mjg1IDI1Ljc1NTYgMjkuMDA0OCAyNS45MTk3QzI5LjA5MjUgMjYuMDAxMiAyOS4xNTk0IDI2LjA2NzkgMjkuMjAyNiAyNi4xMTIyQzI5LjIyNDEgMjYuMTM0MyAyOS4yMzk3IDI2LjE1MDcgMjkuMjQ4OCAyNi4xNjA1TDI5LjI1NzQgMjYuMTY5N0MyOS4yNTc0IDI2LjE2OTcgMjkuMjU2NyAyNi4xNjkgMzAgMjUuNUMzMC43NDMzIDI0LjgzMSAzMC43NDI5IDI0LjgzMDYgMzAuNzQyOSAyNC44MzA2TDMwLjc0MTQgMjQuODI5TDMwLjczODkgMjQuODI2MkwzMC43MzE4IDI0LjgxODRMMzAuNzA5NyAyNC43OTQ2QzMwLjY5MTUgMjQuNzc1MSAzMC42NjYzIDI0Ljc0ODUgMzAuNjM0NiAyNC43MTZDMzAuNTcxMSAyNC42NTA5IDMwLjQ4MDkgMjQuNTYxMyAzMC4zNjcgMjQuNDU1M0MzMC4xNDAzIDI0LjI0NDQgMjkuODE0IDIzLjk2MzYgMjkuNDExOSAyMy42ODE0QzI4LjYzMTQgMjMuMTMzNyAyNy40NTExIDIyLjUgMjYuMSAyMi41SDI1VjIwLjVIMjUuNzVDMjYuNDQ0MyAyMC41IDI3LjExOTMgMjAuNzAxMSAyNy42NDMyIDIwLjkyMTZDMjcuOTAwMyAyMS4wMjk5IDI4LjEwOTIgMjEuMTM3OCAyOC4yNTA5IDIxLjIxNjlDMjguMzIxNSAyMS4yNTY0IDI4LjM3NDcgMjEuMjg4MiAyOC40MDggMjEuMzA4N0MyOC40MjQ3IDIxLjMxODkgMjguNDM2MyAyMS4zMjYzIDI4LjQ0MjcgMjEuMzMwNEwyOC40NDU3IDIxLjMzMjNDMjguNDQ1NyAyMS4zMzIzIDI4LjQ0NTMgMjEuMzMyMSAyOSAyMC41QzI5LjU1NDcgMTkuNjY3OSAyOS41NTQyIDE5LjY2NzYgMjkuNTU0MiAxOS42Njc2TDI5LjU1MjcgMTkuNjY2NkwyOS41NTAxIDE5LjY2NDlMMjkuNTQzMiAxOS42NjA0TDI5LjUyMjggMTkuNjQ3MkMyOS41MDYzIDE5LjYzNjYgMjkuNDg0IDE5LjYyMjUgMjkuNDU2MiAxOS42MDU0QzI5LjQwMDcgMTkuNTcxMiAyOS4zMjMgMTkuNTI0OSAyOS4yMjU2IDE5LjQ3MDZDMjkuMDMxNSAxOS4zNjIyIDI4Ljc1NTkgMTkuMjIwMSAyOC40MTkzIDE5LjA3ODRDMjcuNzU1NyAxOC43OTg5IDI2LjgwNTcgMTguNSAyNS43NSAxOC41SDI1VjE3SDM2VjMwSDI4LjVDMjguNSAyOS40Mzc5IDI4LjIzMjQgMjguOTQ1MiAyNy45NjQxIDI4LjU4NzVDMjcuNjgwMyAyOC4yMDkyIDI3LjMwNTQgMjcuODYwNiAyNi45MDA3IDI3LjU2NjNDMjYuMzY3NSAyNy4xNzg1IDI1LjY5ODkgMjYuODI1NyAyNSAyNi42MzkxVjI0LjVaTTI2LjQ5MjkgMzBDMjYuNDc5NyAyOS45NjcgMjYuNDQ1NyAyOS44OTY0IDI2LjM2NDEgMjkuNzg3NUMyNi4yMjU5IDI5LjYwMzMgMjYuMDA3MSAyOS4zODk0IDI1LjcyNDMgMjkuMTgzN0MyNS4xNDc4IDI4Ljc2NDUgMjQuNDkzNyAyOC41MTE3IDI0LjAzMiAyOC41MDA0QzIzLjQ4NzcgMjguNTQ2NCAyMi44MDUyIDI4LjgyNTIgMjIuMjQ0OSAyOS4yMjdDMjEuOTY1NyAyOS40MjcyIDIxLjc1NTYgMjkuNjMwNyAyMS42MjUyIDI5LjgwMzhDMjEuNTQ5NiAyOS45MDQzIDIxLjUxODQgMjkuOTY5NCAyMS41MDYzIDMwSDI2LjQ5MjlaIiBmaWxsPSIjYjQ1MzA5Ii8+Cjwvc3ZnPgo=", + "created": 1700000000000 + }, + "img_bicon46": { + "mimeType": "image/svg+xml", + "id": "img_bicon46", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiNiNDUzMDkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyIDV2MTYiIC8+CiAgPHBhdGggZD0iTTIwLjAwMSAxOUEyIDIgMCAwMDIyIDE3VjVhMiAyIDAgMDAtMS45OTktMkwxNiAzLjAwMkE1IDUgMCAwMDEyIDVhNSA1IDAgMDAtNC0ySDRhMiAyIDAgMDAtMiAydjEyYTIgMiAwIDAwMS45OTkgMkg4YTUgNSAwIDAxNCAyIDUgNSAwIDAxNC0yeiIgLz4KPC9zdmc+Cg==", + "created": 1700000000000 + } + } +} \ No newline at end of file diff --git a/knowledge/drafts/pillars-b3.excalidraw b/knowledge/drafts/pillars-b3.excalidraw new file mode 100644 index 0000000..d50416d --- /dev/null +++ b/knowledge/drafts/pillars-b3.excalidraw @@ -0,0 +1,3350 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "oidm-knowledge/tools/diagrams", + "elements": [ + { + "type": "rectangle", + "id": "band48", + "x": 0, + "y": 373.05, + "width": 880, + "height": 198.24999999999994, + "strokeColor": "#b45309", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1095, + "version": 1, + "versionNonce": 1096, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "fill83", + "x": -1.0, + "y": 373.05, + "width": 33, + "height": 32.0, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1165, + "version": 1, + "versionNonce": 1166, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill84", + "x": 848, + "y": 373.05, + "width": 33, + "height": 32.0, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1167, + "version": 1, + "versionNonce": 1168, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "band32", + "x": 0, + "y": 151.05, + "width": 880, + "height": 258.0, + "strokeColor": "#0f766e", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1063, + "version": 1, + "versionNonce": 1064, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "fill81", + "x": -1.0, + "y": 377.05, + "width": 33, + "height": 32.0, + "strokeColor": "transparent", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1161, + "version": 1, + "versionNonce": 1162, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill82", + "x": 848, + "y": 377.05, + "width": 33, + "height": 32.0, + "strokeColor": "transparent", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1163, + "version": 1, + "versionNonce": 1164, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill69", + "x": -1.0, + "y": 151.05, + "width": 33, + "height": 32.0, + "strokeColor": "transparent", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1137, + "version": 1, + "versionNonce": 1138, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill70", + "x": 848, + "y": 151.05, + "width": 33, + "height": 32.0, + "strokeColor": "transparent", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1139, + "version": 1, + "versionNonce": 1140, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "band14", + "x": 0, + "y": 95.65, + "width": 880, + "height": 79.4, + "strokeColor": "#6d28d9", + "backgroundColor": "#ede9fe", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1027, + "version": 1, + "versionNonce": 1028, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "fill67", + "x": -1.0, + "y": 143.05, + "width": 33, + "height": 32.0, + "strokeColor": "transparent", + "backgroundColor": "#ede9fe", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1133, + "version": 1, + "versionNonce": 1134, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill68", + "x": 848, + "y": 143.05, + "width": 33, + "height": 32.0, + "strokeColor": "transparent", + "backgroundColor": "#ede9fe", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1135, + "version": 1, + "versionNonce": 1136, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill51", + "x": 423.0, + "y": 95.65, + "width": 33, + "height": 32.0, + "strokeColor": "transparent", + "backgroundColor": "#ede9fe", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1101, + "version": 1, + "versionNonce": 1102, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill52", + "x": 848, + "y": 95.65, + "width": 33, + "height": 32.0, + "strokeColor": "transparent", + "backgroundColor": "#ede9fe", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1103, + "version": 1, + "versionNonce": 1104, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "panel1", + "x": 0, + "y": 0, + "width": 304.0, + "height": 71.65, + "strokeColor": "#be123c", + "backgroundColor": "#ffe4e6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1001, + "version": 1, + "versionNonce": 1002, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "panel2", + "x": 424.0, + "y": 0, + "width": 456.0, + "height": 119.65, + "strokeColor": "#15803d", + "backgroundColor": "#dcfce7", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1003, + "version": 1, + "versionNonce": 1004, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "fill49", + "x": 423.0, + "y": 87.65, + "width": 33, + "height": 32.0, + "strokeColor": "transparent", + "backgroundColor": "#dcfce7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1097, + "version": 1, + "versionNonce": 1098, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill50", + "x": 848, + "y": 87.65, + "width": 33, + "height": 32.0, + "strokeColor": "transparent", + "backgroundColor": "#dcfce7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1099, + "version": 1, + "versionNonce": 1100, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "image", + "id": "bicon3", + "x": 18, + "y": 14.0, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1005, + "version": 1, + "versionNonce": 1006, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon3", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle4", + "x": 58, + "y": 16, + "width": 93.96, + "height": 22.5, + "strokeColor": "#881337", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1007, + "version": 1, + "versionNonce": 1008, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Use Cases", + "originalText": "Use Cases", + "fontSize": 18, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub5", + "x": 58, + "y": 39.400000000000006, + "width": 211.11999999999998, + "height": 16.25, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1009, + "version": 1, + "versionNonce": 1010, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "what the project wants built", + "originalText": "what the project wants built", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon6", + "x": 442.0, + "y": 14.0, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1011, + "version": 1, + "versionNonce": 1012, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon6", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle7", + "x": 482.0, + "y": 16, + "width": 198.35999999999999, + "height": 22.5, + "strokeColor": "#14532d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1013, + "version": 1, + "versionNonce": 1014, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Sample Applications", + "originalText": "Sample Applications", + "fontSize": 18, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub8", + "x": 482.0, + "y": 39.400000000000006, + "width": 143.26, + "height": 16.25, + "strokeColor": "#15803d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1015, + "version": 1, + "versionNonce": 1016, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "what has been built", + "originalText": "what has been built", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "conn9", + "x": 306.0, + "y": 35.825, + "width": 116.0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1017, + "version": 1, + "versionNonce": 1018, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 116.0, + 0 + ] + ] + }, + { + "type": "rectangle", + "id": "chip10", + "x": 327.55, + "y": 24.700000000000003, + "width": 72.9, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1019, + "version": 1, + "versionNonce": 1020, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "chipt11", + "x": 336.55, + "y": 27.700000000000003, + "width": 54.900000000000006, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1021, + "version": 1, + "versionNonce": 1022, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "illustrates", + "originalText": "illustrates", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon12", + "x": 18, + "y": 109.65, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1023, + "version": 1, + "versionNonce": 1024, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon12", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle13", + "x": 58, + "y": 111.65, + "width": 41.76, + "height": 22.5, + "strokeColor": "#4c1d95", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1025, + "version": 1, + "versionNonce": 1026, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "SDKs", + "originalText": "SDKs", + "fontSize": 18, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon15", + "x": 18, + "y": 183.05, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1029, + "version": 1, + "versionNonce": 1030, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon15", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle16", + "x": 58, + "y": 185.05, + "width": 174.0, + "height": 25.0, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1031, + "version": 1, + "versionNonce": 1032, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Data Structures", + "originalText": "Data Structures", + "fontSize": 20, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub17", + "x": 58, + "y": 211.05, + "width": 226.2, + "height": 16.25, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1033, + "version": 1, + "versionNonce": 1034, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "this patient \u00b7 Patient Context", + "originalText": "this patient \u00b7 Patient Context", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk18", + "x": 20.0, + "y": 241.3, + "width": 188.5, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1035, + "version": 1, + "versionNonce": 1036, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki19", + "x": 100.25, + "y": 261.675, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1037, + "version": 1, + "versionNonce": 1038, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki19", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt20", + "x": 26.0, + "y": 295.675, + "width": 176.5, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1039, + "version": 1, + "versionNonce": 1040, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Observation", + "originalText": "Observation", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk21", + "x": 228.5, + "y": 241.3, + "width": 188.5, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1041, + "version": 1, + "versionNonce": 1042, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki22", + "x": 308.75, + "y": 252.3, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1043, + "version": 1, + "versionNonce": 1044, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki22", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt23", + "x": 234.5, + "y": 286.3, + "width": 176.5, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1045, + "version": 1, + "versionNonce": 1046, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Exam Finding", + "originalText": "Exam Finding", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkt24", + "x": 234.5, + "y": 305.05, + "width": 176.5, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1047, + "version": 1, + "versionNonce": 1048, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "List", + "originalText": "List", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk25", + "x": 437.0, + "y": 241.3, + "width": 188.5, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1049, + "version": 1, + "versionNonce": 1050, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki26", + "x": 517.25, + "y": 252.3, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1051, + "version": 1, + "versionNonce": 1052, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki26", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt27", + "x": 443.0, + "y": 286.3, + "width": 176.5, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1053, + "version": 1, + "versionNonce": 1054, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Imaging Problem", + "originalText": "Imaging Problem", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkt28", + "x": 443.0, + "y": 305.05, + "width": 176.5, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1055, + "version": 1, + "versionNonce": 1056, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "List", + "originalText": "List", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk29", + "x": 645.5, + "y": 241.3, + "width": 188.5, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1057, + "version": 1, + "versionNonce": 1058, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki30", + "x": 723.75, + "y": 259.675, + "width": 32, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1059, + "version": 1, + "versionNonce": 1060, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki30", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt31", + "x": 651.5, + "y": 295.675, + "width": 176.5, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1061, + "version": 1, + "versionNonce": 1062, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Imaging Persona", + "originalText": "Imaging Persona", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon33", + "x": 18, + "y": 416.05, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1065, + "version": 1, + "versionNonce": 1066, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon33", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle34", + "x": 58, + "y": 418.05, + "width": 208.79999999999998, + "height": 25.0, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1067, + "version": 1, + "versionNonce": 1068, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Foundation Context", + "originalText": "Foundation Context", + "fontSize": 20, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub35", + "x": 58, + "y": 444.05, + "width": 188.5, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1069, + "version": 1, + "versionNonce": 1070, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "shared, curated knowledge", + "originalText": "shared, curated knowledge", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk36", + "x": 20.0, + "y": 472.3, + "width": 266.6666666666667, + "height": 84.0, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1071, + "version": 1, + "versionNonce": 1072, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki37", + "x": 139.33333333333334, + "y": 477.8, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1073, + "version": 1, + "versionNonce": 1074, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki37", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt38", + "x": 26.0, + "y": 511.8, + "width": 254.66666666666669, + "height": 18.75, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1075, + "version": 1, + "versionNonce": 1076, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Finding/diagnosis definitions", + "originalText": "Finding/diagnosis definitions", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkd39", + "x": 26.0, + "y": 532.55, + "width": 254.66666666666669, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1077, + "version": 1, + "versionNonce": 1078, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "finding models \u00b7 CDEs", + "originalText": "finding models \u00b7 CDEs", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk40", + "x": 306.6666666666667, + "y": 472.3, + "width": 266.6666666666667, + "height": 84.0, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1079, + "version": 1, + "versionNonce": 1080, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki41", + "x": 424.0, + "y": 475.8, + "width": 32, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1081, + "version": 1, + "versionNonce": 1082, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki41", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt42", + "x": 312.6666666666667, + "y": 511.8, + "width": 254.66666666666669, + "height": 18.75, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1083, + "version": 1, + "versionNonce": 1084, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Anatomic locations", + "originalText": "Anatomic locations", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkd43", + "x": 312.6666666666667, + "y": 532.55, + "width": 254.66666666666669, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1085, + "version": 1, + "versionNonce": 1086, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "anchored in RadLex", + "originalText": "anchored in RadLex", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk44", + "x": 593.3333333333334, + "y": 472.3, + "width": 266.6666666666667, + "height": 84.0, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1087, + "version": 1, + "versionNonce": 1088, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki45", + "x": 710.6666666666667, + "y": 475.8, + "width": 32, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1089, + "version": 1, + "versionNonce": 1090, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki45", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt46", + "x": 599.3333333333334, + "y": 511.8, + "width": 254.66666666666669, + "height": 18.75, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1091, + "version": 1, + "versionNonce": 1092, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Exam types", + "originalText": "Exam types", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkd47", + "x": 599.3333333333334, + "y": 532.55, + "width": 254.66666666666669, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1093, + "version": 1, + "versionNonce": 1094, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "LOINC/RSNA Playbook", + "originalText": "LOINC/RSNA Playbook", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "fill53", + "x": 423.0, + "y": 95.65, + "width": 36.076923076923094, + "height": 27.0, + "strokeColor": "transparent", + "backgroundColor": "#ede9fe", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1105, + "version": 1, + "versionNonce": 1106, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill54", + "x": 529.2307692307693, + "y": 95.65, + "width": 35.076923076923094, + "height": 27.0, + "strokeColor": "transparent", + "backgroundColor": "#ede9fe", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1107, + "version": 1, + "versionNonce": 1108, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill55", + "x": 634.4615384615385, + "y": 95.65, + "width": 35.076923076923094, + "height": 27.0, + "strokeColor": "transparent", + "backgroundColor": "#ede9fe", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1109, + "version": 1, + "versionNonce": 1110, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill56", + "x": 739.6923076923077, + "y": 95.65, + "width": 35.076923076923094, + "height": 27.0, + "strokeColor": "transparent", + "backgroundColor": "#ede9fe", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1111, + "version": 1, + "versionNonce": 1112, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill57", + "x": 844.9230769230769, + "y": 95.65, + "width": 36.076923076923094, + "height": 27.0, + "strokeColor": "transparent", + "backgroundColor": "#ede9fe", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1113, + "version": 1, + "versionNonce": 1114, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "line", + "id": "ln58", + "x": 424.0, + "y": 63.650000000000006, + "width": 0.0, + "height": 32.0, + "strokeColor": "#15803d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1115, + "version": 1, + "versionNonce": 1116, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln59", + "x": 880, + "y": 63.650000000000006, + "width": 0, + "height": 32.0, + "strokeColor": "#15803d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1117, + "version": 1, + "versionNonce": 1118, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln60", + "x": 880, + "y": 95.65, + "width": 0, + "height": 56.0, + "strokeColor": "#6d28d9", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1119, + "version": 1, + "versionNonce": 1120, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 0, + 56.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln61", + "x": 424.0, + "y": 95.65, + "width": 456.0, + "height": 24.0, + "strokeColor": "#15803d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1121, + "version": 1, + "versionNonce": 1122, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 35.076923076923094, + 0.0 + ], + [ + 35.076923076923094, + 24.0 + ], + [ + 105.23076923076928, + 24.0 + ], + [ + 105.23076923076928, + 0.0 + ], + [ + 140.30769230769238, + 0.0 + ], + [ + 140.30769230769238, + 24.0 + ], + [ + 210.46153846153845, + 24.0 + ], + [ + 210.46153846153845, + 0.0 + ], + [ + 245.53846153846155, + 0.0 + ], + [ + 245.53846153846155, + 24.0 + ], + [ + 315.69230769230774, + 24.0 + ], + [ + 315.69230769230774, + 0.0 + ], + [ + 350.76923076923083, + 0.0 + ], + [ + 350.76923076923083, + 24.0 + ], + [ + 420.9230769230769, + 24.0 + ], + [ + 420.9230769230769, + 0.0 + ], + [ + 456.0, + 0.0 + ] + ], + "roundness": null + }, + { + "type": "text", + "id": "jw62", + "x": 459.0769230769231, + "y": 99.525, + "width": 70.15384615384619, + "height": 16.25, + "strokeColor": "#14532d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1123, + "version": 1, + "versionNonce": 1124, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "create", + "originalText": "create", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "jw63", + "x": 564.3076923076924, + "y": 99.525, + "width": 70.15384615384608, + "height": 16.25, + "strokeColor": "#14532d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1125, + "version": 1, + "versionNonce": 1126, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "read", + "originalText": "read", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "jw64", + "x": 669.5384615384615, + "y": 99.525, + "width": 70.15384615384619, + "height": 16.25, + "strokeColor": "#14532d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1127, + "version": 1, + "versionNonce": 1128, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "resolve", + "originalText": "resolve", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "jw65", + "x": 774.7692307692308, + "y": 99.525, + "width": 70.15384615384608, + "height": 16.25, + "strokeColor": "#14532d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1129, + "version": 1, + "versionNonce": 1130, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "author", + "originalText": "author", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "jl66", + "x": 459.0769230769231, + "y": 69.4, + "width": 143.26, + "height": 16.25, + "strokeColor": "#15803d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1131, + "version": 1, + "versionNonce": 1132, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "an application can:", + "originalText": "an application can:", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "fill71", + "x": -1.0, + "y": 151.05, + "width": 121.85714285714286, + "height": 27.0, + "strokeColor": "transparent", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1141, + "version": 1, + "versionNonce": 1142, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill72", + "x": 362.57142857142856, + "y": 151.05, + "width": 120.85714285714289, + "height": 27.0, + "strokeColor": "transparent", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1143, + "version": 1, + "versionNonce": 1144, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill73", + "x": 725.1428571428571, + "y": 151.05, + "width": 120.85714285714289, + "height": 27.0, + "strokeColor": "transparent", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1145, + "version": 1, + "versionNonce": 1146, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "line", + "id": "ln74", + "x": 0.0, + "y": 119.05000000000001, + "width": 0.0, + "height": 32.0, + "strokeColor": "#6d28d9", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1147, + "version": 1, + "versionNonce": 1148, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln75", + "x": 0.0, + "y": 151.05, + "width": 0.0, + "height": 56.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1149, + "version": 1, + "versionNonce": 1150, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 56.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln76", + "x": 880, + "y": 119.05000000000001, + "width": 0, + "height": 32.0, + "strokeColor": "#6d28d9", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1151, + "version": 1, + "versionNonce": 1152, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln77", + "x": 880, + "y": 151.05, + "width": 0, + "height": 56.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1153, + "version": 1, + "versionNonce": 1154, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 0, + 56.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln78", + "x": 0.0, + "y": 151.05, + "width": 846.0, + "height": 24.0, + "strokeColor": "#6d28d9", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1155, + "version": 1, + "versionNonce": 1156, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 120.85714285714286, + 0.0 + ], + [ + 120.85714285714286, + 24.0 + ], + [ + 362.57142857142856, + 24.0 + ], + [ + 362.57142857142856, + 0.0 + ], + [ + 483.42857142857144, + 0.0 + ], + [ + 483.42857142857144, + 24.0 + ], + [ + 725.1428571428571, + 24.0 + ], + [ + 725.1428571428571, + 0.0 + ], + [ + 846.0, + 0.0 + ] + ], + "roundness": null + }, + { + "type": "text", + "id": "jw79", + "x": 120.85714285714286, + "y": 154.925, + "width": 241.7142857142857, + "height": 16.25, + "strokeColor": "#4c1d95", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1157, + "version": 1, + "versionNonce": 1158, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "wraps", + "originalText": "wraps", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "jw80", + "x": 483.42857142857144, + "y": 154.925, + "width": 241.71428571428567, + "height": 16.25, + "strokeColor": "#4c1d95", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1159, + "version": 1, + "versionNonce": 1160, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "manipulates instances", + "originalText": "manipulates instances", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "fill85", + "x": -1.0, + "y": 373.05, + "width": 51.0, + "height": 39.0, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1169, + "version": 1, + "versionNonce": 1170, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill86", + "x": 150.0, + "y": 373.05, + "width": 50.0, + "height": 39.0, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1171, + "version": 1, + "versionNonce": 1172, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill87", + "x": 300.0, + "y": 373.05, + "width": 50.0, + "height": 39.0, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1173, + "version": 1, + "versionNonce": 1174, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill88", + "x": 450.0, + "y": 373.05, + "width": 50.0, + "height": 39.0, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1175, + "version": 1, + "versionNonce": 1176, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill89", + "x": 600.0, + "y": 373.05, + "width": 281.0, + "height": 39.0, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1177, + "version": 1, + "versionNonce": 1178, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "line", + "id": "ln90", + "x": 0.0, + "y": 341.05, + "width": 0.0, + "height": 32.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1179, + "version": 1, + "versionNonce": 1180, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln91", + "x": 0.0, + "y": 373.05, + "width": 0.0, + "height": 68.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1181, + "version": 1, + "versionNonce": 1182, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 68.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln92", + "x": 880, + "y": 341.05, + "width": 0, + "height": 32.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1183, + "version": 1, + "versionNonce": 1184, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln93", + "x": 880, + "y": 373.05, + "width": 0, + "height": 68.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1185, + "version": 1, + "versionNonce": 1186, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 0, + 68.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln94", + "x": 0.0, + "y": 373.05, + "width": 880.0, + "height": 36.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1187, + "version": 1, + "versionNonce": 1188, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 50.0, + 0.0 + ], + [ + 50.0, + 36.0 + ], + [ + 150.0, + 36.0 + ], + [ + 150.0, + 0.0 + ], + [ + 200.0, + 0.0 + ], + [ + 200.0, + 36.0 + ], + [ + 300.0, + 36.0 + ], + [ + 300.0, + 0.0 + ], + [ + 350.0, + 0.0 + ], + [ + 350.0, + 36.0 + ], + [ + 450.0, + 36.0 + ], + [ + 450.0, + 0.0 + ], + [ + 500.0, + 0.0 + ], + [ + 500.0, + 36.0 + ], + [ + 600.0, + 36.0 + ], + [ + 600.0, + 0.0 + ], + [ + 880.0, + 0.0 + ] + ], + "roundness": null + }, + { + "type": "text", + "id": "jw95", + "x": 50.0, + "y": 382.925, + "width": 100.0, + "height": 16.25, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1189, + "version": 1, + "versionNonce": 1190, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "finding", + "originalText": "finding", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "jw96", + "x": 200.0, + "y": 382.925, + "width": 100.0, + "height": 16.25, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1191, + "version": 1, + "versionNonce": 1192, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "diagnosis", + "originalText": "diagnosis", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "jw97", + "x": 350.0, + "y": 382.925, + "width": 100.0, + "height": 16.25, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1193, + "version": 1, + "versionNonce": 1194, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "location", + "originalText": "location", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "jw98", + "x": 500.0, + "y": 382.925, + "width": 100.0, + "height": 16.25, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1195, + "version": 1, + "versionNonce": 1196, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "exam type", + "originalText": "exam type", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "jl99", + "x": 50.0, + "y": 346.8, + "width": 180.95999999999998, + "height": 16.25, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1197, + "version": 1, + "versionNonce": 1198, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "woven together at every:", + "originalText": "woven together at every:", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "fill100", + "x": 846.0, + "y": 151.05, + "width": 34.0, + "height": 222.0, + "strokeColor": "transparent", + "backgroundColor": "#ede9fe", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1199, + "version": 1, + "versionNonce": 1200, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill101", + "x": 650.0, + "y": 373.05, + "width": 230.0, + "height": 36.0, + "strokeColor": "transparent", + "backgroundColor": "#ede9fe", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1201, + "version": 1, + "versionNonce": 1202, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "line", + "id": "ln102", + "x": 846.0, + "y": 151.05, + "width": 230.0, + "height": 258.0, + "strokeColor": "#6d28d9", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1203, + "version": 1, + "versionNonce": 1204, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 222.0 + ], + [ + -196.0, + 222.0 + ], + [ + -196.0, + 258.0 + ], + [ + 34.0, + 258.0 + ], + [ + 34.0, + 0.0 + ] + ], + "roundness": null + }, + { + "type": "text", + "id": "lanet103", + "x": 650.0, + "y": 382.925, + "width": 230.0, + "height": 16.25, + "strokeColor": "#4c1d95", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1205, + "version": 1, + "versionNonce": 1206, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "attaches to \u00b7 authors & maintains", + "originalText": "attaches to \u00b7 authors & maintains", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + } + ], + "appState": { + "viewBackgroundColor": "#ffffff", + "gridSize": null + }, + "files": { + "img_bicon3": { + "mimeType": "image/svg+xml", + "id": "img_bicon3", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiNiZTEyM2MiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTE1IDE0Yy4yLTEgLjctMS43IDEuNS0yLjUgMS0uOSAxLjUtMi4yIDEuNS0zLjVBNiA2IDAgMCAwIDYgOGMwIDEgLjIgMi4yIDEuNSAzLjUuNy43IDEuMyAxLjUgMS41IDIuNSIgLz4KICA8cGF0aCBkPSJNOSAxOGg2IiAvPgogIDxwYXRoIGQ9Ik0xMCAyMmg0IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_bicon6": { + "mimeType": "image/svg+xml", + "id": "img_bicon6", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMxNTgwM2QiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHJlY3QgeD0iMiIgeT0iNCIgd2lkdGg9IjIwIiBoZWlnaHQ9IjE2IiByeD0iMiIgLz4KICA8cGF0aCBkPSJNMTAgNHY0IiAvPgogIDxwYXRoIGQ9Ik0yIDhoMjAiIC8+CiAgPHBhdGggZD0iTTYgNHY0IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_bicon12": { + "mimeType": "image/svg+xml", + "id": "img_bicon12", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiM2ZDI4ZDkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTExIDIxLjczYTIgMiAwIDAgMCAyIDBsNy00QTIgMiAwIDAgMCAyMSAxNlY4YTIgMiAwIDAgMC0xLTEuNzNsLTctNGEyIDIgMCAwIDAtMiAwbC03IDRBMiAyIDAgMCAwIDMgOHY4YTIgMiAwIDAgMCAxIDEuNzN6IiAvPgogIDxwYXRoIGQ9Ik0xMiAyMlYxMiIgLz4KICA8cG9seWxpbmUgcG9pbnRzPSIzLjI5IDcgMTIgMTIgMjAuNzEgNyIgLz4KICA8cGF0aCBkPSJtNy41IDQuMjcgOSA1LjE1IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_bicon15": { + "mimeType": "image/svg+xml", + "id": "img_bicon15", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyLjgzIDIuMThhMiAyIDAgMCAwLTEuNjYgMEwyLjYgNi4wOGExIDEgMCAwIDAgMCAxLjgzbDguNTggMy45MWEyIDIgMCAwIDAgMS42NiAwbDguNTgtMy45YTEgMSAwIDAgMCAwLTEuODN6IiAvPgogIDxwYXRoIGQ9Ik0yIDEyYTEgMSAwIDAgMCAuNTguOTFsOC42IDMuOTFhMiAyIDAgMCAwIDEuNjUgMGw4LjU4LTMuOUExIDEgMCAwIDAgMjIgMTIiIC8+CiAgPHBhdGggZD0iTTIgMTdhMSAxIDAgMCAwIC41OC45MWw4LjYgMy45MWEyIDIgMCAwIDAgMS42NSAwbDguNTgtMy45QTEgMSAwIDAgMCAyMiAxNyIgLz4KPC9zdmc+Cg==", + "created": 1700000000000 + }, + "img_blki19": { + "mimeType": "image/svg+xml", + "id": "img_blki19", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHJlY3Qgd2lkdGg9IjgiIGhlaWdodD0iNCIgeD0iOCIgeT0iMiIgcng9IjEiIHJ5PSIxIiAvPgogIDxwYXRoIGQ9Ik0xNiA0aDJhMiAyIDAgMCAxIDIgMnYxNGEyIDIgMCAwIDEtMiAySDZhMiAyIDAgMCAxLTItMlY2YTIgMiAwIDAgMSAyLTJoMiIgLz4KPC9zdmc+Cg==", + "created": 1700000000000 + }, + "img_blki22": { + "mimeType": "image/svg+xml", + "id": "img_blki22", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHJlY3Qgd2lkdGg9IjgiIGhlaWdodD0iNCIgeD0iOCIgeT0iMiIgcng9IjEiIHJ5PSIxIiAvPgogIDxwYXRoIGQ9Ik0xNiA0aDJhMiAyIDAgMCAxIDIgMnYxNGEyIDIgMCAwIDEtMiAySDZhMiAyIDAgMCAxLTItMlY2YTIgMiAwIDAgMSAyLTJoMiIgLz4KICA8cGF0aCBkPSJNMTIgMTFoNCIgLz4KICA8cGF0aCBkPSJNMTIgMTZoNCIgLz4KICA8cGF0aCBkPSJNOCAxMWguMDEiIC8+CiAgPHBhdGggZD0iTTggMTZoLjAxIiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki26": { + "mimeType": "image/svg+xml", + "id": "img_blki26", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTMgNWguMDEiIC8+CiAgPHBhdGggZD0iTTMgMTJoLjAxIiAvPgogIDxwYXRoIGQ9Ik0zIDE5aC4wMSIgLz4KICA8cGF0aCBkPSJNOCA1aDEzIiAvPgogIDxwYXRoIGQ9Ik04IDEyaDEzIiAvPgogIDxwYXRoIGQ9Ik04IDE5aDEzIiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki30": { + "mimeType": "image/svg+xml", + "id": "img_blki30", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yNCAyNEMyOC40MjA0IDI0IDMyIDIwLjQyMDQgMzIgMTZDMzIgMTEuNTc5NiAyOC40MjA0IDggMjQgOEMxOS41Nzk2IDggMTYgMTEuNTc5NiAxNiAxNkMxNiAyMC40MjA0IDE5LjU3OTYgMjQgMjQgMjRaTTM0IDE2QzM0IDIxLjUyNSAyOS41MjUgMjYgMjQgMjZDMTguNDc1IDI2IDE0IDIxLjUyNSAxNCAxNkMxNCAxMC40NzUgMTguNDc1IDYgMjQgNkMyOS41MjUgNiAzNCAxMC40NzUgMzQgMTZaIiBmaWxsPSIjMGY3NjZlIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNOS4yMjM0OCAzNC4yMTE5QzguMjIwMzggMzUuMDIxMSA4IDM1LjYyOTEgOCAzNlY0MEg0MFYzNkM0MCAzNS42MjkxIDM5Ljc3OTYgMzUuMDIxMSAzOC43NzY1IDM0LjIxMTlDMzcuNzk1OCAzMy40MjA3IDM2LjMzNDEgMzIuNjY2OSAzNC41NjIyIDMyLjAxNUMzMS4wMTk5IDMwLjcxMTcgMjYuNzUzMiAzMCAyNCAzMEMyMS4yNDY4IDMwIDE2Ljk4MDEgMzAuNzExNyAxMy40Mzc4IDMyLjAxNUMxMS42NjU5IDMyLjY2NjkgMTAuMjA0MiAzMy40MjA3IDkuMjIzNDggMzQuMjExOVpNMjQgMjhDMTcuOTkyNSAyOCA2IDMxLjAzNDcgNiAzNlY0Mkg0MlYzNkM0MiAzMS4wMzQ3IDMwLjAwNzUgMjggMjQgMjhaIiBmaWxsPSIjMGY3NjZlIi8+Cjwvc3ZnPgo=", + "created": 1700000000000 + }, + "img_bicon33": { + "mimeType": "image/svg+xml", + "id": "img_bicon33", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiNiNDUzMDkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyIDV2MTYiIC8+CiAgPHBhdGggZD0iTTIwLjAwMSAxOUEyIDIgMCAwMDIyIDE3VjVhMiAyIDAgMDAtMS45OTktMkwxNiAzLjAwMkE1IDUgMCAwMDEyIDVhNSA1IDAgMDAtNC0ySDRhMiAyIDAgMDAtMiAydjEyYTIgMiAwIDAwMS45OTkgMkg4YTUgNSAwIDAxNCAyIDUgNSAwIDAxNC0yeiIgLz4KPC9zdmc+Cg==", + "created": 1700000000000 + }, + "img_blki37": { + "mimeType": "image/svg+xml", + "id": "img_blki37", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiNiNDUzMDkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyLjU4NiAyLjU4NkEyIDIgMCAwIDAgMTEuMTcyIDJINGEyIDIgMCAwIDAtMiAydjcuMTcyYTIgMiAwIDAgMCAuNTg2IDEuNDE0bDguNzA0IDguNzA0YTIuNDI2IDIuNDI2IDAgMCAwIDMuNDIgMGw2LjU4LTYuNThhMi40MjYgMi40MjYgMCAwIDAgMC0zLjQyeiIgLz4KICA8Y2lyY2xlIGN4PSI3LjUiIGN5PSI3LjUiIHI9Ii41IiBmaWxsPSIjYjQ1MzA5IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki41": { + "mimeType": "image/svg+xml", + "id": "img_blki41", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yMyA2LjAwMDEzQzIzIDYuMDAwMDQgMjMgNiAyNCA2SDI0LjE3NjFDMjQuMjUzMyA2IDI0LjMyMzMgNiAyNC4zODY4IDZDMjUgNi4wMDAwMSAyNSA2LjAwMDA1IDI1IDYuMDAwMTNWMjAuNUMyNSAyMS44OTc3IDI1LjU2NDEgMjIuNDQyMSAyNi4wMDM5IDIyLjY5ODdDMjYuMDUzIDIyLjcyNzMgMjYuMTAyNCAyMi43NTMzIDI2LjE1MTYgMjIuNzc3QzI2LjE1MDYgMjIuNjU2OCAyNi4xNDkzIDIyLjUzMTYgMjYuMTQ3OSAyMi40MDE5TDI2LjE0NzkgMjIuNDAwM0MyNi4xMTAxIDE4Ljg3MTYgMjYuMDM2NSAxMS45OTk3IDMxLjQ3NTMgMTEuOTk5N0MzOC45MjU5IDExLjk5OTcgNDQuMjQ3OCAzOC4wMDYyIDQxLjA1NDcgNDAuNjU5OUMzNy44NjE1IDQzLjMxMzYgMzEuNDc1MyA0MS43MjE0IDI4LjI4MjIgMzguNTM2OUMyNS43MDQyIDM1Ljk2NTkgMjUuOTI3MiAyOS45NTgzIDI2LjA4NzMgMjUuNjQ1N0wyNi4wODc0IDI1LjY0NDNDMjYuMDk3MSAyNS4zODE5IDI2LjEwNjcgMjUuMTI1OCAyNi4xMTUzIDI0Ljg3NzFDMjUuNzkgMjQuNzk2MiAyNS4zOTU5IDI0LjY1OTUgMjQuOTk2MiAyNC40MjYzQzI0LjYzOTggMjQuMjE4NCAyNC4yOTc1IDIzLjk0NDIgMjQgMjMuNTkxOUMyMy43MDI2IDIzLjk0NDIgMjMuMzYwMyAyNC4yMTg0IDIzLjAwMzkgMjQuNDI2M0MyMi42MDQxIDI0LjY1OTUgMjIuMjEwMSAyNC43OTYyIDIxLjg4NDggMjQuODc3MUMyMS44OTM0IDI1LjEyNjEgMjEuOTAyOSAyNS4zODI2IDIxLjkxMjcgMjUuNjQ1M0MyMi4wNzI4IDI5Ljk1NzkgMjIuMjk1OSAzNS45NjYyIDE5LjcxNzkgMzguNTM3MkMxNi41MjQ3IDQxLjcyMTcgMTAuMTM4NSA0My4zMTM5IDYuOTQ1MzYgNDAuNjYwMkMzLjc1MjIyIDM4LjAwNjUgOS4wNzQxMyAxMiAxNi41MjQ3IDEyQzIxLjk2MzYgMTIgMjEuODkgMTguODcxNyAyMS44NTIyIDIyLjQwMDNDMjEuODUyIDIyLjQxNjYgMjEuODUxOCAyMi40MzI4IDIxLjg1MTYgMjIuNDQ4OUMyMS44NTA0IDIyLjU2MTkgMjEuODQ5MyAyMi42NzE0IDIxLjg0ODQgMjIuNzc3QzIxLjg5NzcgMjIuNzUzNCAyMS45NDcxIDIyLjcyNzQgMjEuOTk2MiAyMi42OTg3QzIyLjQzNiAyMi40NDIxIDIzIDIxLjg5NzcgMjMgMjAuNVY2LjAwMDEzWk0zMS40NzUzIDEzLjk5OTdDMzAuNTIxMiAxMy45OTk3IDI5Ljk4NDMgMTQuMzAwMiAyOS42MDg2IDE0LjY4NjlDMjkuMTc1MiAxNS4xMzMxIDI4LjgxMzIgMTUuODUwNyAyOC41NTkgMTYuODY0NkMyOC4xMTQxIDE4LjYzOTUgMjguMTMzIDIwLjY4MTkgMjguMTQ4MyAyMi4zMjkzQzI4LjE1MDkgMjIuNjE0MiAyOC4xNTM0IDIyLjg4NzQgMjguMTUzNCAyMy4xNDUzQzI4LjE1MzQgMjMuOTA1MyAyOC4xMTk2IDI0LjgxNTMgMjguMDg0NSAyNS43NjIxQzI4LjA3MDcgMjYuMTM0OSAyOC4wNTY2IDI2LjUxMzMgMjguMDQ0MyAyNi44OTA1QzI3Ljk5OTYgMjguMjY1NyAyNy45NzQxIDI5LjcwNTUgMjguMDQwNSAzMS4wOTgyQzI4LjEwNzIgMzIuNDk4NSAyOC4yNjQyIDMzLjc4MzUgMjguNTU3MyAzNC44NTk2QzI4Ljg1MzggMzUuOTQ4MyAyOS4yNTA5IDM2LjY3ODQgMjkuNjk0NCAzNy4xMjA4QzMwLjk3MjYgMzguMzk1NCAzMi45OTA4IDM5LjQyNTEgMzUuMDQ5MiAzOS44MjQzQzM3LjA4NDIgNDAuMjE4OSAzOC43MjI0IDM5LjkyNjkgMzkuNjgxOCAzOS4xOTY5QzM5LjY4NjggMzkuMTg1NyAzOS42OTIzIDM5LjE3MjYgMzkuNjk4NCAzOS4xNTc0QzM5Ljc1NzYgMzkuMDA5NSAzOS44Mjk0IDM4Ljc1NTQgMzkuODg3OCAzOC4zNjgzQzQwLjAwNDcgMzcuNTkzMyA0MC4wMzUgMzYuNTEyMiAzOS45NTYyIDM1LjE4MDNDMzkuNzk5NSAzMi41MzA1IDM5LjIyODYgMjkuMTY4OSAzOC4zMjY4IDI1Ljg2MDZDMzcuNDIxNiAyMi41Mzk2IDM2LjIxNzMgMTkuMzk5OCAzNC44NTIxIDE3LjEzODNDMzQuMTY4OCAxNi4wMDYyIDMzLjQ5NTEgMTUuMTc4NiAzMi44NzAzIDE0LjY1MzVDMzIuMjUxOCAxNC4xMzM3IDMxLjc5MzUgMTMuOTk5NyAzMS40NzUzIDEzLjk5OTdaTTE2LjUyNDcgMTRDMTcuNDc4OCAxNCAxOC4wMTU4IDE0LjMwMDUgMTguMzkxNCAxNC42ODcyQzE4LjgyNDggMTUuMTMzNCAxOS4xODY4IDE1Ljg1MSAxOS40NDEgMTYuODY0OUMxOS44ODU5IDE4LjYzOTkgMTkuODY3IDIwLjY4MjIgMTkuODUxOCAyMi4zMjk2QzE5Ljg0OTEgMjIuNjE0NiAxOS44NDY2IDIyLjg4NzcgMTkuODQ2NiAyMy4xNDU2QzE5Ljg0NjYgMjMuOTA1NiAxOS44ODA0IDI0LjgxNTYgMTkuOTE1NSAyNS43NjI0QzE5LjkyOTQgMjYuMTM1IDE5Ljk0MzQgMjYuNTEzOCAxOS45NTU3IDI2Ljg5MDhDMjAuMDAwNSAyOC4yNjYgMjAuMDI1OSAyOS43MDU4IDE5Ljk1OTYgMzEuMDk4NUMxOS44OTI5IDMyLjQ5ODggMTkuNzM1OSAzMy43ODM4IDE5LjQ0MjcgMzQuODU5OUMxOS4xNDYyIDM1Ljk0ODYgMTguNzQ5MiAzNi42Nzg3IDE4LjMwNTYgMzcuMTIxMUMxNy4wMjc1IDM4LjM5NTcgMTUuMDA5MyAzOS40MjU0IDEyLjk1MDkgMzkuODI0NkMxMC45MTU5IDQwLjIxOTIgOS4yNzc2OCAzOS45MjcyIDguMzE4MjMgMzkuMTk3MkM4LjMxMzI2IDM5LjE4NiA4LjMwNzcgMzkuMTcyOSA4LjMwMTYyIDM5LjE1NzdDOC4yNDI0MSAzOS4wMDk4IDguMTcwNjEgMzguNzU1NyA4LjExMjI0IDM4LjM2ODZDNy45OTUzOSAzNy41OTM2IDcuOTY1IDM2LjUxMjUgOC4wNDM4IDM1LjE4MDZDOC4yMDA1NiAzMi41MzA4IDguNzcxNDcgMjkuMTY5MiA5LjY3MzI0IDI1Ljg2MDlDMTAuNTc4NSAyMi41Mzk5IDExLjc4MjcgMTkuNDAwMSAxMy4xNDc5IDE3LjEzODZDMTMuODMxMyAxNi4wMDY1IDE0LjUwNDkgMTUuMTc4OSAxNS4xMjk4IDE0LjY1MzhDMTUuNzQ4MiAxNC4xMzQgMTYuMjA2NSAxNCAxNi41MjQ3IDE0WiIgZmlsbD0iI2I0NTMwOSIvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki45": { + "mimeType": "image/svg+xml", + "id": "img_blki45", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yOSA5QzI5IDExLjc2MTQgMjYuNzYxNCAxNCAyNCAxNEMyMS4yMzg2IDE0IDE5IDExLjc2MTQgMTkgOUMxOSA2LjIzODU4IDIxLjIzODYgNCAyNCA0QzI2Ljc2MTQgNCAyOSA2LjIzODU4IDI5IDlaTTI3IDlDMjcgMTAuNjU2OSAyNS42NTY5IDEyIDI0IDEyQzIyLjM0MzEgMTIgMjEgMTAuNjU2OSAyMSA5QzIxIDcuMzQzMTUgMjIuMzQzMSA2IDI0IDZDMjUuNjU2OSA2IDI3IDcuMzQzMTUgMjcgOVoiIGZpbGw9IiNiNDUzMDkiLz4KPHBhdGggZD0iTTE2Ljk5OTggNDFWMzRIMTguOTk5OFY0MUMxOC45OTk4IDQxLjU1MjMgMTkuNDQ3NSA0MiAxOS45OTk4IDQySDIwLjA4NjVDMjAuNjAzNyA0MiAyMS4wMzU2IDQxLjYwNTYgMjEuMDgyNCA0MS4wOTA1TDIxLjcyNyAzNEgyMy43MzUzTDIzLjA3NDIgNDEuMjcxNkMyMy4wNjkgNDEuMzI4OCAyMy4wNjIyIDQxLjM4NTYgMjMuMDUzOSA0MS40NDE3QzIzLjAzNTcgNDEuNTY0NyAyMy4wMTAxIDQxLjY4NTEgMjIuOTc3NiA0MS44MDI1QzIyLjYyNDIgNDMuMDc5OCAyMS40NTQ5IDQ0IDIwLjA4NjUgNDRIMTkuOTk5OEMxOC4zNDI5IDQ0IDE2Ljk5OTggNDIuNjU2OSAxNi45OTk4IDQxWiIgZmlsbD0iI2I0NTMwOSIvPgo8cGF0aCBkPSJNMjYuOTE3MSA0MS4wOTA1TDI2LjI3MjUgMzRIMjQuMjY0MkwyNC45MjUzIDQxLjI3MTZDMjQuOTMwNSA0MS4zMjg4IDI0LjkzNzMgNDEuMzg1NiAyNC45NDU2IDQxLjQ0MTdDMjQuOTYzOCA0MS41NjQ3IDI0Ljk4OTQgNDEuNjg1MSAyNS4wMjE5IDQxLjgwMjVDMjUuMzc1MyA0My4wNzk4IDI2LjU0NDYgNDQgMjcuOTEzIDQ0SDI3Ljk5OThDMjkuNjU2NiA0NCAzMC45OTk4IDQyLjY1NjkgMzAuOTk5OCA0MVYzNEgyOC45OTk4VjQxQzI4Ljk5OTggNDEuNTUyMyAyOC41NTIgNDIgMjcuOTk5OCA0MkgyNy45MTNDMjcuMzk1OCA0MiAyNi45NjM5IDQxLjYwNTYgMjYuOTE3MSA0MS4wOTA1WiIgZmlsbD0iI2I0NTMwOSIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTExIDE1QzEwLjQ0NzcgMTUgMTAgMTUuNDQ3NyAxMCAxNlYzMUMxMCAzMS41NTIzIDEwLjQ0NzcgMzIgMTEgMzJIMzdDMzcuNTUyMyAzMiAzOCAzMS41NTIzIDM4IDMxVjE2QzM4IDE1LjQ0NzcgMzcuNTUyMyAxNSAzNyAxNUgxMVpNMTIgMTdWMzBIMTkuNUMxOS41IDI5LjQ0MjQgMTkuNzU5MSAyOC45NTcyIDIwLjAyNzYgMjguNjAwNkMyMC4zMDg2IDI4LjIyNzYgMjAuNjc5NiAyNy44ODgzIDIxLjA3OTQgMjcuNjAxNkMyMS42MjUyIDI3LjIxMDMgMjIuMjk4NiAyNi44NjUgMjMgMjYuNjY3OFYyNC41SDIyLjJDMjEuNTk3MyAyNC41IDIwLjc1MzUgMjQuODY0MiAxOS45NDMzIDI1LjM1NTJDMTkuNTYzOCAyNS41ODUyIDE5LjIzMzcgMjUuODE2NyAxOC45OTg0IDI1Ljk5MTFDMTguODgxMiAyNi4wNzc4IDE4Ljc4ODggMjYuMTQ5NSAxOC43MjcgMjYuMTk4NEMxOC42OTYxIDI2LjIyMjggMTguNjczIDI2LjI0MTUgMTguNjU4MiAyNi4yNTM1TDE4LjY0MjYgMjYuMjY2M0wxOC42Mzk5IDI2LjI2ODRDMTguNjM5OSAyNi4yNjg0IDE4LjY0MDIgMjYuMjY4MiAxOCAyNS41QzE3LjM1OTggMjQuNzMxOCAxNy4zNjAxIDI0LjczMTUgMTcuMzYwMSAyNC43MzE1TDE3LjM2MTQgMjQuNzMwNUwxNy4zNjM4IDI0LjcyODVMMTcuMzcxMyAyNC43MjIzTDE3LjM5NjYgMjQuNzAxNkMxNy40MTc5IDI0LjY4NDMgMTcuNDQ4IDI0LjY2IDE3LjQ4NjMgMjQuNjI5N0MxNy41NjI3IDI0LjU2OTMgMTcuNjcxOSAyNC40ODQ3IDE3LjgwNzkgMjQuMzgzOUMxOC4wNzg4IDI0LjE4MzMgMTguNDYxMiAyMy45MTQ4IDE4LjkwNjcgMjMuNjQ0OEMxOS43NDY1IDIzLjEzNTggMjEuMDAyNyAyMi41IDIyLjIgMjIuNUgyM1YyMC41SDIyLjVDMjEuOTMwOSAyMC41IDIxLjE5MDkgMjAuNjk5MiAyMC41MjkyIDIwLjkzOThDMjAuMjEyIDIxLjA1NTIgMTkuOTM3IDIxLjE3MDkgMTkuNzQyMSAyMS4yNTc2QzE5LjY0NDkgMjEuMzAwNyAxOS41Njg1IDIxLjMzNjMgMTkuNTE3NiAyMS4zNjA1QzE5LjQ5MjIgMjEuMzcyNSAxOS40NzMyIDIxLjM4MTcgMTkuNDYxMyAyMS4zODc1TDE5LjQ0ODcgMjEuMzkzN0wxOS40NDcgMjEuMzk0NUMxOS40NDcgMjEuMzk0NSAxOS40NDcyIDIxLjM5NDQgMTkgMjAuNUMxOC41NTI4IDE5LjYwNTYgMTguNTUzMSAxOS42MDU0IDE4LjU1MzEgMTkuNjA1NEwxOC41NTY0IDE5LjYwMzhMMTguNTYyOSAxOS42MDA2TDE4LjU4NDQgMTkuNTlDMTguNjAyNSAxOS41ODEyIDE4LjYyNzkgMTkuNTY4OSAxOC42NjAxIDE5LjU1MzZDMTguNzI0NSAxOS41MjMxIDE4LjgxNiAxOS40ODA1IDE4LjkyOTggMTkuNDI5OUMxOS4xNTY3IDE5LjMyOTEgMTkuNDc1NSAxOS4xOTQ4IDE5Ljg0NTggMTkuMDYwMkMyMC41NTkxIDE4LjgwMDggMjEuNTY5MSAxOC41IDIyLjUgMTguNUgyM1YxN0gxMlpNMjUgMjQuNUgyNi4xQzI2Ljg0ODkgMjQuNSAyNy42MTg2IDI0Ljg2NjMgMjguMjYzMSAyNS4zMTg2QzI4LjU3MzUgMjUuNTM2NCAyOC44Mjg1IDI1Ljc1NTYgMjkuMDA0OCAyNS45MTk3QzI5LjA5MjUgMjYuMDAxMiAyOS4xNTk0IDI2LjA2NzkgMjkuMjAyNiAyNi4xMTIyQzI5LjIyNDEgMjYuMTM0MyAyOS4yMzk3IDI2LjE1MDcgMjkuMjQ4OCAyNi4xNjA1TDI5LjI1NzQgMjYuMTY5N0MyOS4yNTc0IDI2LjE2OTcgMjkuMjU2NyAyNi4xNjkgMzAgMjUuNUMzMC43NDMzIDI0LjgzMSAzMC43NDI5IDI0LjgzMDYgMzAuNzQyOSAyNC44MzA2TDMwLjc0MTQgMjQuODI5TDMwLjczODkgMjQuODI2MkwzMC43MzE4IDI0LjgxODRMMzAuNzA5NyAyNC43OTQ2QzMwLjY5MTUgMjQuNzc1MSAzMC42NjYzIDI0Ljc0ODUgMzAuNjM0NiAyNC43MTZDMzAuNTcxMSAyNC42NTA5IDMwLjQ4MDkgMjQuNTYxMyAzMC4zNjcgMjQuNDU1M0MzMC4xNDAzIDI0LjI0NDQgMjkuODE0IDIzLjk2MzYgMjkuNDExOSAyMy42ODE0QzI4LjYzMTQgMjMuMTMzNyAyNy40NTExIDIyLjUgMjYuMSAyMi41SDI1VjIwLjVIMjUuNzVDMjYuNDQ0MyAyMC41IDI3LjExOTMgMjAuNzAxMSAyNy42NDMyIDIwLjkyMTZDMjcuOTAwMyAyMS4wMjk5IDI4LjEwOTIgMjEuMTM3OCAyOC4yNTA5IDIxLjIxNjlDMjguMzIxNSAyMS4yNTY0IDI4LjM3NDcgMjEuMjg4MiAyOC40MDggMjEuMzA4N0MyOC40MjQ3IDIxLjMxODkgMjguNDM2MyAyMS4zMjYzIDI4LjQ0MjcgMjEuMzMwNEwyOC40NDU3IDIxLjMzMjNDMjguNDQ1NyAyMS4zMzIzIDI4LjQ0NTMgMjEuMzMyMSAyOSAyMC41QzI5LjU1NDcgMTkuNjY3OSAyOS41NTQyIDE5LjY2NzYgMjkuNTU0MiAxOS42Njc2TDI5LjU1MjcgMTkuNjY2NkwyOS41NTAxIDE5LjY2NDlMMjkuNTQzMiAxOS42NjA0TDI5LjUyMjggMTkuNjQ3MkMyOS41MDYzIDE5LjYzNjYgMjkuNDg0IDE5LjYyMjUgMjkuNDU2MiAxOS42MDU0QzI5LjQwMDcgMTkuNTcxMiAyOS4zMjMgMTkuNTI0OSAyOS4yMjU2IDE5LjQ3MDZDMjkuMDMxNSAxOS4zNjIyIDI4Ljc1NTkgMTkuMjIwMSAyOC40MTkzIDE5LjA3ODRDMjcuNzU1NyAxOC43OTg5IDI2LjgwNTcgMTguNSAyNS43NSAxOC41SDI1VjE3SDM2VjMwSDI4LjVDMjguNSAyOS40Mzc5IDI4LjIzMjQgMjguOTQ1MiAyNy45NjQxIDI4LjU4NzVDMjcuNjgwMyAyOC4yMDkyIDI3LjMwNTQgMjcuODYwNiAyNi45MDA3IDI3LjU2NjNDMjYuMzY3NSAyNy4xNzg1IDI1LjY5ODkgMjYuODI1NyAyNSAyNi42MzkxVjI0LjVaTTI2LjQ5MjkgMzBDMjYuNDc5NyAyOS45NjcgMjYuNDQ1NyAyOS44OTY0IDI2LjM2NDEgMjkuNzg3NUMyNi4yMjU5IDI5LjYwMzMgMjYuMDA3MSAyOS4zODk0IDI1LjcyNDMgMjkuMTgzN0MyNS4xNDc4IDI4Ljc2NDUgMjQuNDkzNyAyOC41MTE3IDI0LjAzMiAyOC41MDA0QzIzLjQ4NzcgMjguNTQ2NCAyMi44MDUyIDI4LjgyNTIgMjIuMjQ0OSAyOS4yMjdDMjEuOTY1NyAyOS40MjcyIDIxLjc1NTYgMjkuNjMwNyAyMS42MjUyIDI5LjgwMzhDMjEuNTQ5NiAyOS45MDQzIDIxLjUxODQgMjkuOTY5NCAyMS41MDYzIDMwSDI2LjQ5MjlaIiBmaWxsPSIjYjQ1MzA5Ii8+Cjwvc3ZnPgo=", + "created": 1700000000000 + } + } +} \ No newline at end of file diff --git a/knowledge/drafts/pillars-b3.svg b/knowledge/drafts/pillars-b3.svg new file mode 100644 index 0000000..80a9d11 --- /dev/null +++ b/knowledge/drafts/pillars-b3.svg @@ -0,0 +1,2 @@ +Use Caseswhat the project wants builtSample Applicationswhat has been builtillustratesSDKsData Structuresthis patient · Patient ContextObservationExam FindingListImaging ProblemListImaging PersonaFoundation Contextshared, curated knowledgeFinding/diagnosis definitionsfinding models · CDEsAnatomic locationsanchored in RadLexExam typesLOINC/RSNA Playbookcreatereadresolveauthoran application can:wrapsmanipulates instancesfindingdiagnosislocationexam typewoven together at every:attaches to · authors & maintains \ No newline at end of file diff --git a/knowledge/drafts/pillars-c.excalidraw b/knowledge/drafts/pillars-c.excalidraw new file mode 100644 index 0000000..87609e1 --- /dev/null +++ b/knowledge/drafts/pillars-c.excalidraw @@ -0,0 +1,4731 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "oidm-knowledge/tools/diagrams", + "elements": [ + { + "type": "rectangle", + "id": "band53", + "x": 0, + "y": 441.05, + "width": 880, + "height": 221.49999999999994, + "strokeColor": "#b45309", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1105, + "version": 1, + "versionNonce": 1106, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "fill58", + "x": -1, + "y": 441.05, + "width": 33, + "height": 32.0, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1115, + "version": 1, + "versionNonce": 1116, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill59", + "x": 848, + "y": 441.05, + "width": 33, + "height": 32.0, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1117, + "version": 1, + "versionNonce": 1118, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "line", + "id": "ln60", + "x": 0, + "y": 441.05, + "width": 0, + "height": 32.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1119, + "version": 1, + "versionNonce": 1120, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln61", + "x": 880, + "y": 441.05, + "width": 0, + "height": 32.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1121, + "version": 1, + "versionNonce": 1122, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "band33", + "x": 0, + "y": 187.3, + "width": 880, + "height": 189.75, + "strokeColor": "#0f766e", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1065, + "version": 1, + "versionNonce": 1066, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "fill54", + "x": -1, + "y": 345.05, + "width": 33, + "height": 32.0, + "strokeColor": "transparent", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1107, + "version": 1, + "versionNonce": 1108, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "rectangle", + "id": "fill55", + "x": 848, + "y": 345.05, + "width": 33, + "height": 32.0, + "strokeColor": "transparent", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1109, + "version": 1, + "versionNonce": 1110, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "line", + "id": "ln56", + "x": 0, + "y": 345.05, + "width": 0, + "height": 32.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1111, + "version": 1, + "versionNonce": 1112, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln57", + "x": 880, + "y": 345.05, + "width": 0, + "height": 32.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1113, + "version": 1, + "versionNonce": 1114, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "band15", + "x": 0, + "y": 91.65, + "width": 880, + "height": 71.65, + "strokeColor": "#6d28d9", + "backgroundColor": "#ede9fe", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1029, + "version": 1, + "versionNonce": 1030, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "panel1", + "x": 0, + "y": 0, + "width": 388.0, + "height": 67.65, + "strokeColor": "#be123c", + "backgroundColor": "#ffe4e6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1001, + "version": 1, + "versionNonce": 1002, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "panel2", + "x": 492.0, + "y": 0, + "width": 388.0, + "height": 67.65, + "strokeColor": "#15803d", + "backgroundColor": "#dcfce7", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1003, + "version": 1, + "versionNonce": 1004, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "bicon3", + "x": 18, + "y": 12.0, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1005, + "version": 1, + "versionNonce": 1006, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon3", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle4", + "x": 58, + "y": 14, + "width": 93.96, + "height": 22.5, + "strokeColor": "#881337", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1007, + "version": 1, + "versionNonce": 1008, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Use Cases", + "originalText": "Use Cases", + "fontSize": 18, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub5", + "x": 58, + "y": 37.400000000000006, + "width": 211.11999999999998, + "height": 16.25, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1009, + "version": 1, + "versionNonce": 1010, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "what the project wants built", + "originalText": "what the project wants built", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon6", + "x": 510.0, + "y": 12.0, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1011, + "version": 1, + "versionNonce": 1012, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon6", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle7", + "x": 550.0, + "y": 14, + "width": 198.35999999999999, + "height": 22.5, + "strokeColor": "#14532d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1013, + "version": 1, + "versionNonce": 1014, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Sample Applications", + "originalText": "Sample Applications", + "fontSize": 18, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub8", + "x": 550.0, + "y": 37.400000000000006, + "width": 143.26, + "height": 16.25, + "strokeColor": "#15803d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1015, + "version": 1, + "versionNonce": 1016, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "what has been built", + "originalText": "what has been built", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "conn9", + "x": 390.0, + "y": 33.825, + "width": 100.0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1017, + "version": 1, + "versionNonce": 1018, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 100.0, + 0 + ] + ] + }, + { + "type": "rectangle", + "id": "chip10", + "x": 389.53, + "y": 4.575000000000003, + "width": 100.94, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1019, + "version": 1, + "versionNonce": 1020, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "chipt11", + "x": 398.53, + "y": 7.575000000000003, + "width": 82.94, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1021, + "version": 1, + "versionNonce": 1022, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "illustrates", + "originalText": "illustrates", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon12", + "x": 18, + "y": 105.65, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1023, + "version": 1, + "versionNonce": 1024, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon12", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle13", + "x": 58, + "y": 107.65, + "width": 41.76, + "height": 22.5, + "strokeColor": "#4c1d95", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1025, + "version": 1, + "versionNonce": 1026, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "SDKs", + "originalText": "SDKs", + "fontSize": 18, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub14", + "x": 58, + "y": 131.05, + "width": 520.26, + "height": 16.25, + "strokeColor": "#6d28d9", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1027, + "version": 1, + "versionNonce": 1028, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "wrap the structures \u00b7 attach the shared knowledge \u00b7 support authoring", + "originalText": "wrap the structures \u00b7 attach the shared knowledge \u00b7 support authoring", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon16", + "x": 18, + "y": 203.3, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1031, + "version": 1, + "versionNonce": 1032, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon16", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle17", + "x": 58, + "y": 205.3, + "width": 174.0, + "height": 25.0, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1033, + "version": 1, + "versionNonce": 1034, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Data Structures", + "originalText": "Data Structures", + "fontSize": 20, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub18", + "x": 58, + "y": 231.3, + "width": 226.2, + "height": 16.25, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1035, + "version": 1, + "versionNonce": 1036, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "this patient \u00b7 Patient Context", + "originalText": "this patient \u00b7 Patient Context", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk19", + "x": 20.0, + "y": 261.55, + "width": 195.0, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1037, + "version": 1, + "versionNonce": 1038, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki20", + "x": 103.5, + "y": 281.925, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1039, + "version": 1, + "versionNonce": 1040, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki20", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt21", + "x": 26.0, + "y": 315.925, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1041, + "version": 1, + "versionNonce": 1042, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Observation", + "originalText": "Observation", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk22", + "x": 235.0, + "y": 261.55, + "width": 195.0, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1043, + "version": 1, + "versionNonce": 1044, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki23", + "x": 318.5, + "y": 272.55, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1045, + "version": 1, + "versionNonce": 1046, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki23", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt24", + "x": 241.0, + "y": 306.55, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1047, + "version": 1, + "versionNonce": 1048, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Exam Finding", + "originalText": "Exam Finding", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkt25", + "x": 241.0, + "y": 325.3, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1049, + "version": 1, + "versionNonce": 1050, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "List", + "originalText": "List", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk26", + "x": 450.0, + "y": 261.55, + "width": 195.0, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1051, + "version": 1, + "versionNonce": 1052, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki27", + "x": 533.5, + "y": 272.55, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1053, + "version": 1, + "versionNonce": 1054, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki27", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt28", + "x": 456.0, + "y": 306.55, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1055, + "version": 1, + "versionNonce": 1056, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Imaging Problem", + "originalText": "Imaging Problem", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkt29", + "x": 456.0, + "y": 325.3, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1057, + "version": 1, + "versionNonce": 1058, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "List", + "originalText": "List", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk30", + "x": 665.0, + "y": 261.55, + "width": 195.0, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1059, + "version": 1, + "versionNonce": 1060, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki31", + "x": 746.5, + "y": 279.925, + "width": 32, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1061, + "version": 1, + "versionNonce": 1062, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki31", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt32", + "x": 671.0, + "y": 315.925, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1063, + "version": 1, + "versionNonce": 1064, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Imaging Persona", + "originalText": "Imaging Persona", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon34", + "x": 18, + "y": 459.05, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1067, + "version": 1, + "versionNonce": 1068, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon34", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle35", + "x": 58, + "y": 461.05, + "width": 208.79999999999998, + "height": 25.0, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1069, + "version": 1, + "versionNonce": 1070, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Foundation Context", + "originalText": "Foundation Context", + "fontSize": 20, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub36", + "x": 58, + "y": 487.05, + "width": 188.5, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1071, + "version": 1, + "versionNonce": 1072, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "shared, curated knowledge", + "originalText": "shared, curated knowledge", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "chip37", + "x": 381.99, + "y": 515.3, + "width": 116.02, + "height": 22.25, + "strokeColor": "#b45309", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1073, + "version": 1, + "versionNonce": 1074, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "chipt38", + "x": 390.99, + "y": 518.3, + "width": 98.02, + "height": 16.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1075, + "version": 1, + "versionNonce": 1076, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "relationships", + "originalText": "relationships", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk39", + "x": 20.0, + "y": 547.55, + "width": 237.33333333333334, + "height": 95.0, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1077, + "version": 1, + "versionNonce": 1078, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki40", + "x": 124.66666666666669, + "y": 558.55, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1079, + "version": 1, + "versionNonce": 1080, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki40", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt41", + "x": 26.0, + "y": 592.55, + "width": 225.33333333333334, + "height": 18.75, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1081, + "version": 1, + "versionNonce": 1082, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Finding/diagnosis definitions", + "originalText": "Finding/diagnosis definitions", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkd42", + "x": 26.0, + "y": 613.3, + "width": 225.33333333333334, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1083, + "version": 1, + "versionNonce": 1084, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "finding models \u00b7 CDEs", + "originalText": "finding models \u00b7 CDEs", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk43", + "x": 321.33333333333337, + "y": 547.55, + "width": 237.33333333333334, + "height": 95.0, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1085, + "version": 1, + "versionNonce": 1086, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki44", + "x": 424.00000000000006, + "y": 556.55, + "width": 32, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1087, + "version": 1, + "versionNonce": 1088, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki44", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt45", + "x": 327.33333333333337, + "y": 592.55, + "width": 225.33333333333334, + "height": 18.75, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1089, + "version": 1, + "versionNonce": 1090, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Anatomic locations", + "originalText": "Anatomic locations", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkd46", + "x": 327.33333333333337, + "y": 613.3, + "width": 225.33333333333334, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1091, + "version": 1, + "versionNonce": 1092, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "anchored in RadLex", + "originalText": "anchored in RadLex", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk47", + "x": 622.6666666666667, + "y": 547.55, + "width": 237.33333333333334, + "height": 95.0, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1093, + "version": 1, + "versionNonce": 1094, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki48", + "x": 725.3333333333334, + "y": 556.55, + "width": 32, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1095, + "version": 1, + "versionNonce": 1096, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki48", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt49", + "x": 628.6666666666667, + "y": 592.55, + "width": 225.33333333333334, + "height": 18.75, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1097, + "version": 1, + "versionNonce": 1098, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Exam types", + "originalText": "Exam types", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkd50", + "x": 628.6666666666667, + "y": 613.3, + "width": 225.33333333333334, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1099, + "version": 1, + "versionNonce": 1100, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "LOINC/RSNA Playbook", + "originalText": "LOINC/RSNA Playbook", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "conn51", + "x": 263.33333333333337, + "y": 595.05, + "width": 52.0, + "height": 0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1101, + "version": 1, + "versionNonce": 1102, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 52.0, + 0 + ] + ], + "startArrowhead": "arrow", + "endArrowhead": "arrow" + }, + { + "type": "arrow", + "id": "conn52", + "x": 564.6666666666667, + "y": 595.05, + "width": 52.0, + "height": 0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1103, + "version": 1, + "versionNonce": 1104, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 52.0, + 0 + ] + ], + "startArrowhead": "arrow", + "endArrowhead": "arrow" + }, + { + "type": "rectangle", + "id": "fill62", + "x": 0, + "y": 377.05, + "width": 880, + "height": 64.0, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1123, + "version": 1, + "versionNonce": 1124, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": null + }, + { + "type": "line", + "id": "ln63", + "x": 864.0, + "y": 377.05, + "width": 16.0, + "height": 16.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1125, + "version": 1, + "versionNonce": 1126, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 16.0, + 16.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln64", + "x": 848.0, + "y": 377.05, + "width": 32.0, + "height": 32.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1127, + "version": 1, + "versionNonce": 1128, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 32.0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln65", + "x": 832.0, + "y": 377.05, + "width": 48.0, + "height": 48.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1129, + "version": 1, + "versionNonce": 1130, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 48.0, + 48.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln66", + "x": 816.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1131, + "version": 1, + "versionNonce": 1132, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln67", + "x": 800.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1133, + "version": 1, + "versionNonce": 1134, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln68", + "x": 784.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1135, + "version": 1, + "versionNonce": 1136, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln69", + "x": 768.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1137, + "version": 1, + "versionNonce": 1138, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln70", + "x": 752.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1139, + "version": 1, + "versionNonce": 1140, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln71", + "x": 736.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1141, + "version": 1, + "versionNonce": 1142, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln72", + "x": 720.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1143, + "version": 1, + "versionNonce": 1144, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln73", + "x": 704.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1145, + "version": 1, + "versionNonce": 1146, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln74", + "x": 688.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1147, + "version": 1, + "versionNonce": 1148, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln75", + "x": 672.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1149, + "version": 1, + "versionNonce": 1150, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln76", + "x": 656.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1151, + "version": 1, + "versionNonce": 1152, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln77", + "x": 640.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1153, + "version": 1, + "versionNonce": 1154, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln78", + "x": 624.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1155, + "version": 1, + "versionNonce": 1156, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln79", + "x": 608.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1157, + "version": 1, + "versionNonce": 1158, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln80", + "x": 592.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1159, + "version": 1, + "versionNonce": 1160, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln81", + "x": 576.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1161, + "version": 1, + "versionNonce": 1162, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln82", + "x": 560.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1163, + "version": 1, + "versionNonce": 1164, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln83", + "x": 544.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1165, + "version": 1, + "versionNonce": 1166, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln84", + "x": 528.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1167, + "version": 1, + "versionNonce": 1168, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln85", + "x": 512.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1169, + "version": 1, + "versionNonce": 1170, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln86", + "x": 496.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1171, + "version": 1, + "versionNonce": 1172, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln87", + "x": 480.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1173, + "version": 1, + "versionNonce": 1174, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln88", + "x": 464.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1175, + "version": 1, + "versionNonce": 1176, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln89", + "x": 448.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1177, + "version": 1, + "versionNonce": 1178, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln90", + "x": 432.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1179, + "version": 1, + "versionNonce": 1180, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln91", + "x": 416.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1181, + "version": 1, + "versionNonce": 1182, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln92", + "x": 400.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1183, + "version": 1, + "versionNonce": 1184, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln93", + "x": 384.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1185, + "version": 1, + "versionNonce": 1186, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln94", + "x": 368.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1187, + "version": 1, + "versionNonce": 1188, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln95", + "x": 352.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1189, + "version": 1, + "versionNonce": 1190, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln96", + "x": 336.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1191, + "version": 1, + "versionNonce": 1192, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln97", + "x": 320.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1193, + "version": 1, + "versionNonce": 1194, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln98", + "x": 304.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1195, + "version": 1, + "versionNonce": 1196, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln99", + "x": 288.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1197, + "version": 1, + "versionNonce": 1198, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln100", + "x": 272.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1199, + "version": 1, + "versionNonce": 1200, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln101", + "x": 256.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1201, + "version": 1, + "versionNonce": 1202, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln102", + "x": 240.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1203, + "version": 1, + "versionNonce": 1204, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln103", + "x": 224.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1205, + "version": 1, + "versionNonce": 1206, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln104", + "x": 208.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1207, + "version": 1, + "versionNonce": 1208, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln105", + "x": 192.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1209, + "version": 1, + "versionNonce": 1210, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln106", + "x": 176.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1211, + "version": 1, + "versionNonce": 1212, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln107", + "x": 160.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1213, + "version": 1, + "versionNonce": 1214, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln108", + "x": 144.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1215, + "version": 1, + "versionNonce": 1216, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln109", + "x": 128.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1217, + "version": 1, + "versionNonce": 1218, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln110", + "x": 112.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1219, + "version": 1, + "versionNonce": 1220, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln111", + "x": 96.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1221, + "version": 1, + "versionNonce": 1222, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln112", + "x": 80.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1223, + "version": 1, + "versionNonce": 1224, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln113", + "x": 64.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1225, + "version": 1, + "versionNonce": 1226, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln114", + "x": 48.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1227, + "version": 1, + "versionNonce": 1228, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln115", + "x": 32.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1229, + "version": 1, + "versionNonce": 1230, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln116", + "x": 16.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1231, + "version": 1, + "versionNonce": 1232, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln117", + "x": 0.0, + "y": 377.05, + "width": 64.0, + "height": 64.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1233, + "version": 1, + "versionNonce": 1234, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 64.0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln118", + "x": 0.0, + "y": 393.05, + "width": 48.0, + "height": 48.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1235, + "version": 1, + "versionNonce": 1236, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 48.0, + 48.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln119", + "x": 0.0, + "y": 409.05, + "width": 32.0, + "height": 32.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1237, + "version": 1, + "versionNonce": 1238, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 32.0, + 32.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln120", + "x": 0.0, + "y": 425.05, + "width": 16.0, + "height": 16.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 25, + "angle": 0, + "seed": 1239, + "version": 1, + "versionNonce": 1240, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 16.0, + 16.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln121", + "x": 0, + "y": 377.05, + "width": 880, + "height": 0.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1241, + "version": 1, + "versionNonce": 1242, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 880, + 0.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln122", + "x": 0, + "y": 441.05, + "width": 880, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1243, + "version": 1, + "versionNonce": 1244, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 880, + 0.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln123", + "x": 0, + "y": 377.05, + "width": 0, + "height": 64.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 55, + "angle": 0, + "seed": 1245, + "version": 1, + "versionNonce": 1246, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln124", + "x": 880, + "y": 377.05, + "width": 0, + "height": 64.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 55, + "angle": 0, + "seed": 1247, + "version": 1, + "versionNonce": 1248, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 0, + 64.0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "plate125", + "x": 20.0, + "y": 397.925, + "width": 142.17999999999998, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1249, + "version": 1, + "versionNonce": 1250, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "platet126", + "x": 27.0, + "y": 400.925, + "width": 128.17999999999998, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1251, + "version": 1, + "versionNonce": 1252, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "attachment points", + "originalText": "attachment points", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "ln127", + "x": 222.57, + "y": 368.05, + "width": 0.0, + "height": 27.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1253, + "version": 1, + "versionNonce": 1254, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 27.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln128", + "x": 222.57, + "y": 423.05, + "width": 0.0, + "height": 27.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1255, + "version": 1, + "versionNonce": 1256, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 27.0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "pill129", + "x": 182.17999999999998, + "y": 395.05, + "width": 80.78, + "height": 28.0, + "strokeColor": "#64748b", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1257, + "version": 1, + "versionNonce": 1258, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "pillt130", + "x": 182.17999999999998, + "y": 400.925, + "width": 80.78, + "height": 16.25, + "strokeColor": "#334155", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1259, + "version": 1, + "versionNonce": 1260, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "finding", + "originalText": "finding", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "ln131", + "x": 416.5566666666667, + "y": 368.05, + "width": 0.0, + "height": 27.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1261, + "version": 1, + "versionNonce": 1262, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 27.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln132", + "x": 416.5566666666667, + "y": 423.05, + "width": 0.0, + "height": 27.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1263, + "version": 1, + "versionNonce": 1264, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 27.0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "pill133", + "x": 368.62666666666667, + "y": 395.05, + "width": 95.86, + "height": 28.0, + "strokeColor": "#64748b", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1265, + "version": 1, + "versionNonce": 1266, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "pillt134", + "x": 368.62666666666667, + "y": 400.925, + "width": 95.86, + "height": 16.25, + "strokeColor": "#334155", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1267, + "version": 1, + "versionNonce": 1268, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "diagnosis", + "originalText": "diagnosis", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "ln135", + "x": 614.3133333333334, + "y": 368.05, + "width": 0.0, + "height": 27.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1269, + "version": 1, + "versionNonce": 1270, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 27.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln136", + "x": 614.3133333333334, + "y": 423.05, + "width": 0.0, + "height": 27.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1271, + "version": 1, + "versionNonce": 1272, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 27.0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "pill137", + "x": 570.1533333333334, + "y": 395.05, + "width": 88.32, + "height": 28.0, + "strokeColor": "#64748b", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1273, + "version": 1, + "versionNonce": 1274, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "pillt138", + "x": 570.1533333333334, + "y": 400.925, + "width": 88.32, + "height": 16.25, + "strokeColor": "#334155", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1275, + "version": 1, + "versionNonce": 1276, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "location", + "originalText": "location", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "ln139", + "x": 812.07, + "y": 368.05, + "width": 0.0, + "height": 27.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1277, + "version": 1, + "versionNonce": 1278, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 27.0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "ln140", + "x": 812.07, + "y": 423.05, + "width": 0.0, + "height": 27.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1279, + "version": 1, + "versionNonce": 1280, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 0.0, + 27.0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "pill141", + "x": 764.1400000000001, + "y": 395.05, + "width": 95.86, + "height": 28.0, + "strokeColor": "#64748b", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1281, + "version": 1, + "versionNonce": 1282, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "pillt142", + "x": 764.1400000000001, + "y": 400.925, + "width": 95.86, + "height": 16.25, + "strokeColor": "#334155", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1283, + "version": 1, + "versionNonce": 1284, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "exam type", + "originalText": "exam type", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + } + ], + "appState": { + "viewBackgroundColor": "#ffffff", + "gridSize": null + }, + "files": { + "img_bicon3": { + "mimeType": "image/svg+xml", + "id": "img_bicon3", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiNiZTEyM2MiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTE1IDE0Yy4yLTEgLjctMS43IDEuNS0yLjUgMS0uOSAxLjUtMi4yIDEuNS0zLjVBNiA2IDAgMCAwIDYgOGMwIDEgLjIgMi4yIDEuNSAzLjUuNy43IDEuMyAxLjUgMS41IDIuNSIgLz4KICA8cGF0aCBkPSJNOSAxOGg2IiAvPgogIDxwYXRoIGQ9Ik0xMCAyMmg0IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_bicon6": { + "mimeType": "image/svg+xml", + "id": "img_bicon6", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMxNTgwM2QiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHJlY3QgeD0iMiIgeT0iNCIgd2lkdGg9IjIwIiBoZWlnaHQ9IjE2IiByeD0iMiIgLz4KICA8cGF0aCBkPSJNMTAgNHY0IiAvPgogIDxwYXRoIGQ9Ik0yIDhoMjAiIC8+CiAgPHBhdGggZD0iTTYgNHY0IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_bicon12": { + "mimeType": "image/svg+xml", + "id": "img_bicon12", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiM2ZDI4ZDkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTExIDIxLjczYTIgMiAwIDAgMCAyIDBsNy00QTIgMiAwIDAgMCAyMSAxNlY4YTIgMiAwIDAgMC0xLTEuNzNsLTctNGEyIDIgMCAwIDAtMiAwbC03IDRBMiAyIDAgMCAwIDMgOHY4YTIgMiAwIDAgMCAxIDEuNzN6IiAvPgogIDxwYXRoIGQ9Ik0xMiAyMlYxMiIgLz4KICA8cG9seWxpbmUgcG9pbnRzPSIzLjI5IDcgMTIgMTIgMjAuNzEgNyIgLz4KICA8cGF0aCBkPSJtNy41IDQuMjcgOSA1LjE1IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_bicon16": { + "mimeType": "image/svg+xml", + "id": "img_bicon16", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyLjgzIDIuMThhMiAyIDAgMCAwLTEuNjYgMEwyLjYgNi4wOGExIDEgMCAwIDAgMCAxLjgzbDguNTggMy45MWEyIDIgMCAwIDAgMS42NiAwbDguNTgtMy45YTEgMSAwIDAgMCAwLTEuODN6IiAvPgogIDxwYXRoIGQ9Ik0yIDEyYTEgMSAwIDAgMCAuNTguOTFsOC42IDMuOTFhMiAyIDAgMCAwIDEuNjUgMGw4LjU4LTMuOUExIDEgMCAwIDAgMjIgMTIiIC8+CiAgPHBhdGggZD0iTTIgMTdhMSAxIDAgMCAwIC41OC45MWw4LjYgMy45MWEyIDIgMCAwIDAgMS42NSAwbDguNTgtMy45QTEgMSAwIDAgMCAyMiAxNyIgLz4KPC9zdmc+Cg==", + "created": 1700000000000 + }, + "img_blki20": { + "mimeType": "image/svg+xml", + "id": "img_blki20", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHJlY3Qgd2lkdGg9IjgiIGhlaWdodD0iNCIgeD0iOCIgeT0iMiIgcng9IjEiIHJ5PSIxIiAvPgogIDxwYXRoIGQ9Ik0xNiA0aDJhMiAyIDAgMCAxIDIgMnYxNGEyIDIgMCAwIDEtMiAySDZhMiAyIDAgMCAxLTItMlY2YTIgMiAwIDAgMSAyLTJoMiIgLz4KPC9zdmc+Cg==", + "created": 1700000000000 + }, + "img_blki23": { + "mimeType": "image/svg+xml", + "id": "img_blki23", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHJlY3Qgd2lkdGg9IjgiIGhlaWdodD0iNCIgeD0iOCIgeT0iMiIgcng9IjEiIHJ5PSIxIiAvPgogIDxwYXRoIGQ9Ik0xNiA0aDJhMiAyIDAgMCAxIDIgMnYxNGEyIDIgMCAwIDEtMiAySDZhMiAyIDAgMCAxLTItMlY2YTIgMiAwIDAgMSAyLTJoMiIgLz4KICA8cGF0aCBkPSJNMTIgMTFoNCIgLz4KICA8cGF0aCBkPSJNMTIgMTZoNCIgLz4KICA8cGF0aCBkPSJNOCAxMWguMDEiIC8+CiAgPHBhdGggZD0iTTggMTZoLjAxIiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki27": { + "mimeType": "image/svg+xml", + "id": "img_blki27", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTMgNWguMDEiIC8+CiAgPHBhdGggZD0iTTMgMTJoLjAxIiAvPgogIDxwYXRoIGQ9Ik0zIDE5aC4wMSIgLz4KICA8cGF0aCBkPSJNOCA1aDEzIiAvPgogIDxwYXRoIGQ9Ik04IDEyaDEzIiAvPgogIDxwYXRoIGQ9Ik04IDE5aDEzIiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki31": { + "mimeType": "image/svg+xml", + "id": "img_blki31", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yNCAyNEMyOC40MjA0IDI0IDMyIDIwLjQyMDQgMzIgMTZDMzIgMTEuNTc5NiAyOC40MjA0IDggMjQgOEMxOS41Nzk2IDggMTYgMTEuNTc5NiAxNiAxNkMxNiAyMC40MjA0IDE5LjU3OTYgMjQgMjQgMjRaTTM0IDE2QzM0IDIxLjUyNSAyOS41MjUgMjYgMjQgMjZDMTguNDc1IDI2IDE0IDIxLjUyNSAxNCAxNkMxNCAxMC40NzUgMTguNDc1IDYgMjQgNkMyOS41MjUgNiAzNCAxMC40NzUgMzQgMTZaIiBmaWxsPSIjMGY3NjZlIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNOS4yMjM0OCAzNC4yMTE5QzguMjIwMzggMzUuMDIxMSA4IDM1LjYyOTEgOCAzNlY0MEg0MFYzNkM0MCAzNS42MjkxIDM5Ljc3OTYgMzUuMDIxMSAzOC43NzY1IDM0LjIxMTlDMzcuNzk1OCAzMy40MjA3IDM2LjMzNDEgMzIuNjY2OSAzNC41NjIyIDMyLjAxNUMzMS4wMTk5IDMwLjcxMTcgMjYuNzUzMiAzMCAyNCAzMEMyMS4yNDY4IDMwIDE2Ljk4MDEgMzAuNzExNyAxMy40Mzc4IDMyLjAxNUMxMS42NjU5IDMyLjY2NjkgMTAuMjA0MiAzMy40MjA3IDkuMjIzNDggMzQuMjExOVpNMjQgMjhDMTcuOTkyNSAyOCA2IDMxLjAzNDcgNiAzNlY0Mkg0MlYzNkM0MiAzMS4wMzQ3IDMwLjAwNzUgMjggMjQgMjhaIiBmaWxsPSIjMGY3NjZlIi8+Cjwvc3ZnPgo=", + "created": 1700000000000 + }, + "img_bicon34": { + "mimeType": "image/svg+xml", + "id": "img_bicon34", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiNiNDUzMDkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyIDV2MTYiIC8+CiAgPHBhdGggZD0iTTIwLjAwMSAxOUEyIDIgMCAwMDIyIDE3VjVhMiAyIDAgMDAtMS45OTktMkwxNiAzLjAwMkE1IDUgMCAwMDEyIDVhNSA1IDAgMDAtNC0ySDRhMiAyIDAgMDAtMiAydjEyYTIgMiAwIDAwMS45OTkgMkg4YTUgNSAwIDAxNCAyIDUgNSAwIDAxNC0yeiIgLz4KPC9zdmc+Cg==", + "created": 1700000000000 + }, + "img_blki40": { + "mimeType": "image/svg+xml", + "id": "img_blki40", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiNiNDUzMDkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyLjU4NiAyLjU4NkEyIDIgMCAwIDAgMTEuMTcyIDJINGEyIDIgMCAwIDAtMiAydjcuMTcyYTIgMiAwIDAgMCAuNTg2IDEuNDE0bDguNzA0IDguNzA0YTIuNDI2IDIuNDI2IDAgMCAwIDMuNDIgMGw2LjU4LTYuNThhMi40MjYgMi40MjYgMCAwIDAgMC0zLjQyeiIgLz4KICA8Y2lyY2xlIGN4PSI3LjUiIGN5PSI3LjUiIHI9Ii41IiBmaWxsPSIjYjQ1MzA5IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki44": { + "mimeType": "image/svg+xml", + "id": "img_blki44", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yMyA2LjAwMDEzQzIzIDYuMDAwMDQgMjMgNiAyNCA2SDI0LjE3NjFDMjQuMjUzMyA2IDI0LjMyMzMgNiAyNC4zODY4IDZDMjUgNi4wMDAwMSAyNSA2LjAwMDA1IDI1IDYuMDAwMTNWMjAuNUMyNSAyMS44OTc3IDI1LjU2NDEgMjIuNDQyMSAyNi4wMDM5IDIyLjY5ODdDMjYuMDUzIDIyLjcyNzMgMjYuMTAyNCAyMi43NTMzIDI2LjE1MTYgMjIuNzc3QzI2LjE1MDYgMjIuNjU2OCAyNi4xNDkzIDIyLjUzMTYgMjYuMTQ3OSAyMi40MDE5TDI2LjE0NzkgMjIuNDAwM0MyNi4xMTAxIDE4Ljg3MTYgMjYuMDM2NSAxMS45OTk3IDMxLjQ3NTMgMTEuOTk5N0MzOC45MjU5IDExLjk5OTcgNDQuMjQ3OCAzOC4wMDYyIDQxLjA1NDcgNDAuNjU5OUMzNy44NjE1IDQzLjMxMzYgMzEuNDc1MyA0MS43MjE0IDI4LjI4MjIgMzguNTM2OUMyNS43MDQyIDM1Ljk2NTkgMjUuOTI3MiAyOS45NTgzIDI2LjA4NzMgMjUuNjQ1N0wyNi4wODc0IDI1LjY0NDNDMjYuMDk3MSAyNS4zODE5IDI2LjEwNjcgMjUuMTI1OCAyNi4xMTUzIDI0Ljg3NzFDMjUuNzkgMjQuNzk2MiAyNS4zOTU5IDI0LjY1OTUgMjQuOTk2MiAyNC40MjYzQzI0LjYzOTggMjQuMjE4NCAyNC4yOTc1IDIzLjk0NDIgMjQgMjMuNTkxOUMyMy43MDI2IDIzLjk0NDIgMjMuMzYwMyAyNC4yMTg0IDIzLjAwMzkgMjQuNDI2M0MyMi42MDQxIDI0LjY1OTUgMjIuMjEwMSAyNC43OTYyIDIxLjg4NDggMjQuODc3MUMyMS44OTM0IDI1LjEyNjEgMjEuOTAyOSAyNS4zODI2IDIxLjkxMjcgMjUuNjQ1M0MyMi4wNzI4IDI5Ljk1NzkgMjIuMjk1OSAzNS45NjYyIDE5LjcxNzkgMzguNTM3MkMxNi41MjQ3IDQxLjcyMTcgMTAuMTM4NSA0My4zMTM5IDYuOTQ1MzYgNDAuNjYwMkMzLjc1MjIyIDM4LjAwNjUgOS4wNzQxMyAxMiAxNi41MjQ3IDEyQzIxLjk2MzYgMTIgMjEuODkgMTguODcxNyAyMS44NTIyIDIyLjQwMDNDMjEuODUyIDIyLjQxNjYgMjEuODUxOCAyMi40MzI4IDIxLjg1MTYgMjIuNDQ4OUMyMS44NTA0IDIyLjU2MTkgMjEuODQ5MyAyMi42NzE0IDIxLjg0ODQgMjIuNzc3QzIxLjg5NzcgMjIuNzUzNCAyMS45NDcxIDIyLjcyNzQgMjEuOTk2MiAyMi42OTg3QzIyLjQzNiAyMi40NDIxIDIzIDIxLjg5NzcgMjMgMjAuNVY2LjAwMDEzWk0zMS40NzUzIDEzLjk5OTdDMzAuNTIxMiAxMy45OTk3IDI5Ljk4NDMgMTQuMzAwMiAyOS42MDg2IDE0LjY4NjlDMjkuMTc1MiAxNS4xMzMxIDI4LjgxMzIgMTUuODUwNyAyOC41NTkgMTYuODY0NkMyOC4xMTQxIDE4LjYzOTUgMjguMTMzIDIwLjY4MTkgMjguMTQ4MyAyMi4zMjkzQzI4LjE1MDkgMjIuNjE0MiAyOC4xNTM0IDIyLjg4NzQgMjguMTUzNCAyMy4xNDUzQzI4LjE1MzQgMjMuOTA1MyAyOC4xMTk2IDI0LjgxNTMgMjguMDg0NSAyNS43NjIxQzI4LjA3MDcgMjYuMTM0OSAyOC4wNTY2IDI2LjUxMzMgMjguMDQ0MyAyNi44OTA1QzI3Ljk5OTYgMjguMjY1NyAyNy45NzQxIDI5LjcwNTUgMjguMDQwNSAzMS4wOTgyQzI4LjEwNzIgMzIuNDk4NSAyOC4yNjQyIDMzLjc4MzUgMjguNTU3MyAzNC44NTk2QzI4Ljg1MzggMzUuOTQ4MyAyOS4yNTA5IDM2LjY3ODQgMjkuNjk0NCAzNy4xMjA4QzMwLjk3MjYgMzguMzk1NCAzMi45OTA4IDM5LjQyNTEgMzUuMDQ5MiAzOS44MjQzQzM3LjA4NDIgNDAuMjE4OSAzOC43MjI0IDM5LjkyNjkgMzkuNjgxOCAzOS4xOTY5QzM5LjY4NjggMzkuMTg1NyAzOS42OTIzIDM5LjE3MjYgMzkuNjk4NCAzOS4xNTc0QzM5Ljc1NzYgMzkuMDA5NSAzOS44Mjk0IDM4Ljc1NTQgMzkuODg3OCAzOC4zNjgzQzQwLjAwNDcgMzcuNTkzMyA0MC4wMzUgMzYuNTEyMiAzOS45NTYyIDM1LjE4MDNDMzkuNzk5NSAzMi41MzA1IDM5LjIyODYgMjkuMTY4OSAzOC4zMjY4IDI1Ljg2MDZDMzcuNDIxNiAyMi41Mzk2IDM2LjIxNzMgMTkuMzk5OCAzNC44NTIxIDE3LjEzODNDMzQuMTY4OCAxNi4wMDYyIDMzLjQ5NTEgMTUuMTc4NiAzMi44NzAzIDE0LjY1MzVDMzIuMjUxOCAxNC4xMzM3IDMxLjc5MzUgMTMuOTk5NyAzMS40NzUzIDEzLjk5OTdaTTE2LjUyNDcgMTRDMTcuNDc4OCAxNCAxOC4wMTU4IDE0LjMwMDUgMTguMzkxNCAxNC42ODcyQzE4LjgyNDggMTUuMTMzNCAxOS4xODY4IDE1Ljg1MSAxOS40NDEgMTYuODY0OUMxOS44ODU5IDE4LjYzOTkgMTkuODY3IDIwLjY4MjIgMTkuODUxOCAyMi4zMjk2QzE5Ljg0OTEgMjIuNjE0NiAxOS44NDY2IDIyLjg4NzcgMTkuODQ2NiAyMy4xNDU2QzE5Ljg0NjYgMjMuOTA1NiAxOS44ODA0IDI0LjgxNTYgMTkuOTE1NSAyNS43NjI0QzE5LjkyOTQgMjYuMTM1IDE5Ljk0MzQgMjYuNTEzOCAxOS45NTU3IDI2Ljg5MDhDMjAuMDAwNSAyOC4yNjYgMjAuMDI1OSAyOS43MDU4IDE5Ljk1OTYgMzEuMDk4NUMxOS44OTI5IDMyLjQ5ODggMTkuNzM1OSAzMy43ODM4IDE5LjQ0MjcgMzQuODU5OUMxOS4xNDYyIDM1Ljk0ODYgMTguNzQ5MiAzNi42Nzg3IDE4LjMwNTYgMzcuMTIxMUMxNy4wMjc1IDM4LjM5NTcgMTUuMDA5MyAzOS40MjU0IDEyLjk1MDkgMzkuODI0NkMxMC45MTU5IDQwLjIxOTIgOS4yNzc2OCAzOS45MjcyIDguMzE4MjMgMzkuMTk3MkM4LjMxMzI2IDM5LjE4NiA4LjMwNzcgMzkuMTcyOSA4LjMwMTYyIDM5LjE1NzdDOC4yNDI0MSAzOS4wMDk4IDguMTcwNjEgMzguNzU1NyA4LjExMjI0IDM4LjM2ODZDNy45OTUzOSAzNy41OTM2IDcuOTY1IDM2LjUxMjUgOC4wNDM4IDM1LjE4MDZDOC4yMDA1NiAzMi41MzA4IDguNzcxNDcgMjkuMTY5MiA5LjY3MzI0IDI1Ljg2MDlDMTAuNTc4NSAyMi41Mzk5IDExLjc4MjcgMTkuNDAwMSAxMy4xNDc5IDE3LjEzODZDMTMuODMxMyAxNi4wMDY1IDE0LjUwNDkgMTUuMTc4OSAxNS4xMjk4IDE0LjY1MzhDMTUuNzQ4MiAxNC4xMzQgMTYuMjA2NSAxNCAxNi41MjQ3IDE0WiIgZmlsbD0iI2I0NTMwOSIvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki48": { + "mimeType": "image/svg+xml", + "id": "img_blki48", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yOSA5QzI5IDExLjc2MTQgMjYuNzYxNCAxNCAyNCAxNEMyMS4yMzg2IDE0IDE5IDExLjc2MTQgMTkgOUMxOSA2LjIzODU4IDIxLjIzODYgNCAyNCA0QzI2Ljc2MTQgNCAyOSA2LjIzODU4IDI5IDlaTTI3IDlDMjcgMTAuNjU2OSAyNS42NTY5IDEyIDI0IDEyQzIyLjM0MzEgMTIgMjEgMTAuNjU2OSAyMSA5QzIxIDcuMzQzMTUgMjIuMzQzMSA2IDI0IDZDMjUuNjU2OSA2IDI3IDcuMzQzMTUgMjcgOVoiIGZpbGw9IiNiNDUzMDkiLz4KPHBhdGggZD0iTTE2Ljk5OTggNDFWMzRIMTguOTk5OFY0MUMxOC45OTk4IDQxLjU1MjMgMTkuNDQ3NSA0MiAxOS45OTk4IDQySDIwLjA4NjVDMjAuNjAzNyA0MiAyMS4wMzU2IDQxLjYwNTYgMjEuMDgyNCA0MS4wOTA1TDIxLjcyNyAzNEgyMy43MzUzTDIzLjA3NDIgNDEuMjcxNkMyMy4wNjkgNDEuMzI4OCAyMy4wNjIyIDQxLjM4NTYgMjMuMDUzOSA0MS40NDE3QzIzLjAzNTcgNDEuNTY0NyAyMy4wMTAxIDQxLjY4NTEgMjIuOTc3NiA0MS44MDI1QzIyLjYyNDIgNDMuMDc5OCAyMS40NTQ5IDQ0IDIwLjA4NjUgNDRIMTkuOTk5OEMxOC4zNDI5IDQ0IDE2Ljk5OTggNDIuNjU2OSAxNi45OTk4IDQxWiIgZmlsbD0iI2I0NTMwOSIvPgo8cGF0aCBkPSJNMjYuOTE3MSA0MS4wOTA1TDI2LjI3MjUgMzRIMjQuMjY0MkwyNC45MjUzIDQxLjI3MTZDMjQuOTMwNSA0MS4zMjg4IDI0LjkzNzMgNDEuMzg1NiAyNC45NDU2IDQxLjQ0MTdDMjQuOTYzOCA0MS41NjQ3IDI0Ljk4OTQgNDEuNjg1MSAyNS4wMjE5IDQxLjgwMjVDMjUuMzc1MyA0My4wNzk4IDI2LjU0NDYgNDQgMjcuOTEzIDQ0SDI3Ljk5OThDMjkuNjU2NiA0NCAzMC45OTk4IDQyLjY1NjkgMzAuOTk5OCA0MVYzNEgyOC45OTk4VjQxQzI4Ljk5OTggNDEuNTUyMyAyOC41NTIgNDIgMjcuOTk5OCA0MkgyNy45MTNDMjcuMzk1OCA0MiAyNi45NjM5IDQxLjYwNTYgMjYuOTE3MSA0MS4wOTA1WiIgZmlsbD0iI2I0NTMwOSIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTExIDE1QzEwLjQ0NzcgMTUgMTAgMTUuNDQ3NyAxMCAxNlYzMUMxMCAzMS41NTIzIDEwLjQ0NzcgMzIgMTEgMzJIMzdDMzcuNTUyMyAzMiAzOCAzMS41NTIzIDM4IDMxVjE2QzM4IDE1LjQ0NzcgMzcuNTUyMyAxNSAzNyAxNUgxMVpNMTIgMTdWMzBIMTkuNUMxOS41IDI5LjQ0MjQgMTkuNzU5MSAyOC45NTcyIDIwLjAyNzYgMjguNjAwNkMyMC4zMDg2IDI4LjIyNzYgMjAuNjc5NiAyNy44ODgzIDIxLjA3OTQgMjcuNjAxNkMyMS42MjUyIDI3LjIxMDMgMjIuMjk4NiAyNi44NjUgMjMgMjYuNjY3OFYyNC41SDIyLjJDMjEuNTk3MyAyNC41IDIwLjc1MzUgMjQuODY0MiAxOS45NDMzIDI1LjM1NTJDMTkuNTYzOCAyNS41ODUyIDE5LjIzMzcgMjUuODE2NyAxOC45OTg0IDI1Ljk5MTFDMTguODgxMiAyNi4wNzc4IDE4Ljc4ODggMjYuMTQ5NSAxOC43MjcgMjYuMTk4NEMxOC42OTYxIDI2LjIyMjggMTguNjczIDI2LjI0MTUgMTguNjU4MiAyNi4yNTM1TDE4LjY0MjYgMjYuMjY2M0wxOC42Mzk5IDI2LjI2ODRDMTguNjM5OSAyNi4yNjg0IDE4LjY0MDIgMjYuMjY4MiAxOCAyNS41QzE3LjM1OTggMjQuNzMxOCAxNy4zNjAxIDI0LjczMTUgMTcuMzYwMSAyNC43MzE1TDE3LjM2MTQgMjQuNzMwNUwxNy4zNjM4IDI0LjcyODVMMTcuMzcxMyAyNC43MjIzTDE3LjM5NjYgMjQuNzAxNkMxNy40MTc5IDI0LjY4NDMgMTcuNDQ4IDI0LjY2IDE3LjQ4NjMgMjQuNjI5N0MxNy41NjI3IDI0LjU2OTMgMTcuNjcxOSAyNC40ODQ3IDE3LjgwNzkgMjQuMzgzOUMxOC4wNzg4IDI0LjE4MzMgMTguNDYxMiAyMy45MTQ4IDE4LjkwNjcgMjMuNjQ0OEMxOS43NDY1IDIzLjEzNTggMjEuMDAyNyAyMi41IDIyLjIgMjIuNUgyM1YyMC41SDIyLjVDMjEuOTMwOSAyMC41IDIxLjE5MDkgMjAuNjk5MiAyMC41MjkyIDIwLjkzOThDMjAuMjEyIDIxLjA1NTIgMTkuOTM3IDIxLjE3MDkgMTkuNzQyMSAyMS4yNTc2QzE5LjY0NDkgMjEuMzAwNyAxOS41Njg1IDIxLjMzNjMgMTkuNTE3NiAyMS4zNjA1QzE5LjQ5MjIgMjEuMzcyNSAxOS40NzMyIDIxLjM4MTcgMTkuNDYxMyAyMS4zODc1TDE5LjQ0ODcgMjEuMzkzN0wxOS40NDcgMjEuMzk0NUMxOS40NDcgMjEuMzk0NSAxOS40NDcyIDIxLjM5NDQgMTkgMjAuNUMxOC41NTI4IDE5LjYwNTYgMTguNTUzMSAxOS42MDU0IDE4LjU1MzEgMTkuNjA1NEwxOC41NTY0IDE5LjYwMzhMMTguNTYyOSAxOS42MDA2TDE4LjU4NDQgMTkuNTlDMTguNjAyNSAxOS41ODEyIDE4LjYyNzkgMTkuNTY4OSAxOC42NjAxIDE5LjU1MzZDMTguNzI0NSAxOS41MjMxIDE4LjgxNiAxOS40ODA1IDE4LjkyOTggMTkuNDI5OUMxOS4xNTY3IDE5LjMyOTEgMTkuNDc1NSAxOS4xOTQ4IDE5Ljg0NTggMTkuMDYwMkMyMC41NTkxIDE4LjgwMDggMjEuNTY5MSAxOC41IDIyLjUgMTguNUgyM1YxN0gxMlpNMjUgMjQuNUgyNi4xQzI2Ljg0ODkgMjQuNSAyNy42MTg2IDI0Ljg2NjMgMjguMjYzMSAyNS4zMTg2QzI4LjU3MzUgMjUuNTM2NCAyOC44Mjg1IDI1Ljc1NTYgMjkuMDA0OCAyNS45MTk3QzI5LjA5MjUgMjYuMDAxMiAyOS4xNTk0IDI2LjA2NzkgMjkuMjAyNiAyNi4xMTIyQzI5LjIyNDEgMjYuMTM0MyAyOS4yMzk3IDI2LjE1MDcgMjkuMjQ4OCAyNi4xNjA1TDI5LjI1NzQgMjYuMTY5N0MyOS4yNTc0IDI2LjE2OTcgMjkuMjU2NyAyNi4xNjkgMzAgMjUuNUMzMC43NDMzIDI0LjgzMSAzMC43NDI5IDI0LjgzMDYgMzAuNzQyOSAyNC44MzA2TDMwLjc0MTQgMjQuODI5TDMwLjczODkgMjQuODI2MkwzMC43MzE4IDI0LjgxODRMMzAuNzA5NyAyNC43OTQ2QzMwLjY5MTUgMjQuNzc1MSAzMC42NjYzIDI0Ljc0ODUgMzAuNjM0NiAyNC43MTZDMzAuNTcxMSAyNC42NTA5IDMwLjQ4MDkgMjQuNTYxMyAzMC4zNjcgMjQuNDU1M0MzMC4xNDAzIDI0LjI0NDQgMjkuODE0IDIzLjk2MzYgMjkuNDExOSAyMy42ODE0QzI4LjYzMTQgMjMuMTMzNyAyNy40NTExIDIyLjUgMjYuMSAyMi41SDI1VjIwLjVIMjUuNzVDMjYuNDQ0MyAyMC41IDI3LjExOTMgMjAuNzAxMSAyNy42NDMyIDIwLjkyMTZDMjcuOTAwMyAyMS4wMjk5IDI4LjEwOTIgMjEuMTM3OCAyOC4yNTA5IDIxLjIxNjlDMjguMzIxNSAyMS4yNTY0IDI4LjM3NDcgMjEuMjg4MiAyOC40MDggMjEuMzA4N0MyOC40MjQ3IDIxLjMxODkgMjguNDM2MyAyMS4zMjYzIDI4LjQ0MjcgMjEuMzMwNEwyOC40NDU3IDIxLjMzMjNDMjguNDQ1NyAyMS4zMzIzIDI4LjQ0NTMgMjEuMzMyMSAyOSAyMC41QzI5LjU1NDcgMTkuNjY3OSAyOS41NTQyIDE5LjY2NzYgMjkuNTU0MiAxOS42Njc2TDI5LjU1MjcgMTkuNjY2NkwyOS41NTAxIDE5LjY2NDlMMjkuNTQzMiAxOS42NjA0TDI5LjUyMjggMTkuNjQ3MkMyOS41MDYzIDE5LjYzNjYgMjkuNDg0IDE5LjYyMjUgMjkuNDU2MiAxOS42MDU0QzI5LjQwMDcgMTkuNTcxMiAyOS4zMjMgMTkuNTI0OSAyOS4yMjU2IDE5LjQ3MDZDMjkuMDMxNSAxOS4zNjIyIDI4Ljc1NTkgMTkuMjIwMSAyOC40MTkzIDE5LjA3ODRDMjcuNzU1NyAxOC43OTg5IDI2LjgwNTcgMTguNSAyNS43NSAxOC41SDI1VjE3SDM2VjMwSDI4LjVDMjguNSAyOS40Mzc5IDI4LjIzMjQgMjguOTQ1MiAyNy45NjQxIDI4LjU4NzVDMjcuNjgwMyAyOC4yMDkyIDI3LjMwNTQgMjcuODYwNiAyNi45MDA3IDI3LjU2NjNDMjYuMzY3NSAyNy4xNzg1IDI1LjY5ODkgMjYuODI1NyAyNSAyNi42MzkxVjI0LjVaTTI2LjQ5MjkgMzBDMjYuNDc5NyAyOS45NjcgMjYuNDQ1NyAyOS44OTY0IDI2LjM2NDEgMjkuNzg3NUMyNi4yMjU5IDI5LjYwMzMgMjYuMDA3MSAyOS4zODk0IDI1LjcyNDMgMjkuMTgzN0MyNS4xNDc4IDI4Ljc2NDUgMjQuNDkzNyAyOC41MTE3IDI0LjAzMiAyOC41MDA0QzIzLjQ4NzcgMjguNTQ2NCAyMi44MDUyIDI4LjgyNTIgMjIuMjQ0OSAyOS4yMjdDMjEuOTY1NyAyOS40MjcyIDIxLjc1NTYgMjkuNjMwNyAyMS42MjUyIDI5LjgwMzhDMjEuNTQ5NiAyOS45MDQzIDIxLjUxODQgMjkuOTY5NCAyMS41MDYzIDMwSDI2LjQ5MjlaIiBmaWxsPSIjYjQ1MzA5Ii8+Cjwvc3ZnPgo=", + "created": 1700000000000 + } + } +} \ No newline at end of file diff --git a/knowledge/drafts/pillars.excalidraw b/knowledge/drafts/pillars.excalidraw new file mode 100644 index 0000000..b467354 --- /dev/null +++ b/knowledge/drafts/pillars.excalidraw @@ -0,0 +1,2161 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "oidm-knowledge/tools/diagrams", + "elements": [ + { + "type": "rectangle", + "id": "band53", + "x": 0, + "y": 375.05, + "width": 880, + "height": 319.74999999999994, + "strokeColor": "#b45309", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1105, + "version": 1, + "versionNonce": 1106, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "band33", + "x": 0, + "y": 187.3, + "width": 880, + "height": 223.75, + "strokeColor": "#0f766e", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1065, + "version": 1, + "versionNonce": 1066, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "band15", + "x": 0, + "y": 91.65, + "width": 880, + "height": 71.65, + "strokeColor": "#6d28d9", + "backgroundColor": "#ede9fe", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1029, + "version": 1, + "versionNonce": 1030, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "panel1", + "x": 0, + "y": 0, + "width": 388.0, + "height": 67.65, + "strokeColor": "#be123c", + "backgroundColor": "#ffe4e6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1001, + "version": 1, + "versionNonce": 1002, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "panel2", + "x": 492.0, + "y": 0, + "width": 388.0, + "height": 67.65, + "strokeColor": "#15803d", + "backgroundColor": "#dcfce7", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1003, + "version": 1, + "versionNonce": 1004, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "bicon3", + "x": 18, + "y": 12.0, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1005, + "version": 1, + "versionNonce": 1006, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon3", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle4", + "x": 58, + "y": 14, + "width": 93.96, + "height": 22.5, + "strokeColor": "#881337", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1007, + "version": 1, + "versionNonce": 1008, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Use Cases", + "originalText": "Use Cases", + "fontSize": 18, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub5", + "x": 58, + "y": 37.400000000000006, + "width": 211.11999999999998, + "height": 16.25, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1009, + "version": 1, + "versionNonce": 1010, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "what the project wants built", + "originalText": "what the project wants built", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon6", + "x": 510.0, + "y": 12.0, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1011, + "version": 1, + "versionNonce": 1012, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon6", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle7", + "x": 550.0, + "y": 14, + "width": 198.35999999999999, + "height": 22.5, + "strokeColor": "#14532d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1013, + "version": 1, + "versionNonce": 1014, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Sample Applications", + "originalText": "Sample Applications", + "fontSize": 18, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub8", + "x": 550.0, + "y": 37.400000000000006, + "width": 143.26, + "height": 16.25, + "strokeColor": "#15803d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1015, + "version": 1, + "versionNonce": 1016, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "what has been built", + "originalText": "what has been built", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "conn9", + "x": 390.0, + "y": 33.825, + "width": 100.0, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1017, + "version": 1, + "versionNonce": 1018, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 100.0, + 0 + ] + ] + }, + { + "type": "rectangle", + "id": "chip10", + "x": 389.53, + "y": 4.575000000000003, + "width": 100.94, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1019, + "version": 1, + "versionNonce": 1020, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "chipt11", + "x": 398.53, + "y": 7.575000000000003, + "width": 82.94, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1021, + "version": 1, + "versionNonce": 1022, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "illustrates", + "originalText": "illustrates", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon12", + "x": 18, + "y": 105.65, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1023, + "version": 1, + "versionNonce": 1024, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon12", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle13", + "x": 58, + "y": 107.65, + "width": 41.76, + "height": 22.5, + "strokeColor": "#4c1d95", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1025, + "version": 1, + "versionNonce": 1026, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "SDKs", + "originalText": "SDKs", + "fontSize": 18, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub14", + "x": 58, + "y": 131.05, + "width": 520.26, + "height": 16.25, + "strokeColor": "#6d28d9", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1027, + "version": 1, + "versionNonce": 1028, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "wrap the structures \u00b7 attach the shared knowledge \u00b7 support authoring", + "originalText": "wrap the structures \u00b7 attach the shared knowledge \u00b7 support authoring", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon16", + "x": 18, + "y": 203.3, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1031, + "version": 1, + "versionNonce": 1032, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon16", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle17", + "x": 58, + "y": 205.3, + "width": 174.0, + "height": 25.0, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1033, + "version": 1, + "versionNonce": 1034, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Data Structures", + "originalText": "Data Structures", + "fontSize": 20, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub18", + "x": 58, + "y": 231.3, + "width": 226.2, + "height": 16.25, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1035, + "version": 1, + "versionNonce": 1036, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "this patient \u00b7 Patient Context", + "originalText": "this patient \u00b7 Patient Context", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk19", + "x": 20.0, + "y": 261.55, + "width": 195.0, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1037, + "version": 1, + "versionNonce": 1038, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki20", + "x": 103.5, + "y": 281.925, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1039, + "version": 1, + "versionNonce": 1040, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki20", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt21", + "x": 26.0, + "y": 315.925, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1041, + "version": 1, + "versionNonce": 1042, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Observation", + "originalText": "Observation", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk22", + "x": 235.0, + "y": 261.55, + "width": 195.0, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1043, + "version": 1, + "versionNonce": 1044, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki23", + "x": 318.5, + "y": 272.55, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1045, + "version": 1, + "versionNonce": 1046, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki23", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt24", + "x": 241.0, + "y": 306.55, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1047, + "version": 1, + "versionNonce": 1048, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Exam Finding", + "originalText": "Exam Finding", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkt25", + "x": 241.0, + "y": 325.3, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1049, + "version": 1, + "versionNonce": 1050, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "List", + "originalText": "List", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk26", + "x": 450.0, + "y": 261.55, + "width": 195.0, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1051, + "version": 1, + "versionNonce": 1052, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki27", + "x": 533.5, + "y": 272.55, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1053, + "version": 1, + "versionNonce": 1054, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki27", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt28", + "x": 456.0, + "y": 306.55, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1055, + "version": 1, + "versionNonce": 1056, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Imaging Problem", + "originalText": "Imaging Problem", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkt29", + "x": 456.0, + "y": 325.3, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1057, + "version": 1, + "versionNonce": 1058, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "List", + "originalText": "List", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk30", + "x": 665.0, + "y": 261.55, + "width": 195.0, + "height": 95.5, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1059, + "version": 1, + "versionNonce": 1060, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki31", + "x": 746.5, + "y": 279.925, + "width": 32, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1061, + "version": 1, + "versionNonce": 1062, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki31", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt32", + "x": 671.0, + "y": 315.925, + "width": 183.0, + "height": 18.75, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1063, + "version": 1, + "versionNonce": 1064, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Imaging Persona", + "originalText": "Imaging Persona", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "bicon34", + "x": 18, + "y": 491.3, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1067, + "version": 1, + "versionNonce": 1068, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_bicon34", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "btitle35", + "x": 58, + "y": 493.3, + "width": 208.79999999999998, + "height": 25.0, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1069, + "version": 1, + "versionNonce": 1070, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Foundation Context", + "originalText": "Foundation Context", + "fontSize": 20, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bsub36", + "x": 58, + "y": 519.3, + "width": 188.5, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1071, + "version": 1, + "versionNonce": 1072, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "shared, curated knowledge", + "originalText": "shared, curated knowledge", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "chip37", + "x": 381.99, + "y": 547.55, + "width": 116.02, + "height": 22.25, + "strokeColor": "#b45309", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1073, + "version": 1, + "versionNonce": 1074, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "chipt38", + "x": 390.99, + "y": 550.55, + "width": 98.02, + "height": 16.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1075, + "version": 1, + "versionNonce": 1076, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "relationships", + "originalText": "relationships", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk39", + "x": 20.0, + "y": 579.8, + "width": 237.33333333333334, + "height": 95.0, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1077, + "version": 1, + "versionNonce": 1078, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki40", + "x": 124.66666666666669, + "y": 590.8, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1079, + "version": 1, + "versionNonce": 1080, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki40", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt41", + "x": 26.0, + "y": 624.8, + "width": 225.33333333333334, + "height": 18.75, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1081, + "version": 1, + "versionNonce": 1082, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Finding/diagnosis definitions", + "originalText": "Finding/diagnosis definitions", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkd42", + "x": 26.0, + "y": 645.55, + "width": 225.33333333333334, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1083, + "version": 1, + "versionNonce": 1084, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "finding models \u00b7 CDEs", + "originalText": "finding models \u00b7 CDEs", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk43", + "x": 321.33333333333337, + "y": 579.8, + "width": 237.33333333333334, + "height": 95.0, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1085, + "version": 1, + "versionNonce": 1086, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki44", + "x": 424.00000000000006, + "y": 588.8, + "width": 32, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1087, + "version": 1, + "versionNonce": 1088, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki44", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt45", + "x": 327.33333333333337, + "y": 624.8, + "width": 225.33333333333334, + "height": 18.75, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1089, + "version": 1, + "versionNonce": 1090, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Anatomic locations", + "originalText": "Anatomic locations", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkd46", + "x": 327.33333333333337, + "y": 645.55, + "width": 225.33333333333334, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1091, + "version": 1, + "versionNonce": 1092, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "anchored in RadLex", + "originalText": "anchored in RadLex", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "blk47", + "x": 622.6666666666667, + "y": 579.8, + "width": 237.33333333333334, + "height": 95.0, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1093, + "version": 1, + "versionNonce": 1094, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "blki48", + "x": 725.3333333333334, + "y": 588.8, + "width": 32, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1095, + "version": 1, + "versionNonce": 1096, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_blki48", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "blkt49", + "x": 628.6666666666667, + "y": 624.8, + "width": 225.33333333333334, + "height": 18.75, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1097, + "version": 1, + "versionNonce": 1098, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Exam types", + "originalText": "Exam types", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "blkd50", + "x": 628.6666666666667, + "y": 645.55, + "width": 225.33333333333334, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1099, + "version": 1, + "versionNonce": 1100, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "LOINC/RSNA Playbook", + "originalText": "LOINC/RSNA Playbook", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "conn51", + "x": 263.33333333333337, + "y": 627.3, + "width": 52.0, + "height": 0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1101, + "version": 1, + "versionNonce": 1102, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 52.0, + 0 + ] + ], + "startArrowhead": "arrow", + "endArrowhead": "arrow" + }, + { + "type": "arrow", + "id": "conn52", + "x": 564.6666666666667, + "y": 627.3, + "width": 52.0, + "height": 0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1103, + "version": 1, + "versionNonce": 1104, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 52.0, + 0 + ] + ], + "startArrowhead": "arrow", + "endArrowhead": "arrow" + }, + { + "type": "line", + "id": "thread54", + "x": 62.0, + "y": 367.05, + "width": 0, + "height": 48.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1107, + "version": 1, + "versionNonce": 1108, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 48.0 + ] + ] + }, + { + "type": "line", + "id": "thread55", + "x": 130.72727272727275, + "y": 407.05, + "width": 0, + "height": 44.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1109, + "version": 1, + "versionNonce": 1110, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 44.0 + ] + ] + }, + { + "type": "line", + "id": "thread56", + "x": 199.45454545454547, + "y": 367.05, + "width": 0, + "height": 48.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1111, + "version": 1, + "versionNonce": 1112, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 48.0 + ] + ] + }, + { + "type": "line", + "id": "thread57", + "x": 268.1818181818182, + "y": 407.05, + "width": 0, + "height": 44.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1113, + "version": 1, + "versionNonce": 1114, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 44.0 + ] + ] + }, + { + "type": "line", + "id": "thread58", + "x": 336.90909090909093, + "y": 367.05, + "width": 0, + "height": 48.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1115, + "version": 1, + "versionNonce": 1116, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 48.0 + ] + ] + }, + { + "type": "line", + "id": "thread59", + "x": 405.6363636363636, + "y": 407.05, + "width": 0, + "height": 44.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1117, + "version": 1, + "versionNonce": 1118, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 44.0 + ] + ] + }, + { + "type": "line", + "id": "thread60", + "x": 474.3636363636364, + "y": 367.05, + "width": 0, + "height": 48.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1119, + "version": 1, + "versionNonce": 1120, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 48.0 + ] + ] + }, + { + "type": "line", + "id": "thread61", + "x": 543.090909090909, + "y": 407.05, + "width": 0, + "height": 44.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1121, + "version": 1, + "versionNonce": 1122, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 44.0 + ] + ] + }, + { + "type": "line", + "id": "thread62", + "x": 611.8181818181819, + "y": 367.05, + "width": 0, + "height": 48.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1123, + "version": 1, + "versionNonce": 1124, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 48.0 + ] + ] + }, + { + "type": "line", + "id": "thread63", + "x": 680.5454545454545, + "y": 407.05, + "width": 0, + "height": 44.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1125, + "version": 1, + "versionNonce": 1126, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 44.0 + ] + ] + }, + { + "type": "line", + "id": "thread64", + "x": 749.2727272727273, + "y": 367.05, + "width": 0, + "height": 48.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1127, + "version": 1, + "versionNonce": 1128, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 48.0 + ] + ] + }, + { + "type": "line", + "id": "thread65", + "x": 818.0, + "y": 407.05, + "width": 0, + "height": 44.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1129, + "version": 1, + "versionNonce": 1130, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 44.0 + ] + ] + }, + { + "type": "text", + "id": "seaml66", + "x": 0, + "y": 461.05, + "width": 880, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1131, + "version": 1, + "versionNonce": 1132, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "interconnected at every finding, diagnosis, location, and exam type", + "originalText": "interconnected at every finding, diagnosis, location, and exam type", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + } + ], + "appState": { + "viewBackgroundColor": "#ffffff", + "gridSize": null + }, + "files": { + "img_bicon3": { + "mimeType": "image/svg+xml", + "id": "img_bicon3", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiNiZTEyM2MiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTE1IDE0Yy4yLTEgLjctMS43IDEuNS0yLjUgMS0uOSAxLjUtMi4yIDEuNS0zLjVBNiA2IDAgMCAwIDYgOGMwIDEgLjIgMi4yIDEuNSAzLjUuNy43IDEuMyAxLjUgMS41IDIuNSIgLz4KICA8cGF0aCBkPSJNOSAxOGg2IiAvPgogIDxwYXRoIGQ9Ik0xMCAyMmg0IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_bicon6": { + "mimeType": "image/svg+xml", + "id": "img_bicon6", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMxNTgwM2QiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHJlY3QgeD0iMiIgeT0iNCIgd2lkdGg9IjIwIiBoZWlnaHQ9IjE2IiByeD0iMiIgLz4KICA8cGF0aCBkPSJNMTAgNHY0IiAvPgogIDxwYXRoIGQ9Ik0yIDhoMjAiIC8+CiAgPHBhdGggZD0iTTYgNHY0IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_bicon12": { + "mimeType": "image/svg+xml", + "id": "img_bicon12", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiM2ZDI4ZDkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTExIDIxLjczYTIgMiAwIDAgMCAyIDBsNy00QTIgMiAwIDAgMCAyMSAxNlY4YTIgMiAwIDAgMC0xLTEuNzNsLTctNGEyIDIgMCAwIDAtMiAwbC03IDRBMiAyIDAgMCAwIDMgOHY4YTIgMiAwIDAgMCAxIDEuNzN6IiAvPgogIDxwYXRoIGQ9Ik0xMiAyMlYxMiIgLz4KICA8cG9seWxpbmUgcG9pbnRzPSIzLjI5IDcgMTIgMTIgMjAuNzEgNyIgLz4KICA8cGF0aCBkPSJtNy41IDQuMjcgOSA1LjE1IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_bicon16": { + "mimeType": "image/svg+xml", + "id": "img_bicon16", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyLjgzIDIuMThhMiAyIDAgMCAwLTEuNjYgMEwyLjYgNi4wOGExIDEgMCAwIDAgMCAxLjgzbDguNTggMy45MWEyIDIgMCAwIDAgMS42NiAwbDguNTgtMy45YTEgMSAwIDAgMCAwLTEuODN6IiAvPgogIDxwYXRoIGQ9Ik0yIDEyYTEgMSAwIDAgMCAuNTguOTFsOC42IDMuOTFhMiAyIDAgMCAwIDEuNjUgMGw4LjU4LTMuOUExIDEgMCAwIDAgMjIgMTIiIC8+CiAgPHBhdGggZD0iTTIgMTdhMSAxIDAgMCAwIC41OC45MWw4LjYgMy45MWEyIDIgMCAwIDAgMS42NSAwbDguNTgtMy45QTEgMSAwIDAgMCAyMiAxNyIgLz4KPC9zdmc+Cg==", + "created": 1700000000000 + }, + "img_blki20": { + "mimeType": "image/svg+xml", + "id": "img_blki20", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHJlY3Qgd2lkdGg9IjgiIGhlaWdodD0iNCIgeD0iOCIgeT0iMiIgcng9IjEiIHJ5PSIxIiAvPgogIDxwYXRoIGQ9Ik0xNiA0aDJhMiAyIDAgMCAxIDIgMnYxNGEyIDIgMCAwIDEtMiAySDZhMiAyIDAgMCAxLTItMlY2YTIgMiAwIDAgMSAyLTJoMiIgLz4KPC9zdmc+Cg==", + "created": 1700000000000 + }, + "img_blki23": { + "mimeType": "image/svg+xml", + "id": "img_blki23", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHJlY3Qgd2lkdGg9IjgiIGhlaWdodD0iNCIgeD0iOCIgeT0iMiIgcng9IjEiIHJ5PSIxIiAvPgogIDxwYXRoIGQ9Ik0xNiA0aDJhMiAyIDAgMCAxIDIgMnYxNGEyIDIgMCAwIDEtMiAySDZhMiAyIDAgMCAxLTItMlY2YTIgMiAwIDAgMSAyLTJoMiIgLz4KICA8cGF0aCBkPSJNMTIgMTFoNCIgLz4KICA8cGF0aCBkPSJNMTIgMTZoNCIgLz4KICA8cGF0aCBkPSJNOCAxMWguMDEiIC8+CiAgPHBhdGggZD0iTTggMTZoLjAxIiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki27": { + "mimeType": "image/svg+xml", + "id": "img_blki27", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTMgNWguMDEiIC8+CiAgPHBhdGggZD0iTTMgMTJoLjAxIiAvPgogIDxwYXRoIGQ9Ik0zIDE5aC4wMSIgLz4KICA8cGF0aCBkPSJNOCA1aDEzIiAvPgogIDxwYXRoIGQ9Ik04IDEyaDEzIiAvPgogIDxwYXRoIGQ9Ik04IDE5aDEzIiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki31": { + "mimeType": "image/svg+xml", + "id": "img_blki31", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yNCAyNEMyOC40MjA0IDI0IDMyIDIwLjQyMDQgMzIgMTZDMzIgMTEuNTc5NiAyOC40MjA0IDggMjQgOEMxOS41Nzk2IDggMTYgMTEuNTc5NiAxNiAxNkMxNiAyMC40MjA0IDE5LjU3OTYgMjQgMjQgMjRaTTM0IDE2QzM0IDIxLjUyNSAyOS41MjUgMjYgMjQgMjZDMTguNDc1IDI2IDE0IDIxLjUyNSAxNCAxNkMxNCAxMC40NzUgMTguNDc1IDYgMjQgNkMyOS41MjUgNiAzNCAxMC40NzUgMzQgMTZaIiBmaWxsPSIjMGY3NjZlIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNOS4yMjM0OCAzNC4yMTE5QzguMjIwMzggMzUuMDIxMSA4IDM1LjYyOTEgOCAzNlY0MEg0MFYzNkM0MCAzNS42MjkxIDM5Ljc3OTYgMzUuMDIxMSAzOC43NzY1IDM0LjIxMTlDMzcuNzk1OCAzMy40MjA3IDM2LjMzNDEgMzIuNjY2OSAzNC41NjIyIDMyLjAxNUMzMS4wMTk5IDMwLjcxMTcgMjYuNzUzMiAzMCAyNCAzMEMyMS4yNDY4IDMwIDE2Ljk4MDEgMzAuNzExNyAxMy40Mzc4IDMyLjAxNUMxMS42NjU5IDMyLjY2NjkgMTAuMjA0MiAzMy40MjA3IDkuMjIzNDggMzQuMjExOVpNMjQgMjhDMTcuOTkyNSAyOCA2IDMxLjAzNDcgNiAzNlY0Mkg0MlYzNkM0MiAzMS4wMzQ3IDMwLjAwNzUgMjggMjQgMjhaIiBmaWxsPSIjMGY3NjZlIi8+Cjwvc3ZnPgo=", + "created": 1700000000000 + }, + "img_bicon34": { + "mimeType": "image/svg+xml", + "id": "img_bicon34", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiNiNDUzMDkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyIDV2MTYiIC8+CiAgPHBhdGggZD0iTTIwLjAwMSAxOUEyIDIgMCAwMDIyIDE3VjVhMiAyIDAgMDAtMS45OTktMkwxNiAzLjAwMkE1IDUgMCAwMDEyIDVhNSA1IDAgMDAtNC0ySDRhMiAyIDAgMDAtMiAydjEyYTIgMiAwIDAwMS45OTkgMkg4YTUgNSAwIDAxNCAyIDUgNSAwIDAxNC0yeiIgLz4KPC9zdmc+Cg==", + "created": 1700000000000 + }, + "img_blki40": { + "mimeType": "image/svg+xml", + "id": "img_blki40", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiNiNDUzMDkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyLjU4NiAyLjU4NkEyIDIgMCAwIDAgMTEuMTcyIDJINGEyIDIgMCAwIDAtMiAydjcuMTcyYTIgMiAwIDAgMCAuNTg2IDEuNDE0bDguNzA0IDguNzA0YTIuNDI2IDIuNDI2IDAgMCAwIDMuNDIgMGw2LjU4LTYuNThhMi40MjYgMi40MjYgMCAwIDAgMC0zLjQyeiIgLz4KICA8Y2lyY2xlIGN4PSI3LjUiIGN5PSI3LjUiIHI9Ii41IiBmaWxsPSIjYjQ1MzA5IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki44": { + "mimeType": "image/svg+xml", + "id": "img_blki44", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yMyA2LjAwMDEzQzIzIDYuMDAwMDQgMjMgNiAyNCA2SDI0LjE3NjFDMjQuMjUzMyA2IDI0LjMyMzMgNiAyNC4zODY4IDZDMjUgNi4wMDAwMSAyNSA2LjAwMDA1IDI1IDYuMDAwMTNWMjAuNUMyNSAyMS44OTc3IDI1LjU2NDEgMjIuNDQyMSAyNi4wMDM5IDIyLjY5ODdDMjYuMDUzIDIyLjcyNzMgMjYuMTAyNCAyMi43NTMzIDI2LjE1MTYgMjIuNzc3QzI2LjE1MDYgMjIuNjU2OCAyNi4xNDkzIDIyLjUzMTYgMjYuMTQ3OSAyMi40MDE5TDI2LjE0NzkgMjIuNDAwM0MyNi4xMTAxIDE4Ljg3MTYgMjYuMDM2NSAxMS45OTk3IDMxLjQ3NTMgMTEuOTk5N0MzOC45MjU5IDExLjk5OTcgNDQuMjQ3OCAzOC4wMDYyIDQxLjA1NDcgNDAuNjU5OUMzNy44NjE1IDQzLjMxMzYgMzEuNDc1MyA0MS43MjE0IDI4LjI4MjIgMzguNTM2OUMyNS43MDQyIDM1Ljk2NTkgMjUuOTI3MiAyOS45NTgzIDI2LjA4NzMgMjUuNjQ1N0wyNi4wODc0IDI1LjY0NDNDMjYuMDk3MSAyNS4zODE5IDI2LjEwNjcgMjUuMTI1OCAyNi4xMTUzIDI0Ljg3NzFDMjUuNzkgMjQuNzk2MiAyNS4zOTU5IDI0LjY1OTUgMjQuOTk2MiAyNC40MjYzQzI0LjYzOTggMjQuMjE4NCAyNC4yOTc1IDIzLjk0NDIgMjQgMjMuNTkxOUMyMy43MDI2IDIzLjk0NDIgMjMuMzYwMyAyNC4yMTg0IDIzLjAwMzkgMjQuNDI2M0MyMi42MDQxIDI0LjY1OTUgMjIuMjEwMSAyNC43OTYyIDIxLjg4NDggMjQuODc3MUMyMS44OTM0IDI1LjEyNjEgMjEuOTAyOSAyNS4zODI2IDIxLjkxMjcgMjUuNjQ1M0MyMi4wNzI4IDI5Ljk1NzkgMjIuMjk1OSAzNS45NjYyIDE5LjcxNzkgMzguNTM3MkMxNi41MjQ3IDQxLjcyMTcgMTAuMTM4NSA0My4zMTM5IDYuOTQ1MzYgNDAuNjYwMkMzLjc1MjIyIDM4LjAwNjUgOS4wNzQxMyAxMiAxNi41MjQ3IDEyQzIxLjk2MzYgMTIgMjEuODkgMTguODcxNyAyMS44NTIyIDIyLjQwMDNDMjEuODUyIDIyLjQxNjYgMjEuODUxOCAyMi40MzI4IDIxLjg1MTYgMjIuNDQ4OUMyMS44NTA0IDIyLjU2MTkgMjEuODQ5MyAyMi42NzE0IDIxLjg0ODQgMjIuNzc3QzIxLjg5NzcgMjIuNzUzNCAyMS45NDcxIDIyLjcyNzQgMjEuOTk2MiAyMi42OTg3QzIyLjQzNiAyMi40NDIxIDIzIDIxLjg5NzcgMjMgMjAuNVY2LjAwMDEzWk0zMS40NzUzIDEzLjk5OTdDMzAuNTIxMiAxMy45OTk3IDI5Ljk4NDMgMTQuMzAwMiAyOS42MDg2IDE0LjY4NjlDMjkuMTc1MiAxNS4xMzMxIDI4LjgxMzIgMTUuODUwNyAyOC41NTkgMTYuODY0NkMyOC4xMTQxIDE4LjYzOTUgMjguMTMzIDIwLjY4MTkgMjguMTQ4MyAyMi4zMjkzQzI4LjE1MDkgMjIuNjE0MiAyOC4xNTM0IDIyLjg4NzQgMjguMTUzNCAyMy4xNDUzQzI4LjE1MzQgMjMuOTA1MyAyOC4xMTk2IDI0LjgxNTMgMjguMDg0NSAyNS43NjIxQzI4LjA3MDcgMjYuMTM0OSAyOC4wNTY2IDI2LjUxMzMgMjguMDQ0MyAyNi44OTA1QzI3Ljk5OTYgMjguMjY1NyAyNy45NzQxIDI5LjcwNTUgMjguMDQwNSAzMS4wOTgyQzI4LjEwNzIgMzIuNDk4NSAyOC4yNjQyIDMzLjc4MzUgMjguNTU3MyAzNC44NTk2QzI4Ljg1MzggMzUuOTQ4MyAyOS4yNTA5IDM2LjY3ODQgMjkuNjk0NCAzNy4xMjA4QzMwLjk3MjYgMzguMzk1NCAzMi45OTA4IDM5LjQyNTEgMzUuMDQ5MiAzOS44MjQzQzM3LjA4NDIgNDAuMjE4OSAzOC43MjI0IDM5LjkyNjkgMzkuNjgxOCAzOS4xOTY5QzM5LjY4NjggMzkuMTg1NyAzOS42OTIzIDM5LjE3MjYgMzkuNjk4NCAzOS4xNTc0QzM5Ljc1NzYgMzkuMDA5NSAzOS44Mjk0IDM4Ljc1NTQgMzkuODg3OCAzOC4zNjgzQzQwLjAwNDcgMzcuNTkzMyA0MC4wMzUgMzYuNTEyMiAzOS45NTYyIDM1LjE4MDNDMzkuNzk5NSAzMi41MzA1IDM5LjIyODYgMjkuMTY4OSAzOC4zMjY4IDI1Ljg2MDZDMzcuNDIxNiAyMi41Mzk2IDM2LjIxNzMgMTkuMzk5OCAzNC44NTIxIDE3LjEzODNDMzQuMTY4OCAxNi4wMDYyIDMzLjQ5NTEgMTUuMTc4NiAzMi44NzAzIDE0LjY1MzVDMzIuMjUxOCAxNC4xMzM3IDMxLjc5MzUgMTMuOTk5NyAzMS40NzUzIDEzLjk5OTdaTTE2LjUyNDcgMTRDMTcuNDc4OCAxNCAxOC4wMTU4IDE0LjMwMDUgMTguMzkxNCAxNC42ODcyQzE4LjgyNDggMTUuMTMzNCAxOS4xODY4IDE1Ljg1MSAxOS40NDEgMTYuODY0OUMxOS44ODU5IDE4LjYzOTkgMTkuODY3IDIwLjY4MjIgMTkuODUxOCAyMi4zMjk2QzE5Ljg0OTEgMjIuNjE0NiAxOS44NDY2IDIyLjg4NzcgMTkuODQ2NiAyMy4xNDU2QzE5Ljg0NjYgMjMuOTA1NiAxOS44ODA0IDI0LjgxNTYgMTkuOTE1NSAyNS43NjI0QzE5LjkyOTQgMjYuMTM1IDE5Ljk0MzQgMjYuNTEzOCAxOS45NTU3IDI2Ljg5MDhDMjAuMDAwNSAyOC4yNjYgMjAuMDI1OSAyOS43MDU4IDE5Ljk1OTYgMzEuMDk4NUMxOS44OTI5IDMyLjQ5ODggMTkuNzM1OSAzMy43ODM4IDE5LjQ0MjcgMzQuODU5OUMxOS4xNDYyIDM1Ljk0ODYgMTguNzQ5MiAzNi42Nzg3IDE4LjMwNTYgMzcuMTIxMUMxNy4wMjc1IDM4LjM5NTcgMTUuMDA5MyAzOS40MjU0IDEyLjk1MDkgMzkuODI0NkMxMC45MTU5IDQwLjIxOTIgOS4yNzc2OCAzOS45MjcyIDguMzE4MjMgMzkuMTk3MkM4LjMxMzI2IDM5LjE4NiA4LjMwNzcgMzkuMTcyOSA4LjMwMTYyIDM5LjE1NzdDOC4yNDI0MSAzOS4wMDk4IDguMTcwNjEgMzguNzU1NyA4LjExMjI0IDM4LjM2ODZDNy45OTUzOSAzNy41OTM2IDcuOTY1IDM2LjUxMjUgOC4wNDM4IDM1LjE4MDZDOC4yMDA1NiAzMi41MzA4IDguNzcxNDcgMjkuMTY5MiA5LjY3MzI0IDI1Ljg2MDlDMTAuNTc4NSAyMi41Mzk5IDExLjc4MjcgMTkuNDAwMSAxMy4xNDc5IDE3LjEzODZDMTMuODMxMyAxNi4wMDY1IDE0LjUwNDkgMTUuMTc4OSAxNS4xMjk4IDE0LjY1MzhDMTUuNzQ4MiAxNC4xMzQgMTYuMjA2NSAxNCAxNi41MjQ3IDE0WiIgZmlsbD0iI2I0NTMwOSIvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_blki48": { + "mimeType": "image/svg+xml", + "id": "img_blki48", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yOSA5QzI5IDExLjc2MTQgMjYuNzYxNCAxNCAyNCAxNEMyMS4yMzg2IDE0IDE5IDExLjc2MTQgMTkgOUMxOSA2LjIzODU4IDIxLjIzODYgNCAyNCA0QzI2Ljc2MTQgNCAyOSA2LjIzODU4IDI5IDlaTTI3IDlDMjcgMTAuNjU2OSAyNS42NTY5IDEyIDI0IDEyQzIyLjM0MzEgMTIgMjEgMTAuNjU2OSAyMSA5QzIxIDcuMzQzMTUgMjIuMzQzMSA2IDI0IDZDMjUuNjU2OSA2IDI3IDcuMzQzMTUgMjcgOVoiIGZpbGw9IiNiNDUzMDkiLz4KPHBhdGggZD0iTTE2Ljk5OTggNDFWMzRIMTguOTk5OFY0MUMxOC45OTk4IDQxLjU1MjMgMTkuNDQ3NSA0MiAxOS45OTk4IDQySDIwLjA4NjVDMjAuNjAzNyA0MiAyMS4wMzU2IDQxLjYwNTYgMjEuMDgyNCA0MS4wOTA1TDIxLjcyNyAzNEgyMy43MzUzTDIzLjA3NDIgNDEuMjcxNkMyMy4wNjkgNDEuMzI4OCAyMy4wNjIyIDQxLjM4NTYgMjMuMDUzOSA0MS40NDE3QzIzLjAzNTcgNDEuNTY0NyAyMy4wMTAxIDQxLjY4NTEgMjIuOTc3NiA0MS44MDI1QzIyLjYyNDIgNDMuMDc5OCAyMS40NTQ5IDQ0IDIwLjA4NjUgNDRIMTkuOTk5OEMxOC4zNDI5IDQ0IDE2Ljk5OTggNDIuNjU2OSAxNi45OTk4IDQxWiIgZmlsbD0iI2I0NTMwOSIvPgo8cGF0aCBkPSJNMjYuOTE3MSA0MS4wOTA1TDI2LjI3MjUgMzRIMjQuMjY0MkwyNC45MjUzIDQxLjI3MTZDMjQuOTMwNSA0MS4zMjg4IDI0LjkzNzMgNDEuMzg1NiAyNC45NDU2IDQxLjQ0MTdDMjQuOTYzOCA0MS41NjQ3IDI0Ljk4OTQgNDEuNjg1MSAyNS4wMjE5IDQxLjgwMjVDMjUuMzc1MyA0My4wNzk4IDI2LjU0NDYgNDQgMjcuOTEzIDQ0SDI3Ljk5OThDMjkuNjU2NiA0NCAzMC45OTk4IDQyLjY1NjkgMzAuOTk5OCA0MVYzNEgyOC45OTk4VjQxQzI4Ljk5OTggNDEuNTUyMyAyOC41NTIgNDIgMjcuOTk5OCA0MkgyNy45MTNDMjcuMzk1OCA0MiAyNi45NjM5IDQxLjYwNTYgMjYuOTE3MSA0MS4wOTA1WiIgZmlsbD0iI2I0NTMwOSIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTExIDE1QzEwLjQ0NzcgMTUgMTAgMTUuNDQ3NyAxMCAxNlYzMUMxMCAzMS41NTIzIDEwLjQ0NzcgMzIgMTEgMzJIMzdDMzcuNTUyMyAzMiAzOCAzMS41NTIzIDM4IDMxVjE2QzM4IDE1LjQ0NzcgMzcuNTUyMyAxNSAzNyAxNUgxMVpNMTIgMTdWMzBIMTkuNUMxOS41IDI5LjQ0MjQgMTkuNzU5MSAyOC45NTcyIDIwLjAyNzYgMjguNjAwNkMyMC4zMDg2IDI4LjIyNzYgMjAuNjc5NiAyNy44ODgzIDIxLjA3OTQgMjcuNjAxNkMyMS42MjUyIDI3LjIxMDMgMjIuMjk4NiAyNi44NjUgMjMgMjYuNjY3OFYyNC41SDIyLjJDMjEuNTk3MyAyNC41IDIwLjc1MzUgMjQuODY0MiAxOS45NDMzIDI1LjM1NTJDMTkuNTYzOCAyNS41ODUyIDE5LjIzMzcgMjUuODE2NyAxOC45OTg0IDI1Ljk5MTFDMTguODgxMiAyNi4wNzc4IDE4Ljc4ODggMjYuMTQ5NSAxOC43MjcgMjYuMTk4NEMxOC42OTYxIDI2LjIyMjggMTguNjczIDI2LjI0MTUgMTguNjU4MiAyNi4yNTM1TDE4LjY0MjYgMjYuMjY2M0wxOC42Mzk5IDI2LjI2ODRDMTguNjM5OSAyNi4yNjg0IDE4LjY0MDIgMjYuMjY4MiAxOCAyNS41QzE3LjM1OTggMjQuNzMxOCAxNy4zNjAxIDI0LjczMTUgMTcuMzYwMSAyNC43MzE1TDE3LjM2MTQgMjQuNzMwNUwxNy4zNjM4IDI0LjcyODVMMTcuMzcxMyAyNC43MjIzTDE3LjM5NjYgMjQuNzAxNkMxNy40MTc5IDI0LjY4NDMgMTcuNDQ4IDI0LjY2IDE3LjQ4NjMgMjQuNjI5N0MxNy41NjI3IDI0LjU2OTMgMTcuNjcxOSAyNC40ODQ3IDE3LjgwNzkgMjQuMzgzOUMxOC4wNzg4IDI0LjE4MzMgMTguNDYxMiAyMy45MTQ4IDE4LjkwNjcgMjMuNjQ0OEMxOS43NDY1IDIzLjEzNTggMjEuMDAyNyAyMi41IDIyLjIgMjIuNUgyM1YyMC41SDIyLjVDMjEuOTMwOSAyMC41IDIxLjE5MDkgMjAuNjk5MiAyMC41MjkyIDIwLjkzOThDMjAuMjEyIDIxLjA1NTIgMTkuOTM3IDIxLjE3MDkgMTkuNzQyMSAyMS4yNTc2QzE5LjY0NDkgMjEuMzAwNyAxOS41Njg1IDIxLjMzNjMgMTkuNTE3NiAyMS4zNjA1QzE5LjQ5MjIgMjEuMzcyNSAxOS40NzMyIDIxLjM4MTcgMTkuNDYxMyAyMS4zODc1TDE5LjQ0ODcgMjEuMzkzN0wxOS40NDcgMjEuMzk0NUMxOS40NDcgMjEuMzk0NSAxOS40NDcyIDIxLjM5NDQgMTkgMjAuNUMxOC41NTI4IDE5LjYwNTYgMTguNTUzMSAxOS42MDU0IDE4LjU1MzEgMTkuNjA1NEwxOC41NTY0IDE5LjYwMzhMMTguNTYyOSAxOS42MDA2TDE4LjU4NDQgMTkuNTlDMTguNjAyNSAxOS41ODEyIDE4LjYyNzkgMTkuNTY4OSAxOC42NjAxIDE5LjU1MzZDMTguNzI0NSAxOS41MjMxIDE4LjgxNiAxOS40ODA1IDE4LjkyOTggMTkuNDI5OUMxOS4xNTY3IDE5LjMyOTEgMTkuNDc1NSAxOS4xOTQ4IDE5Ljg0NTggMTkuMDYwMkMyMC41NTkxIDE4LjgwMDggMjEuNTY5MSAxOC41IDIyLjUgMTguNUgyM1YxN0gxMlpNMjUgMjQuNUgyNi4xQzI2Ljg0ODkgMjQuNSAyNy42MTg2IDI0Ljg2NjMgMjguMjYzMSAyNS4zMTg2QzI4LjU3MzUgMjUuNTM2NCAyOC44Mjg1IDI1Ljc1NTYgMjkuMDA0OCAyNS45MTk3QzI5LjA5MjUgMjYuMDAxMiAyOS4xNTk0IDI2LjA2NzkgMjkuMjAyNiAyNi4xMTIyQzI5LjIyNDEgMjYuMTM0MyAyOS4yMzk3IDI2LjE1MDcgMjkuMjQ4OCAyNi4xNjA1TDI5LjI1NzQgMjYuMTY5N0MyOS4yNTc0IDI2LjE2OTcgMjkuMjU2NyAyNi4xNjkgMzAgMjUuNUMzMC43NDMzIDI0LjgzMSAzMC43NDI5IDI0LjgzMDYgMzAuNzQyOSAyNC44MzA2TDMwLjc0MTQgMjQuODI5TDMwLjczODkgMjQuODI2MkwzMC43MzE4IDI0LjgxODRMMzAuNzA5NyAyNC43OTQ2QzMwLjY5MTUgMjQuNzc1MSAzMC42NjYzIDI0Ljc0ODUgMzAuNjM0NiAyNC43MTZDMzAuNTcxMSAyNC42NTA5IDMwLjQ4MDkgMjQuNTYxMyAzMC4zNjcgMjQuNDU1M0MzMC4xNDAzIDI0LjI0NDQgMjkuODE0IDIzLjk2MzYgMjkuNDExOSAyMy42ODE0QzI4LjYzMTQgMjMuMTMzNyAyNy40NTExIDIyLjUgMjYuMSAyMi41SDI1VjIwLjVIMjUuNzVDMjYuNDQ0MyAyMC41IDI3LjExOTMgMjAuNzAxMSAyNy42NDMyIDIwLjkyMTZDMjcuOTAwMyAyMS4wMjk5IDI4LjEwOTIgMjEuMTM3OCAyOC4yNTA5IDIxLjIxNjlDMjguMzIxNSAyMS4yNTY0IDI4LjM3NDcgMjEuMjg4MiAyOC40MDggMjEuMzA4N0MyOC40MjQ3IDIxLjMxODkgMjguNDM2MyAyMS4zMjYzIDI4LjQ0MjcgMjEuMzMwNEwyOC40NDU3IDIxLjMzMjNDMjguNDQ1NyAyMS4zMzIzIDI4LjQ0NTMgMjEuMzMyMSAyOSAyMC41QzI5LjU1NDcgMTkuNjY3OSAyOS41NTQyIDE5LjY2NzYgMjkuNTU0MiAxOS42Njc2TDI5LjU1MjcgMTkuNjY2NkwyOS41NTAxIDE5LjY2NDlMMjkuNTQzMiAxOS42NjA0TDI5LjUyMjggMTkuNjQ3MkMyOS41MDYzIDE5LjYzNjYgMjkuNDg0IDE5LjYyMjUgMjkuNDU2MiAxOS42MDU0QzI5LjQwMDcgMTkuNTcxMiAyOS4zMjMgMTkuNTI0OSAyOS4yMjU2IDE5LjQ3MDZDMjkuMDMxNSAxOS4zNjIyIDI4Ljc1NTkgMTkuMjIwMSAyOC40MTkzIDE5LjA3ODRDMjcuNzU1NyAxOC43OTg5IDI2LjgwNTcgMTguNSAyNS43NSAxOC41SDI1VjE3SDM2VjMwSDI4LjVDMjguNSAyOS40Mzc5IDI4LjIzMjQgMjguOTQ1MiAyNy45NjQxIDI4LjU4NzVDMjcuNjgwMyAyOC4yMDkyIDI3LjMwNTQgMjcuODYwNiAyNi45MDA3IDI3LjU2NjNDMjYuMzY3NSAyNy4xNzg1IDI1LjY5ODkgMjYuODI1NyAyNSAyNi42MzkxVjI0LjVaTTI2LjQ5MjkgMzBDMjYuNDc5NyAyOS45NjcgMjYuNDQ1NyAyOS44OTY0IDI2LjM2NDEgMjkuNzg3NUMyNi4yMjU5IDI5LjYwMzMgMjYuMDA3MSAyOS4zODk0IDI1LjcyNDMgMjkuMTgzN0MyNS4xNDc4IDI4Ljc2NDUgMjQuNDkzNyAyOC41MTE3IDI0LjAzMiAyOC41MDA0QzIzLjQ4NzcgMjguNTQ2NCAyMi44MDUyIDI4LjgyNTIgMjIuMjQ0OSAyOS4yMjdDMjEuOTY1NyAyOS40MjcyIDIxLjc1NTYgMjkuNjMwNyAyMS42MjUyIDI5LjgwMzhDMjEuNTQ5NiAyOS45MDQzIDIxLjUxODQgMjkuOTY5NCAyMS41MDYzIDMwSDI2LjQ5MjlaIiBmaWxsPSIjYjQ1MzA5Ii8+Cjwvc3ZnPgo=", + "created": 1700000000000 + } + } +} \ No newline at end of file diff --git a/knowledge/drafts/pillars.svg b/knowledge/drafts/pillars.svg new file mode 100644 index 0000000..046a563 --- /dev/null +++ b/knowledge/drafts/pillars.svg @@ -0,0 +1,2 @@ +Use Caseswhat the project wants builtSample Applicationswhat has been builtillustratesSDKswrap the structures · attach the shared knowledge · support authoringData Structuresthis patient · Patient ContextObservationExam FindingListImaging ProblemListImaging PersonaFoundation Contextshared, curated knowledgerelationshipsFinding/diagnosis definitionsfinding models · CDEsAnatomic locationsanchored in RadLexExam typesLOINC/RSNA Playbookinterconnected at every finding, diagnosis, location, and exam type \ No newline at end of file diff --git a/knowledge/drafts/relationships.md b/knowledge/drafts/relationships.md new file mode 100644 index 0000000..e3b752d --- /dev/null +++ b/knowledge/drafts/relationships.md @@ -0,0 +1,111 @@ +--- +type: Concept +title: Relationships among definitions +description: "The typed relationships among finding/diagnosis definitions: manifestation and causation, associated findings and components, how strongly a relationship holds, deriving the differential, assessment schemes, and a proposal for role tagging." +tags: [foundation-context, next-gen-schema, relationships, finding-models, cdes, differential, graph] +status: draft +generated: { by: claude-opus-5/2026-09-30-restructure/relationships-page, at: 2026-09-30T16:12:00Z } +sources: + - id: lead-relationships + resource: docs/plans/2026-09-22-layout-plan.md + title: The project lead's statement of 2026-09-30 on this page - the subsection titles, the pyelonephritis appears-as wording, the instruction to include associated findings and the edge properties, the instruction to leave the HPO and Orphanet reference out of the prose, and the two sentences on assessment schemes (recorded verbatim in the layout plan) + last_modified: 2026-09-30 + - id: cde-branch + resource: https://github.com/RSNA/ACR-RSNA-CDEs/tree/b541b74c22a33b64834309244569a60d06de79e4 + title: The ACR/RSNA CDE schema repository, next-gen-2026 branch at b541b74 - the branch of record for the next-generation schema work, read at this commit on 2026-09-30 + last_modified: 2026-09-23 + - id: cde-relationships + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/b541b74c22a33b64834309244569a60d06de79e4/docs/next-gen-schema/07-relationship-family.md + title: The Finding and Diagnosis Relationship Family, ACR-RSNA-CDEs next-gen-2026 at b541b74 - the catalog with domains, ranges, inverses and symmetry, the manifestation and causation test, the typicality and specificity scales, and the differential as a derived view + last_modified: 2026-09-09 + - id: cde-graph + resource: https://github.com/RSNA/ACR-RSNA-CDEs/tree/b541b74c22a33b64834309244569a60d06de79e4/docs/next-gen-schema/graph + title: "The vocabulary written as JSON Lines, ACR-RSNA-CDEs next-gen-2026 at b541b74: core.jsonl declares each relationship type with its inverse, symmetry, domain, range and permitted properties; pyelonephritis.jsonl and pleural-effusion.jsonl hold the two worked families" + last_modified: 2026-09-09 + - id: cde-worked-examples + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/b541b74c22a33b64834309244569a60d06de79e4/docs/next-gen-schema/08-worked-examples.md + title: Worked Examples, Acute Pyelonephritis, Pleural Effusion, and One Report, ACR-RSNA-CDEs next-gen-2026 at b541b74 - the striated nephrogram and renal abscess edges as written, with their provenance warning + last_modified: 2026-09-09 + - id: cde-decisions + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/b541b74c22a33b64834309244569a60d06de79e4/docs/next-gen-schema/10-decision-record-2026-09-02.md + title: The decision record, ACR-RSNA-CDEs next-gen-2026 at b541b74 - S33 and S58 on components, S39 to S41 on assessment schemes, each row carrying a provenance mark, OWNER for what the project lead stated and CLAUDE DEFAULT for what an assistant chose to keep moving + last_modified: 2026-09-23 + - id: cde-structures + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/b541b74c22a33b64834309244569a60d06de79e4/docs/next-gen-schema/03-draft-structures.md + title: Draft Structures for Worked Examples, ACR-RSNA-CDEs next-gen-2026 at b541b74 - the edge catalog, the AssessmentScheme update under S40 and S41, and the definition-plane and report-plane component edges under their older names + last_modified: 2026-09-15 + - id: cde-alpha-shape + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/b541b74c22a33b64834309244569a60d06de79e4/docs/next-gen-schema/alpha/SHAPE.md + title: "The alpha's generated node and edge documentation, ACR-RSNA-CDEs next-gen-2026 at b541b74: the committed edge names with their signatures, counts and properties, and the rule that co-occurrence relates two findings or two diagnoses" + last_modified: 2026-09-14 + - id: cde-alpha-graph + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/b541b74c22a33b64834309244569a60d06de79e4/docs/next-gen-schema/alpha/graph/definition-graph.json + title: "The reviewer's alpha definition graph, ACR-RSNA-CDEs next-gen-2026 at b541b74: the typed edges as actually authored, including the component, co-occurrence, manifestation, causation and assessment edges counted here, the implementation approach the project lead adopted as the basis going forward" + last_modified: 2026-09-14 + - id: oifm-associated + resource: https://github.com/openimagingdata/findingmodels/blob/4475ac1bcb591f1a0951b2082b59208def173a5d/prompts/fragments/associated_vs_component.md + title: "Associated findings vs components, the Open Imaging Finding Models authoring fragment, main at 4475ac1: the independence test, the pneumonia and pleural effusion example, associated findings as one multichoice attribute, and components as their own models" + last_modified: 2026-04-18 + - id: oifm-scoring + resource: https://github.com/openimagingdata/findingmodels/blob/4475ac1bcb591f1a0951b2082b59208def173a5d/prompts/overview.md + title: "The Open Imaging Finding Models authoring prompt, main at 4475ac1: a scoring system is modeled separately from the observations it assesses, because different radiologists may describe the same nodule and assign different categories" + last_modified: 2026-04-18 + - id: rgo + resource: https://www.gamuts.net/about.php + title: Radiology Gamuts Ontology, the ontology-backed successor to Reeder and Felson - 55,000+ links over two relation types, with every differential produced by traversal (Budovec, Lam and Kahn, RadioGraphics 2014) + - id: hpo-format + resource: https://hpo-annotation-qc.readthedocs.io/en/latest/annotationFormat.html + title: Human Phenotype Ontology annotation format - the frequency scale and its percentage anchors, named in the CDE relationship catalog as the source of typicality + - id: orphadata + resource: https://www.orphadata.com/docs/OrphadataScienceDataDescription.pdf + title: Orphadata science data description - the frequency bins and the pathognomonic definition, named in the CDE relationship catalog as the source of the top specificity value + - id: board-role-tagging + resource: internal project board, not published + title: "Open Imaging Data Model project board (internal), undated; schema idea only" +--- + +# Relationships among definitions + +Definitions relate to one another through a small, typed family of relationships, each declared once in the shared graph with its domain, range, inverse, and symmetry: subtype, component, manifestation, causation, co-occurrence, progression, and assessment.[^cde-relationships][^cde-graph][^cde-branch] The CDE project calls the family tentative and non-comprehensive.[^cde-relationships] + +# Findings ↔ Diagnoses: manifestation and causation + +A diagnosis connects to findings in two ways.[^cde-relationships] A finding can be the diagnosis as it appears on imaging: pyelonephritis *appears as* a striated nephrogram, and when the pyelonephritis resolves, the striation goes with it.[^lead-relationships][^cde-relationships][^cde-graph] Or a diagnosis can bring about a separate entity with its own course: pyelonephritis *may cause* a renal abscess, a complication rather than an appearance, which may have sequela beyond the course of the acute pyelonephritis episode.[^lead-relationships][^cde-relationships][^cde-graph][^cde-worked-examples] The schema records these as two edges, MAY_MANIFEST_AS and MAY_CAUSE.[^cde-graph][^cde-alpha-shape] + +# Associated findings + +Findings and diagnoses also occur together whether or not one causes the other: pleural effusion and atelectasis each occur alone and often occur together.[^lead-relationships][^cde-relationships][^cde-graph][^cde-alpha-graph][^oifm-associated] The schema records this as an OCCURS_WITH edge.[^cde-graph][^cde-alpha-shape] An associated finding is distinct from a component, which is an intrinsic part of another finding, such as the solid component of a part-solid nodule, and is joined by a HAS_COMPONENT edge.[^oifm-associated][^cde-decisions][^cde-alpha-shape][^cde-alpha-graph] + +# How strongly + +The edges themselves carry properties that say how commonly the relationship holds.[^lead-relationships][^cde-graph] A manifestation edge can carry a typicality, from obligate through very frequent, frequent, and occasional to very rare, and a specificity, whether the finding is pathognomonic for the diagnosis, highly suggestive of it, or merely suggestive.[^cde-relationships][^cde-graph] A property left off means no judgment has been recorded, not that the relationship is rare.[^cde-relationships] + +# Deriving the differential + +The schema distinguishes manifestation and causation to enable inference: a manifestation edge can be read backward, from a finding to the diagnoses that appear that way, while a causation edge is read forward, from a diagnosis to the complications to watch for.[^lead-relationships][^cde-relationships][^cde-graph] The differential for a finding is therefore derived, not stored: the diagnoses reachable over manifestation edges in reverse, ranked by the typicality and specificity on those edges, on the precedent of the Radiology Gamuts Ontology.[^cde-relationships][^rgo] No edge type called "differential" exists.[^cde-relationships][^cde-graph] + +# Assessment schemes + +A pulmonary nodule definition specifies how a pulmonary nodule will be described.[^lead-relationships][^oifm-scoring] The assessment is a separate assertion, defined by the AssessmentScheme definition, which allows for evaluation of the nodule according to the defined criteria.[^lead-relationships][^cde-decisions][^oifm-scoring] The scheme is its own node, joined to the definitions it evaluates by an ASSESSED_BY edge.[^lead-relationships][^cde-decisions][^cde-alpha-shape][^cde-graph] + +# A proposal: role tagging of elements + +From a project board: tag element definitions with standard codes for their role, presence, location, size, modality-specific measures, so a consuming system can find the right element across definitions by role rather than by hard-coded identifier.[^board-role-tagging] Proposed, not implemented.[^board-role-tagging] + +The relationship types, with their domains, ranges, inverses, and provenance labels, are listed on the [next-generation schema page](./next-generation-schema.md) and in the schema's own relationship file.[^cde-graph][^cde-relationships] + +[^lead-relationships]: The project lead, 2026-09-30, recorded verbatim in the layout plan under "The guidance, verbatim". On this page: the ruling that emphasizing the relationships are held "strictly apart" "makes it seem like THAT'S the issue", and the subsection titles "Findings <-> Diagnoses: Manifestation and Causation" and "Deriving the Differential"; "Pyelonephritis APPEARS AS striated nephrogram..."; "when the pyelonephritis resolves, the striation goes with it..."; "The schema distinguishes manifestation and causation to enable inference:..."; "We should ALSO include the idea of associated findings here, and the properties of the edges themselves that get at how commonly findings/diagnoses are associated in the specified way"; "Don't include the 'HPO and Orphanet' reference", which is why the origin of the typicality scale appears only in the note below and not in the text; "a pulmonary nodule definition specifies how a pulmonary nodule WILL BE DESCRIBED. The assessment is a separate assertion, defined by the AssessmentScheme definition, which allows for evaluation of the nodule according to the defined criteria."; and "...by an ASSESSED_BY edge". A second statement of 2026-09-30, recorded in the same plan after this page was reviewed, settles four wordings: (1) the associated-findings example changes to a pair the graph records as a co-occurrence edge; (2) the renal abscess clause becomes "...may have sequela beyond the course of the acute pyelonephritis episode."; (3) "whether or not one causes the other"; and (4) the schema's own specificity words, pathognomonic, highly suggestive, suggestive ("they're cooler"). Decisions 1, 3 and 4 move the prose onto what the repository states, and the sentences carrying them now rest on the repository as well as on this statement. Decision 2 is the project lead's own clinical wording. Two things on this page therefore rest on this statement alone for what they actually claim. The clause "which may have sequela beyond the course of the acute pyelonephritis episode" is the project lead's wording and clinical judgment: the repository establishes that the abscess is a separate entity the infection produced and says nothing about its subsequent course.[^cde-worked-examples] And the second sentence of the assessment-schemes section is the project lead's own framing: the repository separates an assessment scheme from what it assesses and joins the two by `ASSESSED_BY`, but nothing in it describes the assessment as "a separate assertion", and the reading that the scheme "allows for evaluation of the nodule according to the defined criteria" goes past S40, which is explicit that it "does not decide automated scoring or report-result structure".[^cde-decisions][^cde-structures] +[^cde-branch]: The ACR/RSNA CDE schema repository, next-gen-2026 branch, read on 2026-09-30 at commit b541b74 of 2026-09-23. Every statement attributed to the repository here is taken from files committed at that commit; the branch had uncommitted working-tree changes on that date, which were not read. The family is working material and carries the project's own provenance labels.[^cde-decisions] +[^cde-relationships]: "The Finding and Diagnosis Relationship Family", the catalog this page summarizes. Its own status line describes it as "a tentative, explicitly non-comprehensive catalog of the relationships needed between findings and diagnoses, to validate against the proposed edge object", written for review. §1 is the family: "Seven pairs and one escape hatch", `SUBTYPE_OF`, the component pair, `MAY_CAUSE`, `MAY_MANIFEST_AS`, `OCCURS_WITH`, `MAY_PROGRESS_TO` and `ASSESSED_BY`, which are the seven this page names, plus `MAY_BE_RELATED_TO`, a symmetric catch-all for "an association the author cannot yet type; a triage queue, not a home", which this page does not list. §2 keeps manifestation and causation apart: manifestation "is constitutive", where "A striated nephrogram is pyelonephritis appearing on imaging, not a second disease", and causation "is consequential", where "A renal abscess is a new thing pyelonephritis made"; the test is "if the target resolved, would a clinician say the source 'got better,' or that 'a complication resolved'? The first is manifestation, the second is causation." §3 is the two edge properties, both optional. Typicality is the HPO and Orphanet frequency scale adopted with its percentage anchors, `obligate` 100%, `very_frequent` 80 to 99%, `frequent` 30 to 79%, `occasional` 5 to 29%, `very_rare` 1 to 4%, and a sixth value this page does not name, `excluded` 0%, the negative assertion that the finding is essentially never seen with the diagnosis, whose fit on an edge named `MAY_MANIFEST_AS` the document itself flags for review; an exact cohort ratio or percentage may be given in place of a bin.[^hpo-format][^orphadata] Specificity is three ordered values, whose committed names and source definitions are `pathognomonic`, "seeing the finding is by itself sufficient to make the diagnosis"; `highly_suggestive`, which "strongly narrows the differential toward this diagnosis but is not independently conclusive; roughly Orphanet's 'major diagnostic criterion' territory"; and `suggestive`, which "meaningfully raises suspicion relative to a coincidental finding, without strongly narrowing the differential on its own".[^orphadata] The text above names these three values directly, on the project lead's decision of 2026-09-30, so its wording is the enumeration rather than a gloss on it; the only word that is not part of a committed name is "merely", which is the page's rendering of the third value and carries no meaning the catalog's own definition of `suggestive` does not.[^lead-relationships] The document is also explicit that there is no `nonspecific` value and that "an absent property means no judgment is recorded". §4 is the derived differential: "The differential of a finding is the set of diagnoses reachable over `MAY_REPRESENT`", the inverse of the manifestation edge, "filtered by the context edges (age stage, modality, anatomic scope), ranked by specificity then typicality", and "No `DIFFERENTIAL_OF` edge type exists". Two differences from the text above, left as differences. The catalog ranks by specificity and then typicality, in that order; this page names the two properties without fixing their order. And the catalog's derivation also gathers the diagnosis subtypes of what it reaches, on a taxonomy rule S57 has since moved.[^cde-decisions] §7 lists what is still open, including whether `OCCURS_WITH` needs an association-strength property and whether the causal pair takes typicality at all; the latter is assumed yes in the worked examples so they could be written, which is a recorded assistant default, not a decision.[^cde-worked-examples][^cde-decisions] +[^cde-graph]: The vocabulary written as JSON Lines. `core.jsonl` declares each relationship type as its own node carrying its definition, domain, range, inverse, symmetry, formal name where one exists, and the properties it may carry, which is the "declared once" this page's first sentence rests on. Checked one by one at this commit: `MAY_MANIFEST_AS`, domain Diagnosis, range FindingClass or Diagnosis, inverse `MAY_REPRESENT`, properties `typicality` and `specificity`; `MAY_CAUSE`, domain and range FindingClass or Diagnosis, inverse `MAY_BE_CAUSED_BY`, formal name RadLex `May_Cause`, properties including `typicality`; `OCCURS_WITH`, symmetric, domain and range FindingClass or Diagnosis, formal name SNOMED `Associated with`, and no strength property, whose declared definition on line 13 of that file is "Seen together; asserts and excludes nothing about causality or sequence", so the relation as the schema declares it is agnostic about causation rather than excluding it, which is what "whether or not one causes the other" says; `SUBTYPE_OF`, `MAY_PROGRESS_TO`, `SCOPED_TO`, `HAS_ELEMENT`, `INTERPRETED_FROM` and `ASSESSED_BY`. No relationship type named for a differential is declared. Four of the five edge names in the text above are committed names in this file: `MAY_MANIFEST_AS`, `MAY_CAUSE`, `OCCURS_WITH` and `ASSESSED_BY`. Only `HAS_COMPONENT` is absent under that name, and it is footnoted where it appears; the `ASSESSED_BY` declaration here differs from the alpha in its range rather than in its name.[^cde-alpha-shape][^cde-structures] `pyelonephritis.jsonl` holds the two pyelonephritis edges this page names: acute pyelonephritis `MAY_MANIFEST_AS` striated nephrogram, typicality `frequent` and specificity `highly_suggestive`, and acute pyelonephritis `MAY_CAUSE` renal abscess, typicality `occasional`, whose own note records that it "assumes 07 Q2 answered yes: the causal pair takes typicality". `pleural-effusion.jsonl` is where the pneumonia and pleural effusion pair is actually written, and it is written as `MAY_CAUSE` with typicality `frequent`, not as co-occurrence; the one `OCCURS_WITH` edge in that file joins pleural effusion to pleural thickening.[^cde-alpha-shape] +[^cde-worked-examples]: "Worked Examples, Acute Pyelonephritis, Pleural Effusion, and One Report", §2 on the pyelonephritis family: "`acute pyelonephritis MAY_CAUSE renal abscess`, typicality occasional, on the assumption that the causal pair takes typicality", with renal abscess a Diagnosis in its own right and a subtype of renal lesion. That node classification is the whole of what the repository supports about the abscess being an entity separate from the infection; it says nothing about the abscess's subsequent course. The clause "which may have sequela beyond the course of the acute pyelonephritis episode" is the project lead's wording and clinical judgment, decided on 2026-09-30, and it is consistent with the repository's own test for the distinction, "if the target resolved, would a clinician say the source 'got better,' or that 'a complication resolved'?"[^lead-relationships][^cde-relationships] The same document warns, before any of its content is used: "Read the provenance before trusting a number. The owner chose the two examples and the effusion's cause list. Every typicality and specificity value, every `expected` hint, the subtype trees, the element choices, and the close-versus-exact code matches are Claude's clinical and terminological estimates, unreviewed." The two examples' relationship content is recorded in the decision record as a Claude invention.[^cde-decisions] +[^cde-decisions]: The decision record carries a provenance column on every row. **OWNER** means "The owner stated it. The quotation is verbatim from the session. This is the decision."; **CLAUDE DEFAULT** means "Claude chose it to keep moving and recorded the choice. The owner has not reviewed it. Reversible."; **CLAUDE INVENTION** means content "that no one has checked. Treat as unverified." A further caution applies from S49 onward: S49 records the project lead's own ruling that nothing is settled by the project's internal discussion, so a decision the project lead and an assistant reached together is a proposal to put to the external reviewer. The rows used here. S33 (2026-09-13) is where `HAS_COMPONENT`, with inverse `COMPONENT_OF`, is named, PROPOSED and ACCEPTED, replacing an earlier two-relationship form, with a count on the container's side and a component-of scope on the component's side, and the rule that "A class with a component-of scope is never reported on its own". **S58 withdraws that form**: the disposition is the reviewer's two distinct edges, the whole must have the part and the part occurs only in that whole, with a minimum count proposed on the first, OWNER, pending joint confirmation. The edge name this page uses survives both rows. S39, Measurement and DataElement as distinct definition types, PROPOSED and ACCEPTED with OWNER clarifications. S40, AssessmentScheme "a separate definition type, organized more like FindingClass with edges to multiple DataElement-like descriptors", OWNER, from "I actually like the idea of AssessmentScheme being a separate definition type"; the same row states that it "does not decide automated scoring or report-result structure", and records that Lung-RADS and cancer staging are the project lead's motivating examples, not clinical definitions adopted there. S41 settles the descriptors as ordinary DataElements, OWNER. S40 and S41 are marked documentation only. No row in the record decides `OCCURS_WITH` itself; the two uses of it in the worked families, hydronephrosis with pyelonephritis and pleural thickening with pleural effusion, are recorded under C2 and C4 as CLAUDE INVENTION.[^cde-worked-examples][^cde-graph] S57 has since moved the taxonomy rule the differential derivation in the catalog relies on, so that a diagnosis is never a subtype of a finding.[^cde-relationships] +[^cde-structures]: "Draft Structures for Worked Examples". Its §1 node table carries the AssessmentScheme row, and the §1 update under S40 and S41 states the separation this page's assessment section describes: "a scheme has edges to multiple ordinary DataElements, analogous to FindingClass's organization"; "The scheme, its dimensions, and their permissible values are different objects"; and "Older examples that represent assessment schemes as finding definitions are not the current direction". The same row leaves binding names and any use of Measurements for quantitative components open. This document is also where the component name collision is visible: at this commit it writes the definition-plane edge `MAY_HAVE_COMPONENT` and reserves `HAS_COMPONENT` for the report-plane edge between two Observations, so the two planes used the same word for different things before S33 renamed the definition-plane edge.[^cde-decisions] +[^cde-alpha-shape]: The alpha's generated node and edge documentation, generated from the build on 2026-09-14 and not hand-edited. §4 tabulates every edge with its signature, count and properties, and opens with the caveat any use of it has to carry: "Signatures are the tail and head types observed in the build, not everything the edge is permitted to take." All five edge names in the text above are committed names here: `MAY_MANIFEST_AS` (Diagnosis to FindingClass, 38 edges, properties `specificity` and `typicality`), `MAY_CAUSE` (10 edges, property `typicality`), `OCCURS_WITH` (FindingClass to FindingClass, 4 edges, symmetric and "Stored once; consumers traverse the predicate in both directions"), `HAS_COMPONENT` ("The whole must have this sub-part", 1 edge) alongside `COMPONENT_OF` ("This sub-part belongs only to that whole; says nothing about whether the whole has one", 2 edges), and `ASSESSED_BY` (FindingClass or Diagnosis to AssessmentScheme, 5 edges). Two differences from the earlier representation are left standing rather than merged, and they are different kinds of difference: one changed name and one changed range. The name: `core.jsonl` at the same commit still declares the component edge as `MAY_HAVE_COMPONENT` with inverse `MAY_BE_COMPONENT_OF`, so `HAS_COMPONENT` is the one body edge name absent from that file. The range: that file does declare `ASSESSED_BY` under this same name, but ranges it on a FindingClass acting as an assessment rather than on an AssessmentScheme node. That file predates S33, S40 and S41.[^cde-graph][^cde-decisions][^cde-structures] This document is also where the rule is written that the associated-findings example above satisfies: `occurs-with-same-type` states that "OCCURS_WITH relates two findings or two diagnoses. Between a diagnosis and a finding a more specific edge already exists (MAY_MANIFEST_AS or MAY_CAUSE), so reaching for co-occurrence there is declining to say which". Pleural effusion and atelectasis are both FindingClass nodes, so the pair sits inside that rule. The page's earlier example did not: pneumonia is a Diagnosis and pleural effusion a FindingClass, and the alpha records that pair as "a **`MAY_CAUSE`**, not a `MAY_MANIFEST_AS`. Pneumonia does not show itself as an effusion, it produces one", which is why the project lead replaced the example on 2026-09-30.[^cde-alpha-graph][^cde-graph][^lead-relationships] +[^cde-alpha-graph]: The reviewer's alpha definition graph, the export inspected here, which the project lead selected as the implementation approach going forward on 2026-09-14 while noting that "Selecting the implementation approach does not automatically accept every structural choice in the alpha". The component edges in it, read one by one: `HAS_COMPONENT` from part-solid pulmonary nodule to solid component of part-solid pulmonary nodule, the single edge of that type and the example this page names, and `COMPONENT_OF` from that solid component back to the part-solid nodule and from mural nodule to complex renal cyst. Its four `OCCURS_WITH` edges all run from pleural effusion, to atelectasis, consolidation, ground-glass opacity and mediastinal lymphadenopathy, each between two FindingClass nodes. Pleural effusion with atelectasis is the first of those and is the example the sentence above uses. One limit of it: that edge carries no properties, and no co-occurrence edge in either authored graph carries any, because `core.jsonl` declares the relation with no strength property and whether it needs one is still an open question in the catalog. "Often occur together" is therefore an ordinary clinical statement rather than something the graph records; the frequency properties described further down this page sit on manifestation and causal edges only.[^cde-graph][^cde-relationships] Pneumonia reaches pleural effusion here by `MAY_CAUSE` with typicality `frequent`, as it does in the JSON Lines family, which is why it is no longer the page's co-occurrence example.[^cde-alpha-shape][^lead-relationships] +[^oifm-associated]: "Associated findings vs components", the Open Imaging Finding Models authoring fragment, which is where the distinction this page draws is stated on the finding-model side and where the pneumonia and pleural effusion example comes from. An associated finding is "a separate, independent finding that happens to co-occur with the index finding. It has its own lifecycle", and its independence test is "could you see this related thing *without* the index finding, or vice versa?" The example, verbatim: "pneumonia and pleural effusion. A patient can have pneumonia without effusion, or effusion without pneumonia. They co-occur frequently but are separate entities with their own attributes". A component is "a structural part of the index finding itself - not a separate entity, but a piece of it complex enough to justify its own model", and its test is "would you ever document this thing as a standalone observation without its parent? If not, it's a component"; its example is the solid and ground-glass components of a mixed pulmonary nodule, "parts of what the nodule IS". Note that the authoring rule is document-shaped rather than graph-shaped: an associated finding is recorded as "One multichoice `associated findings` attribute on the index model", presence-level only, whose values name other finding models, while a component is extracted into a model of its own. The graph edges above are the CDE schema's way of holding the same distinction; no source read for this page states that the two mechanisms were reconciled.[^cde-graph][^cde-alpha-shape] Note that this fragment's own example of an associated pair is pneumonia and pleural effusion, which is not the pair the sentence above uses. Both authored CDE graphs join pneumonia to pleural effusion by a causal edge instead, and the alpha's same-type rule would not permit a co-occurrence edge between a diagnosis and a finding, so the project lead's decision of 2026-09-30 moved the page's example onto a pair the graph does record as a co-occurrence.[^cde-graph][^cde-alpha-shape][^cde-alpha-graph][^lead-relationships] This fragment is cited above for the distinction itself, which both collections draw the same way, not for the choice of example. On the sentence's other half, the independence test establishes that either finding can occur without the other, and it takes no position on whether one causes the other when they do occur together, which is the same agnosticism the CDE catalog states in SNOMED's words, an association "without either asserting or excluding a causal or sequential relationship".[^cde-relationships] +[^oifm-scoring]: The Open Imaging Finding Models authoring prompt, which states on the finding-model side that the thing assessed and the assessment are different definitions: "**Scoring systems and structured assessments are valid findings**, but should be modeled separately from the observations they assess. A 'pulmonary nodule' finding model captures what the nodule looks like (size, morphology, location). A 'Lung-RADS category' finding model captures the risk assessment assigned to it. These are separate because different radiologists might describe the same nodule but assign different risk categories - and systems need to reason about both independently." The companion authoring fragment on scope repeats it: scoring systems "are valid findings in their own right, modeled **separately** from the observations they assess". This supports the separation and the pulmonary nodule and Lung-RADS pairing, not the AssessmentScheme node type, which is the CDE schema's construct; in this collection both sides are finding models.[^cde-decisions] +[^rgo]: Radiology Gamuts Ontology, the precedent the CDE relationship catalog cites by name for deriving rather than storing a differential: "The Radiology Gamuts Ontology, the ontology-backed successor to Reeder and Felson, carries 55,000+ links using exactly two relation types, is-a and may-cause, and produces every differential by traversing incoming causal links to a finding (Budovec, Lam, and Kahn, RadioGraphics 2014; gamuts.net)." The catalog also records that no source it surveyed, across that ontology, HPO and Orphanet, SNOMED CT, UMLS, Radiopaedia and STATdx, stores differentials as diagnosis-to-diagnosis edges. Cited here as the CDE catalog cites it; the ontology's own site and the 2014 paper were not re-read for this page.[^cde-relationships] +[^hpo-format]: Human Phenotype Ontology annotation format, named in the CDE relationship catalog as the source of the typicality scale, whose bins and percentage anchors the catalog adopts verbatim and whose permission to give an exact cohort ratio in place of a bin it also adopts. Recorded here only, at the project lead's instruction that the reference stay out of the prose.[^lead-relationships][^cde-relationships] +[^orphadata]: Orphadata science data description, named in the CDE relationship catalog alongside the HPO annotation format for the frequency bins, and as the source of the `pathognomonic` definition the catalog quotes, "a sign whose presence indicates that a particular disease is present beyond any doubt". Recorded here only, at the project lead's instruction that the reference stay out of the prose.[^lead-relationships][^cde-relationships] +[^board-role-tagging]: Open Imaging Data Model project board (internal), undated; schema idea only. The proposal is to tag each element definition with a standard code, SNOMED or RadLex, naming the role it plays: presence, location, size in its several measures, and modality-specific measures such as radiodensity, echogenicity and MR signal, so that a consuming system finds the right element by looking up the code for the role rather than hard-coding a set-specific identifier. It is a working proposal with no date and no implementation cited, and nothing read for this page connects it to the graph's own route to the same reuse, one shared DataElement node bound by many definitions.[^cde-structures] diff --git a/knowledge/drafts/sample-applications.md b/knowledge/drafts/sample-applications.md new file mode 100644 index 0000000..c9902cd --- /dev/null +++ b/knowledge/drafts/sample-applications.md @@ -0,0 +1,160 @@ +--- +type: Concept +title: Sample Applications +description: Applications that author shared definitions, display imaging histories, extract and review findings, and demonstrate structured exchange. +tags: [applications, authoring, imaging-history, extraction, interoperability] +status: draft +generated: { by: codex/2026-09-22-restructure-sample-applications, at: 2026-09-22T13:52:23Z } +sources: + - id: forge-workflow + resource: https://github.com/openimagingdata/FindingModelForge/blob/15d9ebcf64734b889081feed4d645a0afca67e61/docs/finding-model-creation-workflow.md + title: Finding Model Forge creation workflow, dev snapshot of 2026-01-02 + - id: forge-drafts + resource: https://github.com/openimagingdata/FindingModelForge/blob/15d9ebcf64734b889081feed4d645a0afca67e61/docs/DRAFT_WORKFLOW.md + title: Finding Model Forge draft lifecycle, dev snapshot of 2026-01-02 + - id: catalog-loader + resource: https://github.com/openimagingdata/finding-models-site/blob/6298fa3b900bb46b488f82d0a5b9aab06f70ca69/src/data/loadFindingModels.ts + title: Finding model catalog loader, main snapshot of 2025-06-19 + - id: catalog-page + resource: https://github.com/openimagingdata/finding-models-site/blob/6298fa3b900bb46b488f82d0a5b9aab06f70ca69/src/pages/models/%5Bslug%5D.astro + title: Finding model catalog detail page, main snapshot of 2025-06-19 + - id: findingmodel-cli + resource: https://github.com/openimagingdata/findingmodel/blob/75afd39a400419dcfaf7c8d4a34f065b4d804e0d/packages/findingmodel/README.md + title: Findingmodel command-line tools, main snapshot of 2026-03-04 + - id: anatomy-cli + resource: https://github.com/openimagingdata/findingmodel/blob/75afd39a400419dcfaf7c8d4a34f065b4d804e0d/docs/anatomic-locations.md + title: Anatomic locations command-line tools, main snapshot of 2026-03-04 + - id: viewer-one + resource: https://github.com/openimagingdata/imaging-problem-list/blob/06f64a7893b444b761dc069ed86140a081195eac/viewer/app.js + title: IPL viewer implementation, main snapshot of 2025-11-18 + - id: viewer-one-notes + resource: https://github.com/openimagingdata/imaging-problem-list/blob/06f64a7893b444b761dc069ed86140a081195eac/CLAUDE.md + title: IPL viewer notes, main snapshot of 2025-11-18 + - id: viewer-demos + resource: https://oidm-public.t3.tigrisfiles.io/oidm-knowledge-sources/IPL%20Webinar%20Deck.html + title: SIIM IPL webinar, 2026-07-15, live prototype slides 26 and 33 + - id: viewer-two + resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/docs/plans/viewer-v2-anatomy-dashboard.md + title: Anatomy viewer implementation and design, dev snapshot of 2026-07-22 + - id: viewer-metadata + resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/viewer_v2/src/App.tsx + title: Anatomy viewer instance, definition, and anatomy panels, dev snapshot of 2026-07-22 + - id: extraction-platform + resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/README.md + title: Extraction and persistence platform, dev snapshot of 2026-07-22 + - id: extraction-internals + resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/docs/extraction-internals.md + title: Extraction and reviewer contracts, dev snapshot of 2026-07-22 + - id: coding-design + resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/docs/coding-agent-design.md + title: Independent coding pipeline design, updated 2026-03-16 + - id: validator-prompt + resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/prompts/validator_prompt_example.md + title: Chunk reviewer prompt and failure taxonomy, dev snapshot of 2026-07-22 + - id: human-review + resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/docs/plans/extraction-reviewer-ux.md + title: Standalone extraction reviewer, implementation review of 2026-07-20 + - id: evaluation-plan + resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/docs/plans/extractor-evals-redesign.md + title: Extractor evaluation redesign, scope decision of 2026-07-07 + - id: local-policy + resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/src/finding_extractor/llm/policy.py + title: Local inference policy implementation, dev snapshot of 2026-07-22 + - id: local-limits + resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/docs/plans/local-only-future-tightening.md + title: Local-only operation, documented limits and deferred checks, dev snapshot of 2026-07-22 + - id: early-pipeline + resource: https://github.com/openimagingdata/IPL-MVP-ExtractionAndLabeling/blob/b06948fa417aeff0a6a4b97729c915b3ce5d5ed4/README.md + title: Earlier extraction and labeling pipeline, main snapshot of 2025-10-20 + - id: early-prompt + resource: https://github.com/openimagingdata/IPL-MVP-ExtractionAndLabeling/blob/b06948fa417aeff0a6a4b97729c915b3ce5d5ed4/config.py + title: Earlier extraction prompt and matching threshold, main snapshot of 2025-10-20 + - id: siim-rendering + resource: https://www.openimagingdata.org/siim-update/ + title: OIDM SIIM Update, completed template-rendering demonstration, 2023-06-26 + - id: template-demo + resource: https://github.com/openimagingdata/CDETemplateDemo/blob/e09f2553de58b2c88ea26e9673750a62803d4dbc/mapper-logic/src/mappers/obsToMustache.ts + title: CDE Template Demo observation-to-template renderer, master snapshot of 2023-06-15 + - id: siim-search + resource: https://www.openimagingdata.org/siim-2024-update-hackathon-edition/ + title: OIDM SIIM 2024 Update, completed ontology-search demonstration, 2024-07-02 + - id: rsna-team-demo + resource: https://www.openimagingdata.org/2024-new-year-update/ + title: OIDM 2024 New Year Update, reporting framework and AI in Practice demonstrations, 2024-01-12 + - id: nodule-workflow + resource: Internal source archive, Pulm Nodule Demo Project working board, schema and workflow portions only + title: Pulm Nodule Demo Project, undated working board, schema and workflow content +--- + +# Sample Applications + +These examples accompany [Foundation Context](./foundation-context.md), [Data Structures](./data-structures.md), and [SDKs](./sdks.md). [Use Cases](./use-cases.md) describes the team's proposed applications. The implementation dates below identify the source versions. + +## Authoring and inspecting shared definitions + +[Finding Model Forge](https://fmf.oidm.org) provides a browser workflow for authoring [finding models](./finding-models-and-cdes.md). In its January 2026 development version, users review an AI-generated description, check for similar models, and edit attributes before generating a model with identifiers and standard codes. Submission locks the draft for review. The lifecycle distinguishes drafting, submission, review, acceptance into the collection, and rejection.[^forge-workflow][^forge-drafts] + +The [catalog site](https://openimagingdata.github.io/finding-models-site/) provides a reading interface to those definitions. Its June 2025 implementation builds pages from the definition files, showing each model's name, description, and raw JSON.[^catalog-loader][^catalog-page] + +The March 2026 command-line tools expose other ways to inspect that content. `findingmodel` searches definitions, validates their JSON, and renders Markdown. `anatomic-locations` looks up locations by identifier, name, or synonym and displays containment ancestors and descendants. These are applications of the reusable packages described under [SDKs](./sdks.md).[^findingmodel-cli][^anatomy-cli] + +The team's SIIM 2024 hackathon front end demonstrated full-text and semantic search across Anatomic Locations, RadLex, and SNOMED CT, returning ranked candidates from six searches.[^siim-search] + +## Viewing a patient's imaging history + +The [first Imaging Problem List viewer](https://imaging-problem-list.pages.dev) connects the [longitudinal finding list](./data-structures.md) to individual Exam Finding Lists and report text.[^viewer-demos] In the November 2025 `main` code, status filters distinguish present, resolved, and never-present findings. Its body-region filter uses a curated finding-to-region table, although the repository notes describe keyword inference.[^viewer-one][^viewer-one-notes] + +The [second viewer](https://main.ipl-anatomy.pages.dev), also demonstrated in the July 2026 webinar, uses coded anatomy for a body-map display.[^viewer-demos] Its July 2026 development version provides progressive drill-down to findings, observations, and source reports. Its design explicitly prohibits anatomy grouping from merging or splitting IPL entries. Generic or unspecified laterality stays separate from left and right, and unresolved anatomy remains visible as unlocalized.[^viewer-two] + +The detail view separates patient instance data, finding-definition metadata, and anatomy metadata. A reader can distinguish the finding's actual site and history from the definition's typical anatomy. The interface also displays warnings for missing definitions, missing anatomy, and evidence text that cannot be matched exactly.[^viewer-metadata][^viewer-two] + +## Extracting, coding, and reviewing reports + +The July 2026 `imaging-problem-list` development version implements report extraction and persistence for [structured imaging findings](./data-structures.md). It stores each extraction with its report, model, reasoning setting, and output. Reviewer corrections are separate objects for additions, changes, or comments.[^extraction-platform] + +Coding is an independent job that can run again over a saved extraction. Exact-name or synonym lookup comes first. Unresolved findings go through search-term generation, index search, and code selection, with finding type and anatomic location handled separately. One finding's coding failure does not block the others.[^coding-design] + +Extraction works in report chunks and requires verbatim supporting text. A different model can review each chunk and request targeted re-extraction. Its failure taxonomy covers unsupported content, missed findings, wrong presence, excessive specificity, mishandled blanket negatives, and incorrect location. Review timeouts do not stop the pipeline, and output can complete with explicit warnings.[^extraction-internals][^validator-prompt] + +The standalone human-review application opens as a local HTML file without a runtime network connection. Reviewers approve, flag, or mark findings unsure, inspect their evidence in the full report, record missed findings, and export review decisions.[^human-review] + +The July 2026 evaluation redesign remains a plan. It rejects raw finding yield as evidence of better recall because fabricated findings can increase yield. The proposed replacement matches evidence quotes first, scores attribute values, freezes run settings, and compares outputs with human-adjudicated gold held out from prompt examples.[^evaluation-plan] + +For protected reports, the platform supports local Ollama and approved on-premises vLLM inference. Its local-only policy has documented limits, including undetected cloud aliases and first-use model downloads.[^local-policy][^local-limits] + +### Earlier extraction pipeline + +The October 2025 MVP separates extraction from vocabulary matching in a smaller experiment. Its prompt requests finding names and binary presence, including explicit negatives, while its README lists negation as unsupported. A second step matches names to a small definition set through embedding similarity and flags results below a threshold for review. Its README reports 5 matches among 87 extracted findings using 15 neuro finding models.[^early-prompt][^early-pipeline] + +## Demonstrations of rendering and exchange + +At SIIM 2023, the team demonstrated a service that renders CDE-labeled FHIR Observations as prose. Its front end let users edit sample observations and templates to change the output. The [CDE Template Demo implementation](https://github.com/openimagingdata/CDETemplateDemo/tree/e09f2553de58b2c88ea26e9673750a62803d4dbc) renders observation components through Mustache templates.[^siim-rendering][^template-demo] + +The team's January 2024 update reports an OIDM-based assisted-reporting demonstration at RSNA and AI in Practice demonstrations presented by OIDM members.[^rsna-team-demo] The more detailed [pulmonary nodule exchange workflow](./use-cases.md) remains a board proposal, with tracking-ID assignment and cross-exam association open.[^nodule-workflow] + +[^forge-workflow]: Finding Model Forge creation workflow, dev snapshot of 2026-01-02. +[^forge-drafts]: Finding Model Forge draft lifecycle, dev snapshot of 2026-01-02. +[^catalog-loader]: Catalog loader, main snapshot of 2025-06-19. +[^catalog-page]: Catalog detail page, main snapshot of 2025-06-19. +[^findingmodel-cli]: Findingmodel README, CLI section, main snapshot of 2026-03-04. +[^anatomy-cli]: Anatomic locations guide, CLI commands, main snapshot of 2026-03-04. +[^viewer-one]: IPL viewer code, loadFindingRegionMappings, getBodyRegions, and computeFindingStatus, main snapshot of 2025-11-18. +[^viewer-one-notes]: IPL architecture notes, IPL Viewer Application, main snapshot of 2025-11-18. These notes describe keyword inference, unlike the table lookup in the code at the same commit. +[^viewer-demos]: SIIM IPL webinar, 2026-07-15, slides 26 and 33. The slides identify the two live prototype addresses. +[^viewer-two]: Anatomy viewer plan, implementation notes and anatomy mapping rules, dev snapshot of 2026-07-22. +[^viewer-metadata]: Anatomy viewer application, MetadataSections, ObservationDrilldown, and warning display, dev snapshot of 2026-07-22. +[^extraction-platform]: IPL README, extraction and persistence sections, dev snapshot of 2026-07-22. +[^extraction-internals]: Extraction internals, chunk and reviewer contracts and terminal outcomes, dev snapshot of 2026-07-22. +[^coding-design]: Coding Agent Design, independent-job architecture and failure handling, updated 2026-03-16. +[^validator-prompt]: Validator prompt, issue taxonomy and evidence boundary, dev snapshot of 2026-07-22. +[^human-review]: Extraction Reviewer UX plan, verified implementation update of 2026-07-20. +[^evaluation-plan]: Extractor Evals Redesign Plan, scope decision and core decisions of 2026-07-07. +[^local-policy]: Inference policy, enforce_local_only, dev snapshot of 2026-07-22. +[^local-limits]: Future Local-Only Tightening, deferred alias detection and model-download behavior, dev snapshot of 2026-07-22. The remaining tightening is marked not started. +[^early-pipeline]: IPL-MVP-ExtractionAndLabeling README, mapping workflow and reported experiment, main snapshot of 2025-10-20. +[^early-prompt]: Earlier pipeline configuration, extraction prompt and similarity threshold, main snapshot of 2025-10-20. +[^siim-rendering]: [OIDM SIIM Update](https://www.openimagingdata.org/siim-update/), Hackathon Project, 2023-06-26. +[^template-demo]: CDE Template Demo, obsToMustache renderer, master snapshot of 2023-06-15. +[^siim-search]: [OIDM SIIM 2024 Update](https://www.openimagingdata.org/siim-2024-update-hackathon-edition/), demonstrated search front end and ranked results, 2024-07-02. +[^rsna-team-demo]: [OIDM 2024 New Year Update](https://www.openimagingdata.org/2024-new-year-update/), OIDM Assisted Reporting Framework Enhancements and AI in Practice Demos, 2024-01-12. +[^nodule-workflow]: Pulm Nodule Demo Project board, schema and workflow portions only. Named individuals and collaboration history are omitted. diff --git a/knowledge/drafts/sdks.md b/knowledge/drafts/sdks.md new file mode 100644 index 0000000..def201e --- /dev/null +++ b/knowledge/drafts/sdks.md @@ -0,0 +1,145 @@ +--- +type: Concept +title: SDKs +description: The tools that wrap the data structures and resolve their codes into Foundation Context, plus the libraries that help author that context. +tags: [sdks, foundation-context, findingmodel, anatomic-locations, terminologies] +status: draft +generated: { by: claude-opus-5/2026-09-22-restructure/draft-sdks, at: 2026-09-22T13:20:00Z } +stale_after: 2027-09-22 +sources: + - id: notes + resource: Joint working notes for the restructure, docs/plans/restructure-joint-notes.md + title: "Decisions of 2026-09-22: the five pillars, in the project lead's words" + - id: siim + resource: https://oidm-public.t3.tigrisfiles.io/oidm-knowledge-sources/SIIM%202026%20Reports-of-the-Future.pptx + title: SIIM 2026 annual meeting talk, June 2026, Mass General Brigham, slides 13-15 + - id: gamma + resource: https://gamma.app/docs/Open-Imaging-Data-Model-2026-Status-Update-Realizing-Object-Oriented-Imaging-Results-yfxzx4q9zssafal + title: Open Imaging Data Model 2026 Status Update, January 2026, applications pillar and call to action + - id: fm-readme + resource: https://github.com/openimagingdata/findingmodel/blob/75afd39a400419dcfaf7c8d4a34f065b4d804e0d/packages/findingmodel/README.md + title: findingmodel package README, released snapshot 2026-03-04 + - id: fm-mcp + resource: https://github.com/openimagingdata/findingmodel/blob/75afd39a400419dcfaf7c8d4a34f065b4d804e0d/docs/mcp_server.md + title: Finding Model MCP server guide, released snapshot 2026-03-04 + - id: fm-ai + resource: https://github.com/openimagingdata/findingmodel/blob/75afd39a400419dcfaf7c8d4a34f065b4d804e0d/packages/findingmodel-ai/README.md + title: findingmodel-ai package README, released snapshot 2026-03-04 + - id: fm-rewrite + resource: https://github.com/openimagingdata/findingmodel/blob/1942b06a91d6a5c5eefe10f99a7273e41e24be01/docs/canonical-structured-metadata-and-enrichment-rewrite.md + title: Canonical Structured Metadata and Enrichment Rewrite, metadata-cleanup snapshot 2026-06-29 + - id: adr-schema + resource: https://github.com/openimagingdata/findingmodel/blob/1942b06a91d6a5c5eefe10f99a7273e41e24be01/docs/adr/0001-lean-metadata-docs-schema-is-spec.md + title: Architecture decision record 0001, metadata-cleanup snapshot 2026-06-29 + - id: adr-dualdb + resource: https://github.com/openimagingdata/findingmodel/blob/1942b06a91d6a5c5eefe10f99a7273e41e24be01/docs/adr/0003-dual-db-pre-post-metadata-release.md + title: Architecture decision record 0003, metadata-cleanup snapshot 2026-06-29 + - id: al-readme + resource: https://github.com/openimagingdata/findingmodel/blob/75afd39a400419dcfaf7c8d4a34f065b4d804e0d/packages/anatomic-locations/README.md + title: anatomic-locations package README, released snapshot 2026-03-04 + - id: bpi-ts + resource: https://github.com/talkasab/BodyPartIndex.ts/blob/dec578e10293d722e6136802cc5dfda2599f0f45/README.md + title: BodyPartIndex.ts README, last changed 2022-12-18 + - id: bpi-py + resource: https://github.com/talkasab/BodyPartIndex.py/blob/388ae0a6da92f5ee4cf36620bbeeabe223938471/README.md + title: BodyPartIndex.py README, last changed 2024-02-03 + - id: bpi-todo + resource: https://github.com/talkasab/BodyPartIndex.py/blob/388ae0a6da92f5ee4cf36620bbeeabe223938471/TODO.md + title: BodyPartIndex.py open work list, updated 2024-02-03 + - id: molu-readme + resource: https://github.com/openimagingdata/med-ontology-lookup/blob/9cc3eec2c7af32e366e3f05e027b223b4a870077/README.md + title: med-ontology-lookup README, snapshot 2026-09-18 + - id: molu-roadmap + resource: https://github.com/openimagingdata/med-ontology-lookup/blob/9cc3eec2c7af32e366e3f05e027b223b4a870077/docs/product-roadmap.md + title: "Product direction: an agent-ready medical terminology graph gateway, 2026-08-16" + - id: molu-review + resource: https://github.com/openimagingdata/med-ontology-lookup/blob/9cc3eec2c7af32e366e3f05e027b223b4a870077/docs/project-review-and-proposal.md + title: med-ontology-lookup project review and proposal, 2026-09-03 + - id: site-2024 + resource: https://www.openimagingdata.org/2024-new-year-update/ + title: 2024 New Year Update, openimagingdata.org, 2024-01-12 + - id: ipl-issue + resource: https://github.com/openimagingdata/imaging-problem-list/issues/1 + title: "imaging-problem-list issue #1, Create System of Data Models, open and unassigned as of 2026-09-22" + - id: ipl-coding + resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/docs/coding-agent-design.md + title: Coding Agent Design, development snapshot, document last updated 2026-03-16 +--- + +# What an SDK is in this project + +The project lead defined this pillar on 2026-09-22 as "the tools that wrap the data structures and enable developers working in the application layer to manipulate instances in real-world applications (and some around helping with definition of the foundation context, obviously)".[^notes] Some of what sits here serves developers building applications, and some serves the people and agents who author the shared definitions those applications resolve against. + +The June 2026 SIIM talk gives the pillar a single shared job, under the heading "Resolve, don't reinvent": an Observation carries a code, the code is a pointer, and the pointer resolves into Foundation Context. The slide states the goal directly, "OIDM SDKs make resolution easy and standardized — every app pulls the same context the same way", and names two families of consumer. Determinative tools want "reliable, machine-readable rules" for "safety checks, protocoling, quality metrics". Generative agents want "grounding that reduces hallucination" and "a citable, shared context across apps".[^siim] The preceding slide makes the case by example: for a pulmonary nodule, an abdominal aortic aneurysm and a renal calculus, "none of it was in the patient's record — all of it came from resolving the codes, the same way for every finding".[^siim] The talk's closing ask lists three items, the third being "Build against SDKs".[^siim] That is a stated goal as of June 2026, not a description of a finished toolkit. + +The definitions being resolved into are described in [Foundation Context](./foundation-context.md); the structures being wrapped are in [Data Structures](./data-structures.md). + +# Capabilities that exist today + +## Resolving and searching finding models + +The `findingmodel` package gives a developer the finding model format as objects, with identifiers, attributes and index codes on the loaded object, and an index that resolves a name, a synonym or an identifier to a definition. It also ships a Model Context Protocol server that exposes the same index to agents as three tools: search, retrieve by identifier or name, and index statistics. Implemented example, released snapshot 2026-03-04.[^fm-readme][^fm-mcp] + +Over that corpus the team separated three retrieval modes rather than overloading one. Query-driven search combines full-text and vector retrieval, with metadata filters pushed into candidate generation before ranking. Browse is filter-only with pagination, and explicitly replaces an earlier arrangement where an empty search string carried tag filters. Related-model lookup is deterministic with no language model, scoring metadata overlap with configurable weights, anatomic location weighted highest, then index codes, then entity type, then body region and the remaining facets. Filters are OR within a facet and AND across facets, while tags keep all-of semantics. The rewrite document records the weights as provisional and says they "must be tuned against a gold case set before release".[^fm-rewrite] Implemented example on the development and metadata branches, metadata-cleanup snapshot 2026-06-29; absent from the released snapshot. + +## Helping author the Foundation Context + +The same workspace carries the authoring half of the project lead's definition. A developer can generate a finding's basic information from its name, add detail with citations, turn a Markdown outline into a model, and create a stub model to start from. Implemented example, released snapshot 2026-03-04.[^fm-ai] The metadata rewrite adds one entrypoint for metadata assignment that returns the updated model together with a separate review artifact holding raw candidates, normalization notes and review-oriented reasoning; its design rules keep query generation, candidate gathering, normalization and fallback behaviour in code, leaving the model-facing step to classify typed input into typed output. Implemented example on the metadata branch, metadata-cleanup snapshot 2026-06-29; absent from the released snapshot.[^fm-rewrite] + +Reusable authoring capability belongs here. The content itself, and the rules for reviewing it, are in [Finding models and CDEs](./finding-models-and-cdes.md); the authoring applications built on top are in [Sample Applications](./sample-applications.md).[^notes] + +## The SDK's own recorded decisions + +Two architecture decision records state how this SDK treats its own documentation and its own releases. They are decisions about that package, recorded by the team on its metadata-cleanup branch, and nothing about them is a project-wide rule.[^adr-schema][^adr-dualdb] + +The first is titled "Metadata docs are a lean decision/policy record; the Pydantic schema is the spec". Its decision is that the metadata documents hold judgments and rules, while field types, patterns, the code object's shape and value-normalization behaviour live in the models and are read from code. The stated cause is that hand-maintained structural documents drift and produce stale content, with a prior consolidation named as the example that "lost and duplicated exactly this kind of detail". Architecture decision, metadata-cleanup snapshot 2026-06-29.[^adr-schema] + +The second publishes two database artifacts built from the same enriched source commit: one in the legacy shape readable by the currently published runtime, and one metadata-aware, carrying structured-metadata columns, enriched JSON and a provenance table. The stated reason is that existing consumers keep working unchanged while metadata-aware consumers get the new data, "rather than forcing a breaking single-DB migration". Architecture decision, partly implemented, metadata-cleanup snapshot 2026-06-29.[^adr-dualdb] + +## Resolving anatomic locations + +The `anatomic-locations` package gives a developer lookup by an identifier, or by a description or synonym matched without regard to case; traversal of the parent and child hierarchy; laterality variants; and hybrid full-text and semantic search, including a batch path that takes several queries in one embedding call. Implemented example, released snapshot 2026-03-04.[^al-readme] The location set itself is in [Anatomic locations](./anatomic-locations.md). + +Its dated predecessors are two wrapper libraries over the 2022 anatomic location set. Both give a developer retrieval by a RadLex, SNOMED or FMA code, the containing and part-of parents of a location, a test of whether one location is contained by another, and the three-way sided arrangement in which the index holds an unsided, a left and a right version of a sided part, each aware of the others. The TypeScript library documents walks in both directions, immediate and full, for both relations; the corresponding section of the Python library's README is an empty stub. Implemented examples, last changed 2022-12-18 for the TypeScript library and 2024-02-03 for the Python one.[^bpi-ts][^bpi-py] The Python library's open work list, updated 2024-02-03, records intent never carried out there: move the repository to the openimagingdata organization, adopt the ACR Common codes, acknowledge the DICOM codes, and rework the body part as a Pydantic model.[^bpi-todo] + +## Resolving terminology + +`med-ontology-lookup` gives a developer one normalized interface over RadLex, SNOMED CT, FMA, LOINC and UMLS, reached through the BioPortal and UMLS Terminology Services interfaces. Its stated version 0.1 capability is free-text search across those vocabularies with results balanced per ontology "so SNOMED does not crowd out RadLex", retrieval of a concept by CUI, RadLex identifier, SNOMED code or FMA identifier, crosswalk through UMLS CUIs into other vocabularies, one-hop parents and children for hierarchy checks, semantic-type filters, auto-detection of whether an input is a term, a code or a CUI, and a portable agent skill carried in the repository. Implemented example, snapshot 2026-09-18.[^molu-readme] + +Two team documents state where it should go, and they agree on the destination while differing on what comes first. The product direction of 2026-08-16 calls for "the small, dependable layer that lets people and agents resolve medical language to versioned concepts", with an explicit radiology default profile over RadLex, LOINC including the Playbook, SNOMED CT, FMA and UMLS as the CUI hub, with mapping direction, scope and provenance preserved instead of treating every cross-reference as equivalence, and with equal support for Python, structured command-line output and an agent protocol.[^molu-roadmap] The project review of 2026-09-03 calls the package "a credible alpha nucleus" that "is not ready to expand broadly", and puts hardening first: stop hiding provider failures, stop silently truncating graph-shaped responses, stop presenting ambiguous or weak mappings as unqualified crosswalks, with bounded graph operations added only after those contracts are trustworthy.[^molu-review] Working proposals, both dated. The vocabularies themselves are in [Standards](./standards.md). + +# Proposed SDKs + +## An Imaging Problem List SDK + +Working proposal. Issue #1 on `imaging-problem-list`, "Create System of Data Models", asks for models for Observation with an Extracted Observation sub-type raised as an open question, for the Exam Finding List, and for the Imaging Problem List; written in Pydantic; with "extensive annotation to generate JSON schemas"; and with camelCase aliases in export over snake_case object attributes. The issue was open, uncommented and unassigned as of 2026-09-22, and no plan in the repositories read for this knowledgebase claims it.[^ipl-issue] The structures it would formalize are described in [Data Structures](./data-structures.md). + +The issue names no existing work as a starting point.[^ipl-issue] Separately, on the same repository's development branch, the report extraction, coding, persistence and review platform already treats coding as a job of its own: its coding design document, last updated 2026-03-16, states that coding "is an **independent job** — fully decoupled from extraction", that extraction output persists without codes, and that coding is triggered separately and can be re-run with different models or settings.[^ipl-coding] That platform is covered in [Sample Applications](./sample-applications.md). + +## An Open Imaging Reporting SDK + +Working proposal, and the longest-standing one. A project update of 2024-01-12 reports that a reporting vendor "showcased advanced capabilities of the OIDM-based assisted reporting framework, incorporating large language models", and states the intent to "collaborate with vendors and the OIDM community to develop an open-standard toolkit for assisted reporting systems".[^site-2024] The January 2026 status update carries that intent forward under a name, listing an "Open Imaging Reporting SDK (vendor-driven innovation)" in its applications pillar, with a call to action for vendor-driven work that names a reporting vendor's SDKs as its example.[^gamma] Demonstrations of the framework were built and shown; what none of the repositories read for this knowledgebase contains is an implementation of the toolkit itself. What such an SDK would serve is described in [Use Cases](./use-cases.md). + +# Where the neighbouring pillars begin + +The command-line front ends over these libraries, Finding Model Forge, the finding models catalog site, the Imaging Problem List viewers and the extraction platform are applications built on this layer, not part of it, and they are covered in [Sample Applications](./sample-applications.md). Reusable authoring capability stays here; the content those tools author, and the principles for reviewing it, are in [Finding models and CDEs](./finding-models-and-cdes.md).[^notes] + +[^notes]: Joint working notes for the restructure, decisions of 2026-09-22 +[^siim]: SIIM 2026 annual meeting talk, June 2026, Mass General Brigham +[^gamma]: Open Imaging Data Model 2026 Status Update, January 2026 +[^fm-readme]: findingmodel package README, released snapshot 2026-03-04 +[^fm-mcp]: Finding Model MCP server guide, released snapshot 2026-03-04 +[^fm-ai]: findingmodel-ai package README, released snapshot 2026-03-04 +[^fm-rewrite]: Canonical Structured Metadata and Enrichment Rewrite, metadata-cleanup snapshot 2026-06-29 +[^adr-schema]: Architecture decision record 0001, metadata-cleanup snapshot 2026-06-29 +[^adr-dualdb]: Architecture decision record 0003, metadata-cleanup snapshot 2026-06-29 +[^al-readme]: anatomic-locations package README, released snapshot 2026-03-04 +[^bpi-ts]: BodyPartIndex.ts README, last changed 2022-12-18 +[^bpi-py]: BodyPartIndex.py README, last changed 2024-02-03 +[^bpi-todo]: BodyPartIndex.py open work list, updated 2024-02-03 +[^molu-readme]: med-ontology-lookup README, snapshot 2026-09-18 +[^molu-roadmap]: Product direction for med-ontology-lookup, 2026-08-16 +[^molu-review]: med-ontology-lookup project review and proposal, 2026-09-03 +[^site-2024]: 2024 New Year Update, openimagingdata.org, 2024-01-12 +[^ipl-issue]: imaging-problem-list issue #1, Create System of Data Models +[^ipl-coding]: Coding Agent Design, imaging-problem-list development branch, updated 2026-03-16 diff --git a/knowledge/drafts/standards.md b/knowledge/drafts/standards.md new file mode 100644 index 0000000..7b1b2a8 --- /dev/null +++ b/knowledge/drafts/standards.md @@ -0,0 +1,56 @@ +--- +type: Concept +title: Standards the foundation layers over +description: Which existing standard each Foundation Context axis layers over, the role each terminology plays, the external citations the deck names, and search recall as the gate. +tags: [foundation-context, terminologies, radlex, snomed, loinc, fma] +status: draft +generated: { by: claude-opus-5/2026-09-22-restructure/draft-axes, at: 2026-09-22T12:53:11Z } +sources: + - id: siim2026 + resource: https://oidm-public.t3.tigrisfiles.io/oidm-knowledge-sources/SIIM%202026%20Reports-of-the-Future.pptx + title: Structured Results and Context for Next-Generation Imaging Resulting Tools, SIIM 2026 annual meeting talk, June 2026, Mass General Brigham, slides 8 and 12 + - id: jdim-al + resource: "Anatomic Locations Index: A Spatial Containment Hierarchy for Localizing Imaging Findings, manuscript under review at the Journal of Digital Imaging and Informatics in Medicine, 2026" + title: Manuscript under review, Methods "Term selection" and Discussion; reviewer correspondence not used + - id: cde-radlex-baseline + resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/docs/next-gen-schema/05-radlex-baseline.md + title: "RadLex Baseline: Synonyms and External References, ACR-RSNA-CDEs next-gen-2026 branch" + - id: radlex-search + resource: https://github.com/RSNA/RadLex/blob/5162a65db531c8170139656f8a8ed27d96b6dd20/docs/plans/hybrid-fts-search.md + title: Hybrid exact and BM25 full-text search over the RadLex graph, shipped and verified 2026-08-20 + - id: molu-roadmap + resource: https://github.com/openimagingdata/med-ontology-lookup/blob/9cc3eec2c7af32e366e3f05e027b223b4a870077/docs/product-roadmap.md + title: "Product direction: an agent-ready medical terminology graph gateway, med-ontology-lookup, research date 2026-08-16" +--- + +# One axis, one standard + +The June 2026 SIIM talk presents Foundation Context as three axes, each described as an OIDM layer over something that already exists, adding imaging-specific knowledge rather than reinventing it. A code on an Observation is a pointer into one of these axes; the axes also point to each other and out to external references.[^siim2026] + +| Axis | Question | Layers over | +|---|---|---| +| Observation Type | what was found | CDE and OIFM definitions | +| Anatomic Location | where it is | a [RadLex](/glossary/radlex.md)-anchored body map | +| Exam Type | how it was seen | [LOINC Playbook](/glossary/loinc-rsna-radiology-playbook.md) study types | + +The talk's own label for the first axis is Observation Type; this bundle explains that axis under [finding models and CDEs](./finding-models-and-cdes.md). See [anatomic locations](./anatomic-locations.md) and [exam types](./exam-types.md) for what the other two layers add. + +# What each terminology is for + +The manuscript under review states why RadLex was chosen as the foundation: coverage of anatomy at the level of detail radiologists report, governance by the RSNA providing a defined pathway for contributing terms back, and stable identifiers. It recommends [SNOMED CT](/glossary/snomed-ct.md) as the cross-reference for enterprise coding, citing a 2024 HIMSS-SIIM assessment, and argues that adoption can proceed through existing bindings, since DICOM's anatomic region sequence and FHIR's body site value sets already bind to SNOMED CT. On that argument the index sits above the coding scheme rather than competing. [FMA](/glossary/fma.md), MeSH, and [UMLS](/glossary/umls.md) are further cross-reference targets.[^jdim-al] The terminology gateway's roadmap gives LOINC and the Playbook the orderables; findings, anatomy, and report language stay with RadLex.[^molu-roadmap] + +Where those cross-references live is a separate question from which system is the target. The next-generation vocabulary work checked the published RadLex release directly and found effectively no SNOMED CT mapping in it: six codes from the retired pre-CT SNOMED against 33,404 FMA references, against an assumption on record that SNOMED mappings would be maintained at the RadLex level. For anatomy it records the gap as already closed upstream, because the anatomic locations data carries modern SNOMED CT codes on about 60% of its nodes and those mappings travel with it as it becomes a RadLex collection. For findings no such source exists, so the vocabulary carries its own mappings.[^cde-radlex-baseline] + +# External citations + +The talk's "connective tissue" slide names two kinds of outward link: citations to Radiopaedia and Wikipedia, and references to SNOMED, RadLex, LOINC, FMA, ICD, and CPT.[^siim2026] The gateway roadmap keeps ICD and CPT out of the radiology default: ICD's billing-oriented labels would crowd out findings, and CPT is licensed, available only through UMLS when the caller's license covers it, so a failed CPT call must report a license problem rather than an absence of hits.[^molu-roadmap] + +# Search recall is the gate + +A lookup that fails silently is worse than one that fails loudly: an agent then concludes the concept is missing and proposes a duplicate. The RadLex search plan names that false-gap outcome as the worst failure mode the project has, and sets the target as recall good enough that a miss is real evidence of an ontology gap rather than evidence of unlucky phrasing. Its design keeps exact label and synonym tiers as the confidence signal and adds full-text relevance as the recall layer. A categorical match type carries the confidence contract, because full-text scores are not comparable across queries; the numeric scores stay alongside it as tiebreakers.[^radlex-search] The gateway roadmap states a related boundary: a shared concept identifier is evidence of connection, not proof of exact equivalence.[^molu-roadmap] The tool itself belongs to the SDKs pillar; see [SDKs](./sdks.md). + +[^siim2026]: SIIM 2026 annual meeting talk, June 2026, Mass General Brigham +[^jdim-al]: Anatomic Locations Index manuscript, under review at the Journal of Digital Imaging and Informatics in Medicine, 2026 +[^cde-radlex-baseline]: RadLex Baseline, ACR-RSNA-CDEs next-gen-2026 +[^radlex-search]: Hybrid full-text search over the RadLex graph, RSNA RadLex +[^molu-roadmap]: Product direction, med-ontology-lookup, 2026-08-16 diff --git a/knowledge/drafts/three-axes.excalidraw b/knowledge/drafts/three-axes.excalidraw new file mode 100644 index 0000000..b0aa919 --- /dev/null +++ b/knowledge/drafts/three-axes.excalidraw @@ -0,0 +1,5762 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "oidm-knowledge/tools/diagrams", + "elements": [ + { + "type": "rectangle", + "id": "col1", + "x": 0, + "y": 0, + "width": 316, + "height": 822.5, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1001, + "version": 1, + "versionNonce": 1002, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "coli2", + "x": 140.0, + "y": 16, + "width": 36, + "height": 36, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1003, + "version": 1, + "versionNonce": 1004, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_coli2", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "colt3", + "x": 8, + "y": 61, + "width": 300, + "height": 21.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1005, + "version": 1, + "versionNonce": 1006, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Findings/Diagnoses", + "originalText": "Findings/Diagnoses", + "fontSize": 17, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "coltag4", + "x": 8, + "y": 87.25, + "width": 300, + "height": 17.5, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1007, + "version": 1, + "versionNonce": 1008, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "WHAT was found", + "originalText": "WHAT was found", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "rule5", + "x": 18, + "y": 115.75, + "width": 280, + "height": 0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 35, + "angle": 0, + "seed": 1009, + "version": 1, + "versionNonce": 1010, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 280, + 0 + ] + ] + }, + { + "type": "rectangle", + "id": "tb6", + "x": 18, + "y": 127.75, + "width": 280, + "height": 20, + "strokeColor": "transparent", + "backgroundColor": "#fcd34d", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1011, + "version": 1, + "versionNonce": 1012, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "tbt7", + "x": 28, + "y": 129.625, + "width": 60.31999999999999, + "height": 16.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1013, + "version": 1, + "versionNonce": 1014, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Findings", + "originalText": "Findings", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tn8", + "x": 34, + "y": 156.5, + "width": 129.92, + "height": 17.5, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1015, + "version": 1, + "versionNonce": 1016, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "pulmonary nodule", + "originalText": "pulmonary nodule", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc9", + "x": 41, + "y": 175.25, + "width": 0, + "height": 13.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1017, + "version": 1, + "versionNonce": 1018, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 13.0 + ] + ] + }, + { + "type": "line", + "id": "tc10", + "x": 41, + "y": 188.25, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1019, + "version": 1, + "versionNonce": 1020, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn11", + "x": 52, + "y": 180.125, + "width": 37.699999999999996, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1021, + "version": 1, + "versionNonce": 1022, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "solid", + "originalText": "solid", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc12", + "x": 41, + "y": 175.25, + "width": 0, + "height": 36.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1023, + "version": 1, + "versionNonce": 1024, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 36.0 + ] + ] + }, + { + "type": "line", + "id": "tc13", + "x": 41, + "y": 211.25, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1025, + "version": 1, + "versionNonce": 1026, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn14", + "x": 52, + "y": 203.125, + "width": 75.39999999999999, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1027, + "version": 1, + "versionNonce": 1028, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "part-solid", + "originalText": "part-solid", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc15", + "x": 41, + "y": 175.25, + "width": 0, + "height": 59.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1029, + "version": 1, + "versionNonce": 1030, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 59.0 + ] + ] + }, + { + "type": "line", + "id": "tc16", + "x": 41, + "y": 234.25, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1031, + "version": 1, + "versionNonce": 1032, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn17", + "x": 52, + "y": 226.125, + "width": 67.86, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1033, + "version": 1, + "versionNonce": 1034, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "non-solid", + "originalText": "non-solid", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "tb18", + "x": 18, + "y": 257.75, + "width": 280, + "height": 20, + "strokeColor": "transparent", + "backgroundColor": "#fcd34d", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1035, + "version": 1, + "versionNonce": 1036, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "tbt19", + "x": 28, + "y": 259.625, + "width": 67.86, + "height": 16.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1037, + "version": 1, + "versionNonce": 1038, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Diagnoses", + "originalText": "Diagnoses", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tn20", + "x": 34, + "y": 286.5, + "width": 146.16, + "height": 17.5, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1039, + "version": 1, + "versionNonce": 1040, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "pulmonary neoplasm", + "originalText": "pulmonary neoplasm", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc21", + "x": 41, + "y": 305.25, + "width": 0, + "height": 13.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1041, + "version": 1, + "versionNonce": 1042, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 13.0 + ] + ] + }, + { + "type": "line", + "id": "tc22", + "x": 41, + "y": 318.25, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1043, + "version": 1, + "versionNonce": 1044, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn23", + "x": 52, + "y": 310.125, + "width": 196.04, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1045, + "version": 1, + "versionNonce": 1046, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "non-small cell lung cancer", + "originalText": "non-small cell lung cancer", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc24", + "x": 59, + "y": 328.25, + "width": 0, + "height": 13.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1047, + "version": 1, + "versionNonce": 1048, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 13.0 + ] + ] + }, + { + "type": "line", + "id": "tc25", + "x": 59, + "y": 341.25, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1049, + "version": 1, + "versionNonce": 1050, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn26", + "x": 70, + "y": 333.125, + "width": 196.04, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1051, + "version": 1, + "versionNonce": 1052, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "adenocarcinoma of the lung", + "originalText": "adenocarcinoma of the lung", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "tb27", + "x": 18, + "y": 364.75, + "width": 280, + "height": 20, + "strokeColor": "transparent", + "backgroundColor": "#fcd34d", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1053, + "version": 1, + "versionNonce": 1054, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "tbt28", + "x": 28, + "y": 366.625, + "width": 82.94, + "height": 16.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1055, + "version": 1, + "versionNonce": 1056, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Assessments", + "originalText": "Assessments", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tn29", + "x": 34, + "y": 393.5, + "width": 73.08, + "height": 17.5, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1057, + "version": 1, + "versionNonce": 1058, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Lung-RADS", + "originalText": "Lung-RADS", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tn30", + "x": 34, + "y": 416.5, + "width": 178.64, + "height": 17.5, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1059, + "version": 1, + "versionNonce": 1060, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Salter-Harris category", + "originalText": "Salter-Harris category", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "tb31", + "x": 18, + "y": 448.75, + "width": 280, + "height": 20, + "strokeColor": "transparent", + "backgroundColor": "#fcd34d", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1061, + "version": 1, + "versionNonce": 1062, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "tbt32", + "x": 28, + "y": 450.625, + "width": 98.02, + "height": 16.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1063, + "version": 1, + "versionNonce": 1064, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Data Elements", + "originalText": "Data Elements", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tn33", + "x": 34, + "y": 477.5, + "width": 64.96, + "height": 17.5, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1065, + "version": 1, + "versionNonce": 1066, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "presence", + "originalText": "presence", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "ta34", + "x": 42, + "y": 501.125, + "width": 316.67999999999995, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1067, + "version": 1, + "versionNonce": 1068, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "present \u00b7 absent \u00b7 indeterminate \u00b7 unknown", + "originalText": "present \u00b7 absent \u00b7 indeterminate \u00b7 unknown", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tn35", + "x": 34, + "y": 523.5, + "width": 64.96, + "height": 17.5, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1069, + "version": 1, + "versionNonce": 1070, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "severity", + "originalText": "severity", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "ta36", + "x": 42, + "y": 547.125, + "width": 256.35999999999996, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1071, + "version": 1, + "versionNonce": 1072, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "minimal \u00b7 mild \u00b7 moderate \u00b7 severe", + "originalText": "minimal \u00b7 mild \u00b7 moderate \u00b7 severe", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "tb37", + "x": 18, + "y": 578.75, + "width": 280, + "height": 20, + "strokeColor": "transparent", + "backgroundColor": "#fcd34d", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1073, + "version": 1, + "versionNonce": 1074, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "tbt38", + "x": 28, + "y": 580.625, + "width": 90.47999999999999, + "height": 16.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1075, + "version": 1, + "versionNonce": 1076, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Measurements", + "originalText": "Measurements", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tn39", + "x": 34, + "y": 607.5, + "width": 48.72, + "height": 17.5, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1077, + "version": 1, + "versionNonce": 1078, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "length", + "originalText": "length", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "ta40", + "x": 42, + "y": 631.125, + "width": 82.94, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1079, + "version": 1, + "versionNonce": 1080, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "mm, cm, ...", + "originalText": "mm, cm, ...", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tn41", + "x": 34, + "y": 653.5, + "width": 81.19999999999999, + "height": 17.5, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1081, + "version": 1, + "versionNonce": 1082, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "CT density", + "originalText": "CT density", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "ta42", + "x": 42, + "y": 677.125, + "width": 15.079999999999998, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1083, + "version": 1, + "versionNonce": 1084, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "HU", + "originalText": "HU", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "colblk43", + "x": 18, + "y": 758.0, + "width": 280, + "height": 48.5, + "strokeColor": "#78350f", + "backgroundColor": "#b45309", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1085, + "version": 1, + "versionNonce": 1086, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "colblkt44", + "x": 24, + "y": 768.0, + "width": 268, + "height": 16.25, + "strokeColor": "#fef3c7", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1087, + "version": 1, + "versionNonce": 1088, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "layered over: finding models", + "originalText": "layered over: finding models", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "colblkt45", + "x": 24, + "y": 784.25, + "width": 268, + "height": 16.25, + "strokeColor": "#fef3c7", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1089, + "version": 1, + "versionNonce": 1090, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "\u00b7 ACR/RSNA CDEs", + "originalText": "\u00b7 ACR/RSNA CDEs", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "col46", + "x": 336, + "y": 0, + "width": 316, + "height": 822.5, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1091, + "version": 1, + "versionNonce": 1092, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "coli47", + "x": 476.0, + "y": 16, + "width": 36, + "height": 36, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1093, + "version": 1, + "versionNonce": 1094, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_coli47", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "colt48", + "x": 344, + "y": 61, + "width": 300, + "height": 21.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1095, + "version": 1, + "versionNonce": 1096, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Anatomic Locations", + "originalText": "Anatomic Locations", + "fontSize": 17, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "coltag49", + "x": 344, + "y": 87.25, + "width": 300, + "height": 17.5, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1097, + "version": 1, + "versionNonce": 1098, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "WHERE it is", + "originalText": "WHERE it is", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "rule50", + "x": 354, + "y": 115.75, + "width": 280, + "height": 0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 35, + "angle": 0, + "seed": 1099, + "version": 1, + "versionNonce": 1100, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 280, + 0 + ] + ] + }, + { + "type": "rectangle", + "id": "tb51", + "x": 354, + "y": 127.75, + "width": 280, + "height": 20, + "strokeColor": "transparent", + "backgroundColor": "#fcd34d", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1101, + "version": 1, + "versionNonce": 1102, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "tbt52", + "x": 364, + "y": 129.625, + "width": 45.239999999999995, + "height": 16.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1103, + "version": 1, + "versionNonce": 1104, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "thorax", + "originalText": "thorax", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tn53", + "x": 370, + "y": 156.24404761904762, + "width": 32.48, + "height": 17.5, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1105, + "version": 1, + "versionNonce": 1106, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "lung", + "originalText": "lung", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc54", + "x": 377, + "y": 174.99404761904762, + "width": 0, + "height": 12.48809523809524, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1107, + "version": 1, + "versionNonce": 1108, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 12.48809523809524 + ] + ] + }, + { + "type": "line", + "id": "tc55", + "x": 377, + "y": 187.48214285714286, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1109, + "version": 1, + "versionNonce": 1110, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn56", + "x": 388, + "y": 179.35714285714286, + "width": 75.39999999999999, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1111, + "version": 1, + "versionNonce": 1112, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "right lung", + "originalText": "right lung", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc57", + "x": 395, + "y": 197.48214285714286, + "width": 0, + "height": 12.48809523809524, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1113, + "version": 1, + "versionNonce": 1114, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 12.48809523809524 + ] + ] + }, + { + "type": "line", + "id": "tc58", + "x": 395, + "y": 209.9702380952381, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1115, + "version": 1, + "versionNonce": 1116, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn59", + "x": 406, + "y": 201.8452380952381, + "width": 180.95999999999998, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1117, + "version": 1, + "versionNonce": 1118, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "upper lobe of right lung", + "originalText": "upper lobe of right lung", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc60", + "x": 395, + "y": 197.48214285714286, + "width": 0, + "height": 34.97619047619048, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1119, + "version": 1, + "versionNonce": 1120, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 34.97619047619048 + ] + ] + }, + { + "type": "line", + "id": "tc61", + "x": 395, + "y": 232.45833333333334, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1121, + "version": 1, + "versionNonce": 1122, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn62", + "x": 406, + "y": 224.33333333333334, + "width": 188.5, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1123, + "version": 1, + "versionNonce": 1124, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "middle lobe of right lung", + "originalText": "middle lobe of right lung", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc63", + "x": 395, + "y": 197.48214285714286, + "width": 0, + "height": 57.46428571428572, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1125, + "version": 1, + "versionNonce": 1126, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 57.46428571428572 + ] + ] + }, + { + "type": "line", + "id": "tc64", + "x": 395, + "y": 254.94642857142858, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1127, + "version": 1, + "versionNonce": 1128, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn65", + "x": 406, + "y": 246.82142857142858, + "width": 180.95999999999998, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1129, + "version": 1, + "versionNonce": 1130, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "lower lobe of right lung", + "originalText": "lower lobe of right lung", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc66", + "x": 377, + "y": 174.99404761904762, + "width": 0, + "height": 102.44047619047618, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1131, + "version": 1, + "versionNonce": 1132, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 102.44047619047618 + ] + ] + }, + { + "type": "line", + "id": "tc67", + "x": 377, + "y": 277.4345238095238, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1133, + "version": 1, + "versionNonce": 1134, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn68", + "x": 388, + "y": 269.3095238095238, + "width": 67.86, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1135, + "version": 1, + "versionNonce": 1136, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "left lung", + "originalText": "left lung", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tn69", + "x": 370, + "y": 291.172619047619, + "width": 105.55999999999999, + "height": 17.5, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1137, + "version": 1, + "versionNonce": 1138, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "pleural space", + "originalText": "pleural space", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tn70", + "x": 370, + "y": 313.66071428571416, + "width": 89.32, + "height": 17.5, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1139, + "version": 1, + "versionNonce": 1140, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "mediastinum", + "originalText": "mediastinum", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc71", + "x": 377, + "y": 332.41071428571416, + "width": 0, + "height": 12.488095238095184, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1141, + "version": 1, + "versionNonce": 1142, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 12.488095238095184 + ] + ] + }, + { + "type": "line", + "id": "tc72", + "x": 377, + "y": 344.89880952380935, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1143, + "version": 1, + "versionNonce": 1144, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn73", + "x": 388, + "y": 336.77380952380935, + "width": 37.699999999999996, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1145, + "version": 1, + "versionNonce": 1146, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "heart", + "originalText": "heart", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "tb74", + "x": 354, + "y": 368.14285714285694, + "width": 280, + "height": 20, + "strokeColor": "transparent", + "backgroundColor": "#fcd34d", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1147, + "version": 1, + "versionNonce": 1148, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "tbt75", + "x": 364, + "y": 370.01785714285694, + "width": 52.779999999999994, + "height": 16.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1149, + "version": 1, + "versionNonce": 1150, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "abdomen", + "originalText": "abdomen", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tn76", + "x": 370, + "y": 396.63690476190453, + "width": 48.72, + "height": 17.5, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1151, + "version": 1, + "versionNonce": 1152, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "kidney", + "originalText": "kidney", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc77", + "x": 377, + "y": 415.38690476190453, + "width": 0, + "height": 12.488095238095184, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1153, + "version": 1, + "versionNonce": 1154, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 12.488095238095184 + ] + ] + }, + { + "type": "line", + "id": "tc78", + "x": 377, + "y": 427.8749999999997, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1155, + "version": 1, + "versionNonce": 1156, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn79", + "x": 388, + "y": 419.7499999999997, + "width": 82.94, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1157, + "version": 1, + "versionNonce": 1158, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "left kidney", + "originalText": "left kidney", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc80", + "x": 377, + "y": 415.38690476190453, + "width": 0, + "height": 34.97619047619037, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1159, + "version": 1, + "versionNonce": 1160, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 34.97619047619037 + ] + ] + }, + { + "type": "line", + "id": "tc81", + "x": 377, + "y": 450.3630952380949, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1161, + "version": 1, + "versionNonce": 1162, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn82", + "x": 388, + "y": 442.2380952380949, + "width": 90.47999999999999, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1163, + "version": 1, + "versionNonce": 1164, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "right kidney", + "originalText": "right kidney", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc83", + "x": 395, + "y": 460.3630952380949, + "width": 0, + "height": 12.488095238095184, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1165, + "version": 1, + "versionNonce": 1166, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 12.488095238095184 + ] + ] + }, + { + "type": "line", + "id": "tc84", + "x": 395, + "y": 472.8511904761901, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1167, + "version": 1, + "versionNonce": 1168, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn85", + "x": 406, + "y": 464.7261904761901, + "width": 90.47999999999999, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1169, + "version": 1, + "versionNonce": 1170, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "renal pelvis", + "originalText": "renal pelvis", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tn86", + "x": 370, + "y": 486.58928571428527, + "width": 40.599999999999994, + "height": 17.5, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1171, + "version": 1, + "versionNonce": 1172, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "liver", + "originalText": "liver", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tn87", + "x": 370, + "y": 509.0773809523805, + "width": 48.72, + "height": 17.5, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1173, + "version": 1, + "versionNonce": 1174, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "spleen", + "originalText": "spleen", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "tb88", + "x": 354, + "y": 541.0714285714281, + "width": 280, + "height": 20, + "strokeColor": "transparent", + "backgroundColor": "#fcd34d", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1175, + "version": 1, + "versionNonce": 1176, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "tbt89", + "x": 364, + "y": 542.9464285714281, + "width": 30.159999999999997, + "height": 16.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1177, + "version": 1, + "versionNonce": 1178, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "head", + "originalText": "head", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tn90", + "x": 370, + "y": 569.5654761904757, + "width": 40.599999999999994, + "height": 17.5, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1179, + "version": 1, + "versionNonce": 1180, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "brain", + "originalText": "brain", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc91", + "x": 377, + "y": 588.3154761904757, + "width": 0, + "height": 12.488095238095184, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1181, + "version": 1, + "versionNonce": 1182, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 12.488095238095184 + ] + ] + }, + { + "type": "line", + "id": "tc92", + "x": 377, + "y": 600.8035714285709, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1183, + "version": 1, + "versionNonce": 1184, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn93", + "x": 388, + "y": 592.6785714285709, + "width": 75.39999999999999, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1185, + "version": 1, + "versionNonce": 1186, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "cerebellum", + "originalText": "cerebellum", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc94", + "x": 377, + "y": 588.3154761904757, + "width": 0, + "height": 34.97619047619037, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1187, + "version": 1, + "versionNonce": 1188, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 34.97619047619037 + ] + ] + }, + { + "type": "line", + "id": "tc95", + "x": 377, + "y": 623.2916666666661, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1189, + "version": 1, + "versionNonce": 1190, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn96", + "x": 388, + "y": 615.1666666666661, + "width": 90.47999999999999, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1191, + "version": 1, + "versionNonce": 1192, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "frontal lobe", + "originalText": "frontal lobe", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tn97", + "x": 370, + "y": 637.0297619047612, + "width": 40.599999999999994, + "height": 17.5, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1193, + "version": 1, + "versionNonce": 1194, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "orbit", + "originalText": "orbit", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "tb98", + "x": 354, + "y": 669.0238095238088, + "width": 280, + "height": 20, + "strokeColor": "transparent", + "backgroundColor": "#fcd34d", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1195, + "version": 1, + "versionNonce": 1196, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "tbt99", + "x": 364, + "y": 670.8988095238088, + "width": 45.239999999999995, + "height": 16.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1197, + "version": 1, + "versionNonce": 1198, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "pelvis", + "originalText": "pelvis", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tn100", + "x": 370, + "y": 697.5178571428564, + "width": 121.8, + "height": 17.5, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1199, + "version": 1, + "versionNonce": 1200, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "urinary bladder", + "originalText": "urinary bladder", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tn101", + "x": 370, + "y": 720.0059523809516, + "width": 64.96, + "height": 17.5, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1201, + "version": 1, + "versionNonce": 1202, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "prostate", + "originalText": "prostate", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "colblk102", + "x": 354, + "y": 758.0, + "width": 280, + "height": 48.5, + "strokeColor": "#78350f", + "backgroundColor": "#b45309", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1203, + "version": 1, + "versionNonce": 1204, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "colblkt103", + "x": 360, + "y": 776.125, + "width": 268, + "height": 16.25, + "strokeColor": "#fef3c7", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1205, + "version": 1, + "versionNonce": 1206, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "layered over: RadLex", + "originalText": "layered over: RadLex", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "col104", + "x": 672, + "y": 0, + "width": 316, + "height": 822.5, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1207, + "version": 1, + "versionNonce": 1208, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "coli105", + "x": 812.0, + "y": 16, + "width": 36, + "height": 36, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1209, + "version": 1, + "versionNonce": 1210, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_coli105", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "colt106", + "x": 680, + "y": 61, + "width": 300, + "height": 21.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1211, + "version": 1, + "versionNonce": 1212, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Exam Types", + "originalText": "Exam Types", + "fontSize": 17, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "coltag107", + "x": 680, + "y": 87.25, + "width": 300, + "height": 17.5, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1213, + "version": 1, + "versionNonce": 1214, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "HOW it was seen", + "originalText": "HOW it was seen", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "rule108", + "x": 690, + "y": 115.75, + "width": 280, + "height": 0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 35, + "angle": 0, + "seed": 1215, + "version": 1, + "versionNonce": 1216, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 280, + 0 + ] + ] + }, + { + "type": "rectangle", + "id": "tb109", + "x": 690, + "y": 127.75, + "width": 280, + "height": 20, + "strokeColor": "transparent", + "backgroundColor": "#fcd34d", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1217, + "version": 1, + "versionNonce": 1218, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "tbt110", + "x": 700, + "y": 129.625, + "width": 15.079999999999998, + "height": 16.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1219, + "version": 1, + "versionNonce": 1220, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "CT", + "originalText": "CT", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tn111", + "x": 706, + "y": 154.5, + "width": 64.96, + "height": 17.5, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1221, + "version": 1, + "versionNonce": 1222, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "CT Chest", + "originalText": "CT Chest", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tns112", + "x": 772.1, + "y": 155.125, + "width": 135.72, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1223, + "version": 1, + "versionNonce": 1224, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "(preferred family)", + "originalText": "(preferred family)", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc113", + "x": 713, + "y": 173.25, + "width": 0, + "height": 9.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1225, + "version": 1, + "versionNonce": 1226, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 9.0 + ] + ] + }, + { + "type": "line", + "id": "tc114", + "x": 713, + "y": 182.25, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1227, + "version": 1, + "versionNonce": 1228, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn115", + "x": 724, + "y": 174.125, + "width": 150.79999999999998, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1229, + "version": 1, + "versionNonce": 1230, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "CT Chest WO contrast", + "originalText": "CT Chest WO contrast", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc116", + "x": 713, + "y": 173.25, + "width": 0, + "height": 28.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1231, + "version": 1, + "versionNonce": 1232, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 28.0 + ] + ] + }, + { + "type": "line", + "id": "tc117", + "x": 713, + "y": 201.25, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1233, + "version": 1, + "versionNonce": 1234, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn118", + "x": 724, + "y": 193.125, + "width": 165.88, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1235, + "version": 1, + "versionNonce": 1236, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "CT Chest W contrast IV", + "originalText": "CT Chest W contrast IV", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc119", + "x": 713, + "y": 173.25, + "width": 0, + "height": 47.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1237, + "version": 1, + "versionNonce": 1238, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 47.0 + ] + ] + }, + { + "type": "line", + "id": "tc120", + "x": 713, + "y": 220.25, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1239, + "version": 1, + "versionNonce": 1240, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn121", + "x": 724, + "y": 212.125, + "width": 218.66, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1241, + "version": 1, + "versionNonce": 1242, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "CT Chest WO and W contrast IV", + "originalText": "CT Chest WO and W contrast IV", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc122", + "x": 713, + "y": 173.25, + "width": 0, + "height": 66.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1243, + "version": 1, + "versionNonce": 1244, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 66.0 + ] + ] + }, + { + "type": "line", + "id": "tc123", + "x": 713, + "y": 239.25, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1245, + "version": 1, + "versionNonce": 1246, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn124", + "x": 724, + "y": 231.125, + "width": 226.2, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1247, + "version": 1, + "versionNonce": 1248, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "CT Lung parenchyma WO contrast", + "originalText": "CT Lung parenchyma WO contrast", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc125", + "x": 713, + "y": 173.25, + "width": 0, + "height": 85.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1249, + "version": 1, + "versionNonce": 1250, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 85.0 + ] + ] + }, + { + "type": "line", + "id": "tc126", + "x": 713, + "y": 258.25, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1251, + "version": 1, + "versionNonce": 1252, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn127", + "x": 724, + "y": 250.125, + "width": 128.17999999999998, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1253, + "version": 1, + "versionNonce": 1254, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "CTA Chest vessels", + "originalText": "CTA Chest vessels", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "tb128", + "x": 690, + "y": 279.75, + "width": 280, + "height": 20, + "strokeColor": "transparent", + "backgroundColor": "#fcd34d", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1255, + "version": 1, + "versionNonce": 1256, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "tbt129", + "x": 700, + "y": 281.625, + "width": 15.079999999999998, + "height": 16.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1257, + "version": 1, + "versionNonce": 1258, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "MR", + "originalText": "MR", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tn130", + "x": 706, + "y": 306.5, + "width": 56.839999999999996, + "height": 17.5, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1259, + "version": 1, + "versionNonce": 1260, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "MR Knee", + "originalText": "MR Knee", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tns131", + "x": 771.4, + "y": 307.125, + "width": 135.72, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1261, + "version": 1, + "versionNonce": 1262, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "(preferred family)", + "originalText": "(preferred family)", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc132", + "x": 713, + "y": 325.25, + "width": 0, + "height": 9.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1263, + "version": 1, + "versionNonce": 1264, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 9.0 + ] + ] + }, + { + "type": "line", + "id": "tc133", + "x": 713, + "y": 334.25, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1265, + "version": 1, + "versionNonce": 1266, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn134", + "x": 724, + "y": 326.125, + "width": 143.26, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1267, + "version": 1, + "versionNonce": 1268, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "MR Knee WO contrast", + "originalText": "MR Knee WO contrast", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc135", + "x": 713, + "y": 325.25, + "width": 0, + "height": 28.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1269, + "version": 1, + "versionNonce": 1270, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 28.0 + ] + ] + }, + { + "type": "line", + "id": "tc136", + "x": 713, + "y": 353.25, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1271, + "version": 1, + "versionNonce": 1272, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn137", + "x": 724, + "y": 345.125, + "width": 158.33999999999997, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1273, + "version": 1, + "versionNonce": 1274, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "MR Knee W contrast IV", + "originalText": "MR Knee W contrast IV", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tn138", + "x": 706, + "y": 369.5, + "width": 64.96, + "height": 17.5, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1275, + "version": 1, + "versionNonce": 1276, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "MR Brain", + "originalText": "MR Brain", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tns139", + "x": 771.3, + "y": 370.125, + "width": 135.72, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1277, + "version": 1, + "versionNonce": 1278, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "(preferred family)", + "originalText": "(preferred family)", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc140", + "x": 713, + "y": 388.25, + "width": 0, + "height": 9.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1279, + "version": 1, + "versionNonce": 1280, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 9.0 + ] + ] + }, + { + "type": "line", + "id": "tc141", + "x": 713, + "y": 397.25, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1281, + "version": 1, + "versionNonce": 1282, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn142", + "x": 724, + "y": 389.125, + "width": 150.79999999999998, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1283, + "version": 1, + "versionNonce": 1284, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "MR Brain WO contrast", + "originalText": "MR Brain WO contrast", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc143", + "x": 713, + "y": 388.25, + "width": 0, + "height": 28.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1285, + "version": 1, + "versionNonce": 1286, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 28.0 + ] + ] + }, + { + "type": "line", + "id": "tc144", + "x": 713, + "y": 416.25, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1287, + "version": 1, + "versionNonce": 1288, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn145", + "x": 724, + "y": 408.125, + "width": 218.66, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1289, + "version": 1, + "versionNonce": 1290, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "MR Brain WO and W contrast IV", + "originalText": "MR Brain WO and W contrast IV", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "tb146", + "x": 690, + "y": 437.75, + "width": 280, + "height": 20, + "strokeColor": "transparent", + "backgroundColor": "#fcd34d", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1291, + "version": 1, + "versionNonce": 1292, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "tbt147", + "x": 700, + "y": 439.625, + "width": 15.079999999999998, + "height": 16.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1293, + "version": 1, + "versionNonce": 1294, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "XR", + "originalText": "XR", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tn148", + "x": 706, + "y": 464.5, + "width": 56.839999999999996, + "height": 17.5, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1295, + "version": 1, + "versionNonce": 1296, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "XR Knee", + "originalText": "XR Knee", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tns149", + "x": 769.0, + "y": 465.125, + "width": 135.72, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1297, + "version": 1, + "versionNonce": 1298, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "(preferred family)", + "originalText": "(preferred family)", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc150", + "x": 713, + "y": 483.25, + "width": 0, + "height": 9.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1299, + "version": 1, + "versionNonce": 1300, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 9.0 + ] + ] + }, + { + "type": "line", + "id": "tc151", + "x": 713, + "y": 492.25, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1301, + "version": 1, + "versionNonce": 1302, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn152", + "x": 724, + "y": 484.125, + "width": 113.1, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1303, + "version": 1, + "versionNonce": 1304, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "XR Knee 2 Views", + "originalText": "XR Knee 2 Views", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc153", + "x": 713, + "y": 483.25, + "width": 0, + "height": 28.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1305, + "version": 1, + "versionNonce": 1306, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 28.0 + ] + ] + }, + { + "type": "line", + "id": "tc154", + "x": 713, + "y": 511.25, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1307, + "version": 1, + "versionNonce": 1308, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn155", + "x": 724, + "y": 503.125, + "width": 113.1, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1309, + "version": 1, + "versionNonce": 1310, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "XR Knee 3 Views", + "originalText": "XR Knee 3 Views", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tn156", + "x": 706, + "y": 527.5, + "width": 64.96, + "height": 17.5, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1311, + "version": 1, + "versionNonce": 1312, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "XR Chest", + "originalText": "XR Chest", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tns157", + "x": 772.9, + "y": 528.125, + "width": 135.72, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1313, + "version": 1, + "versionNonce": 1314, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "(preferred family)", + "originalText": "(preferred family)", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc158", + "x": 713, + "y": 546.25, + "width": 0, + "height": 9.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1315, + "version": 1, + "versionNonce": 1316, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 9.0 + ] + ] + }, + { + "type": "line", + "id": "tc159", + "x": 713, + "y": 555.25, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1317, + "version": 1, + "versionNonce": 1318, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn160", + "x": 724, + "y": 547.125, + "width": 120.63999999999999, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1319, + "version": 1, + "versionNonce": 1320, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "XR Chest 2 Views", + "originalText": "XR Chest 2 Views", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc161", + "x": 713, + "y": 546.25, + "width": 0, + "height": 28.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1321, + "version": 1, + "versionNonce": 1322, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 28.0 + ] + ] + }, + { + "type": "line", + "id": "tc162", + "x": 713, + "y": 574.25, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1323, + "version": 1, + "versionNonce": 1324, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn163", + "x": 724, + "y": 566.125, + "width": 173.42, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1325, + "version": 1, + "versionNonce": 1326, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "XR Chest PA and Lateral", + "originalText": "XR Chest PA and Lateral", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "tb164", + "x": 690, + "y": 595.75, + "width": 280, + "height": 20, + "strokeColor": "transparent", + "backgroundColor": "#fcd34d", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1327, + "version": 1, + "versionNonce": 1328, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "tbt165", + "x": 700, + "y": 597.625, + "width": 15.079999999999998, + "height": 16.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1329, + "version": 1, + "versionNonce": 1330, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "US", + "originalText": "US", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tn166", + "x": 706, + "y": 622.5, + "width": 81.19999999999999, + "height": 17.5, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1331, + "version": 1, + "versionNonce": 1332, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "US Abdomen", + "originalText": "US Abdomen", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tns167", + "x": 796.3, + "y": 623.125, + "width": 135.72, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1333, + "version": 1, + "versionNonce": 1334, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "(preferred family)", + "originalText": "(preferred family)", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc168", + "x": 713, + "y": 641.25, + "width": 0, + "height": 9.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1335, + "version": 1, + "versionNonce": 1336, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 9.0 + ] + ] + }, + { + "type": "line", + "id": "tc169", + "x": 713, + "y": 650.25, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1337, + "version": 1, + "versionNonce": 1338, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn170", + "x": 724, + "y": 642.125, + "width": 135.72, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1339, + "version": 1, + "versionNonce": 1340, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "US Abdomen limited", + "originalText": "US Abdomen limited", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "tc171", + "x": 713, + "y": 641.25, + "width": 0, + "height": 28.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1341, + "version": 1, + "versionNonce": 1342, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 28.0 + ] + ] + }, + { + "type": "line", + "id": "tc172", + "x": 713, + "y": 669.25, + "width": 7, + "height": 0.0, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 45, + "angle": 0, + "seed": 1343, + "version": 1, + "versionNonce": 1344, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 7, + 0.0 + ] + ] + }, + { + "type": "text", + "id": "tn173", + "x": 724, + "y": 661.125, + "width": 105.55999999999999, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1345, + "version": 1, + "versionNonce": 1346, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "US Abdomen RUQ", + "originalText": "US Abdomen RUQ", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "tn174", + "x": 706, + "y": 685.5, + "width": 129.92, + "height": 17.5, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1347, + "version": 1, + "versionNonce": 1348, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "US Thyroid gland", + "originalText": "US Thyroid gland", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "coln175", + "x": 690, + "y": 723.75, + "width": 241.27999999999997, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1349, + "version": 1, + "versionNonce": 1350, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "each a LOINC/RSNA Playbook entry", + "originalText": "each a LOINC/RSNA Playbook entry", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "colblk176", + "x": 690, + "y": 758.0, + "width": 280, + "height": 48.5, + "strokeColor": "#78350f", + "backgroundColor": "#b45309", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1351, + "version": 1, + "versionNonce": 1352, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "colblkt177", + "x": 696, + "y": 768.0, + "width": 268, + "height": 16.25, + "strokeColor": "#fef3c7", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1353, + "version": 1, + "versionNonce": 1354, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "layered over: LOINC/RSNA", + "originalText": "layered over: LOINC/RSNA", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "colblkt178", + "x": 696, + "y": 784.25, + "width": 268, + "height": 16.25, + "strokeColor": "#fef3c7", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1355, + "version": 1, + "versionNonce": 1356, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Playbook", + "originalText": "Playbook", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + } + ], + "appState": { + "viewBackgroundColor": "#ffffff", + "gridSize": null + }, + "files": { + "img_coli2": { + "mimeType": "image/svg+xml", + "id": "img_coli2", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiNiNDUzMDkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyLjU4NiAyLjU4NkEyIDIgMCAwIDAgMTEuMTcyIDJINGEyIDIgMCAwIDAtMiAydjcuMTcyYTIgMiAwIDAgMCAuNTg2IDEuNDE0bDguNzA0IDguNzA0YTIuNDI2IDIuNDI2IDAgMCAwIDMuNDIgMGw2LjU4LTYuNThhMi40MjYgMi40MjYgMCAwIDAgMC0zLjQyeiIgLz4KICA8Y2lyY2xlIGN4PSI3LjUiIGN5PSI3LjUiIHI9Ii41IiBmaWxsPSIjYjQ1MzA5IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_coli47": { + "mimeType": "image/svg+xml", + "id": "img_coli47", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yMyA2LjAwMDEzQzIzIDYuMDAwMDQgMjMgNiAyNCA2SDI0LjE3NjFDMjQuMjUzMyA2IDI0LjMyMzMgNiAyNC4zODY4IDZDMjUgNi4wMDAwMSAyNSA2LjAwMDA1IDI1IDYuMDAwMTNWMjAuNUMyNSAyMS44OTc3IDI1LjU2NDEgMjIuNDQyMSAyNi4wMDM5IDIyLjY5ODdDMjYuMDUzIDIyLjcyNzMgMjYuMTAyNCAyMi43NTMzIDI2LjE1MTYgMjIuNzc3QzI2LjE1MDYgMjIuNjU2OCAyNi4xNDkzIDIyLjUzMTYgMjYuMTQ3OSAyMi40MDE5TDI2LjE0NzkgMjIuNDAwM0MyNi4xMTAxIDE4Ljg3MTYgMjYuMDM2NSAxMS45OTk3IDMxLjQ3NTMgMTEuOTk5N0MzOC45MjU5IDExLjk5OTcgNDQuMjQ3OCAzOC4wMDYyIDQxLjA1NDcgNDAuNjU5OUMzNy44NjE1IDQzLjMxMzYgMzEuNDc1MyA0MS43MjE0IDI4LjI4MjIgMzguNTM2OUMyNS43MDQyIDM1Ljk2NTkgMjUuOTI3MiAyOS45NTgzIDI2LjA4NzMgMjUuNjQ1N0wyNi4wODc0IDI1LjY0NDNDMjYuMDk3MSAyNS4zODE5IDI2LjEwNjcgMjUuMTI1OCAyNi4xMTUzIDI0Ljg3NzFDMjUuNzkgMjQuNzk2MiAyNS4zOTU5IDI0LjY1OTUgMjQuOTk2MiAyNC40MjYzQzI0LjYzOTggMjQuMjE4NCAyNC4yOTc1IDIzLjk0NDIgMjQgMjMuNTkxOUMyMy43MDI2IDIzLjk0NDIgMjMuMzYwMyAyNC4yMTg0IDIzLjAwMzkgMjQuNDI2M0MyMi42MDQxIDI0LjY1OTUgMjIuMjEwMSAyNC43OTYyIDIxLjg4NDggMjQuODc3MUMyMS44OTM0IDI1LjEyNjEgMjEuOTAyOSAyNS4zODI2IDIxLjkxMjcgMjUuNjQ1M0MyMi4wNzI4IDI5Ljk1NzkgMjIuMjk1OSAzNS45NjYyIDE5LjcxNzkgMzguNTM3MkMxNi41MjQ3IDQxLjcyMTcgMTAuMTM4NSA0My4zMTM5IDYuOTQ1MzYgNDAuNjYwMkMzLjc1MjIyIDM4LjAwNjUgOS4wNzQxMyAxMiAxNi41MjQ3IDEyQzIxLjk2MzYgMTIgMjEuODkgMTguODcxNyAyMS44NTIyIDIyLjQwMDNDMjEuODUyIDIyLjQxNjYgMjEuODUxOCAyMi40MzI4IDIxLjg1MTYgMjIuNDQ4OUMyMS44NTA0IDIyLjU2MTkgMjEuODQ5MyAyMi42NzE0IDIxLjg0ODQgMjIuNzc3QzIxLjg5NzcgMjIuNzUzNCAyMS45NDcxIDIyLjcyNzQgMjEuOTk2MiAyMi42OTg3QzIyLjQzNiAyMi40NDIxIDIzIDIxLjg5NzcgMjMgMjAuNVY2LjAwMDEzWk0zMS40NzUzIDEzLjk5OTdDMzAuNTIxMiAxMy45OTk3IDI5Ljk4NDMgMTQuMzAwMiAyOS42MDg2IDE0LjY4NjlDMjkuMTc1MiAxNS4xMzMxIDI4LjgxMzIgMTUuODUwNyAyOC41NTkgMTYuODY0NkMyOC4xMTQxIDE4LjYzOTUgMjguMTMzIDIwLjY4MTkgMjguMTQ4MyAyMi4zMjkzQzI4LjE1MDkgMjIuNjE0MiAyOC4xNTM0IDIyLjg4NzQgMjguMTUzNCAyMy4xNDUzQzI4LjE1MzQgMjMuOTA1MyAyOC4xMTk2IDI0LjgxNTMgMjguMDg0NSAyNS43NjIxQzI4LjA3MDcgMjYuMTM0OSAyOC4wNTY2IDI2LjUxMzMgMjguMDQ0MyAyNi44OTA1QzI3Ljk5OTYgMjguMjY1NyAyNy45NzQxIDI5LjcwNTUgMjguMDQwNSAzMS4wOTgyQzI4LjEwNzIgMzIuNDk4NSAyOC4yNjQyIDMzLjc4MzUgMjguNTU3MyAzNC44NTk2QzI4Ljg1MzggMzUuOTQ4MyAyOS4yNTA5IDM2LjY3ODQgMjkuNjk0NCAzNy4xMjA4QzMwLjk3MjYgMzguMzk1NCAzMi45OTA4IDM5LjQyNTEgMzUuMDQ5MiAzOS44MjQzQzM3LjA4NDIgNDAuMjE4OSAzOC43MjI0IDM5LjkyNjkgMzkuNjgxOCAzOS4xOTY5QzM5LjY4NjggMzkuMTg1NyAzOS42OTIzIDM5LjE3MjYgMzkuNjk4NCAzOS4xNTc0QzM5Ljc1NzYgMzkuMDA5NSAzOS44Mjk0IDM4Ljc1NTQgMzkuODg3OCAzOC4zNjgzQzQwLjAwNDcgMzcuNTkzMyA0MC4wMzUgMzYuNTEyMiAzOS45NTYyIDM1LjE4MDNDMzkuNzk5NSAzMi41MzA1IDM5LjIyODYgMjkuMTY4OSAzOC4zMjY4IDI1Ljg2MDZDMzcuNDIxNiAyMi41Mzk2IDM2LjIxNzMgMTkuMzk5OCAzNC44NTIxIDE3LjEzODNDMzQuMTY4OCAxNi4wMDYyIDMzLjQ5NTEgMTUuMTc4NiAzMi44NzAzIDE0LjY1MzVDMzIuMjUxOCAxNC4xMzM3IDMxLjc5MzUgMTMuOTk5NyAzMS40NzUzIDEzLjk5OTdaTTE2LjUyNDcgMTRDMTcuNDc4OCAxNCAxOC4wMTU4IDE0LjMwMDUgMTguMzkxNCAxNC42ODcyQzE4LjgyNDggMTUuMTMzNCAxOS4xODY4IDE1Ljg1MSAxOS40NDEgMTYuODY0OUMxOS44ODU5IDE4LjYzOTkgMTkuODY3IDIwLjY4MjIgMTkuODUxOCAyMi4zMjk2QzE5Ljg0OTEgMjIuNjE0NiAxOS44NDY2IDIyLjg4NzcgMTkuODQ2NiAyMy4xNDU2QzE5Ljg0NjYgMjMuOTA1NiAxOS44ODA0IDI0LjgxNTYgMTkuOTE1NSAyNS43NjI0QzE5LjkyOTQgMjYuMTM1IDE5Ljk0MzQgMjYuNTEzOCAxOS45NTU3IDI2Ljg5MDhDMjAuMDAwNSAyOC4yNjYgMjAuMDI1OSAyOS43MDU4IDE5Ljk1OTYgMzEuMDk4NUMxOS44OTI5IDMyLjQ5ODggMTkuNzM1OSAzMy43ODM4IDE5LjQ0MjcgMzQuODU5OUMxOS4xNDYyIDM1Ljk0ODYgMTguNzQ5MiAzNi42Nzg3IDE4LjMwNTYgMzcuMTIxMUMxNy4wMjc1IDM4LjM5NTcgMTUuMDA5MyAzOS40MjU0IDEyLjk1MDkgMzkuODI0NkMxMC45MTU5IDQwLjIxOTIgOS4yNzc2OCAzOS45MjcyIDguMzE4MjMgMzkuMTk3MkM4LjMxMzI2IDM5LjE4NiA4LjMwNzcgMzkuMTcyOSA4LjMwMTYyIDM5LjE1NzdDOC4yNDI0MSAzOS4wMDk4IDguMTcwNjEgMzguNzU1NyA4LjExMjI0IDM4LjM2ODZDNy45OTUzOSAzNy41OTM2IDcuOTY1IDM2LjUxMjUgOC4wNDM4IDM1LjE4MDZDOC4yMDA1NiAzMi41MzA4IDguNzcxNDcgMjkuMTY5MiA5LjY3MzI0IDI1Ljg2MDlDMTAuNTc4NSAyMi41Mzk5IDExLjc4MjcgMTkuNDAwMSAxMy4xNDc5IDE3LjEzODZDMTMuODMxMyAxNi4wMDY1IDE0LjUwNDkgMTUuMTc4OSAxNS4xMjk4IDE0LjY1MzhDMTUuNzQ4MiAxNC4xMzQgMTYuMjA2NSAxNCAxNi41MjQ3IDE0WiIgZmlsbD0iI2I0NTMwOSIvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_coli105": { + "mimeType": "image/svg+xml", + "id": "img_coli105", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yOSA5QzI5IDExLjc2MTQgMjYuNzYxNCAxNCAyNCAxNEMyMS4yMzg2IDE0IDE5IDExLjc2MTQgMTkgOUMxOSA2LjIzODU4IDIxLjIzODYgNCAyNCA0QzI2Ljc2MTQgNCAyOSA2LjIzODU4IDI5IDlaTTI3IDlDMjcgMTAuNjU2OSAyNS42NTY5IDEyIDI0IDEyQzIyLjM0MzEgMTIgMjEgMTAuNjU2OSAyMSA5QzIxIDcuMzQzMTUgMjIuMzQzMSA2IDI0IDZDMjUuNjU2OSA2IDI3IDcuMzQzMTUgMjcgOVoiIGZpbGw9IiNiNDUzMDkiLz4KPHBhdGggZD0iTTE2Ljk5OTggNDFWMzRIMTguOTk5OFY0MUMxOC45OTk4IDQxLjU1MjMgMTkuNDQ3NSA0MiAxOS45OTk4IDQySDIwLjA4NjVDMjAuNjAzNyA0MiAyMS4wMzU2IDQxLjYwNTYgMjEuMDgyNCA0MS4wOTA1TDIxLjcyNyAzNEgyMy43MzUzTDIzLjA3NDIgNDEuMjcxNkMyMy4wNjkgNDEuMzI4OCAyMy4wNjIyIDQxLjM4NTYgMjMuMDUzOSA0MS40NDE3QzIzLjAzNTcgNDEuNTY0NyAyMy4wMTAxIDQxLjY4NTEgMjIuOTc3NiA0MS44MDI1QzIyLjYyNDIgNDMuMDc5OCAyMS40NTQ5IDQ0IDIwLjA4NjUgNDRIMTkuOTk5OEMxOC4zNDI5IDQ0IDE2Ljk5OTggNDIuNjU2OSAxNi45OTk4IDQxWiIgZmlsbD0iI2I0NTMwOSIvPgo8cGF0aCBkPSJNMjYuOTE3MSA0MS4wOTA1TDI2LjI3MjUgMzRIMjQuMjY0MkwyNC45MjUzIDQxLjI3MTZDMjQuOTMwNSA0MS4zMjg4IDI0LjkzNzMgNDEuMzg1NiAyNC45NDU2IDQxLjQ0MTdDMjQuOTYzOCA0MS41NjQ3IDI0Ljk4OTQgNDEuNjg1MSAyNS4wMjE5IDQxLjgwMjVDMjUuMzc1MyA0My4wNzk4IDI2LjU0NDYgNDQgMjcuOTEzIDQ0SDI3Ljk5OThDMjkuNjU2NiA0NCAzMC45OTk4IDQyLjY1NjkgMzAuOTk5OCA0MVYzNEgyOC45OTk4VjQxQzI4Ljk5OTggNDEuNTUyMyAyOC41NTIgNDIgMjcuOTk5OCA0MkgyNy45MTNDMjcuMzk1OCA0MiAyNi45NjM5IDQxLjYwNTYgMjYuOTE3MSA0MS4wOTA1WiIgZmlsbD0iI2I0NTMwOSIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTExIDE1QzEwLjQ0NzcgMTUgMTAgMTUuNDQ3NyAxMCAxNlYzMUMxMCAzMS41NTIzIDEwLjQ0NzcgMzIgMTEgMzJIMzdDMzcuNTUyMyAzMiAzOCAzMS41NTIzIDM4IDMxVjE2QzM4IDE1LjQ0NzcgMzcuNTUyMyAxNSAzNyAxNUgxMVpNMTIgMTdWMzBIMTkuNUMxOS41IDI5LjQ0MjQgMTkuNzU5MSAyOC45NTcyIDIwLjAyNzYgMjguNjAwNkMyMC4zMDg2IDI4LjIyNzYgMjAuNjc5NiAyNy44ODgzIDIxLjA3OTQgMjcuNjAxNkMyMS42MjUyIDI3LjIxMDMgMjIuMjk4NiAyNi44NjUgMjMgMjYuNjY3OFYyNC41SDIyLjJDMjEuNTk3MyAyNC41IDIwLjc1MzUgMjQuODY0MiAxOS45NDMzIDI1LjM1NTJDMTkuNTYzOCAyNS41ODUyIDE5LjIzMzcgMjUuODE2NyAxOC45OTg0IDI1Ljk5MTFDMTguODgxMiAyNi4wNzc4IDE4Ljc4ODggMjYuMTQ5NSAxOC43MjcgMjYuMTk4NEMxOC42OTYxIDI2LjIyMjggMTguNjczIDI2LjI0MTUgMTguNjU4MiAyNi4yNTM1TDE4LjY0MjYgMjYuMjY2M0wxOC42Mzk5IDI2LjI2ODRDMTguNjM5OSAyNi4yNjg0IDE4LjY0MDIgMjYuMjY4MiAxOCAyNS41QzE3LjM1OTggMjQuNzMxOCAxNy4zNjAxIDI0LjczMTUgMTcuMzYwMSAyNC43MzE1TDE3LjM2MTQgMjQuNzMwNUwxNy4zNjM4IDI0LjcyODVMMTcuMzcxMyAyNC43MjIzTDE3LjM5NjYgMjQuNzAxNkMxNy40MTc5IDI0LjY4NDMgMTcuNDQ4IDI0LjY2IDE3LjQ4NjMgMjQuNjI5N0MxNy41NjI3IDI0LjU2OTMgMTcuNjcxOSAyNC40ODQ3IDE3LjgwNzkgMjQuMzgzOUMxOC4wNzg4IDI0LjE4MzMgMTguNDYxMiAyMy45MTQ4IDE4LjkwNjcgMjMuNjQ0OEMxOS43NDY1IDIzLjEzNTggMjEuMDAyNyAyMi41IDIyLjIgMjIuNUgyM1YyMC41SDIyLjVDMjEuOTMwOSAyMC41IDIxLjE5MDkgMjAuNjk5MiAyMC41MjkyIDIwLjkzOThDMjAuMjEyIDIxLjA1NTIgMTkuOTM3IDIxLjE3MDkgMTkuNzQyMSAyMS4yNTc2QzE5LjY0NDkgMjEuMzAwNyAxOS41Njg1IDIxLjMzNjMgMTkuNTE3NiAyMS4zNjA1QzE5LjQ5MjIgMjEuMzcyNSAxOS40NzMyIDIxLjM4MTcgMTkuNDYxMyAyMS4zODc1TDE5LjQ0ODcgMjEuMzkzN0wxOS40NDcgMjEuMzk0NUMxOS40NDcgMjEuMzk0NSAxOS40NDcyIDIxLjM5NDQgMTkgMjAuNUMxOC41NTI4IDE5LjYwNTYgMTguNTUzMSAxOS42MDU0IDE4LjU1MzEgMTkuNjA1NEwxOC41NTY0IDE5LjYwMzhMMTguNTYyOSAxOS42MDA2TDE4LjU4NDQgMTkuNTlDMTguNjAyNSAxOS41ODEyIDE4LjYyNzkgMTkuNTY4OSAxOC42NjAxIDE5LjU1MzZDMTguNzI0NSAxOS41MjMxIDE4LjgxNiAxOS40ODA1IDE4LjkyOTggMTkuNDI5OUMxOS4xNTY3IDE5LjMyOTEgMTkuNDc1NSAxOS4xOTQ4IDE5Ljg0NTggMTkuMDYwMkMyMC41NTkxIDE4LjgwMDggMjEuNTY5MSAxOC41IDIyLjUgMTguNUgyM1YxN0gxMlpNMjUgMjQuNUgyNi4xQzI2Ljg0ODkgMjQuNSAyNy42MTg2IDI0Ljg2NjMgMjguMjYzMSAyNS4zMTg2QzI4LjU3MzUgMjUuNTM2NCAyOC44Mjg1IDI1Ljc1NTYgMjkuMDA0OCAyNS45MTk3QzI5LjA5MjUgMjYuMDAxMiAyOS4xNTk0IDI2LjA2NzkgMjkuMjAyNiAyNi4xMTIyQzI5LjIyNDEgMjYuMTM0MyAyOS4yMzk3IDI2LjE1MDcgMjkuMjQ4OCAyNi4xNjA1TDI5LjI1NzQgMjYuMTY5N0MyOS4yNTc0IDI2LjE2OTcgMjkuMjU2NyAyNi4xNjkgMzAgMjUuNUMzMC43NDMzIDI0LjgzMSAzMC43NDI5IDI0LjgzMDYgMzAuNzQyOSAyNC44MzA2TDMwLjc0MTQgMjQuODI5TDMwLjczODkgMjQuODI2MkwzMC43MzE4IDI0LjgxODRMMzAuNzA5NyAyNC43OTQ2QzMwLjY5MTUgMjQuNzc1MSAzMC42NjYzIDI0Ljc0ODUgMzAuNjM0NiAyNC43MTZDMzAuNTcxMSAyNC42NTA5IDMwLjQ4MDkgMjQuNTYxMyAzMC4zNjcgMjQuNDU1M0MzMC4xNDAzIDI0LjI0NDQgMjkuODE0IDIzLjk2MzYgMjkuNDExOSAyMy42ODE0QzI4LjYzMTQgMjMuMTMzNyAyNy40NTExIDIyLjUgMjYuMSAyMi41SDI1VjIwLjVIMjUuNzVDMjYuNDQ0MyAyMC41IDI3LjExOTMgMjAuNzAxMSAyNy42NDMyIDIwLjkyMTZDMjcuOTAwMyAyMS4wMjk5IDI4LjEwOTIgMjEuMTM3OCAyOC4yNTA5IDIxLjIxNjlDMjguMzIxNSAyMS4yNTY0IDI4LjM3NDcgMjEuMjg4MiAyOC40MDggMjEuMzA4N0MyOC40MjQ3IDIxLjMxODkgMjguNDM2MyAyMS4zMjYzIDI4LjQ0MjcgMjEuMzMwNEwyOC40NDU3IDIxLjMzMjNDMjguNDQ1NyAyMS4zMzIzIDI4LjQ0NTMgMjEuMzMyMSAyOSAyMC41QzI5LjU1NDcgMTkuNjY3OSAyOS41NTQyIDE5LjY2NzYgMjkuNTU0MiAxOS42Njc2TDI5LjU1MjcgMTkuNjY2NkwyOS41NTAxIDE5LjY2NDlMMjkuNTQzMiAxOS42NjA0TDI5LjUyMjggMTkuNjQ3MkMyOS41MDYzIDE5LjYzNjYgMjkuNDg0IDE5LjYyMjUgMjkuNDU2MiAxOS42MDU0QzI5LjQwMDcgMTkuNTcxMiAyOS4zMjMgMTkuNTI0OSAyOS4yMjU2IDE5LjQ3MDZDMjkuMDMxNSAxOS4zNjIyIDI4Ljc1NTkgMTkuMjIwMSAyOC40MTkzIDE5LjA3ODRDMjcuNzU1NyAxOC43OTg5IDI2LjgwNTcgMTguNSAyNS43NSAxOC41SDI1VjE3SDM2VjMwSDI4LjVDMjguNSAyOS40Mzc5IDI4LjIzMjQgMjguOTQ1MiAyNy45NjQxIDI4LjU4NzVDMjcuNjgwMyAyOC4yMDkyIDI3LjMwNTQgMjcuODYwNiAyNi45MDA3IDI3LjU2NjNDMjYuMzY3NSAyNy4xNzg1IDI1LjY5ODkgMjYuODI1NyAyNSAyNi42MzkxVjI0LjVaTTI2LjQ5MjkgMzBDMjYuNDc5NyAyOS45NjcgMjYuNDQ1NyAyOS44OTY0IDI2LjM2NDEgMjkuNzg3NUMyNi4yMjU5IDI5LjYwMzMgMjYuMDA3MSAyOS4zODk0IDI1LjcyNDMgMjkuMTgzN0MyNS4xNDc4IDI4Ljc2NDUgMjQuNDkzNyAyOC41MTE3IDI0LjAzMiAyOC41MDA0QzIzLjQ4NzcgMjguNTQ2NCAyMi44MDUyIDI4LjgyNTIgMjIuMjQ0OSAyOS4yMjdDMjEuOTY1NyAyOS40MjcyIDIxLjc1NTYgMjkuNjMwNyAyMS42MjUyIDI5LjgwMzhDMjEuNTQ5NiAyOS45MDQzIDIxLjUxODQgMjkuOTY5NCAyMS41MDYzIDMwSDI2LjQ5MjlaIiBmaWxsPSIjYjQ1MzA5Ii8+Cjwvc3ZnPgo=", + "created": 1700000000000 + } + } +} \ No newline at end of file diff --git a/knowledge/drafts/three-axes.svg b/knowledge/drafts/three-axes.svg new file mode 100644 index 0000000..b79bee0 --- /dev/null +++ b/knowledge/drafts/three-axes.svg @@ -0,0 +1,2 @@ +Findings/DiagnosesWHAT was foundFindingspulmonary nodulesolidpart-solidnon-solidDiagnosespulmonary neoplasmnon-small cell lung canceradenocarcinoma of the lungAssessmentsLung-RADSSalter-Harris categoryData Elementspresencepresent · absent · indeterminate · unknownseverityminimal · mild · moderate · severeMeasurementslengthmm, cm, ...CT densityHUlayered over: finding models· ACR/RSNA CDEsAnatomic LocationsWHERE it isthoraxlungright lungupper lobe of right lungmiddle lobe of right lunglower lobe of right lungleft lungpleural spacemediastinumheartabdomenkidneyleft kidneyright kidneyrenal pelvisliverspleenheadbraincerebellumfrontal lobeorbitpelvisurinary bladderprostatelayered over: RadLexExam TypesHOW it was seenCTCT Chest(preferred family)CT Chest WO contrastCT Chest W contrast IVCT Chest WO and W contrast IVCT Lung parenchyma WO contrastCTA Chest vesselsMRMR Knee(preferred family)MR Knee WO contrastMR Knee W contrast IVMR Brain(preferred family)MR Brain WO contrastMR Brain WO and W contrast IVXRXR Knee(preferred family)XR Knee 2 ViewsXR Knee 3 ViewsXR Chest(preferred family)XR Chest 2 ViewsXR Chest PA and LateralUSUS Abdomen(preferred family)US Abdomen limitedUS Abdomen RUQUS Thyroid glandeach a LOINC/RSNA Playbook entrylayered over: LOINC/RSNAPlaybook \ No newline at end of file diff --git a/knowledge/drafts/two-collections.excalidraw b/knowledge/drafts/two-collections.excalidraw new file mode 100644 index 0000000..7f04134 --- /dev/null +++ b/knowledge/drafts/two-collections.excalidraw @@ -0,0 +1,1662 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "oidm-knowledge/tools/diagrams", + "elements": [ + { + "type": "rectangle", + "id": "panel_oifm", + "x": 0, + "y": 0, + "width": 364, + "height": 272, + "strokeColor": "#059669", + "backgroundColor": "#d1fae5", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1001, + "version": 1, + "versionNonce": 1002, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "rectangle", + "id": "panel_cde", + "x": 536, + "y": 0, + "width": 364, + "height": 272, + "strokeColor": "#059669", + "backgroundColor": "#d1fae5", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1003, + "version": 1, + "versionNonce": 1004, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "hicon1", + "x": 18, + "y": 16, + "width": 26, + "height": 26, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1005, + "version": 1, + "versionNonce": 1006, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_hicon1", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "ht2", + "x": 54, + "y": 18, + "width": 226.8, + "height": 21.25, + "strokeColor": "#064e3b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1007, + "version": 1, + "versionNonce": 1008, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Open Imaging Finding Models", + "originalText": "Open Imaging Finding Models", + "fontSize": 17, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "hs3", + "x": 54, + "y": 50, + "width": 143.8, + "height": 16.25, + "strokeColor": "#047857", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1009, + "version": 1, + "versionNonce": 1010, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "inclusive \u00b7 beta channel \u00b7", + "originalText": "inclusive \u00b7 beta channel \u00b7", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "hs4", + "x": 54, + "y": 66.25, + "width": 159.7, + "height": 16.25, + "strokeColor": "#047857", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1011, + "version": 1, + "versionNonce": 1012, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "rapid additions and updates", + "originalText": "rapid additions and updates", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "hs5", + "x": 54, + "y": 89.5, + "width": 182.8, + "height": 16.25, + "strokeColor": "#047857", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1013, + "version": 1, + "versionNonce": 1014, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "maintained by the OIDM project", + "originalText": "maintained by the OIDM project", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "hicon6", + "x": 554, + "y": 16, + "width": 26, + "height": 26, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1015, + "version": 1, + "versionNonce": 1016, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_hicon6", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "ht7", + "x": 590, + "y": 18, + "width": 277.8, + "height": 21.25, + "strokeColor": "#064e3b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1017, + "version": 1, + "versionNonce": 1018, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "ACR/RSNA Common Data Elements", + "originalText": "ACR/RSNA Common Data Elements", + "fontSize": 17, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "hs8", + "x": 590, + "y": 50, + "width": 228.3, + "height": 16.25, + "strokeColor": "#047857", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1019, + "version": 1, + "versionNonce": 1020, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "well-reviewed \u00b7 release channel \u00b7 stable", + "originalText": "well-reviewed \u00b7 release channel \u00b7 stable", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "hs9", + "x": 590, + "y": 73.25, + "width": 186.4, + "height": 16.25, + "strokeColor": "#047857", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1021, + "version": 1, + "versionNonce": 1022, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "American College of Radiology \u00b7", + "originalText": "American College of Radiology \u00b7", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "hs10", + "x": 590, + "y": 89.5, + "width": 228.2, + "height": 16.25, + "strokeColor": "#047857", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1023, + "version": 1, + "versionNonce": 1024, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Radiological Society of North America \u00b7", + "originalText": "Radiological Society of North America \u00b7", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "hs11", + "x": 590, + "y": 105.75, + "width": 87.4, + "height": 16.25, + "strokeColor": "#047857", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1025, + "version": 1, + "versionNonce": 1026, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "radelement.org", + "originalText": "radelement.org", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "n_hydro", + "x": 18, + "y": 144, + "width": 108.9, + "height": 40, + "strokeColor": "#059669", + "backgroundColor": "#a7f3d0", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1027, + "version": 1, + "versionNonce": 1028, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "n_hydro_t", + "x": 26, + "y": 155.875, + "width": 92.9, + "height": 16.25, + "strokeColor": "#064e3b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1029, + "version": 1, + "versionNonce": 1030, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "hydronephrosis", + "originalText": "hydronephrosis", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "n_calc", + "x": 140.9, + "y": 144, + "width": 99.5, + "height": 40, + "strokeColor": "#059669", + "backgroundColor": "#a7f3d0", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1031, + "version": 1, + "versionNonce": 1032, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "n_calc_t", + "x": 148.9, + "y": 155.875, + "width": 83.5, + "height": 16.25, + "strokeColor": "#064e3b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1033, + "version": 1, + "versionNonce": 1034, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "renal calculus", + "originalText": "renal calculus", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "n_nodule_l", + "x": 222.7, + "y": 200, + "width": 123.3, + "height": 40, + "strokeColor": "#059669", + "backgroundColor": "#a7f3d0", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1035, + "version": 1, + "versionNonce": 1036, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "n_nodule_l_t", + "x": 230.7, + "y": 211.875, + "width": 107.3, + "height": 16.25, + "strokeColor": "#064e3b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1037, + "version": 1, + "versionNonce": 1038, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "pulmonary nodule", + "originalText": "pulmonary nodule", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "n_aaa", + "x": 554, + "y": 144, + "width": 176.1, + "height": 40, + "strokeColor": "#059669", + "backgroundColor": "#a7f3d0", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1039, + "version": 1, + "versionNonce": 1040, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "n_aaa_t", + "x": 562, + "y": 155.875, + "width": 160.1, + "height": 16.25, + "strokeColor": "#064e3b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1041, + "version": 1, + "versionNonce": 1042, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "abdominal aortic aneurysm", + "originalText": "abdominal aortic aneurysm", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "n_nodule_r", + "x": 554, + "y": 200, + "width": 123.3, + "height": 40, + "strokeColor": "#059669", + "backgroundColor": "#a7f3d0", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1043, + "version": 1, + "versionNonce": 1044, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "n_nodule_r_t", + "x": 562, + "y": 211.875, + "width": 107.3, + "height": 16.25, + "strokeColor": "#064e3b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1045, + "version": 1, + "versionNonce": 1046, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "pulmonary nodule", + "originalText": "pulmonary nodule", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bl_grad12", + "x": 381.7, + "y": 28, + "width": 136.6, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1047, + "version": 1, + "versionNonce": 1048, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "definitions proved out", + "originalText": "definitions proved out", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bl_grad13", + "x": 381.7, + "y": 44.25, + "width": 136.6, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1049, + "version": 1, + "versionNonce": 1050, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "here graduate to review", + "originalText": "here graduate to review", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "b_grad", + "x": 368, + "y": 72, + "width": 159.04999999999995, + "height": 0.0, + "strokeColor": "#059669", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1051, + "version": 1, + "versionNonce": 1052, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 159.04999999999995, + 0.0 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "b_grad_h", + "x": 532, + "y": 72, + "width": 0, + "height": 0, + "strokeColor": "#059669", + "backgroundColor": "#059669", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1053, + "version": 1, + "versionNonce": 1054, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -9.0, + 5.579999999999998 + ], + [ + -9.0, + -5.579999999999998 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "ramp14", + "x": 368.0, + "y": 86, + "width": 23.928571428571427, + "height": 16, + "strokeColor": "transparent", + "backgroundColor": "#ecfdf5", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1055, + "version": 1, + "versionNonce": 1056, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "rectangle", + "id": "ramp15", + "x": 391.42857142857144, + "y": 86, + "width": 23.928571428571427, + "height": 16, + "strokeColor": "transparent", + "backgroundColor": "#d1fae5", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1057, + "version": 1, + "versionNonce": 1058, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "rectangle", + "id": "ramp16", + "x": 414.85714285714283, + "y": 86, + "width": 23.928571428571427, + "height": 16, + "strokeColor": "transparent", + "backgroundColor": "#a7f3d0", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1059, + "version": 1, + "versionNonce": 1060, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "rectangle", + "id": "ramp17", + "x": 438.2857142857143, + "y": 86, + "width": 23.928571428571427, + "height": 16, + "strokeColor": "transparent", + "backgroundColor": "#6ee7b7", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1061, + "version": 1, + "versionNonce": 1062, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "rectangle", + "id": "ramp18", + "x": 461.7142857142857, + "y": 86, + "width": 23.928571428571427, + "height": 16, + "strokeColor": "transparent", + "backgroundColor": "#34d399", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1063, + "version": 1, + "versionNonce": 1064, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "rectangle", + "id": "ramp19", + "x": 485.1428571428571, + "y": 86, + "width": 23.928571428571427, + "height": 16, + "strokeColor": "transparent", + "backgroundColor": "#10b981", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1065, + "version": 1, + "versionNonce": 1066, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "rectangle", + "id": "ramp20", + "x": 508.57142857142856, + "y": 86, + "width": 23.928571428571427, + "height": 16, + "strokeColor": "transparent", + "backgroundColor": "#059669", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1067, + "version": 1, + "versionNonce": 1068, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "arrow", + "id": "b_cross", + "x": 532, + "y": 114, + "width": -159.05, + "height": 0.0, + "strokeColor": "#059669", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1069, + "version": 1, + "versionNonce": 1070, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -159.05, + 0.0 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "b_cross_h", + "x": 368, + "y": 114, + "width": 0, + "height": 0, + "strokeColor": "#059669", + "backgroundColor": "#059669", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1071, + "version": 1, + "versionNonce": 1072, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 9.0, + -5.579999999999998 + ], + [ + 9.0, + 5.579999999999998 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "text", + "id": "bl_cross21", + "x": 378.45, + "y": 124, + "width": 143.1, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1073, + "version": 1, + "versionNonce": 1074, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "cross-links: a migrated", + "originalText": "cross-links: a migrated", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bl_cross22", + "x": 378.45, + "y": 140.25, + "width": 143.1, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1075, + "version": 1, + "versionNonce": 1076, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "definition keeps its OIFM", + "originalText": "definition keeps its OIFM", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bl_cross23", + "x": 378.45, + "y": 156.5, + "width": 143.1, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1077, + "version": 1, + "versionNonce": 1078, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "entry and carries its", + "originalText": "entry and carries its", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "bl_cross24", + "x": 378.45, + "y": 172.75, + "width": 143.1, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1079, + "version": 1, + "versionNonce": 1080, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "CDE identity", + "originalText": "CDE identity", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "l_index", + "x": 346.0, + "y": 220.0, + "width": 208.0, + "height": 0.0, + "strokeColor": "#059669", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1081, + "version": 1, + "versionNonce": 1082, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0.0 + ], + [ + 208.0, + 0.0 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "rectangle", + "id": "l_index_l", + "x": 409.3, + "y": 208.875, + "width": 81.4, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1083, + "version": 1, + "versionNonce": 1084, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_index_l_t", + "x": 415.3, + "y": 211.875, + "width": 69.4, + "height": 16.25, + "strokeColor": "#047857", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1085, + "version": 1, + "versionNonce": 1086, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "index codes", + "originalText": "index codes", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "amber", + "x": 0, + "y": 320, + "width": 900, + "height": 92, + "strokeColor": "#b45309", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1087, + "version": 1, + "versionNonce": 1088, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "a_title", + "x": 344.65, + "y": 344.25, + "width": 210.7, + "height": 21.25, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1089, + "version": 1, + "versionNonce": 1090, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "the next-generation schema", + "originalText": "the next-generation schema", + "fontSize": 17, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "a_sub", + "x": 285.25, + "y": 371.5, + "width": 329.5, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1091, + "version": 1, + "versionNonce": 1092, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "one graph of interconnected concepts for both collections", + "originalText": "one graph of interconnected concepts for both collections", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "m_onto0", + "x": 182.0, + "y": 274, + "width": 0.0, + "height": 39.05000000000001, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1093, + "version": 1, + "versionNonce": 1094, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + 0.0, + 39.05000000000001 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "m_onto0_h", + "x": 182.0, + "y": 318, + "width": 0, + "height": 0, + "strokeColor": "#b45309", + "backgroundColor": "#b45309", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1095, + "version": 1, + "versionNonce": 1096, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + -5.5800000000000125, + -9.0 + ], + [ + 5.5800000000000125, + -9.0 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "text", + "id": "m_l25", + "x": 194.0, + "y": 288.0, + "width": 70.8, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1097, + "version": 1, + "versionNonce": 1098, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "moving onto", + "originalText": "moving onto", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "m_onto1", + "x": 718.0, + "y": 274, + "width": 0.0, + "height": 39.05000000000001, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1099, + "version": 1, + "versionNonce": 1100, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + 0.0, + 39.05000000000001 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "m_onto1_h", + "x": 718.0, + "y": 318, + "width": 0, + "height": 0, + "strokeColor": "#b45309", + "backgroundColor": "#b45309", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1101, + "version": 1, + "versionNonce": 1102, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0.0, + 0 + ], + [ + -5.580000000000041, + -9.0 + ], + [ + 5.580000000000041, + -9.0 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "text", + "id": "m_l26", + "x": 730.0, + "y": 288.0, + "width": 70.8, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1103, + "version": 1, + "versionNonce": 1104, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "moving onto", + "originalText": "moving onto", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + } + ], + "appState": { + "viewBackgroundColor": "#ffffff", + "gridSize": null + }, + "files": { + "img_hicon1": { + "mimeType": "image/svg+xml", + "id": "img_hicon1", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwNTk2NjkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyLjU4NiAyLjU4NkEyIDIgMCAwIDAgMTEuMTcyIDJINGEyIDIgMCAwIDAtMiAydjcuMTcyYTIgMiAwIDAgMCAuNTg2IDEuNDE0bDguNzA0IDguNzA0YTIuNDI2IDIuNDI2IDAgMCAwIDMuNDIgMGw2LjU4LTYuNThhMi40MjYgMi40MjYgMCAwIDAgMC0zLjQyeiIgLz4KICA8Y2lyY2xlIGN4PSI3LjUiIGN5PSI3LjUiIHI9Ii41IiBmaWxsPSIjMDU5NjY5IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_hicon6": { + "mimeType": "image/svg+xml", + "id": "img_hicon6", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwNTk2NjkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyLjU4NiAyLjU4NkEyIDIgMCAwIDAgMTEuMTcyIDJINGEyIDIgMCAwIDAtMiAydjcuMTcyYTIgMiAwIDAgMCAuNTg2IDEuNDE0bDguNzA0IDguNzA0YTIuNDI2IDIuNDI2IDAgMCAwIDMuNDIgMGw2LjU4LTYuNThhMi40MjYgMi40MjYgMCAwIDAgMC0zLjQyeiIgLz4KICA8Y2lyY2xlIGN4PSI3LjUiIGN5PSI3LjUiIHI9Ii41IiBmaWxsPSIjMDU5NjY5IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + } + } +} \ No newline at end of file diff --git a/knowledge/drafts/two-collections.svg b/knowledge/drafts/two-collections.svg new file mode 100644 index 0000000..c06dde8 --- /dev/null +++ b/knowledge/drafts/two-collections.svg @@ -0,0 +1,2 @@ +Open Imaging Finding Modelsinclusive · beta channel ·rapid additions and updatesmaintained by the OIDM projectACR/RSNA Common Data Elementswell-reviewed · release channel · stableAmerican College of Radiology ·Radiological Society of North America ·radelement.orghydronephrosisrenal calculuspulmonary noduleabdominal aortic aneurysmpulmonary noduledefinitions proved outhere graduate to reviewcross-links: a migrateddefinition keeps its OIFMentry and carries itsCDE identityindex codesthe next-generation schemaone graph of interconnected concepts for both collectionsmoving ontomoving onto \ No newline at end of file diff --git a/knowledge/drafts/two-planes.excalidraw b/knowledge/drafts/two-planes.excalidraw new file mode 100644 index 0000000..bc705fd --- /dev/null +++ b/knowledge/drafts/two-planes.excalidraw @@ -0,0 +1,4487 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "oidm-knowledge/tools/diagrams", + "elements": [ + { + "type": "line", + "id": "plane_patient", + "x": 55, + "y": 0, + "width": 935, + "height": 190, + "strokeColor": "#0f766e", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1001, + "version": 1, + "versionNonce": 1002, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 880, + 0 + ], + [ + 825, + 190 + ], + [ + -55, + 190 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "line", + "id": "plane_foundation", + "x": 55, + "y": 250, + "width": 935, + "height": 440, + "strokeColor": "#b45309", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1003, + "version": 1, + "versionNonce": 1004, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 880, + 0 + ], + [ + 825, + 440 + ], + [ + -55, + 440 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "image", + "id": "hicon1", + "x": 67, + "y": 14.0, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1005, + "version": 1, + "versionNonce": 1006, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_hicon1", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "htitle2", + "x": 107, + "y": 12, + "width": 174.0, + "height": 25.0, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1007, + "version": 1, + "versionNonce": 1008, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Patient Context", + "originalText": "Patient Context", + "fontSize": 20, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "hsub3", + "x": 107, + "y": 38, + "width": 180.95999999999998, + "height": 16.25, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1009, + "version": 1, + "versionNonce": 1010, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "this patient \u00b7 this exam", + "originalText": "this patient \u00b7 this exam", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "image", + "id": "hicon4", + "x": 68, + "y": 266.0, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1011, + "version": 1, + "versionNonce": 1012, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_hicon4", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "htitle5", + "x": 108, + "y": 264, + "width": 208.79999999999998, + "height": 25.0, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1013, + "version": 1, + "versionNonce": 1014, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Foundation Context", + "originalText": "Foundation Context", + "fontSize": 20, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "hsub6", + "x": 108, + "y": 290, + "width": 188.5, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1015, + "version": 1, + "versionNonce": 1016, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "shared, curated knowledge", + "originalText": "shared, curated knowledge", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "exam", + "x": 140, + "y": 92, + "width": 246, + "height": 66, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1017, + "version": 1, + "versionNonce": 1018, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "ni7", + "x": 152.0, + "y": 111.0, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1019, + "version": 1, + "versionNonce": 1020, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_ni7", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "nt8", + "x": 190, + "y": 105.875, + "width": 186, + "height": 20.0, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1021, + "version": 1, + "versionNonce": 1022, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "CT chest without contrast", + "originalText": "CT chest without contrast", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "ns9", + "x": 190, + "y": 127.875, + "width": 186, + "height": 16.25, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1023, + "version": 1, + "versionNonce": 1024, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "this patient \u00b7 2026-03-04", + "originalText": "this patient \u00b7 2026-03-04", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "nodule", + "x": 470, + "y": 92, + "width": 196, + "height": 66, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1025, + "version": 1, + "versionNonce": 1026, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "ni10", + "x": 482.0, + "y": 111.0, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1027, + "version": 1, + "versionNonce": 1028, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_ni10", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "nt11", + "x": 520, + "y": 105.875, + "width": 136, + "height": 20.0, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1029, + "version": 1, + "versionNonce": 1030, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "pulmonary nodule", + "originalText": "pulmonary nodule", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "ns12", + "x": 520, + "y": 127.875, + "width": 136, + "height": 16.25, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1031, + "version": 1, + "versionNonce": 1032, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "present \u00b7 8 mm \u00b7 new", + "originalText": "present \u00b7 8 mm \u00b7 new", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "effusion", + "x": 706, + "y": 92, + "width": 176, + "height": 66, + "strokeColor": "#0f766e", + "backgroundColor": "#99f6e4", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1033, + "version": 1, + "versionNonce": 1034, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "ni13", + "x": 718.0, + "y": 111.0, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1035, + "version": 1, + "versionNonce": 1036, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_ni13", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "nt14", + "x": 756, + "y": 105.875, + "width": 116, + "height": 20.0, + "strokeColor": "#134e4a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1037, + "version": 1, + "versionNonce": 1038, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "pleural effusion", + "originalText": "pleural effusion", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "ns15", + "x": 756, + "y": 127.875, + "width": 116, + "height": 16.25, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1039, + "version": 1, + "versionNonce": 1040, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "absent", + "originalText": "absent", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "e_found1", + "x": 470, + "y": 125, + "width": -72.5, + "height": 0.0, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1041, + "version": 1, + "versionNonce": 1042, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -72.5, + 0.0 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_found1_h", + "x": 392, + "y": 125, + "width": 0, + "height": 0, + "strokeColor": "#0f766e", + "backgroundColor": "#0f766e", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1043, + "version": 1, + "versionNonce": 1044, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 10.0, + -6.200000000000003 + ], + [ + 10.0, + 6.199999999999989 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "l_found1", + "x": 399.7, + "y": 113.875, + "width": 62.6, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1045, + "version": 1, + "versionNonce": 1046, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_found1_t", + "x": 405.7, + "y": 116.875, + "width": 50.6, + "height": 16.25, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1047, + "version": 1, + "versionNonce": 1048, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "found on", + "originalText": "found on", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "e_found2", + "x": 790, + "y": 92, + "width": -540.0, + "height": -8.5, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1049, + "version": 1, + "versionNonce": 1050, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + -20 + ], + [ + -540, + -20 + ], + [ + -540.0, + -8.5 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "e_found2_h", + "x": 250, + "y": 89, + "width": 0, + "height": 0, + "strokeColor": "#0f766e", + "backgroundColor": "#0f766e", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1051, + "version": 1, + "versionNonce": 1052, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -6.199999999999989, + -10.0 + ], + [ + 6.199999999999989, + -10.0 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "l_found2", + "x": 528.7, + "y": 60.875, + "width": 62.6, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1053, + "version": 1, + "versionNonce": 1054, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_found2_t", + "x": 534.7, + "y": 63.875, + "width": 50.6, + "height": 16.25, + "strokeColor": "#0f766e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1055, + "version": 1, + "versionNonce": 1056, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "found on", + "originalText": "found on", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "exam_type", + "x": 120, + "y": 322, + "width": 218, + "height": 62, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1057, + "version": 1, + "versionNonce": 1058, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "ni16", + "x": 132.55, + "y": 337.0, + "width": 32, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1059, + "version": 1, + "versionNonce": 1060, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_ni16", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "nt17", + "x": 174.55, + "y": 334.5, + "width": 150.9, + "height": 18.75, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1061, + "version": 1, + "versionNonce": 1062, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "CT Chest WO contrast", + "originalText": "CT Chest WO contrast", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "nd18", + "x": 174.55, + "y": 355.25, + "width": 150.9, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1063, + "version": 1, + "versionNonce": 1064, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "exam type \u00b7 29252-4", + "originalText": "exam type \u00b7 29252-4", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "nodule_def", + "x": 370, + "y": 322, + "width": 216, + "height": 62, + "strokeColor": "#059669", + "backgroundColor": "#d1fae5", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1065, + "version": 1, + "versionNonce": 1066, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "ni19", + "x": 382.75, + "y": 339.0, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1067, + "version": 1, + "versionNonce": 1068, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_ni19", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "nt20", + "x": 420.75, + "y": 334.5, + "width": 152.5, + "height": 18.75, + "strokeColor": "#064e3b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1069, + "version": 1, + "versionNonce": 1070, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "pulmonary nodule", + "originalText": "pulmonary nodule", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "nd21", + "x": 420.75, + "y": 355.25, + "width": 152.5, + "height": 16.25, + "strokeColor": "#047857", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1071, + "version": 1, + "versionNonce": 1072, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "finding/diagnosis definition", + "originalText": "finding/diagnosis definition", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "effusion_def", + "x": 618, + "y": 322, + "width": 216, + "height": 62, + "strokeColor": "#059669", + "backgroundColor": "#d1fae5", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1073, + "version": 1, + "versionNonce": 1074, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "ni22", + "x": 630.75, + "y": 339.0, + "width": 28, + "height": 28, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1075, + "version": 1, + "versionNonce": 1076, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_ni22", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "nt23", + "x": 668.75, + "y": 334.5, + "width": 152.5, + "height": 18.75, + "strokeColor": "#064e3b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1077, + "version": 1, + "versionNonce": 1078, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "pleural effusion", + "originalText": "pleural effusion", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "nd24", + "x": 668.75, + "y": 355.25, + "width": 152.5, + "height": 16.25, + "strokeColor": "#047857", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1079, + "version": 1, + "versionNonce": 1080, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "finding/diagnosis definition", + "originalText": "finding/diagnosis definition", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "family", + "x": 130, + "y": 448, + "width": 168, + "height": 56, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1081, + "version": 1, + "versionNonce": 1082, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "nt25", + "x": 138, + "y": 457.5, + "width": 152, + "height": 18.75, + "strokeColor": "#78350f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1083, + "version": 1, + "versionNonce": 1084, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "CT Chest", + "originalText": "CT Chest", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "nd26", + "x": 138, + "y": 478.25, + "width": 152, + "height": 16.25, + "strokeColor": "#b45309", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1085, + "version": 1, + "versionNonce": 1086, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "exam family \u00b7 preferred", + "originalText": "exam family \u00b7 preferred", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "modality", + "x": 382, + "y": 448, + "width": 80, + "height": 56, + "strokeColor": "#6b7280", + "backgroundColor": "#e5e7eb", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1087, + "version": 1, + "versionNonce": 1088, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "nt27", + "x": 390, + "y": 457.5, + "width": 64, + "height": 18.75, + "strokeColor": "#374151", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1089, + "version": 1, + "versionNonce": 1090, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "CT", + "originalText": "CT", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "nd28", + "x": 390, + "y": 478.25, + "width": 64, + "height": 16.25, + "strokeColor": "#4b5563", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1091, + "version": 1, + "versionNonce": 1092, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "modality", + "originalText": "modality", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "r_member", + "x": 200, + "y": 384, + "width": 0.0, + "height": 55.5, + "strokeColor": "#78716c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1093, + "version": 1, + "versionNonce": 1094, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.0, + 55.5 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "r_member_h", + "x": 200, + "y": 445, + "width": 0, + "height": 0, + "strokeColor": "#78716c", + "backgroundColor": "#78716c", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1095, + "version": 1, + "versionNonce": 1096, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -6.199999999999989, + -10.0 + ], + [ + 6.199999999999989, + -10.0 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "l_member", + "x": 144.15, + "y": 404.875, + "width": 111.7, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1097, + "version": 1, + "versionNonce": 1098, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_member_t", + "x": 150.15, + "y": 407.875, + "width": 99.7, + "height": 16.25, + "strokeColor": "#78716c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1099, + "version": 1, + "versionNonce": 1100, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "member of family", + "originalText": "member of family", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "r_modality", + "x": 298, + "y": 476.0, + "width": 75.5, + "height": 0.0, + "strokeColor": "#78716c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1101, + "version": 1, + "versionNonce": 1102, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 75.5, + 0.0 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "r_modality_h", + "x": 379, + "y": 476.0, + "width": 0, + "height": 0, + "strokeColor": "#78716c", + "backgroundColor": "#78716c", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1103, + "version": 1, + "versionNonce": 1104, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + -10.0, + 6.199999999999989 + ], + [ + -10.0, + -6.199999999999989 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "l_modality", + "x": 309.8, + "y": 464.875, + "width": 60.4, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1105, + "version": 1, + "versionNonce": 1106, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_modality_t", + "x": 315.8, + "y": 467.875, + "width": 48.4, + "height": 16.25, + "strokeColor": "#78716c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1107, + "version": 1, + "versionNonce": 1108, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "modality", + "originalText": "modality", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "r_seen", + "x": 422, + "y": 384, + "width": 0.0, + "height": 55.5, + "strokeColor": "#78716c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1109, + "version": 1, + "versionNonce": 1110, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.0, + 55.5 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "r_seen_h", + "x": 422, + "y": 445, + "width": 0, + "height": 0, + "strokeColor": "#78716c", + "backgroundColor": "#78716c", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1111, + "version": 1, + "versionNonce": 1112, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -6.199999999999989, + -10.0 + ], + [ + 6.199999999999989, + -10.0 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "l_seen", + "x": 392.85, + "y": 404.875, + "width": 58.3, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1113, + "version": 1, + "versionNonce": 1114, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_seen_t", + "x": 398.85, + "y": 407.875, + "width": 46.3, + "height": 16.25, + "strokeColor": "#78716c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1115, + "version": 1, + "versionNonce": 1116, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "seen on", + "originalText": "seen on", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "thorax", + "x": 130, + "y": 568, + "width": 130, + "height": 62, + "strokeColor": "#1d4ed8", + "backgroundColor": "#bfdbfe", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1117, + "version": 1, + "versionNonce": 1118, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "nt29", + "x": 138, + "y": 580.5, + "width": 114, + "height": 18.75, + "strokeColor": "#1e3a8a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1119, + "version": 1, + "versionNonce": 1120, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "thorax", + "originalText": "thorax", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "nd30", + "x": 138, + "y": 601.25, + "width": 114, + "height": 16.25, + "strokeColor": "#1d4ed8", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1121, + "version": 1, + "versionNonce": 1122, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "anatomic location", + "originalText": "anatomic location", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "lung", + "x": 342, + "y": 568, + "width": 110, + "height": 62, + "strokeColor": "#1d4ed8", + "backgroundColor": "#bfdbfe", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1123, + "version": 1, + "versionNonce": 1124, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "image", + "id": "ni31", + "x": 361.8, + "y": 583.0, + "width": 32, + "height": 32, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1125, + "version": 1, + "versionNonce": 1126, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "fileId": "img_ni31", + "status": "saved", + "scale": [ + 1, + 1 + ], + "roundness": null, + "crop": null + }, + { + "type": "text", + "id": "nt32", + "x": 403.8, + "y": 589.625, + "width": 28.4, + "height": 18.75, + "strokeColor": "#1e3a8a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1127, + "version": 1, + "versionNonce": 1128, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "lung", + "originalText": "lung", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "upper_lobe", + "x": 554, + "y": 568, + "width": 185, + "height": 62, + "strokeColor": "#1d4ed8", + "backgroundColor": "#bfdbfe", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1129, + "version": 1, + "versionNonce": 1130, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "nt33", + "x": 562, + "y": 589.625, + "width": 169, + "height": 18.75, + "strokeColor": "#1e3a8a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1131, + "version": 1, + "versionNonce": 1132, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "upper lobe of right lung", + "originalText": "upper lobe of right lung", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "pleural_space", + "x": 760, + "y": 568, + "width": 120, + "height": 62, + "strokeColor": "#1d4ed8", + "backgroundColor": "#bfdbfe", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1133, + "version": 1, + "versionNonce": 1134, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "nt34", + "x": 768, + "y": 589.625, + "width": 104, + "height": 18.75, + "strokeColor": "#1e3a8a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1135, + "version": 1, + "versionNonce": 1136, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "pleural space", + "originalText": "pleural space", + "fontSize": 15, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "r_contains1", + "x": 260, + "y": 599.0, + "width": 73.5, + "height": 0.0, + "strokeColor": "#78716c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1137, + "version": 1, + "versionNonce": 1138, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 73.5, + 0.0 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "r_contains1_h", + "x": 339, + "y": 599.0, + "width": 0, + "height": 0, + "strokeColor": "#78716c", + "backgroundColor": "#78716c", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1139, + "version": 1, + "versionNonce": 1140, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + -10.0, + 6.2000000000000455 + ], + [ + -10.0, + -6.2000000000000455 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "l_contains1", + "x": 270.8, + "y": 587.875, + "width": 60.4, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1141, + "version": 1, + "versionNonce": 1142, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_contains1_t", + "x": 276.8, + "y": 590.875, + "width": 48.4, + "height": 16.25, + "strokeColor": "#78716c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1143, + "version": 1, + "versionNonce": 1144, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "contains", + "originalText": "contains", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "r_contains2", + "x": 452, + "y": 599.0, + "width": 93.5, + "height": 0.0, + "strokeColor": "#78716c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1145, + "version": 1, + "versionNonce": 1146, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + 93.5, + 0.0 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "r_contains2_h", + "x": 551, + "y": 599.0, + "width": 0, + "height": 0, + "strokeColor": "#78716c", + "backgroundColor": "#78716c", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1147, + "version": 1, + "versionNonce": 1148, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0.0 + ], + [ + -10.0, + 6.2000000000000455 + ], + [ + -10.0, + -6.2000000000000455 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "l_contains2", + "x": 472.8, + "y": 587.875, + "width": 60.4, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1149, + "version": 1, + "versionNonce": 1150, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_contains2_t", + "x": 478.8, + "y": 590.875, + "width": 48.4, + "height": 16.25, + "strokeColor": "#78716c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1151, + "version": 1, + "versionNonce": 1152, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "contains", + "originalText": "contains", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "r_contains3", + "x": 215, + "y": 630, + "width": 605.0, + "height": 8.5, + "strokeColor": "#78716c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1153, + "version": 1, + "versionNonce": 1154, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 26 + ], + [ + 605, + 26 + ], + [ + 605.0, + 8.5 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "r_contains3_h", + "x": 820, + "y": 633, + "width": 0, + "height": 0, + "strokeColor": "#78716c", + "backgroundColor": "#78716c", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1155, + "version": 1, + "versionNonce": 1156, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 6.2000000000000455, + 10.0 + ], + [ + -6.2000000000000455, + 10.0 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "l_contains3", + "x": 469.8, + "y": 644.875, + "width": 60.4, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1157, + "version": 1, + "versionNonce": 1158, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_contains3_t", + "x": 475.8, + "y": 647.875, + "width": 48.4, + "height": 16.25, + "strokeColor": "#78716c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1159, + "version": 1, + "versionNonce": 1160, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "contains", + "originalText": "contains", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "r_covers", + "x": 200, + "y": 504, + "width": 0.0, + "height": 55.5, + "strokeColor": "#78716c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1161, + "version": 1, + "versionNonce": 1162, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.0, + 55.5 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "r_covers_h", + "x": 200, + "y": 565, + "width": 0, + "height": 0, + "strokeColor": "#78716c", + "backgroundColor": "#78716c", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1163, + "version": 1, + "versionNonce": 1164, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -6.199999999999989, + -10.0 + ], + [ + 6.199999999999989, + -10.0 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "l_covers", + "x": 174.85, + "y": 524.875, + "width": 50.3, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1165, + "version": 1, + "versionNonce": 1166, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_covers_t", + "x": 180.85, + "y": 527.875, + "width": 38.3, + "height": 16.25, + "strokeColor": "#78716c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1167, + "version": 1, + "versionNonce": 1168, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "covers", + "originalText": "covers", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "r_occurs1", + "x": 560, + "y": 384, + "width": -120.0, + "height": 175.5, + "strokeColor": "#78716c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1169, + "version": 1, + "versionNonce": 1170, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 166 + ], + [ + -120, + 166 + ], + [ + -120.0, + 175.5 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "r_occurs1_h", + "x": 440, + "y": 565, + "width": 0, + "height": 0, + "strokeColor": "#78716c", + "backgroundColor": "#78716c", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1171, + "version": 1, + "versionNonce": 1172, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -6.199999999999989, + -10.0 + ], + [ + 6.199999999999989, + -10.0 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "l_occurs1", + "x": 519.65, + "y": 404.875, + "width": 64.7, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1173, + "version": 1, + "versionNonce": 1174, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_occurs1_t", + "x": 525.65, + "y": 407.875, + "width": 52.7, + "height": 16.25, + "strokeColor": "#78716c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1175, + "version": 1, + "versionNonce": 1176, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "occurs at", + "originalText": "occurs at", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "r_occurs2", + "x": 790, + "y": 384, + "width": 0.0, + "height": 175.5, + "strokeColor": "#78716c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1177, + "version": 1, + "versionNonce": 1178, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.0, + 175.5 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "r_occurs2_h", + "x": 790, + "y": 565, + "width": 0, + "height": 0, + "strokeColor": "#78716c", + "backgroundColor": "#78716c", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1179, + "version": 1, + "versionNonce": 1180, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -6.2000000000000455, + -10.0 + ], + [ + 6.2000000000000455, + -10.0 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "l_occurs2", + "x": 757.65, + "y": 404.875, + "width": 64.7, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#fef3c7", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1181, + "version": 1, + "versionNonce": 1182, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "l_occurs2_t", + "x": 763.65, + "y": 407.875, + "width": 52.7, + "height": 16.25, + "strokeColor": "#78716c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1183, + "version": 1, + "versionNonce": 1184, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "occurs at", + "originalText": "occurs at", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "ellipse", + "id": "g1", + "x": 85, + "y": 401, + "width": 22, + "height": 22, + "strokeColor": "#a8a29e", + "backgroundColor": "#e7e5e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 70, + "angle": 0, + "seed": 1185, + "version": 1, + "versionNonce": 1186, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "ellipse", + "id": "g2", + "x": 53, + "y": 439, + "width": 18, + "height": 18, + "strokeColor": "#a8a29e", + "backgroundColor": "#e7e5e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 70, + "angle": 0, + "seed": 1187, + "version": 1, + "versionNonce": 1188, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "ellipse", + "id": "g3", + "x": 82, + "y": 476, + "width": 20, + "height": 20, + "strokeColor": "#a8a29e", + "backgroundColor": "#e7e5e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 70, + "angle": 0, + "seed": 1189, + "version": 1, + "versionNonce": 1190, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "ellipse", + "id": "g4", + "x": 52, + "y": 520, + "width": 16, + "height": 16, + "strokeColor": "#a8a29e", + "backgroundColor": "#e7e5e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 70, + "angle": 0, + "seed": 1191, + "version": 1, + "versionNonce": 1192, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "ellipse", + "id": "g5", + "x": 664, + "y": 440, + "width": 24, + "height": 24, + "strokeColor": "#a8a29e", + "backgroundColor": "#e7e5e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 70, + "angle": 0, + "seed": 1193, + "version": 1, + "versionNonce": 1194, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "ellipse", + "id": "g6", + "x": 703, + "y": 483, + "width": 18, + "height": 18, + "strokeColor": "#a8a29e", + "backgroundColor": "#e7e5e4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 70, + "angle": 0, + "seed": 1195, + "version": 1, + "versionNonce": 1196, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false + }, + { + "type": "line", + "id": "f35", + "x": 96, + "y": 412, + "width": -34, + "height": 36, + "strokeColor": "#a8a29e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 60, + "angle": 0, + "seed": 1197, + "version": 1, + "versionNonce": 1198, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -34, + 36 + ] + ] + }, + { + "type": "line", + "id": "f36", + "x": 96, + "y": 412, + "width": -4, + "height": 74, + "strokeColor": "#a8a29e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 60, + "angle": 0, + "seed": 1199, + "version": 1, + "versionNonce": 1200, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -4, + 74 + ] + ] + }, + { + "type": "line", + "id": "f37", + "x": 92, + "y": 486, + "width": -32, + "height": 42, + "strokeColor": "#a8a29e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 60, + "angle": 0, + "seed": 1201, + "version": 1, + "versionNonce": 1202, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -32, + 42 + ] + ] + }, + { + "type": "line", + "id": "f38", + "x": 104, + "y": 404, + "width": 20, + "height": -16, + "strokeColor": "#a8a29e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 60, + "angle": 0, + "seed": 1203, + "version": 1, + "versionNonce": 1204, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 20, + -16 + ] + ] + }, + { + "type": "line", + "id": "f39", + "x": 66, + "y": 535, + "width": 64, + "height": 55, + "strokeColor": "#a8a29e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 60, + "angle": 0, + "seed": 1205, + "version": 1, + "versionNonce": 1206, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 64, + 55 + ] + ] + }, + { + "type": "line", + "id": "f40", + "x": 676, + "y": 452, + "width": 36, + "height": 40, + "strokeColor": "#a8a29e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 60, + "angle": 0, + "seed": 1207, + "version": 1, + "versionNonce": 1208, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 36, + 40 + ] + ] + }, + { + "type": "line", + "id": "f41", + "x": 676, + "y": 440, + "width": 0, + "height": -56, + "strokeColor": "#a8a29e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 60, + "angle": 0, + "seed": 1209, + "version": 1, + "versionNonce": 1210, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + -56 + ] + ] + }, + { + "type": "arrow", + "id": "x_exam", + "x": 300, + "y": 158, + "width": 0.0, + "height": 153.85000000000002, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 3, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1211, + "version": 1, + "versionNonce": 1212, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.0, + 153.85000000000002 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "x_exam_h", + "x": 300, + "y": 319, + "width": 0, + "height": 0, + "strokeColor": "#be123c", + "backgroundColor": "#be123c", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1213, + "version": 1, + "versionNonce": 1214, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -8.060000000000002, + -13.0 + ], + [ + 8.060000000000002, + -13.0 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "x_exam_l", + "x": 283.9, + "y": 200.875, + "width": 32.2, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1215, + "version": 1, + "versionNonce": 1216, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "x_exam_l_t", + "x": 289.9, + "y": 203.875, + "width": 20.2, + "height": 16.25, + "strokeColor": "#881337", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1217, + "version": 1, + "versionNonce": 1218, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "is a", + "originalText": "is a", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "x_nodule_isa", + "x": 490, + "y": 158, + "width": 0.0, + "height": 153.85000000000002, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 3, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1219, + "version": 1, + "versionNonce": 1220, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.0, + 153.85000000000002 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "x_nodule_isa_h", + "x": 490, + "y": 319, + "width": 0, + "height": 0, + "strokeColor": "#be123c", + "backgroundColor": "#be123c", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1221, + "version": 1, + "versionNonce": 1222, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -8.060000000000002, + -13.0 + ], + [ + 8.060000000000002, + -13.0 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "x_nodule_isa_l", + "x": 473.9, + "y": 200.875, + "width": 32.2, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1223, + "version": 1, + "versionNonce": 1224, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "x_nodule_isa_l_t", + "x": 479.9, + "y": 203.875, + "width": 20.2, + "height": 16.25, + "strokeColor": "#881337", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1225, + "version": 1, + "versionNonce": 1226, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "is a", + "originalText": "is a", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "x_nodule_loc", + "x": 602, + "y": 158, + "width": 0.0, + "height": 399.85, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 3, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1227, + "version": 1, + "versionNonce": 1228, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.0, + 399.85 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "x_nodule_loc_h", + "x": 602, + "y": 565, + "width": 0, + "height": 0, + "strokeColor": "#be123c", + "backgroundColor": "#be123c", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1229, + "version": 1, + "versionNonce": 1230, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -8.059999999999945, + -13.0 + ], + [ + 8.059999999999945, + -13.0 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "x_nodule_loc_l", + "x": 567.8, + "y": 200.875, + "width": 68.4, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1231, + "version": 1, + "versionNonce": 1232, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "x_nodule_loc_l_t", + "x": 573.8, + "y": 203.875, + "width": 56.4, + "height": 16.25, + "strokeColor": "#881337", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1233, + "version": 1, + "versionNonce": 1234, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "located at", + "originalText": "located at", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "x_effusion_isa", + "x": 720, + "y": 158, + "width": 0.0, + "height": 153.85000000000002, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 3, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1235, + "version": 1, + "versionNonce": 1236, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.0, + 153.85000000000002 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "x_effusion_isa_h", + "x": 720, + "y": 319, + "width": 0, + "height": 0, + "strokeColor": "#be123c", + "backgroundColor": "#be123c", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1237, + "version": 1, + "versionNonce": 1238, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -8.059999999999945, + -13.0 + ], + [ + 8.059999999999945, + -13.0 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "x_effusion_isa_l", + "x": 703.9, + "y": 200.875, + "width": 32.2, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1239, + "version": 1, + "versionNonce": 1240, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "x_effusion_isa_l_t", + "x": 709.9, + "y": 203.875, + "width": 20.2, + "height": 16.25, + "strokeColor": "#881337", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1241, + "version": 1, + "versionNonce": 1242, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "is a", + "originalText": "is a", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "x_effusion_loc", + "x": 866, + "y": 158, + "width": -9.824377326810236, + "height": 399.85215720117867, + "strokeColor": "#be123c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 3, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1243, + "version": 1, + "versionNonce": 1244, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -9.824377326810236, + 399.85215720117867 + ] + ], + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "type": "line", + "id": "x_effusion_loc_h", + "x": 856, + "y": 565, + "width": 0, + "height": 0, + "strokeColor": "#be123c", + "backgroundColor": "#be123c", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1245, + "version": 1, + "versionNonce": 1246, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -7.738254294690023, + -13.194052465816299 + ], + [ + 8.376882197198029, + -12.798103166261285 + ], + [ + 0, + 0 + ] + ], + "roundness": null + }, + { + "type": "rectangle", + "id": "x_effusion_loc_l", + "x": 829.8, + "y": 200.875, + "width": 68.4, + "height": 22.25, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 0, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1247, + "version": 1, + "versionNonce": 1248, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "x_effusion_loc_l_t", + "x": 835.8, + "y": 203.875, + "width": 56.4, + "height": 16.25, + "strokeColor": "#881337", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1249, + "version": 1, + "versionNonce": 1250, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "located at", + "originalText": "located at", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "leg42", + "x": 192.45, + "y": 713.6, + "width": 18, + "height": 13, + "strokeColor": "#059669", + "backgroundColor": "#d1fae5", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1251, + "version": 1, + "versionNonce": 1252, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "legt43", + "x": 218.45, + "y": 712, + "width": 152.5, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1253, + "version": 1, + "versionNonce": 1254, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "finding/diagnosis definition", + "originalText": "finding/diagnosis definition", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "leg44", + "x": 398.95, + "y": 713.6, + "width": 18, + "height": 13, + "strokeColor": "#1d4ed8", + "backgroundColor": "#bfdbfe", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1255, + "version": 1, + "versionNonce": 1256, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "legt45", + "x": 424.95, + "y": 712, + "width": 101.2, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1257, + "version": 1, + "versionNonce": 1258, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "anatomic location", + "originalText": "anatomic location", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "leg46", + "x": 554.15, + "y": 713.6, + "width": 18, + "height": 13, + "strokeColor": "#b45309", + "backgroundColor": "#fde68a", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1259, + "version": 1, + "versionNonce": 1260, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "legt47", + "x": 580.15, + "y": 712, + "width": 60.0, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1261, + "version": 1, + "versionNonce": 1262, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "exam type", + "originalText": "exam type", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "leg48", + "x": 668.15, + "y": 713.6, + "width": 18, + "height": 13, + "strokeColor": "#6b7280", + "backgroundColor": "#e5e7eb", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1263, + "version": 1, + "versionNonce": 1264, + "isDeleted": false, + "groupIds": [], + "boundElements": [], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "legt49", + "x": 694.15, + "y": 712, + "width": 48.4, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1265, + "version": 1, + "versionNonce": 1266, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "modality", + "originalText": "modality", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "caption", + "x": 0, + "y": 744, + "width": 935, + "height": 17.5, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1267, + "version": 1, + "versionNonce": 1268, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "every fact about this patient is attached to the shared knowledge of what such a thing is", + "originalText": "every fact about this patient is attached to the shared knowledge of what such a thing is", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + } + ], + "appState": { + "viewBackgroundColor": "#ffffff", + "gridSize": null + }, + "files": { + "img_hicon1": { + "mimeType": "image/svg+xml", + "id": "img_hicon1", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyLjgzIDIuMThhMiAyIDAgMCAwLTEuNjYgMEwyLjYgNi4wOGExIDEgMCAwIDAgMCAxLjgzbDguNTggMy45MWEyIDIgMCAwIDAgMS42NiAwbDguNTgtMy45YTEgMSAwIDAgMCAwLTEuODN6IiAvPgogIDxwYXRoIGQ9Ik0yIDEyYTEgMSAwIDAgMCAuNTguOTFsOC42IDMuOTFhMiAyIDAgMCAwIDEuNjUgMGw4LjU4LTMuOUExIDEgMCAwIDAgMjIgMTIiIC8+CiAgPHBhdGggZD0iTTIgMTdhMSAxIDAgMCAwIC41OC45MWw4LjYgMy45MWEyIDIgMCAwIDAgMS42NSAwbDguNTgtMy45QTEgMSAwIDAgMCAyMiAxNyIgLz4KPC9zdmc+Cg==", + "created": 1700000000000 + }, + "img_hicon4": { + "mimeType": "image/svg+xml", + "id": "img_hicon4", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiNiNDUzMDkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyIDV2MTYiIC8+CiAgPHBhdGggZD0iTTIwLjAwMSAxOUEyIDIgMCAwMDIyIDE3VjVhMiAyIDAgMDAtMS45OTktMkwxNiAzLjAwMkE1IDUgMCAwMDEyIDVhNSA1IDAgMDAtNC0ySDRhMiAyIDAgMDAtMiAydjEyYTIgMiAwIDAwMS45OTkgMkg4YTUgNSAwIDAxNCAyIDUgNSAwIDAxNC0yeiIgLz4KPC9zdmc+Cg==", + "created": 1700000000000 + }, + "img_ni7": { + "mimeType": "image/svg+xml", + "id": "img_ni7", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHJlY3Qgd2lkdGg9IjgiIGhlaWdodD0iNCIgeD0iOCIgeT0iMiIgcng9IjEiIHJ5PSIxIiAvPgogIDxwYXRoIGQ9Ik0xNiA0aDJhMiAyIDAgMCAxIDIgMnYxNGEyIDIgMCAwIDEtMiAySDZhMiAyIDAgMCAxLTItMlY2YTIgMiAwIDAgMSAyLTJoMiIgLz4KICA8cGF0aCBkPSJNMTIgMTFoNCIgLz4KICA8cGF0aCBkPSJNMTIgMTZoNCIgLz4KICA8cGF0aCBkPSJNOCAxMWguMDEiIC8+CiAgPHBhdGggZD0iTTggMTZoLjAxIiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_ni10": { + "mimeType": "image/svg+xml", + "id": "img_ni10", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHJlY3Qgd2lkdGg9IjgiIGhlaWdodD0iNCIgeD0iOCIgeT0iMiIgcng9IjEiIHJ5PSIxIiAvPgogIDxwYXRoIGQ9Ik0xNiA0aDJhMiAyIDAgMCAxIDIgMnYxNGEyIDIgMCAwIDEtMiAySDZhMiAyIDAgMCAxLTItMlY2YTIgMiAwIDAgMSAyLTJoMiIgLz4KPC9zdmc+Cg==", + "created": 1700000000000 + }, + "img_ni13": { + "mimeType": "image/svg+xml", + "id": "img_ni13", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwZjc2NmUiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHJlY3Qgd2lkdGg9IjgiIGhlaWdodD0iNCIgeD0iOCIgeT0iMiIgcng9IjEiIHJ5PSIxIiAvPgogIDxwYXRoIGQ9Ik0xNiA0aDJhMiAyIDAgMCAxIDIgMnYxNGEyIDIgMCAwIDEtMiAySDZhMiAyIDAgMCAxLTItMlY2YTIgMiAwIDAgMSAyLTJoMiIgLz4KPC9zdmc+Cg==", + "created": 1700000000000 + }, + "img_ni16": { + "mimeType": "image/svg+xml", + "id": "img_ni16", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yOSA5QzI5IDExLjc2MTQgMjYuNzYxNCAxNCAyNCAxNEMyMS4yMzg2IDE0IDE5IDExLjc2MTQgMTkgOUMxOSA2LjIzODU4IDIxLjIzODYgNCAyNCA0QzI2Ljc2MTQgNCAyOSA2LjIzODU4IDI5IDlaTTI3IDlDMjcgMTAuNjU2OSAyNS42NTY5IDEyIDI0IDEyQzIyLjM0MzEgMTIgMjEgMTAuNjU2OSAyMSA5QzIxIDcuMzQzMTUgMjIuMzQzMSA2IDI0IDZDMjUuNjU2OSA2IDI3IDcuMzQzMTUgMjcgOVoiIGZpbGw9IiNiNDUzMDkiLz4KPHBhdGggZD0iTTE2Ljk5OTggNDFWMzRIMTguOTk5OFY0MUMxOC45OTk4IDQxLjU1MjMgMTkuNDQ3NSA0MiAxOS45OTk4IDQySDIwLjA4NjVDMjAuNjAzNyA0MiAyMS4wMzU2IDQxLjYwNTYgMjEuMDgyNCA0MS4wOTA1TDIxLjcyNyAzNEgyMy43MzUzTDIzLjA3NDIgNDEuMjcxNkMyMy4wNjkgNDEuMzI4OCAyMy4wNjIyIDQxLjM4NTYgMjMuMDUzOSA0MS40NDE3QzIzLjAzNTcgNDEuNTY0NyAyMy4wMTAxIDQxLjY4NTEgMjIuOTc3NiA0MS44MDI1QzIyLjYyNDIgNDMuMDc5OCAyMS40NTQ5IDQ0IDIwLjA4NjUgNDRIMTkuOTk5OEMxOC4zNDI5IDQ0IDE2Ljk5OTggNDIuNjU2OSAxNi45OTk4IDQxWiIgZmlsbD0iI2I0NTMwOSIvPgo8cGF0aCBkPSJNMjYuOTE3MSA0MS4wOTA1TDI2LjI3MjUgMzRIMjQuMjY0MkwyNC45MjUzIDQxLjI3MTZDMjQuOTMwNSA0MS4zMjg4IDI0LjkzNzMgNDEuMzg1NiAyNC45NDU2IDQxLjQ0MTdDMjQuOTYzOCA0MS41NjQ3IDI0Ljk4OTQgNDEuNjg1MSAyNS4wMjE5IDQxLjgwMjVDMjUuMzc1MyA0My4wNzk4IDI2LjU0NDYgNDQgMjcuOTEzIDQ0SDI3Ljk5OThDMjkuNjU2NiA0NCAzMC45OTk4IDQyLjY1NjkgMzAuOTk5OCA0MVYzNEgyOC45OTk4VjQxQzI4Ljk5OTggNDEuNTUyMyAyOC41NTIgNDIgMjcuOTk5OCA0MkgyNy45MTNDMjcuMzk1OCA0MiAyNi45NjM5IDQxLjYwNTYgMjYuOTE3MSA0MS4wOTA1WiIgZmlsbD0iI2I0NTMwOSIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTExIDE1QzEwLjQ0NzcgMTUgMTAgMTUuNDQ3NyAxMCAxNlYzMUMxMCAzMS41NTIzIDEwLjQ0NzcgMzIgMTEgMzJIMzdDMzcuNTUyMyAzMiAzOCAzMS41NTIzIDM4IDMxVjE2QzM4IDE1LjQ0NzcgMzcuNTUyMyAxNSAzNyAxNUgxMVpNMTIgMTdWMzBIMTkuNUMxOS41IDI5LjQ0MjQgMTkuNzU5MSAyOC45NTcyIDIwLjAyNzYgMjguNjAwNkMyMC4zMDg2IDI4LjIyNzYgMjAuNjc5NiAyNy44ODgzIDIxLjA3OTQgMjcuNjAxNkMyMS42MjUyIDI3LjIxMDMgMjIuMjk4NiAyNi44NjUgMjMgMjYuNjY3OFYyNC41SDIyLjJDMjEuNTk3MyAyNC41IDIwLjc1MzUgMjQuODY0MiAxOS45NDMzIDI1LjM1NTJDMTkuNTYzOCAyNS41ODUyIDE5LjIzMzcgMjUuODE2NyAxOC45OTg0IDI1Ljk5MTFDMTguODgxMiAyNi4wNzc4IDE4Ljc4ODggMjYuMTQ5NSAxOC43MjcgMjYuMTk4NEMxOC42OTYxIDI2LjIyMjggMTguNjczIDI2LjI0MTUgMTguNjU4MiAyNi4yNTM1TDE4LjY0MjYgMjYuMjY2M0wxOC42Mzk5IDI2LjI2ODRDMTguNjM5OSAyNi4yNjg0IDE4LjY0MDIgMjYuMjY4MiAxOCAyNS41QzE3LjM1OTggMjQuNzMxOCAxNy4zNjAxIDI0LjczMTUgMTcuMzYwMSAyNC43MzE1TDE3LjM2MTQgMjQuNzMwNUwxNy4zNjM4IDI0LjcyODVMMTcuMzcxMyAyNC43MjIzTDE3LjM5NjYgMjQuNzAxNkMxNy40MTc5IDI0LjY4NDMgMTcuNDQ4IDI0LjY2IDE3LjQ4NjMgMjQuNjI5N0MxNy41NjI3IDI0LjU2OTMgMTcuNjcxOSAyNC40ODQ3IDE3LjgwNzkgMjQuMzgzOUMxOC4wNzg4IDI0LjE4MzMgMTguNDYxMiAyMy45MTQ4IDE4LjkwNjcgMjMuNjQ0OEMxOS43NDY1IDIzLjEzNTggMjEuMDAyNyAyMi41IDIyLjIgMjIuNUgyM1YyMC41SDIyLjVDMjEuOTMwOSAyMC41IDIxLjE5MDkgMjAuNjk5MiAyMC41MjkyIDIwLjkzOThDMjAuMjEyIDIxLjA1NTIgMTkuOTM3IDIxLjE3MDkgMTkuNzQyMSAyMS4yNTc2QzE5LjY0NDkgMjEuMzAwNyAxOS41Njg1IDIxLjMzNjMgMTkuNTE3NiAyMS4zNjA1QzE5LjQ5MjIgMjEuMzcyNSAxOS40NzMyIDIxLjM4MTcgMTkuNDYxMyAyMS4zODc1TDE5LjQ0ODcgMjEuMzkzN0wxOS40NDcgMjEuMzk0NUMxOS40NDcgMjEuMzk0NSAxOS40NDcyIDIxLjM5NDQgMTkgMjAuNUMxOC41NTI4IDE5LjYwNTYgMTguNTUzMSAxOS42MDU0IDE4LjU1MzEgMTkuNjA1NEwxOC41NTY0IDE5LjYwMzhMMTguNTYyOSAxOS42MDA2TDE4LjU4NDQgMTkuNTlDMTguNjAyNSAxOS41ODEyIDE4LjYyNzkgMTkuNTY4OSAxOC42NjAxIDE5LjU1MzZDMTguNzI0NSAxOS41MjMxIDE4LjgxNiAxOS40ODA1IDE4LjkyOTggMTkuNDI5OUMxOS4xNTY3IDE5LjMyOTEgMTkuNDc1NSAxOS4xOTQ4IDE5Ljg0NTggMTkuMDYwMkMyMC41NTkxIDE4LjgwMDggMjEuNTY5MSAxOC41IDIyLjUgMTguNUgyM1YxN0gxMlpNMjUgMjQuNUgyNi4xQzI2Ljg0ODkgMjQuNSAyNy42MTg2IDI0Ljg2NjMgMjguMjYzMSAyNS4zMTg2QzI4LjU3MzUgMjUuNTM2NCAyOC44Mjg1IDI1Ljc1NTYgMjkuMDA0OCAyNS45MTk3QzI5LjA5MjUgMjYuMDAxMiAyOS4xNTk0IDI2LjA2NzkgMjkuMjAyNiAyNi4xMTIyQzI5LjIyNDEgMjYuMTM0MyAyOS4yMzk3IDI2LjE1MDcgMjkuMjQ4OCAyNi4xNjA1TDI5LjI1NzQgMjYuMTY5N0MyOS4yNTc0IDI2LjE2OTcgMjkuMjU2NyAyNi4xNjkgMzAgMjUuNUMzMC43NDMzIDI0LjgzMSAzMC43NDI5IDI0LjgzMDYgMzAuNzQyOSAyNC44MzA2TDMwLjc0MTQgMjQuODI5TDMwLjczODkgMjQuODI2MkwzMC43MzE4IDI0LjgxODRMMzAuNzA5NyAyNC43OTQ2QzMwLjY5MTUgMjQuNzc1MSAzMC42NjYzIDI0Ljc0ODUgMzAuNjM0NiAyNC43MTZDMzAuNTcxMSAyNC42NTA5IDMwLjQ4MDkgMjQuNTYxMyAzMC4zNjcgMjQuNDU1M0MzMC4xNDAzIDI0LjI0NDQgMjkuODE0IDIzLjk2MzYgMjkuNDExOSAyMy42ODE0QzI4LjYzMTQgMjMuMTMzNyAyNy40NTExIDIyLjUgMjYuMSAyMi41SDI1VjIwLjVIMjUuNzVDMjYuNDQ0MyAyMC41IDI3LjExOTMgMjAuNzAxMSAyNy42NDMyIDIwLjkyMTZDMjcuOTAwMyAyMS4wMjk5IDI4LjEwOTIgMjEuMTM3OCAyOC4yNTA5IDIxLjIxNjlDMjguMzIxNSAyMS4yNTY0IDI4LjM3NDcgMjEuMjg4MiAyOC40MDggMjEuMzA4N0MyOC40MjQ3IDIxLjMxODkgMjguNDM2MyAyMS4zMjYzIDI4LjQ0MjcgMjEuMzMwNEwyOC40NDU3IDIxLjMzMjNDMjguNDQ1NyAyMS4zMzIzIDI4LjQ0NTMgMjEuMzMyMSAyOSAyMC41QzI5LjU1NDcgMTkuNjY3OSAyOS41NTQyIDE5LjY2NzYgMjkuNTU0MiAxOS42Njc2TDI5LjU1MjcgMTkuNjY2NkwyOS41NTAxIDE5LjY2NDlMMjkuNTQzMiAxOS42NjA0TDI5LjUyMjggMTkuNjQ3MkMyOS41MDYzIDE5LjYzNjYgMjkuNDg0IDE5LjYyMjUgMjkuNDU2MiAxOS42MDU0QzI5LjQwMDcgMTkuNTcxMiAyOS4zMjMgMTkuNTI0OSAyOS4yMjU2IDE5LjQ3MDZDMjkuMDMxNSAxOS4zNjIyIDI4Ljc1NTkgMTkuMjIwMSAyOC40MTkzIDE5LjA3ODRDMjcuNzU1NyAxOC43OTg5IDI2LjgwNTcgMTguNSAyNS43NSAxOC41SDI1VjE3SDM2VjMwSDI4LjVDMjguNSAyOS40Mzc5IDI4LjIzMjQgMjguOTQ1MiAyNy45NjQxIDI4LjU4NzVDMjcuNjgwMyAyOC4yMDkyIDI3LjMwNTQgMjcuODYwNiAyNi45MDA3IDI3LjU2NjNDMjYuMzY3NSAyNy4xNzg1IDI1LjY5ODkgMjYuODI1NyAyNSAyNi42MzkxVjI0LjVaTTI2LjQ5MjkgMzBDMjYuNDc5NyAyOS45NjcgMjYuNDQ1NyAyOS44OTY0IDI2LjM2NDEgMjkuNzg3NUMyNi4yMjU5IDI5LjYwMzMgMjYuMDA3MSAyOS4zODk0IDI1LjcyNDMgMjkuMTgzN0MyNS4xNDc4IDI4Ljc2NDUgMjQuNDkzNyAyOC41MTE3IDI0LjAzMiAyOC41MDA0QzIzLjQ4NzcgMjguNTQ2NCAyMi44MDUyIDI4LjgyNTIgMjIuMjQ0OSAyOS4yMjdDMjEuOTY1NyAyOS40MjcyIDIxLjc1NTYgMjkuNjMwNyAyMS42MjUyIDI5LjgwMzhDMjEuNTQ5NiAyOS45MDQzIDIxLjUxODQgMjkuOTY5NCAyMS41MDYzIDMwSDI2LjQ5MjlaIiBmaWxsPSIjYjQ1MzA5Ii8+Cjwvc3ZnPgo=", + "created": 1700000000000 + }, + "img_ni19": { + "mimeType": "image/svg+xml", + "id": "img_ni19", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwNTk2NjkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyLjU4NiAyLjU4NkEyIDIgMCAwIDAgMTEuMTcyIDJINGEyIDIgMCAwIDAtMiAydjcuMTcyYTIgMiAwIDAgMCAuNTg2IDEuNDE0bDguNzA0IDguNzA0YTIuNDI2IDIuNDI2IDAgMCAwIDMuNDIgMGw2LjU4LTYuNThhMi40MjYgMi40MjYgMCAwIDAgMC0zLjQyeiIgLz4KICA8Y2lyY2xlIGN4PSI3LjUiIGN5PSI3LjUiIHI9Ii41IiBmaWxsPSIjMDU5NjY5IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_ni22": { + "mimeType": "image/svg+xml", + "id": "img_ni22", + "dataURL": "data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9IiMwNTk2NjkiCiAgc3Ryb2tlLXdpZHRoPSIyIgogIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICBzdHJva2UtbGluZWpvaW49InJvdW5kIgo+CiAgPHBhdGggZD0iTTEyLjU4NiAyLjU4NkEyIDIgMCAwIDAgMTEuMTcyIDJINGEyIDIgMCAwIDAtMiAydjcuMTcyYTIgMiAwIDAgMCAuNTg2IDEuNDE0bDguNzA0IDguNzA0YTIuNDI2IDIuNDI2IDAgMCAwIDMuNDIgMGw2LjU4LTYuNThhMi40MjYgMi40MjYgMCAwIDAgMC0zLjQyeiIgLz4KICA8Y2lyY2xlIGN4PSI3LjUiIGN5PSI3LjUiIHI9Ii41IiBmaWxsPSIjMDU5NjY5IiAvPgo8L3N2Zz4K", + "created": 1700000000000 + }, + "img_ni31": { + "mimeType": "image/svg+xml", + "id": "img_ni31", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yMyA2LjAwMDEzQzIzIDYuMDAwMDQgMjMgNiAyNCA2SDI0LjE3NjFDMjQuMjUzMyA2IDI0LjMyMzMgNiAyNC4zODY4IDZDMjUgNi4wMDAwMSAyNSA2LjAwMDA1IDI1IDYuMDAwMTNWMjAuNUMyNSAyMS44OTc3IDI1LjU2NDEgMjIuNDQyMSAyNi4wMDM5IDIyLjY5ODdDMjYuMDUzIDIyLjcyNzMgMjYuMTAyNCAyMi43NTMzIDI2LjE1MTYgMjIuNzc3QzI2LjE1MDYgMjIuNjU2OCAyNi4xNDkzIDIyLjUzMTYgMjYuMTQ3OSAyMi40MDE5TDI2LjE0NzkgMjIuNDAwM0MyNi4xMTAxIDE4Ljg3MTYgMjYuMDM2NSAxMS45OTk3IDMxLjQ3NTMgMTEuOTk5N0MzOC45MjU5IDExLjk5OTcgNDQuMjQ3OCAzOC4wMDYyIDQxLjA1NDcgNDAuNjU5OUMzNy44NjE1IDQzLjMxMzYgMzEuNDc1MyA0MS43MjE0IDI4LjI4MjIgMzguNTM2OUMyNS43MDQyIDM1Ljk2NTkgMjUuOTI3MiAyOS45NTgzIDI2LjA4NzMgMjUuNjQ1N0wyNi4wODc0IDI1LjY0NDNDMjYuMDk3MSAyNS4zODE5IDI2LjEwNjcgMjUuMTI1OCAyNi4xMTUzIDI0Ljg3NzFDMjUuNzkgMjQuNzk2MiAyNS4zOTU5IDI0LjY1OTUgMjQuOTk2MiAyNC40MjYzQzI0LjYzOTggMjQuMjE4NCAyNC4yOTc1IDIzLjk0NDIgMjQgMjMuNTkxOUMyMy43MDI2IDIzLjk0NDIgMjMuMzYwMyAyNC4yMTg0IDIzLjAwMzkgMjQuNDI2M0MyMi42MDQxIDI0LjY1OTUgMjIuMjEwMSAyNC43OTYyIDIxLjg4NDggMjQuODc3MUMyMS44OTM0IDI1LjEyNjEgMjEuOTAyOSAyNS4zODI2IDIxLjkxMjcgMjUuNjQ1M0MyMi4wNzI4IDI5Ljk1NzkgMjIuMjk1OSAzNS45NjYyIDE5LjcxNzkgMzguNTM3MkMxNi41MjQ3IDQxLjcyMTcgMTAuMTM4NSA0My4zMTM5IDYuOTQ1MzYgNDAuNjYwMkMzLjc1MjIyIDM4LjAwNjUgOS4wNzQxMyAxMiAxNi41MjQ3IDEyQzIxLjk2MzYgMTIgMjEuODkgMTguODcxNyAyMS44NTIyIDIyLjQwMDNDMjEuODUyIDIyLjQxNjYgMjEuODUxOCAyMi40MzI4IDIxLjg1MTYgMjIuNDQ4OUMyMS44NTA0IDIyLjU2MTkgMjEuODQ5MyAyMi42NzE0IDIxLjg0ODQgMjIuNzc3QzIxLjg5NzcgMjIuNzUzNCAyMS45NDcxIDIyLjcyNzQgMjEuOTk2MiAyMi42OTg3QzIyLjQzNiAyMi40NDIxIDIzIDIxLjg5NzcgMjMgMjAuNVY2LjAwMDEzWk0zMS40NzUzIDEzLjk5OTdDMzAuNTIxMiAxMy45OTk3IDI5Ljk4NDMgMTQuMzAwMiAyOS42MDg2IDE0LjY4NjlDMjkuMTc1MiAxNS4xMzMxIDI4LjgxMzIgMTUuODUwNyAyOC41NTkgMTYuODY0NkMyOC4xMTQxIDE4LjYzOTUgMjguMTMzIDIwLjY4MTkgMjguMTQ4MyAyMi4zMjkzQzI4LjE1MDkgMjIuNjE0MiAyOC4xNTM0IDIyLjg4NzQgMjguMTUzNCAyMy4xNDUzQzI4LjE1MzQgMjMuOTA1MyAyOC4xMTk2IDI0LjgxNTMgMjguMDg0NSAyNS43NjIxQzI4LjA3MDcgMjYuMTM0OSAyOC4wNTY2IDI2LjUxMzMgMjguMDQ0MyAyNi44OTA1QzI3Ljk5OTYgMjguMjY1NyAyNy45NzQxIDI5LjcwNTUgMjguMDQwNSAzMS4wOTgyQzI4LjEwNzIgMzIuNDk4NSAyOC4yNjQyIDMzLjc4MzUgMjguNTU3MyAzNC44NTk2QzI4Ljg1MzggMzUuOTQ4MyAyOS4yNTA5IDM2LjY3ODQgMjkuNjk0NCAzNy4xMjA4QzMwLjk3MjYgMzguMzk1NCAzMi45OTA4IDM5LjQyNTEgMzUuMDQ5MiAzOS44MjQzQzM3LjA4NDIgNDAuMjE4OSAzOC43MjI0IDM5LjkyNjkgMzkuNjgxOCAzOS4xOTY5QzM5LjY4NjggMzkuMTg1NyAzOS42OTIzIDM5LjE3MjYgMzkuNjk4NCAzOS4xNTc0QzM5Ljc1NzYgMzkuMDA5NSAzOS44Mjk0IDM4Ljc1NTQgMzkuODg3OCAzOC4zNjgzQzQwLjAwNDcgMzcuNTkzMyA0MC4wMzUgMzYuNTEyMiAzOS45NTYyIDM1LjE4MDNDMzkuNzk5NSAzMi41MzA1IDM5LjIyODYgMjkuMTY4OSAzOC4zMjY4IDI1Ljg2MDZDMzcuNDIxNiAyMi41Mzk2IDM2LjIxNzMgMTkuMzk5OCAzNC44NTIxIDE3LjEzODNDMzQuMTY4OCAxNi4wMDYyIDMzLjQ5NTEgMTUuMTc4NiAzMi44NzAzIDE0LjY1MzVDMzIuMjUxOCAxNC4xMzM3IDMxLjc5MzUgMTMuOTk5NyAzMS40NzUzIDEzLjk5OTdaTTE2LjUyNDcgMTRDMTcuNDc4OCAxNCAxOC4wMTU4IDE0LjMwMDUgMTguMzkxNCAxNC42ODcyQzE4LjgyNDggMTUuMTMzNCAxOS4xODY4IDE1Ljg1MSAxOS40NDEgMTYuODY0OUMxOS44ODU5IDE4LjYzOTkgMTkuODY3IDIwLjY4MjIgMTkuODUxOCAyMi4zMjk2QzE5Ljg0OTEgMjIuNjE0NiAxOS44NDY2IDIyLjg4NzcgMTkuODQ2NiAyMy4xNDU2QzE5Ljg0NjYgMjMuOTA1NiAxOS44ODA0IDI0LjgxNTYgMTkuOTE1NSAyNS43NjI0QzE5LjkyOTQgMjYuMTM1IDE5Ljk0MzQgMjYuNTEzOCAxOS45NTU3IDI2Ljg5MDhDMjAuMDAwNSAyOC4yNjYgMjAuMDI1OSAyOS43MDU4IDE5Ljk1OTYgMzEuMDk4NUMxOS44OTI5IDMyLjQ5ODggMTkuNzM1OSAzMy43ODM4IDE5LjQ0MjcgMzQuODU5OUMxOS4xNDYyIDM1Ljk0ODYgMTguNzQ5MiAzNi42Nzg3IDE4LjMwNTYgMzcuMTIxMUMxNy4wMjc1IDM4LjM5NTcgMTUuMDA5MyAzOS40MjU0IDEyLjk1MDkgMzkuODI0NkMxMC45MTU5IDQwLjIxOTIgOS4yNzc2OCAzOS45MjcyIDguMzE4MjMgMzkuMTk3MkM4LjMxMzI2IDM5LjE4NiA4LjMwNzcgMzkuMTcyOSA4LjMwMTYyIDM5LjE1NzdDOC4yNDI0MSAzOS4wMDk4IDguMTcwNjEgMzguNzU1NyA4LjExMjI0IDM4LjM2ODZDNy45OTUzOSAzNy41OTM2IDcuOTY1IDM2LjUxMjUgOC4wNDM4IDM1LjE4MDZDOC4yMDA1NiAzMi41MzA4IDguNzcxNDcgMjkuMTY5MiA5LjY3MzI0IDI1Ljg2MDlDMTAuNTc4NSAyMi41Mzk5IDExLjc4MjcgMTkuNDAwMSAxMy4xNDc5IDE3LjEzODZDMTMuODMxMyAxNi4wMDY1IDE0LjUwNDkgMTUuMTc4OSAxNS4xMjk4IDE0LjY1MzhDMTUuNzQ4MiAxNC4xMzQgMTYuMjA2NSAxNCAxNi41MjQ3IDE0WiIgZmlsbD0iIzFkNGVkOCIvPgo8L3N2Zz4K", + "created": 1700000000000 + } + } +} \ No newline at end of file diff --git a/knowledge/drafts/two-planes.svg b/knowledge/drafts/two-planes.svg new file mode 100644 index 0000000..1f0e60e --- /dev/null +++ b/knowledge/drafts/two-planes.svg @@ -0,0 +1,2 @@ +Patient Contextthis patient · this examFoundation Contextshared, curated knowledgeCT chest without contrastthis patient · 2026-03-04pulmonary nodulepresent · 8 mm · newpleural effusionabsentfound onfound onCT Chest WO contrastexam type · 29252-4pulmonary nodulefinding/diagnosis definitionpleural effusionfinding/diagnosis definitionCT Chestexam family · preferredCTmodalitymember of familymodalityseen onthoraxanatomic locationlungupper lobe of right lungpleural spacecontainscontainscontainscoversoccurs atoccurs atis ais alocated atis alocated atfinding/diagnosis definitionanatomic locationexam typemodalityevery fact about this patient is attached to the shared knowledge of what such a thing is \ No newline at end of file diff --git a/knowledge/drafts/use-cases.md b/knowledge/drafts/use-cases.md new file mode 100644 index 0000000..c084573 --- /dev/null +++ b/knowledge/drafts/use-cases.md @@ -0,0 +1,104 @@ +--- +type: Concept +title: Use Cases +description: Proposed reporting assistance, longitudinal care, outcome tracking, and information products built on OIDM context and structures. +tags: [use-cases, reporting, imaging-history, outcomes] +status: draft +generated: { by: codex/2026-09-22-restructure-use-cases, at: 2026-09-22T13:53:10Z } +sources: + - id: reporting-framework + resource: https://www.openimagingdata.org/oidm-based-next-gen-reporting-assistance/ + title: OIDM-Based Next-gen Reporting Assistance Framework, 2023-07-16 + - id: reporting-board + resource: "OIDM Big Picture working board, Reporting Assistance Framework and Next-Generation Assisted Reporting Use Cases frames, undated" + title: OIDM Big Picture, reporting assistance framework and use-case mind map, undated working board + - id: ipl-webinar + resource: https://oidm-public.t3.tigrisfiles.io/oidm-knowledge-sources/IPL%20Webinar%20Deck.html + title: The Imaging Problem List as an Accelerator for Radiology AI Applications, SIIM webinar, 2026-07-15, slides 36–43 and speaker notes + - id: outcome-schema + resource: "Outcome Tracking Schema, undated working board, clinical-event, action, and use-case sections" + title: Outcome Tracking Schema, undated working board, data-model and workflow content + - id: pathology-link + resource: "Radiologist Outcome Feedback working board, Path Result and Biopsy Procedure linking proposal, 2025-06-02" + title: Radiologist Outcome Feedback, shared tracking identifier proposal dated 2025-06-02 + - id: reports-future + resource: https://oidm-public.t3.tigrisfiles.io/oidm-knowledge-sources/SIIM%202026%20Reports-of-the-Future.pptx + title: Structured Results and Context for Next-Generation Imaging Resulting Tools, June 2026, slides 13–14 + - id: usecases-index + resource: https://github.com/openimagingdata/UseCases/blob/71a90d2ab2efeee4c4303dc0aef27ed3d70a6c99/Index.md + title: Index of Potential Use Cases, snapshot of 2024-02-26 + - id: value-categories + resource: https://github.com/openimagingdata/UseCases/blob/71a90d2ab2efeee4c4303dc0aef27ed3d70a6c99/README.md + title: OIDM Use Cases, value categories from the RSNA Reporting Informatics Committee, last changed 2023-09-25 + last_modified: 2023-09-25 + - id: status-deck + resource: https://gamma.app/docs/Open-Imaging-Data-Model-2026-Status-Update:-Realizing-Object-Oriented-Imaging-Results-yfxzx4q9zssafal + title: Open Imaging Data Model 2026 Status Update, January 2026, imaging life cycle and ACR priorities + - id: nodule-exchange + resource: "Pulm Nodule Demo Project, undated working board, exchange aim and structured workflow" + title: Pulm Nodule Demo Project, undated working board, structured exchange workflow + - id: ipl-manuscript + resource: "The Imaging Problem List: A Standards-Based Framework for Longitudinal Tracking of Imaging Findings, manuscript under review at JDIM, 2026" + title: Imaging Problem List manuscript under review, clean abstract and Figure 1; reviewer correspondence not used +--- + +# Use Cases + +This page groups documented application ideas by purpose. The July 2026 IPL webinar presents its applications as a roadmap, including breast work explicitly described as planned.[^ipl-webinar] Implemented examples have a separate home in [Sample Applications](/drafts/sample-applications.md). + +## Reporting assistance + +The July 2023 framework proposes plugins that inspect current findings, prior reports, and exam context. A reporting container would rerun them when context changes. Its four commands would insert text, request information, alert the radiologist, or send data externally.[^reporting-framework] The January 2026 deck names vendor-driven innovation through an Open Imaging Reporting SDK.[^status-deck] The reusable interfaces belong under [SDKs](/drafts/sdks.md). + +The undated reporting board proposes a context object including clinical records, longitudinal findings, and AI, DICOM-SR, and text-extracted data. Its nine-command set includes changing context, retrieving clinical data, showing images, activating communication tools, and requesting image inference. Proposed uses include context-specific templates, AI-result review, references, specialized reporting, and checks for laterality errors or unanswered questions.[^reporting-board] Neither source identifies a superseding command set.[^reporting-framework][^reporting-board] These context proposals relate to the Imaging Persona under [Data Structures](/drafts/data-structures.md). + +## Imaging history across the care cycle + +The July 2026 webinar identifies six IPL application families:[^ipl-webinar] + +- Pre-populate reports with known findings for review, distinguishing carried-forward content from new findings. +- Track incidental findings and overdue follow-up. Report content determines completion: an obscured finding still needs follow-up, while a resolved finding closes surveillance. +- Monitor chronic disease across the full history, including growth that looks small between consecutive scans. +- Surface findings across subspecialties, such as an adrenal nodule previously reported on chest CT. +- Check report consistency and recommendation appropriateness for quality surveillance. +- Select research cohorts through structured findings and assessment scores. + +The 2026 IPL manuscript's Figure 1 groups downstream applications differently: report pre-population, follow-up management, clinical problem lists, combined quality and research, and AI with decision support. Its abstract describes the proposed benefits as awaiting evaluation.[^ipl-manuscript] + +The January 2026 deck covers the imaging life cycle: MRI safety, mobility, and pre-authorization during planning; rules-based protocoling during the exam; findings-oriented views and quality checks during interpretation; and passive screening, research, and outcomes afterward.[^status-deck] + +## Outcomes and follow-up + +The outcome-tracking board proposes connecting reports and recommendations to later imaging, pathology, procedures, and other clinical events. Outputs include individual feedback, overdue-follow-up notifications, review worklists, registries, and aggregate statistics. Named uses include diagnostic-yield audits of malignancy-related *-RADS assessments, trainee report-change notifications, continuous AI monitoring, ordering-provider feedback, and interventional-radiology outcomes.[^outcome-schema] + +A June 2025 proposal would link the imaging finding, targeted biopsy, and pathology result through a shared tracking identifier. That link would support radiology-pathology correlation.[^pathology-link] The outcome model also proposes following pathways from incidental detection through investigation, treatment, and later outcomes.[^outcome-schema] + +## Breast imaging + +The webinar's planned breast example tracks one mass across five exams over eighteen months, through changing BI-RADS assessments, biopsy, and a fibroadenoma diagnosis. The marker clip becomes a re-identification anchor. Proposed applications are a display of findings, assessments, and biopsy outcomes during interpretation, and an automated outcomes audit. The display's proposed design path is focus groups with breast radiologists followed by iterative usability testing toward a pilot. The audit would connect screening assessments with cancer diagnoses within one year, with intended coverage across mammography, ultrasound, and MRI. The source relates this to Mammography Quality Standards Act audit work and explicitly presents design, not results.[^ipl-webinar] + +## Rules and generative assistance + +The June 2026 Reports of the Future deck distinguishes determinative tools for safety checks, protocoling, and quality metrics from generative agents using shared, citable context. These proposed uses resolve patient finding codes into [Foundation Context](/drafts/foundation-context.md). Its examples connect pulmonary-nodule characteristics to follow-up guidance, track aneurysm diameter against a repair threshold, and relate a renal calculus to hydronephrosis. The deck presents these as intended uses of shared definitions and relationships.[^reports-future] + +## Communication and information products + +The catalog uses the RSNA Reporting Informatics Committee's six value categories: reporting efficiency; care-team communication; operations, quality, and safety; research; public health; and education.[^value-categories] The index credits the committee for ideas including actionable summaries, critical-finding messages, problem-list updates, research measurements, implant lists, clinical-question capture, and guideline templates with lay-language explanations. Other catalog ideas include registry submissions, teaching files, similar-case retrieval, prior DEXA exclusions, spine-numbering reconciliation, aortic measurement comparisons, and laboratory cross-checks.[^usecases-index] + +## Shared priorities and exchange + +The January 2026 deck names recommendation tracking, comparison of AI and radiologist observations, quality metrics, and *-RADS support as ACR priorities.[^status-deck] + +The pulmonary-nodule exchange design aims to share radiology findings as CDE-labeled FHIR Observations over FHIRcast across AI, image viewing, reporting, and electronic health record systems. Responsibility for associating nodules and assigning tracking identifiers remains open on the board.[^nodule-exchange] See [Sample Applications](/drafts/sample-applications.md) for demonstrated work. + +[^reporting-framework]: Reporting assistance proposal, 2023-07-16. +[^reporting-board]: OIDM Big Picture, reporting framework and use-case frames. +[^ipl-webinar]: SIIM IPL webinar, 2026-07-15, slides 36–43 and speaker notes. +[^outcome-schema]: Outcome Tracking Schema, clinical-event, action, and use-case sections. +[^pathology-link]: Radiologist Outcome Feedback, pathology-to-biopsy linking proposal, 2025-06-02. +[^reports-future]: Reports of the Future, June 2026, slides 13–14. +[^usecases-index]: Index of Potential Use Cases, 2024-02-26 snapshot. +[^value-categories]: OIDM Use Cases README, value categories. +[^status-deck]: January 2026 status update, imaging life cycle and ACR priorities. +[^nodule-exchange]: Pulm Nodule Demo Project, complete workflow and open questions. +[^ipl-manuscript]: Imaging Problem List manuscript under review at JDIM, 2026, clean abstract and Figure 1. diff --git a/knowledge/glossary/anatomic-location.md b/knowledge/glossary/anatomic-location.md index a83765a..a936d9f 100644 --- a/knowledge/glossary/anatomic-location.md +++ b/knowledge/glossary/anatomic-location.md @@ -4,7 +4,7 @@ title: Anatomic location description: A curated anatomic concept identified by a RadLex identifier, placed in containment and part-of hierarchies with laterality variants and cross-ontology codes. tags: [glossary, semantic-foundation, anatomy] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: al-site resource: https://github.com/talkasab/anatomiclocations.org/blob/1f39fa45f621cef947a3f3ef1f869334cfa5c841/docs/index.markdown @@ -22,7 +22,7 @@ sources: # Anatomic location -A discrete anatomic concept, curated for imaging use and identified by a [RadLex identifier](/glossary/radlex-id.md). The rationale is stated plainly on the project site: "standard identifiers for discrete anatomic locations would enable numerous levels of interoperability if applied broadly," but existing ontologies are unsuited to that job because they lack needed terms, carry too many degenerate ones, and have limited anatomic organization. The response is curation: "we are curating a subset of anatomic concepts from existing ontologies and shaping them into a usable collection of anatomic identifiers for informatics interoperability."[^al-site] +A discrete anatomic concept, curated for imaging use and identified by a [RadLex identifier](/glossary/radlex-id.md). The project site states that "standard identifiers for discrete anatomic locations would enable numerous levels of interoperability if applied broadly," but existing ontologies are unsuited to that job because they lack needed terms, carry too many degenerate ones, and have limited anatomic organization. The project describes its approach: "we are curating a subset of anatomic concepts from existing ontologies and shaping them into a usable collection of anatomic identifiers for informatics interoperability."[^al-site] Two implementations exist. The original curated set holds 2,890 nodes with `radlexId`, `description`, `containedById`, `partOfId`, a `leftId`/`rightId`/`unsidedId` triad, `sexSpecific`, `synonyms`, and `codes` into [SNOMED CT](/glossary/snomed-ct.md), [FMA](/glossary/fma.md), [UMLS](/glossary/umls.md), and MeSH.[^al-code] The newer `anatomic-locations` package normalizes the same material into a richer model with `region`, `location_type`, `body_system`, `structure_type`, a `laterality` enum, precomputed containment and part-of paths, and `left_variant`/`right_variant`/`generic_variant` references.[^al-package] @@ -44,7 +44,7 @@ A [RadLex RID](/glossary/radlex-id.md). Sided variants in the original set use c ## Conflicts -The two lineages are not synchronized and differ in count, field names, and laterality representation; see [Lineage and current implementation](/semantic-foundation/anatomic-locations/lineage-and-current-implementation.md). The next-generation CDE vocabulary defines AnatomicLocation as "an anatomical reference identified by its RadLex identity, with temporary sided-variant exceptions governed by the anatomy track," treating sided variants as provisional, whereas the OIDM sets make them first-class nodes.[^cde-context] +The two lineages differ in count, field names, and laterality representation and are not synchronized. See [Lineage and current implementation](/semantic-foundation/anatomic-locations/lineage-and-current-implementation.md). The next-generation CDE vocabulary defines AnatomicLocation as "an anatomical reference identified by its RadLex identity, with temporary sided-variant exceptions governed by the anatomy track," treating sided variants as provisional, whereas the OIDM sets make them first-class nodes.[^cde-context] [^al-site]: anatomiclocations.org site homepage [^al-code]: anatomiclocations.org data file description diff --git a/knowledge/glossary/anatomic-scope.md b/knowledge/glossary/anatomic-scope.md index bc54aef..8c7adf6 100644 --- a/knowledge/glossary/anatomic-scope.md +++ b/knowledge/glossary/anatomic-scope.md @@ -4,7 +4,7 @@ title: Anatomic scope description: The eligible anatomical places, tissue types, or structure types for a definition, stated as a constraint rather than as a location. tags: [glossary, semantic-foundation, anatomy, next-generation] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: cde-context resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/CONTEXT.md @@ -42,7 +42,7 @@ None. Scope is expressed as a list of concepts or scope specifiers. ## Conflicts -There is no scope field in the OIFM format. Scope exists only as authoring guidance and as reviewer judgment, so it cannot be checked mechanically the way a typed scope specifier could. +There is no scope field in the OIFM format. Scope exists only as authoring guidance and as reviewer judgment, without the automated checks a typed scope specifier could support. [^cde-context]: CDE vocabulary, next-generation working glossary [^overview]: "Finding Models: Overview" diff --git a/knowledge/glossary/assessment-scheme.md b/knowledge/glossary/assessment-scheme.md index fbef425..901bcb5 100644 --- a/knowledge/glossary/assessment-scheme.md +++ b/knowledge/glossary/assessment-scheme.md @@ -4,7 +4,7 @@ title: AssessmentScheme description: A definition of a standardized assessment system whose dimensions are ordinary data elements, distinct from the findings it assesses. tags: [glossary, semantic-foundation, cde, next-generation] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: cde-context resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/CONTEXT.md @@ -24,9 +24,9 @@ sources: "A distinct definition of an assessment system whose descriptive dimensions are ordinary DataElements linked to the scheme, analogous to a FindingClass with its descriptors. The scheme is distinct from any one dimension or that dimension's permissible values."[^cde-context] Lung-RADS, TI-RADS, BI-RADS, and LI-RADS are the systems this node type covers. -The key structural claim is separation. The scheme is not the category value it produces, and it is not the finding it assesses. OIDM's authoring guidance reaches the same conclusion from the finding model side: "scoring systems and structured assessments are valid findings, but should be modeled separately from the observations they assess," because "different radiologists might describe the same nodule but assign different risk categories, and systems need to reason about both independently."[^overview] +The scheme is distinct from its category values and the findings it assesses. OIDM's authoring guidance states: "scoring systems and structured assessments are valid findings, but should be modeled separately from the observations they assess," because "different radiologists might describe the same nodule but assign different risk categories, and systems need to reason about both independently."[^overview] -The lineage FHIR samples already implement that shape. A Lung-RADS Observation carries the category as a component and is `derivedFrom` both the imaging study and the radiologist's pulmonary nodule Observation.[^fhir-sample] IHE IDR calls the pattern a Summary or Derived Observation, with the value in the parent and the children referenced by `derivedFrom`.[^idr] +The lineage FHIR samples implement this separation. A Lung-RADS Observation carries the category as a component and is `derivedFrom` both the imaging study and the radiologist's pulmonary nodule Observation.[^fhir-sample] IHE IDR calls the pattern a Summary or Derived Observation, with the value in the parent and the children referenced by `derivedFrom`.[^idr] ## Synonyms and near-synonyms diff --git a/knowledge/glossary/attribute-value.md b/knowledge/glossary/attribute-value.md index c8f6354..e5f4687 100644 --- a/knowledge/glossary/attribute-value.md +++ b/knowledge/glossary/attribute-value.md @@ -4,7 +4,7 @@ title: Attribute value description: One permissible option of a choice attribute, carrying its own dot-suffixed value code and optional ontology codes. tags: [glossary, semantic-foundation, finding-models] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: fm-py resource: https://github.com/openimagingdata/findingmodel/blob/75afd39a400419dcfaf7c8d4a34f065b4d804e0d/packages/findingmodel/src/findingmodel/finding_model.py diff --git a/knowledge/glossary/attribute.md b/knowledge/glossary/attribute.md index 9363681..0269f1e 100644 --- a/knowledge/glossary/attribute.md +++ b/knowledge/glossary/attribute.md @@ -4,7 +4,7 @@ title: Attribute description: A property a radiologist uses to characterize a finding, either a choice attribute with an enumerated value set or a numeric attribute with a range and unit. tags: [glossary, semantic-foundation, finding-models] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: fm-py resource: https://github.com/openimagingdata/findingmodel/blob/75afd39a400419dcfaf7c8d4a34f065b4d804e0d/packages/findingmodel/src/findingmodel/finding_model.py @@ -22,7 +22,7 @@ sources: # Attribute -"An attribute that a radiologist would use to characterize a particular finding in a radiology report."[^fm-py] Every [finding model](/glossary/finding-model.md) carries at least one. There are exactly two kinds. +"An attribute that a radiologist would use to characterize a particular finding in a radiology report."[^fm-py] Every [finding model](/glossary/finding-model.md) has at least one attribute. There are exactly two kinds. | Kind | Discriminator | Distinctive fields | |---|---|---| @@ -48,7 +48,7 @@ Both kinds carry `oifma_id`, `name`, an optional `description`, a `required` fla ## Conflicts -The committee record shows an unresolved naming debate between "element," "attribute," and "data element" for this concept, and the next-generation working glossary settles on DataElement while OIFM keeps "attribute."[^siim][^cde-context] The two words denote nearly the same thing with different scoping rules, so a document must say which vocabulary it is using. +Committee discussions left the choice between "element," "attribute," and "data element" unresolved. The next-generation glossary uses DataElement, while OIFM uses "attribute."[^siim][^cde-context] The two words denote nearly the same thing with different scoping rules, so a document must say which vocabulary it is using. [^fm-py]: ChoiceAttribute and NumericAttribute in the findingmodel package [^fm-schema]: Finding model schema, prose mirror diff --git a/knowledge/glossary/body-region.md b/knowledge/glossary/body-region.md index c21795a..0839894 100644 --- a/knowledge/glossary/body-region.md +++ b/knowledge/glossary/body-region.md @@ -4,7 +4,7 @@ title: Body region description: A coarse anatomic grouping such as thorax or abdomen, used to scope findings, to fall back when no structure is named, and to filter views. tags: [glossary, semantic-foundation, anatomy] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: al-enums resource: https://github.com/openimagingdata/findingmodel/blob/75afd39a400419dcfaf7c8d4a34f065b4d804e0d/packages/anatomic-locations/src/anatomic_locations/models/enums.py @@ -22,7 +22,7 @@ sources: # Body region -A coarse anatomic grouping, one level above an organ and well above a named structure. Regions do three jobs in OIDM: they classify an [anatomic location](/glossary/anatomic-location.md), they carry broad anatomy on a [finding model](/glossary/finding-model.md) where precise anatomy belongs in `anatomic_locations`, and they provide the fallback when a finding names no anatomic structure at all. +A coarse anatomic grouping, one level above an organ and well above a named structure. Regions classify [anatomic locations](/glossary/anatomic-location.md), describe broad anatomy on [finding models](/glossary/finding-model.md), and provide a fallback when a finding names no structure. Precise anatomy belongs in a finding model's `anatomic_locations`. The fallback rule is explicit. Only findings with no anatomic noun, such as "soft tissue mass" or "generalized osteoporosis," fall back to the exam-scoped coarse region, and the grain is "the coarse region, not a soft-tissue substructure." The rule also states that "organ always wins over exam-region" whenever the finding has a real target organ, including edge-of-exam cases: "no consolidation" on an abdominal CT codes to lung, never to abdomen.[^rules] diff --git a/knowledge/glossary/cde-element.md b/knowledge/glossary/cde-element.md index bff71ae..25dbc48 100644 --- a/knowledge/glossary/cde-element.md +++ b/knowledge/glossary/cde-element.md @@ -4,7 +4,7 @@ title: CDE element description: One property inside a published CDE set, carrying an RDE identifier and a value set, integer, or float definition. tags: [glossary, semantic-foundation, cde] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: schema-diff resource: https://github.com/openimagingdata/openimagingdata.org/blob/fb431dfc81801a5a8e621c0e8bf2acd20f74be7d/schemas/schema_differences.md @@ -22,9 +22,9 @@ sources: # CDE element -One property inside a published [CDE set](/glossary/cde-set.md): the unit that carries a question and its permissible answers. An element definition names the property, declares its value type, and lists the values where the type is categorical. The schema distinguishes a `value_set` from `integer_values` and `float_values`, the latter carrying bounds and a step.[^schema-diff] +A property in a published [CDE set](/glossary/cde-set.md), with a question and permissible answers. Its definition names the property, declares its value type, and lists categorical values. The schema distinguishes a `value_set` from `integer_values` and `float_values`, the latter carrying bounds and a step.[^schema-diff] -In a [CDE-labeled FHIR Observation](/glossary/cde-labeled-fhir-observation.md), elements are what the components carry: the parent Observation's `code` is the set, each component's `code` is an element, and the component value is the chosen value code, for example element `RDE1717` with value `RDE1717.1`.[^fhir-sample] The dot-suffixed value code convention is the same one OIFM uses for [attribute values](/glossary/attribute-value.md). +In a [CDE-labeled FHIR Observation](/glossary/cde-labeled-fhir-observation.md), the parent's `code` identifies the set. Each component's `code` identifies an element, and its value identifies the chosen answer, such as `RDE1717.1` for element `RDE1717`.[^fhir-sample] The dot-suffixed value code convention is the same one OIFM uses for [attribute values](/glossary/attribute-value.md). ## Synonyms and near-synonyms diff --git a/knowledge/glossary/cde-labeled-fhir-observation.md b/knowledge/glossary/cde-labeled-fhir-observation.md index 45a6400..215319b 100644 --- a/knowledge/glossary/cde-labeled-fhir-observation.md +++ b/knowledge/glossary/cde-labeled-fhir-observation.md @@ -4,7 +4,7 @@ title: CDE-labeled FHIR Observation description: The project's founding representation of a finding, a FHIR Observation whose code and component codes are drawn from a published CDE set. tags: [glossary, data-structures, fhir, cde] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: site-findings resource: https://www.openimagingdata.org/findings-cdes-and-observations/ @@ -27,7 +27,7 @@ sources: The project's founding representation of a radiology finding: a FHIR `Observation` whose `code` identifies a [CDE set](/glossary/cde-set.md) and whose `component` codes identify the [CDE elements](/glossary/cde-element.md) inside it, each component's value giving the chosen value code. The phrase comes from the project's own About page and from the 2023 post that set the direction.[^site-about][^site-findings] -The lung screening sample implements it exactly. A radiologist's finding Observation carries `code` as `RDES195 Pulmonary Nodule` with `system` `https://radelement.org`, references the imaging study through `derivedFrom`, and carries element codes such as `RDE1717` in components with `valueCodeableConcept` giving codes such as `RDE1717.1`.[^fhir-sample] The reference implementation models the same shape in Python, with a discriminated union of codeable-concept, string, integer, and boolean components.[^lineage-obs] +In the lung screening sample, a radiologist's finding Observation carries `code` as `RDES195 Pulmonary Nodule` with `system` `https://radelement.org`, references the imaging study through `derivedFrom`, and carries element codes such as `RDE1717` in components with `valueCodeableConcept` giving codes such as `RDE1717.1`.[^fhir-sample] The reference implementation models the same shape in Python, with a discriminated union of codeable-concept, string, integer, and boolean components.[^lineage-obs] ## Synonyms and near-synonyms @@ -45,7 +45,7 @@ None of its own. The identifiers are those of the coding systems used, most ofte ## Conflicts -IHE IDR rejects the component pattern for this purpose. It states that `Observation.component` "is not used," because FHIR limits components to values "not useful on their own" and using it "has the potential to significantly complicate queries," preferring a root Observation with `hasMember` references to associated observations.[^idr] Every OIDM artifact that encodes attributes today, including the documented Exam Finding List mapping and these lineage samples, uses components. Reconciling the two is an open item; see [IHE IDR alignment](/data-structures/ihe-idr-alignment.md). +IHE IDR rejects the component pattern for this purpose. It states that `Observation.component` "is not used," because FHIR limits components to values "not useful on their own" and using it "has the potential to significantly complicate queries," preferring a root Observation with `hasMember` references to associated observations.[^idr] Every OIDM artifact that encodes attributes today, including the documented Exam Finding List mapping and these lineage samples, uses components. Reconciliation remains open. See [IHE IDR alignment](/data-structures/ihe-idr-alignment.md). [^site-findings]: "Findings, CDEs, and Observations", 2023-06-24 [^site-about]: openimagingdata.org About page diff --git a/knowledge/glossary/cde-set.md b/knowledge/glossary/cde-set.md index 1d75aa8..f3f4d96 100644 --- a/knowledge/glossary/cde-set.md +++ b/knowledge/glossary/cde-set.md @@ -4,7 +4,7 @@ title: CDE set description: A published RadElement definition of one finding, grouping the elements that characterize it under an RDES identifier. tags: [glossary, semantic-foundation, cde] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: cde-repo resource: https://github.com/openimagingdata/common_data_elements/blob/35536d8c858bcd33e730a00c919edaef2e310a0b/README.md @@ -22,11 +22,11 @@ sources: # CDE set -A published definition of one radiology finding on [RadElement](/glossary/radelement.md), grouping the [CDE elements](/glossary/cde-element.md) that characterize it. Roughly 140 sets are listed in the OIDM mirror of the published definitions, from Acute Aortic Syndrome to TI-RADS, each named and carrying an `RDES` identifier.[^cde-repo] +A published definition of one radiology finding on [RadElement](/glossary/radelement.md), grouping the [CDE elements](/glossary/cde-element.md) that characterize it. The OIDM mirror lists roughly 140 published sets, from Acute Aortic Syndrome to TI-RADS, each with a name and `RDES` identifier.[^cde-repo] A set carries identity and governance fields as well as its elements: `id`, `name`, `description`, `set_version`, `schema_version`, `current_status`, and `status_history`. The mirror notes that its definitions conform to version 1.0 of the CDE schema rather than the newer version 1.1.[^cde-repo] -In FHIR encodings the set identifier is what labels the parent Observation. The lineage sample codes a radiologist's finding as `RDES195 Pulmonary Nodule` with `system` `https://radelement.org`, and IHE IDR states that "when encoding CDE Sets from radelement.org, it is preferred to use the CDE Set code here."[^fhir-sample][^idr] +In FHIR encodings, the set identifier labels the parent Observation. The lineage sample codes a radiologist's finding as `RDES195 Pulmonary Nodule` with `system` `https://radelement.org`, and IHE IDR states that "when encoding CDE Sets from radelement.org, it is preferred to use the CDE Set code here."[^fhir-sample][^idr] ## Synonyms and near-synonyms diff --git a/knowledge/glossary/cde.md b/knowledge/glossary/cde.md index 50382d2..d6ef2ab 100644 --- a/knowledge/glossary/cde.md +++ b/knowledge/glossary/cde.md @@ -4,7 +4,7 @@ title: CDE description: Common data element, the ACR and RSNA programme of governed, balloted definitions for radiology findings and their elements. tags: [glossary, semantic-foundation, cde] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: cde-repo resource: https://github.com/openimagingdata/common_data_elements/blob/35536d8c858bcd33e730a00c919edaef2e310a0b/README.md @@ -24,7 +24,7 @@ sources: **Common data element (CDE).** A governed definition of a radiology finding or of one property of a finding, authored and balloted through the ACR and RSNA Common Data Elements programme and published on [RadElement](/glossary/radelement.md).[^cde-repo] The word is used at two granularities, which is the main source of confusion: a [CDE set](/glossary/cde-set.md) is a whole finding, a [CDE element](/glossary/cde-element.md) is one property inside it. -CDEs are the standards-track counterpart of OIDM's own [finding models](/glossary/finding-model.md). The 2026 status deck describes finding models as a "CDE workbench": a proving ground where LLM-assisted authoring produces content quickly, and the best of it graduates into the formal CDE process.[^deck] The 2023 site post that set the project's direction describes findings as FHIR Observations "semantically labeled with ACR/RSNA Common Data Element identifiers."[^site-findings] +CDEs are the standards-track counterpart of OIDM's own [finding models](/glossary/finding-model.md). The 2026 status deck describes finding models as a "CDE workbench": a proving ground where LLM-assisted authoring produces content quickly, and the best of it graduates into the formal CDE process.[^deck] The 2023 site post describes findings as FHIR Observations "semantically labeled with ACR/RSNA Common Data Element identifiers."[^site-findings] Between informal authoring and publication sits a staging step: `CDEStaging` holds candidate definitions "prior to their entering the review pipeline."[^staging] diff --git a/knowledge/glossary/change-from-prior.md b/knowledge/glossary/change-from-prior.md index b1dae0c..e6eec1f 100644 --- a/knowledge/glossary/change-from-prior.md +++ b/knowledge/glossary/change-from-prior.md @@ -4,7 +4,7 @@ title: Change from prior description: The companion second attribute of a finding model, recording how the finding compares with the previous exam. tags: [glossary, semantic-foundation, data-structures] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: overview resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/notes/oifm-overview.md @@ -24,7 +24,7 @@ sources: How a finding compares with the previous exam. Authoring guidance makes it the required second [attribute](/glossary/attribute.md) of a [finding model](/glossary/finding-model.md), after [presence](/glossary/presence.md), with values "unchanged, stable, new, resolved, plus clinically appropriate direction-of-change pairs (larger/smaller for masses, worsened/improved for diseases, increased/decreased for quantities)."[^overview] -The attribute exists because a finding is not a snapshot. "Findings exist in time. A radiology report is a snapshot, but the findings it describes persist across exams. A pleural effusion seen today may be the same one from last week, now larger."[^overview] Change from prior is what carries that comparison at the level of a single [observation](/glossary/observation.md), and the documented FHIR mapping singles it out along with presence as the components an Observation should carry.[^ipl-readme] +The attribute exists because a finding is not a snapshot. "Findings exist in time. A radiology report is a snapshot, but the findings it describes persist across exams. A pleural effusion seen today may be the same one from last week, now larger."[^overview] Change from prior records this comparison on a single [observation](/glossary/observation.md). The documented FHIR mapping calls for both change-from-prior and presence components.[^ipl-readme] Change from prior is also what distinguishes an attribute value from a finding. "Stable cardiac silhouette" is not a finding, because "stable" is a change-from-prior value on a cardiac finding.[^overview] @@ -45,7 +45,7 @@ An ordinary `OIFMA_[A-Z]{3,4}_[0-9]{6}` attribute identifier with dot-suffixed v ## Conflicts -The attribute is required by guidance but missing from part of the corpus. The open definition cleanup plan lists adding missing standard attributes, presence and change from prior, to 124 existing models as an ordered step, so consuming code cannot assume the attribute is present.[^cleanup] Value sets also vary by design, since direction-of-change pairs are chosen per finding, so no single enumeration covers the corpus. +Guidance requires this attribute, but some models lack it. The open cleanup plan schedules addition of missing presence and change-from-prior attributes to 124 models. Consumers cannot assume the attribute exists.[^cleanup] Direction-of-change pairs vary by finding, so no single enumeration covers the corpus. [^overview]: "Finding Models: Overview" [^ipl-readme]: imaging-problem-list README diff --git a/knowledge/glossary/coding.md b/knowledge/glossary/coding.md index 2120dd0..9b543fa 100644 --- a/knowledge/glossary/coding.md +++ b/knowledge/glossary/coding.md @@ -4,7 +4,7 @@ title: Coding description: Assigning finding identifiers and anatomic location identifiers to extracted findings, as a job distinct from extraction. tags: [glossary, applications, extraction] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: coding-design resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/docs/coding-agent-design.md @@ -24,7 +24,7 @@ sources: Assigning an [OIFM](/glossary/oifm.md) finding identifier and an [anatomic location](/glossary/anatomic-location.md) identifier to a finding that [extraction](/glossary/extraction.md) produced as free text. "Coding assigns OIFM finding codes and anatomic location codes to extracted findings. It is an independent job, fully decoupled from extraction. Extraction output persists without codes; coding is triggered separately and can be re-run with different models or settings."[^coding-design] -The documented pipeline has five phases, two of which call a language model. A fast path resolves exact and synonym matches by index lookup for both axes, and findings that resolve skip the model entirely. For the rest, two parallel agents generate two or three diverse search terms each for finding and for location; batched index search returns candidates; per-finding selector agents choose a finding code and a location code in parallel; and assembly merges fast-path and model results. Each phase degrades independently, and one finding's failure does not block the others.[^coding-design] +The documented pipeline has five phases, two of which call a language model. Index lookup resolves exact and synonym matches for findings and locations without model calls. For unresolved findings, separate finding and location agents each generate two or three diverse search terms in parallel. Batched index search returns candidates. Selector agents choose finding and location codes in parallel, and assembly combines the results with index matches. Each phase degrades independently, and one finding's failure does not block the others.[^coding-design] Location coding follows its own precedence rules rather than free judgment; see [anatomic location assignment rules](/data-structures/anatomic-location-assignment-rules.md). Codes are resolved by direct lookup rather than semantic search for a named target organ, "to avoid retrieval misses," and "every assigned `locationId` must exist in the ontology," with unrepresented structures left unassigned rather than forced onto a wrong code.[^rules] diff --git a/knowledge/glossary/contained-by-and-part-of.md b/knowledge/glossary/contained-by-and-part-of.md index 9ea7b61..992eaa0 100644 --- a/knowledge/glossary/contained-by-and-part-of.md +++ b/knowledge/glossary/contained-by-and-part-of.md @@ -4,7 +4,7 @@ title: Contained by and part of description: The two orthogonal hierarchies over anatomic locations, one physical containment and one structural or functional membership. tags: [glossary, semantic-foundation, anatomy] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: al-code resource: https://github.com/talkasab/anatomiclocations.org/blob/1f39fa45f621cef947a3f3ef1f869334cfa5c841/docs/code.markdown @@ -27,9 +27,9 @@ The two hierarchies over [anatomic locations](/glossary/anatomic-location.md), k - **Contained by**: "physically contained in (e.g., kidney in the retroperitoneum)."[^al-code] - **Part of**: "a component of a larger structure/system (e.g., adnexa part of female genital system)."[^al-code] -Containment is the primary axis. The curated set is "organized into a directed, rooted tree hierarchy, starting from the whole body and ramifying through body regions," and containment is required on every node while part-of is optional.[^al-site] Part-of carries organ-system membership, which is why a structure can be contained in one region and part of a system that spans several. +Containment is the primary axis. The curated set is "organized into a directed, rooted tree hierarchy, starting from the whole body and ramifying through body regions," and containment is required on every node while part-of is optional.[^al-site] Part-of records organ-system membership. A structure can be contained in one region and belong to a system spanning several. -The newer package materializes both. A location carries `containment_path`, `containment_parent`, `containment_depth`, and `containment_children`, and the same four fields again with a `partof_` prefix, so ancestors and descendants on either axis resolve without walking the graph at query time.[^al-package] +The newer package precomputes both hierarchies. Each location has `containment_path`, `containment_parent`, `containment_depth`, and `containment_children`, and the same four fields again with a `partof_` prefix, so ancestors and descendants on either axis resolve without walking the graph at query time.[^al-package] ## Synonyms and near-synonyms diff --git a/knowledge/glossary/contributor.md b/knowledge/glossary/contributor.md index 306bbfd..ac0aea0 100644 --- a/knowledge/glossary/contributor.md +++ b/knowledge/glossary/contributor.md @@ -4,7 +4,7 @@ title: Contributor description: A person or organization credited on a finding model definition, recorded in a registry keyed by GitHub username or organization code. tags: [glossary, semantic-foundation, finding-models] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: contributor-py resource: https://github.com/openimagingdata/findingmodel/blob/75afd39a400419dcfaf7c8d4a34f065b4d804e0d/packages/findingmodel/src/findingmodel/contributor.py @@ -26,7 +26,7 @@ A person or organization credited on a [finding model](/glossary/finding-model.m | Organization | `name` (at least 5 characters), `code` matching `^[A-Z]{3,4}$` | `url` | | Person | `github_username`, `email`, `name`, `organization_code` | `url` | -Both types register themselves as they are validated, organizations by `code` and people by `github_username`, and both can be loaded from or saved to a JSONL file.[^contributor-py] Seven organizations ship in the base registry: Microsoft, MassGeneral Brigham, Radiology Gamuts Ontology, the Radiological Society of North America, the American College of Radiology, the ACR/RSNA Common Data Elements Project, and the Open Imaging Data Model itself.[^orgs] +Validation registers organizations by `code` and people by `github_username`. Both types support JSONL import and export.[^contributor-py] Seven organizations ship in the base registry: Microsoft, MassGeneral Brigham, Radiology Gamuts Ontology, the Radiological Society of North America, the American College of Radiology, the ACR/RSNA Common Data Elements Project, and the Open Imaging Data Model.[^orgs] In the published corpus of 2,382 definitions, organization contributors appear on Gamuts-derived, OIDM-authored, and CDE-derived models, while MassGeneral Brigham and Microsoft contributions are credited to individual people carrying those organization codes. diff --git a/knowledge/glossary/data-element.md b/knowledge/glossary/data-element.md index e17bd9f..c98fc66 100644 --- a/knowledge/glossary/data-element.md +++ b/knowledge/glossary/data-element.md @@ -4,7 +4,7 @@ title: DataElement description: In the next-generation CDE vocabulary, a shared categorical descriptor whose permissible values may be ordered, reused across definitions through element bindings. tags: [glossary, semantic-foundation, cde, next-generation] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: cde-context resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/CONTEXT.md @@ -19,11 +19,11 @@ sources: # DataElement -In the next-generation CDE vocabulary, "a categorical descriptor whose permissible values may be ordered or unordered. Semantic ordering is explicit and is distinct from display order."[^cde-context] A DataElement is a node in the definition graph, not a field inside a finding definition, and it is shared: a [FindingClass](/glossary/finding-class.md) reaches it through an [element binding](/glossary/element-binding.md), which may restrict the use to a subset of the element's permissible values without changing the element or its other bindings.[^cde-context] +In the next-generation CDE vocabulary, "a categorical descriptor whose permissible values may be ordered or unordered. Semantic ordering is explicit and is distinct from display order."[^cde-context] A DataElement is a shared node in the definition graph. A [FindingClass](/glossary/finding-class.md) references it through an [element binding](/glossary/element-binding.md), which may restrict permissible values for that use without changing the element or its other bindings.[^cde-context] -Three companion rules shape how a DataElement is used. Selection cardinality states "the permitted number of values selected for a DataElement in a use, such as single or multiple selection," explicitly distinct from value ordering and from whether a report mentions the element. Modality applicability separates a descriptor's intrinsic modality limit from its binding-specific applicability. Categorization requires that a distinction be expressed either by a categorizing DataElement or by a taxonomy of named classes, not both for the same distinction in the same model.[^cde-context] +Selection cardinality states "the permitted number of values selected for a DataElement in a use, such as single or multiple selection," explicitly distinct from value ordering and from whether a report mentions the element. Modality applicability separates a descriptor's intrinsic modality limit from its binding-specific applicability. Categorization requires that a distinction be expressed either by a categorizing DataElement or by a taxonomy of named classes, not both for the same distinction in the same model.[^cde-context] -This vocabulary is a working draft on the `next-gen-2026` branch. It is not a settled integration model, and its own preamble says so.[^cde-context] +The `next-gen-2026` vocabulary is a working draft. Its preamble states that the integration model is unsettled.[^cde-context] ## Synonyms and near-synonyms diff --git a/knowledge/glossary/element-binding.md b/knowledge/glossary/element-binding.md index 88a88d9..cae3e50 100644 --- a/knowledge/glossary/element-binding.md +++ b/knowledge/glossary/element-binding.md @@ -4,7 +4,7 @@ title: Element binding description: The relationship in the next-generation CDE vocabulary that connects a definition to a DataElement it uses, optionally restricting the values in that use. tags: [glossary, semantic-foundation, cde, next-generation] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: cde-context resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/CONTEXT.md @@ -21,15 +21,15 @@ sources: "A relationship connecting a definition to a DataElement it uses. A FindingClass's binding may restrict that use to a subset of the element's permissible values without changing the shared element or its other bindings."[^cde-context] -The binding is what makes element reuse safe. One severity element can serve many [FindingClasses](/glossary/finding-class.md); each binding narrows the permissible values, sets [selection cardinality](/glossary/data-element.md), and carries its own modality applicability, which the vocabulary states "is distinct from its binding-specific applicability and is not an overridable default."[^cde-context] +The binding is what makes element reuse safe. One severity element can serve many [FindingClasses](/glossary/finding-class.md). A binding can narrow permissible values, set [selection cardinality](/glossary/data-element.md), and record modality applicability. The descriptor's intrinsic modality limit "is distinct from its binding-specific applicability and is not an overridable default."[^cde-context] -An [AnatomicLocation](/glossary/anatomic-location.md) can also bind directly to DataElements and Measurements "describing that anatomy without requiring a FindingClass," so a property of a normal structure does not need a finding to hang from.[^cde-context] IHE IDR already supports that shape, encoding an observation whose target is an anatomic entity with a property as its code.[^idr] +An [AnatomicLocation](/glossary/anatomic-location.md) can also bind directly to DataElements and Measurements "describing that anatomy without requiring a FindingClass," so normal anatomy can have properties without a finding.[^cde-context] IHE IDR already supports that shape, encoding an observation whose target is an anatomic entity with a property as its code.[^idr] ## Synonyms and near-synonyms - **`HAS_ELEMENT`** is the edge name used in the working definition graph. - **Binding** alone usually means this, but "value binding" and "terminology binding" mean something different in FHIR. -- OIFM has no equivalent. An [attribute](/glossary/attribute.md) is a member of exactly one [finding model](/glossary/finding-model.md) and cannot be shared or restricted, which is the structural difference between the two vocabularies.[^fm-py] +- OIFM has no equivalent. An [attribute](/glossary/attribute.md) is a member of exactly one [finding model](/glossary/finding-model.md) and cannot be shared or restricted.[^fm-py] ## Identifier form diff --git a/knowledge/glossary/exam-finding-list.md b/knowledge/glossary/exam-finding-list.md index caa9816..c41bdda 100644 --- a/knowledge/glossary/exam-finding-list.md +++ b/knowledge/glossary/exam-finding-list.md @@ -4,7 +4,7 @@ title: Exam Finding List description: All findings declared present or absent on one imaging exam, in one queryable structure keyed to the exam and the report. tags: [glossary, data-structures, ipl] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: ipl-readme resource: https://github.com/openimagingdata/imaging-problem-list/blob/06f64a7893b444b761dc069ed86140a081195eac/README.md @@ -26,7 +26,7 @@ sources: The structure carries a `diagnosticReportId`, `patientInfo`, an `examInfo` block holding the study identifier, date and time, [LOINC](/glossary/loinc.md) code and description, and a `findings` array. Each finding carries an `observationId`, a `findingCode` in `OIFM_XXXX_######` form with its description, an `attributes` array of [attribute](/glossary/attribute.md) code, value code, and display text, an optional `anatomicLocation` of `locationId` and `locationDisplay`, and an optional verbatim `reportText`.[^ipl-claude][^efl-sample] -Two properties are stated as requirements rather than conveniences. The exam header must be keyed by a curated list of LOINC codes. And "the same finding type may be declared present multiple times; each time is a separate entry."[^ipl-readme] The deck adds that an Exam Finding List can be "sourced from dictation, AI tools, interpretation-time interfaces," which is why each observation should carry a [provenance](/glossary/provenance.md) marker.[^deck] +Two properties are stated as requirements rather than conveniences. The exam header must be keyed by a curated list of LOINC codes, and "the same finding type may be declared present multiple times; each time is a separate entry."[^ipl-readme] The deck adds that an Exam Finding List can be "sourced from dictation, AI tools, interpretation-time interfaces," so each observation should carry a [provenance](/glossary/provenance.md) marker.[^deck] ## Synonyms and near-synonyms diff --git a/knowledge/glossary/exam-type.md b/knowledge/glossary/exam-type.md index ac9a2f3..3da3eba 100644 --- a/knowledge/glossary/exam-type.md +++ b/knowledge/glossary/exam-type.md @@ -4,7 +4,7 @@ title: Exam type description: The kind of imaging study an exam is, coded with LOINC today and intended to become a first-class OIDM artifact linking modality, technique, and included body parts. tags: [glossary, semantic-foundation, exam-types] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: ipl-claude resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/CLAUDE.md @@ -25,11 +25,11 @@ sources: # Exam type -The kind of imaging study an exam is: modality, body part, technique, and contrast, taken together. Today OIDM identifies an exam type by a [LOINC](/glossary/loinc.md) code carried on the exam header, for example `72133-2` for CT Abdomen and Pelvis Without Contrast.[^ipl-claude] +An imaging study type defined by modality, body part, technique, and contrast. Today OIDM identifies an exam type by a [LOINC](/glossary/loinc.md) code carried on the exam header, for example `72133-2` for CT Abdomen and Pelvis Without Contrast.[^ipl-claude] -Exam type does more work than labelling. It bounds what a finding model should cover: "the scope of a finding model should match what's assessable on a given exam type, not broader."[^overview] It supplies the fallback [body region](/glossary/body-region.md) when a finding names no anatomic structure, and it supplies laterality when the exam itself is sided.[^rules] +Exam type bounds a finding model's scope: "the scope of a finding model should match what's assessable on a given exam type, not broader."[^overview] It supplies the fallback [body region](/glossary/body-region.md) when a finding names no anatomic structure, and it supplies laterality when the exam itself is sided.[^rules] -The stated goal is a first-class exam-type artifact rather than a bare code. The earliest written form asks for "a companion for exam types based on LOINC/RadLex Playbook exam definitions that specify all included body parts for the exam."[^al-site] The most developed written design sits in the terminology tool's roadmap, which makes the [LOINC/RSNA Radiology Playbook](/glossary/loinc-rsna-radiology-playbook.md) first-class in a default radiology profile and plans Playbook-weighted ranking for orderable queries.[^roadmap] +The stated goal is a first-class exam-type artifact rather than a bare code. The earliest proposal asks for "a companion for exam types based on LOINC/RadLex Playbook exam definitions that specify all included body parts for the exam."[^al-site] The terminology tool's roadmap contains the most developed design. It proposes making the [LOINC/RSNA Radiology Playbook](/glossary/loinc-rsna-radiology-playbook.md) first-class in a default radiology profile and plans Playbook-weighted ranking for orderable queries.[^roadmap] ## Synonyms and near-synonyms @@ -48,7 +48,7 @@ A LOINC code today. Legacy `RPID` Playbook identifiers are recognized in the pla ## Conflicts -No exam-type artifact exists. There is no published curated LOINC list, no exam-to-body-parts mapping, and no code that parses modality or body-part axes, even though three separate documents across three repositories describe the same goal. The area is documented as goals plus existing building blocks; see [Exam types](/roadmap/exam-types.md). +Three documents in three repositories describe the goal, but no exam-type artifact exists: no published curated LOINC list, exam-to-body-parts mapping, or code to parse modality or body-part axes. See goals and existing building blocks under [Exam types](/roadmap/exam-types.md). [^ipl-claude]: imaging-problem-list domain model, dev branch [^al-site]: anatomiclocations.org roadmap diff --git a/knowledge/glossary/extraction.md b/knowledge/glossary/extraction.md index 057b87e..8ab4bc1 100644 --- a/knowledge/glossary/extraction.md +++ b/knowledge/glossary/extraction.md @@ -4,7 +4,7 @@ title: Extraction description: Deriving structured findings from narrative radiology report text with a language model, producing findings, presence, location, and attributes with verbatim quotes. tags: [glossary, applications, extraction] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: extraction-plan resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/initial-extraction-plan.md @@ -25,11 +25,11 @@ sources: # Extraction -Deriving structured findings from narrative radiology report text using a language model. It is the first half of the pipeline that turns a report into OIDM data: "an agent reads a radiology report and identifies findings mentioned in the text," and each finding is then matched to a definition.[^overview] The deck states the goal that an [Imaging Problem List](/glossary/imaging-problem-list.md) be "automatically extractable from narrative report text via LLMs."[^deck] +Deriving structured findings from narrative radiology report text using a language model. The authoring overview states: "an agent reads a radiology report and identifies findings mentioned in the text," and each finding is then matched to a definition.[^overview] The deck states the goal that an [Imaging Problem List](/glossary/imaging-problem-list.md) be "automatically extractable from narrative report text via LLMs."[^deck] -Extraction output is uncoded. Its schema names a finding, asserts presence as one of `present`, `absent`, `indeterminate`, or `possible`, gives an optional location of body region, specific anatomy, and laterality, a list of key-value attributes with standard keys such as size, acuity, change from prior, severity, count, and morphology, and a verbatim `report_text` quote.[^extraction-plan] Assigning identifiers is a separate job; see [coding](/glossary/coding.md). +The uncoded output contains a finding name, presence as `present`, `absent`, `indeterminate`, or `possible`, and a verbatim `report_text` quote. An optional location records body region, specific anatomy, and laterality. Key-value attributes use standard keys such as size, acuity, change from prior, severity, count, and morphology.[^extraction-plan] Assigning identifiers is a separate job; see [coding](/glossary/coding.md). -Three design decisions shape the current implementation: long reports are semantically chunked and extracted concurrently then merged and deduplicated, output quotes are validated as verbatim both during and after generation, and a reviewer sub-agent can flag issues and trigger targeted re-extraction of specific chunks.[^ipl-claude] +The implementation splits long reports into semantic chunks, extracts them concurrently, and merges and deduplicates the results. It validates verbatim quotes during and after generation. A reviewer sub-agent can flag issues and trigger re-extraction of specific chunks.[^ipl-claude] ## Synonyms and near-synonyms @@ -48,7 +48,7 @@ None. Extracted findings carry names and quotes, not identifiers, until coding r ## Conflicts -The failure modes extraction guards against are stated in the validator prompt and are worth naming as part of the definition: content unsupported by the chunk text, which is hallucination; report text describing a finding that no structure represents, which is a missed finding; a finding described as present when it is not, or absent when it is possible; a finding name more specific than the text supports; incorrect representation of a blanket negative; and wrong, too specific, or too general location information.[^validator] Separately, the extraction presence value set does not match the finding model one; see [presence](/glossary/presence.md). +The failure modes extraction guards against are stated in the validator prompt: hallucinated content unsupported by the chunk, report text describing a finding that no structure represents, which is a missed finding, a finding described as present when it is not, or absent when it is possible, overly specific finding names, misrepresented blanket negatives, and incorrect or overly specific or general locations.[^validator] Separately, the extraction presence value set does not match the finding model one; see [presence](/glossary/presence.md). [^extraction-plan]: Initial extraction plan [^ipl-claude]: imaging-problem-list architecture notes diff --git a/knowledge/glossary/fhir-condition.md b/knowledge/glossary/fhir-condition.md index 1a9d7ee..e41b3de 100644 --- a/knowledge/glossary/fhir-condition.md +++ b/knowledge/glossary/fhir-condition.md @@ -4,7 +4,7 @@ title: FHIR Condition description: The HL7 FHIR resource for a clinical condition, used in the documented Imaging Problem List mapping as the container for one finding type. tags: [glossary, data-structures, fhir] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: fhir resource: https://www.hl7.org/fhir/condition.html @@ -19,9 +19,9 @@ sources: # FHIR Condition -The HL7 FHIR resource for a clinical condition, problem, or diagnosis.[^fhir] In OIDM it appears in one place: the documented FHIR mapping of an [Imaging Problem List](/glossary/imaging-problem-list.md), which is "a Report containing a list of Condition objects (labeled with the finding identifier), where each Condition object also contains a list of Observation objects which document which exams (DiagnosticReports) the finding type has been documented on, including the exam date and exam type."[^ipl-readme] +The HL7 FHIR resource for a clinical condition, problem, or diagnosis.[^fhir] Its only OIDM use is the documented FHIR mapping of an [Imaging Problem List](/glossary/imaging-problem-list.md), which is "a Report containing a list of Condition objects (labeled with the finding identifier), where each Condition object also contains a list of Observation objects which document which exams (DiagnosticReports) the finding type has been documented on, including the exam date and exam type."[^ipl-readme] -One Condition therefore stands for one finding type in one patient, and the [observations](/glossary/observation.md) under it are the evidence trail across exams. +One Condition represents a finding type in one patient. Its [observations](/glossary/observation.md) record evidence across exams. ## Synonyms and near-synonyms @@ -40,7 +40,7 @@ A FHIR resource identifier. The mapping labels each Condition with the finding i ## Conflicts -Three points are unsettled. The mapping is documented and implemented nowhere; no Condition resource is produced by any OIDM code. Its container is called a "Report," which is not a FHIR resource name. And IHE IDR takes a different position on when Condition is appropriate, routing positive clinical findings to Condition and negative ones to Observation, against an OIDM working default that "every assertion in a radiology report, diagnoses included, is encoded as an Observation," partly because "'consistent with pneumonia' is a radiologist's assertion, not an established clinical condition."[^idr-extract] If that default holds, `Condition.evidence` as the finding-to-diagnosis link has nowhere to attach and an Observation-to-Observation equivalent is needed. +Three points are unsettled. The mapping is documented but unimplemented. No OIDM code produces Condition resources. Its container is called a "Report," which is not a FHIR resource name. IHE IDR routes positive clinical findings to Condition and negative ones to Observation, against an OIDM working default that "every assertion in a radiology report, diagnoses included, is encoded as an Observation," partly because "'consistent with pneumonia' is a radiologist's assertion, not an established clinical condition."[^idr-extract] If that default holds, `Condition.evidence` as the finding-to-diagnosis link has nowhere to attach and an Observation-to-Observation equivalent is needed. [^fhir]: Condition resource, HL7 FHIR [^ipl-readme]: imaging-problem-list README diff --git a/knowledge/glossary/fhir-diagnostic-report.md b/knowledge/glossary/fhir-diagnostic-report.md index 9338687..6eee898 100644 --- a/knowledge/glossary/fhir-diagnostic-report.md +++ b/knowledge/glossary/fhir-diagnostic-report.md @@ -4,7 +4,7 @@ title: FHIR DiagnosticReport description: The HL7 FHIR resource for a diagnostic report, used in OIDM as the interchange encoding of an Exam Finding List. tags: [glossary, data-structures, fhir] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: fhir resource: https://www.hl7.org/fhir/diagnosticreport.html @@ -22,9 +22,9 @@ sources: # FHIR DiagnosticReport -The HL7 FHIR resource for a diagnostic report.[^fhir] In OIDM it is the documented interchange encoding of an [Exam Finding List](/glossary/exam-finding-list.md): "DiagnosticReport containing a list of Observation objects, with a finding code on each Observation and a list of components with attribute codes and values (especially present/absent and change from prior)."[^ipl-readme] In an [Imaging Problem List](/glossary/imaging-problem-list.md), DiagnosticReports are what each observation points back to, giving the exam date and [LOINC](/glossary/loinc.md) exam type.[^ipl-readme] +The HL7 FHIR resource for a diagnostic report.[^fhir] In OIDM it is the documented interchange encoding of an [Exam Finding List](/glossary/exam-finding-list.md): "DiagnosticReport containing a list of Observation objects, with a finding code on each Observation and a list of components with attribute codes and values (especially present/absent and change from prior)."[^ipl-readme] In an [Imaging Problem List](/glossary/imaging-problem-list.md), each observation references a DiagnosticReport for its exam date and [LOINC](/glossary/loinc.md) exam type.[^ipl-readme] -The lineage sample shows the shape with real data: a report with a SNOMED and HL7 category, a LOINC `code`, an inline `ImagingStudy`, `result` references to three [Observations](/glossary/observation.md), and `conclusion` with SNOMED `conclusionCode`.[^fhir-sample] +The lineage sample contains a SNOMED and HL7 category, a LOINC `code`, an inline `ImagingStudy`, `result` references to three [Observations](/glossary/observation.md), and `conclusion` with SNOMED `conclusionCode`.[^fhir-sample] ## Synonyms and near-synonyms @@ -43,7 +43,7 @@ A FHIR resource identifier. The Exam Finding List samples use UUID strings. ## Conflicts -The mapping is documented and unimplemented. No FHIR resource classes exist in the extraction platform's source, and a search for DiagnosticReport across it returns nothing; the only real FHIR documents in the repository are two input samples. Those input samples also do not use the presence and change-from-prior component pattern the specification prescribes, because that pattern describes the output.[^ipl-readme] Separately, IHE IDR would encode the attribute layer with `hasMember` rather than components.[^idr-extract] +The mapping is documented but unimplemented. No FHIR resource classes exist in the extraction platform's source, and a search for DiagnosticReport across it returns nothing; the only real FHIR documents in the repository are two input samples. Those input samples also do not use the presence and change-from-prior component pattern the imaging-problem-list README prescribes, because that pattern describes the output.[^ipl-readme] Separately, IHE IDR would encode the attribute layer with `hasMember` rather than components.[^idr-extract] [^fhir]: DiagnosticReport resource, HL7 FHIR [^ipl-readme]: imaging-problem-list README diff --git a/knowledge/glossary/finding-class.md b/knowledge/glossary/finding-class.md index cd3216c..131d3f6 100644 --- a/knowledge/glossary/finding-class.md +++ b/knowledge/glossary/finding-class.md @@ -4,7 +4,7 @@ title: FindingClass description: The next-generation CDE vocabulary's node type for a finding definition, separated from diagnosis and carrying bindings to shared elements. tags: [glossary, semantic-foundation, cde, next-generation] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: cde-context resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/CONTEXT.md @@ -19,7 +19,7 @@ sources: # FindingClass -The next-generation CDE vocabulary's node type for a finding definition: the counterpart of a [CDE set](/glossary/cde-set.md) or an OIDM [finding model](/glossary/finding-model.md) in a graph-shaped model. A FindingClass is described by ordinary [DataElements](/glossary/data-element.md) reached through [element bindings](/glossary/element-binding.md), sits in an is-a taxonomy of subtypes, and carries [standard clinical metadata](/glossary/tag.md): "the seven facts on a class: modality, body region, subspecialty, sex, age, time course, and etiology."[^cde-context] +The next-generation CDE vocabulary's node type for a finding definition: the counterpart of a [CDE set](/glossary/cde-set.md) or an OIDM [finding model](/glossary/finding-model.md) in a graph model. A FindingClass is described by ordinary [DataElements](/glossary/data-element.md) reached through [element bindings](/glossary/element-binding.md), sits in an is-a taxonomy of subtypes, and carries [standard clinical metadata](/glossary/tag.md): "the seven facts on a class: modality, body region, subspecialty, sex, age, time course, and etiology."[^cde-context] Two scoping mechanisms are defined on classes. [Anatomic scope](/glossary/anatomic-scope.md) states the eligible anatomical places, tissue types, or structure types for the definition. Component-of scope states "the finding classes a component class belongs inside, stated on the component class"; a class with a component-of scope "is never reported on its own," and component classes are specific to a lesion family.[^cde-context] @@ -43,7 +43,7 @@ Working identifiers in the alpha implementation take the form `FC-######`, for e ## Conflicts -IHE IDR uses "finding" for the presence-or-absence determination rather than for the named entity, and routes positive clinical findings to [FHIR Condition](/glossary/fhir-condition.md) while negative ones become Observations. The next-generation notes record a different working default, that every assertion in a radiology report including diagnoses is encoded as an Observation, and list the divergence as an item to raise with IHE.[^idr] +IHE IDR uses "finding" for the presence-or-absence determination rather than for the named entity, and routes positive clinical findings to [FHIR Condition](/glossary/fhir-condition.md) while negative ones become Observations. The next-generation working default encodes every radiology report assertion, including diagnoses, as an Observation. The notes list this difference for discussion with IHE.[^idr] [^cde-context]: CDE vocabulary, next-generation working glossary [^idr]: IHE IDR Phase II extract diff --git a/knowledge/glossary/finding-taxonomy.md b/knowledge/glossary/finding-taxonomy.md index c94e505..a0f1f58 100644 --- a/knowledge/glossary/finding-taxonomy.md +++ b/knowledge/glossary/finding-taxonomy.md @@ -4,7 +4,7 @@ title: Finding taxonomy description: One of the six MGB exam-oriented sub-taxonomies, per-modality hierarchies of finding names exported as CSV, that now set the content direction for the finding model corpus. tags: [glossary, semantic-foundation, finding-models, content] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: lists-readme resource: https://github.com/openimagingdata/findingmodels/blob/a30c3c95fa3943e7340ce87575f4b1b926987eb8/lists/README.md @@ -15,7 +15,7 @@ sources: One of the six MGB exam-oriented sub-taxonomies: per-modality hierarchies of radiology finding names, contributed by Mass General Brigham and exported to the `findingmodels` repository on 2026-08-15 as comma-separated files.[^lists-readme] They replaced the repository's earlier `lists/` content wholesale. -Each file is one hierarchy with the columns `name`, `category`, `parent`, `synonyms`, `finding_type`, `finding_cluster`, and `oifm_id`. Rows are keyed by `name`, unique within a file, so there is no separate identifier column. The `parent` column holds the parent row's `name`; blank means top level. "Parents are generic, children add specificity," the worked example being `lung_abnormality` then `airspace_opacity` then `air_bronchogram`. Two columns are deliberately outside the hierarchy: `category` is "an independent anatomic grouping, not part of the hierarchy," and `finding_type` "separates an observation from a diagnosis."[^lists-readme] +Each file is one hierarchy with the columns `name`, `category`, `parent`, `synonyms`, `finding_type`, `finding_cluster`, and `oifm_id`. The unique `name` keys each row within a file. There is no separate row identifier. `parent` holds the parent row's `name`, or is blank for a top-level row. "Parents are generic, children add specificity," as in `lung_abnormality`, then `airspace_opacity`, then `air_bronchogram`. Two columns are outside the hierarchy: `category` is "an independent anatomic grouping, not part of the hierarchy," and `finding_type` "separates an observation from a diagnosis."[^lists-readme] | File | Rows | OIFM IDs filled | |---|---:|---:| @@ -32,7 +32,7 @@ No identifiers were minted during the export. Filled rows were matched by exact ## Synonyms and near-synonyms - **Finding list** is the older name for the files these replaced. -- **[Finding taxonomy](/glossary/finding-taxonomy.md) is not a [finding model](/glossary/finding-model.md).** A taxonomy row is a name and a place in a hierarchy; a finding model is a full definition with attributes. +- A [finding taxonomy](/glossary/finding-taxonomy.md) row gives a name and hierarchy position. A [finding model](/glossary/finding-model.md) defines the finding and its attributes. - The taxonomies are named after their author in the source repository. This knowledgebase calls them the MGB exam-oriented sub-taxonomies. ## Identifier form diff --git a/knowledge/glossary/fma.md b/knowledge/glossary/fma.md index 67af5fb..d79e1c4 100644 --- a/knowledge/glossary/fma.md +++ b/knowledge/glossary/fma.md @@ -4,7 +4,7 @@ title: FMA description: The Foundational Model of Anatomy, used in OIDM as a cross-reference on anatomic locations and as the basis of the location type classification. tags: [glossary, semantic-foundation, terminologies, anatomy] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: fma resource: https://bioportal.bioontology.org/ontologies/FMA @@ -22,7 +22,7 @@ sources: # FMA -The Foundational Model of Anatomy, a reference ontology of human anatomy.[^fma] OIDM uses it in two ways. It is a cross-reference code on [anatomic locations](/glossary/anatomic-location.md), present on 1,643 of the 2,890 records in the curated set, the second most common system after [SNOMED CT](/glossary/snomed-ct.md).[^al-code] And its top-level organization supplies the shape of the `location_type` classification in the newer package, which maps material anatomical entity to structure, immaterial anatomical entity to space and region, body part to body_part, organ system to system, and set or collection to group.[^al-enums] +The Foundational Model of Anatomy, a reference ontology of human anatomy.[^fma] FMA cross-references appear on [anatomic locations](/glossary/anatomic-location.md), covering 1,643 of the 2,890 curated records. It is the second most common system after [SNOMED CT](/glossary/snomed-ct.md).[^al-code] Its top-level organization supplies the shape of the `location_type` classification in the newer package, which maps material anatomical entity to structure, immaterial anatomical entity to space and region, body part to body_part, organ system to system, and set or collection to group.[^al-enums] FMA is also one of the five terminologies the `molu` lookup tool spans, and the planned `anatomy` profile names FMA first, with the note that "RadLex imaging anatomy sits next to FMA."[^molu] diff --git a/knowledge/glossary/gamuts.md b/knowledge/glossary/gamuts.md index 09272f9..4580311 100644 --- a/knowledge/glossary/gamuts.md +++ b/knowledge/glossary/gamuts.md @@ -4,7 +4,7 @@ title: Gamuts description: The Radiology Gamuts Ontology, source of the largest single block of finding model definitions and of the GMTS organization code. tags: [glossary, semantic-foundation, terminologies, content] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: gamuts resource: https://gamuts.net/ @@ -22,7 +22,7 @@ sources: # Gamuts -The Radiology Gamuts Ontology, a published ontology of radiologic differential diagnosis lists, at `gamuts.net`.[^gamuts] In OIDM it plays two roles at once: it is an [index code](/glossary/index-code.md) system listed alongside SNOMED and RadLex as one of the common ontologies,[^claude-md] and it is a registered contributing organization whose [organization code](/glossary/oidm-organization-code.md) is `GMTS`.[^orgs] +The Radiology Gamuts Ontology, a published ontology of radiologic differential diagnosis lists, at `gamuts.net`.[^gamuts] OIDM uses it as an [index code](/glossary/index-code.md) system listed alongside SNOMED and RadLex as one of the common ontologies,[^claude-md] and it is a registered contributing organization whose [organization code](/glossary/oidm-organization-code.md) is `GMTS`.[^orgs] Gamuts is the single largest source of finding model content. Of the 2,382 definitions published in the corpus, 1,933 carry an `OIFM_GMTS_` identifier, credited to the Radiology Gamuts Ontology as the contributing organization. They were produced by a script that scrapes gamut pages, structures the terms with a language model, and emits them for conversion into definitions. @@ -31,7 +31,7 @@ Gamuts is the single largest source of finding model content. Of the 2,382 defin - **Radiology Gamuts Ontology** is the full name; **gamut** alone means one differential list. - **`GMTS`** is the organization code and the middle segment of the identifiers. - **`GAMUTS`** is the `system` string when a gamut concept is cited as an index code. -- **[Finding taxonomy](/glossary/finding-taxonomy.md)** is the newer content spine that is expected to supersede much of this material. +- **[Finding taxonomy](/glossary/finding-taxonomy.md)** is the newer content source expected to supersede much of this material. ## Identifier form @@ -43,7 +43,7 @@ Finding models derived from this source carry `OIFM_GMTS_######`, for example `O ## Conflicts -A gamut is a differential diagnosis list, so Gamuts-derived definitions carry diagnoses where OIDM's authoring guidance would sometimes want an observation. The open definition cleanup plan lists "gamuts reclassification" as a step that "needs design discussion," and it is the one step in that plan with no agreed approach.[^cleanup] The content roadmap expects the MGB exam-oriented sub-taxonomies to replace many of these definitions. +A gamut is a differential diagnosis list, so Gamuts-derived definitions carry diagnoses where OIDM's authoring guidance would sometimes want an observation. The open definition cleanup plan lists "gamuts reclassification" as a step that "needs design discussion," the only step without an agreed approach.[^cleanup] The content roadmap expects the MGB exam-oriented sub-taxonomies to replace many of these definitions. [^gamuts]: Radiology Gamuts Ontology [^orgs]: Base organization registry diff --git a/knowledge/glossary/imaging-diagnostic-report.md b/knowledge/glossary/imaging-diagnostic-report.md index 64899cc..0112915 100644 --- a/knowledge/glossary/imaging-diagnostic-report.md +++ b/knowledge/glossary/imaging-diagnostic-report.md @@ -4,7 +4,7 @@ title: Imaging Diagnostic Report (IHE IDR) description: The IHE Radiology profile that specifies how a diagnostic imaging report and its findings are encoded as FHIR resources. tags: [glossary, data-structures, fhir, ihe] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: idr-supplement resource: https://www.ihe.net/uploadedFiles/Documents/Radiology/IHE_RAD_Suppl_IDR_PhII_Rev1-2_PC_2026-03-04.pdf @@ -19,7 +19,7 @@ sources: # Imaging Diagnostic Report (IHE IDR) -The Integrating the Healthcare Enterprise Radiology profile that specifies how a diagnostic imaging report and the findings inside it are encoded as FHIR resources. Phase II went out for public comment in March 2026.[^idr-supplement] The deck names the connection from the OIDM side: an [Exam Finding List](/glossary/exam-finding-list.md) "connects to IHE Imaging Diagnostic Report (IDR) FHIR representation."[^deck] +The Integrating the Healthcare Enterprise Radiology profile that specifies how a diagnostic imaging report and the findings inside it are encoded as FHIR resources. Phase II went out for public comment in March 2026.[^idr-supplement] The deck states that an [Exam Finding List](/glossary/exam-finding-list.md) "connects to IHE Imaging Diagnostic Report (IDR) FHIR representation."[^deck] IDR's information model, "heavily influenced by modelling in SNOMED and DICOM," defines three terms OIDM must map onto. Body Structure "encompasses both anatomical structures and morphologic abnormalities (like a lesion, cyst, inflammation, aneurysm, fracture or abscess)." An imaging observation is "a feature or characteristic that is visible in an image," encoded as a FHIR `Observation`. A clinical finding is "the determination that a clinical entity is present or absent," with positive findings encoded as [FHIR Condition](/glossary/fhir-condition.md) and negative ones as Observations.[^idr-extract] @@ -41,7 +41,7 @@ None. IDR constrains FHIR resources and reuses their identifiers. ## Conflicts -IDR and OIDM disagree in three recorded places, all listed as items to raise during public comment. IDR's "finding" is the presence determination, not the named entity, and its "observation" is closer to what the next-generation vocabulary calls a data element value. IDR routes positive diagnoses to Condition while the OIDM working default is that every assertion in a report is an Observation. And IDR states that `Observation.component` "is not used," which is the mechanism every current OIDM encoding relies on.[^idr-extract] The IDR profile is not mentioned anywhere in the `imaging-problem-list` repository, so the alignment exists in the vocabulary work and the deck, not in code. +Three differences are recorded for public comment. IDR's "finding" is the presence determination, not the named entity, and its "observation" is closer to what the next-generation vocabulary calls a data element value. IDR routes positive diagnoses to Condition while the OIDM working default is that every assertion in a report is an Observation. IDR states that `Observation.component` "is not used," which is the mechanism every current OIDM encoding relies on.[^idr-extract] The `imaging-problem-list` repository does not mention IDR. Alignment is documented only in the vocabulary work and the deck. [^idr-supplement]: IHE Imaging Diagnostic Report Phase II public comment draft [^idr-extract]: IHE IDR Phase II extract diff --git a/knowledge/glossary/index-code.md b/knowledge/glossary/index-code.md index 94eebfb..63271d1 100644 --- a/knowledge/glossary/index-code.md +++ b/knowledge/glossary/index-code.md @@ -4,7 +4,7 @@ title: Index code description: A reference from a finding model, attribute, or value to a concept in a standard ontology, carried as system, code, and optional display. tags: [glossary, semantic-foundation, terminologies] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: index-code resource: https://github.com/openimagingdata/findingmodel/blob/75afd39a400419dcfaf7c8d4a34f065b4d804e0d/packages/oidm-common/src/oidm_common/models/index_code.py @@ -22,9 +22,9 @@ sources: # Index code -A "code representing an entry in a standard ontology, e.g., SNOMED or RadLex, which can be applied to a finding or attribute. This is used to standardize the representation of findings and attributes across different systems and to facilitate interoperability between different systems."[^index-code] The shape is three fields: `system`, `code`, and an optional `display`. +A "code representing an entry in a standard ontology, e.g., SNOMED or RadLex, which can be applied to a finding or attribute. This is used to standardize the representation of findings and attributes across different systems and to facilitate interoperability between different systems."[^index-code] The fields are `system`, `code`, and an optional `display`. -Index codes may sit on a [finding model](/glossary/finding-model.md), on an [attribute](/glossary/attribute.md), or on an individual [attribute value](/glossary/attribute-value.md). The same type also carries a finding model's `anatomic_locations`, so an [anatomic location](/glossary/anatomic-location.md) reference on a finding model is structurally an index code, usually with `system: "RADLEX"`.[^index-code] +Index codes may appear on a [finding model](/glossary/finding-model.md), on an [attribute](/glossary/attribute.md), or on an individual [attribute value](/glossary/attribute-value.md). The same type also carries a finding model's `anatomic_locations`, so an [anatomic location](/glossary/anatomic-location.md) reference on a finding model is structurally an index code, usually with `system: "RADLEX"`.[^index-code] The systems most used in the corpus are [SNOMED CT](/glossary/snomed-ct.md), [RadLex](/glossary/radlex.md), and [Gamuts](/glossary/gamuts.md), with [RadElement](/glossary/radelement.md) appearing on CDE-derived definitions.[^claude-md] @@ -32,7 +32,7 @@ The systems most used in the corpus are [SNOMED CT](/glossary/snomed-ct.md), [Ra - **Coding** in FHIR is the analogous triple of `system`, `code`, and `display`. The [CDE-labeled FHIR Observation](/glossary/cde-labeled-fhir-observation.md) pattern uses it the same way. - **Standard code** and **ontology code** are informal names for the same thing. -- **[Index code](/glossary/index-code.md) is not a crosswalk.** It asserts a reference, not an equivalence class across systems. +- An [index code](/glossary/index-code.md) references a concept without defining a crosswalk or asserting equivalence across systems. ## Identifier form @@ -44,7 +44,7 @@ None of its own. The code inside follows the referenced system, for example `RID ## Conflicts -The in-flight metadata rewrite tightens the rule to say that a canonical `index_codes` entry "must be an exact match or a clinically substitutable near-equivalent for the full model concept," sending broader, narrower, and complication-specific codes to a separate review artifact instead.[^metadata-rewrite] The corpus on `main` predates that rule. Separately, the CDE Set schema constrains an index code `system` to `RADLEX`, `SNOMEDCT`, or `LOINC` while the RadElement API does not appear to constrain it, and OIFM does not constrain it either.[^cde-set-schema] +The metadata rewrite in progress requires that an `index_codes` entry "must be an exact match or a clinically substitutable near-equivalent for the full model concept," sending broader, narrower, and complication-specific codes to a separate review artifact instead.[^metadata-rewrite] The corpus on `main` predates that rule. Separately, the CDE Set schema constrains an index code `system` to `RADLEX`, `SNOMEDCT`, or `LOINC` while the RadElement API does not appear to constrain it, and OIFM does not constrain it either.[^cde-set-schema] [^index-code]: IndexCode model in the oidm-common package [^claude-md]: findingmodels repository conventions diff --git a/knowledge/glossary/index.md b/knowledge/glossary/index.md index 702284d..d0d34d6 100644 --- a/knowledge/glossary/index.md +++ b/knowledge/glossary/index.md @@ -1,6 +1,6 @@ # Glossary -One term per file: a precise definition drawn from the sources, its synonyms and near-synonyms, its identifier form where it has one, where it is used, and any conflict between sources. Terms are listed alphabetically. +Each term has a sourced definition, synonyms and near-synonyms, any identifier format, usage links, and source disagreements. Entries are alphabetical, one term per file. * [Anatomic location](./anatomic-location.md) - A curated anatomic concept identified by a RadLex identifier, placed in containment and part-of hierarchies with laterality variants and cross-ontology codes. * [Anatomic scope](./anatomic-scope.md) - The eligible anatomical places, tissue types, or structure types for a definition, stated as a constraint rather than as a location. diff --git a/knowledge/glossary/laterality.md b/knowledge/glossary/laterality.md index cbe160b..c557f0a 100644 --- a/knowledge/glossary/laterality.md +++ b/knowledge/glossary/laterality.md @@ -4,7 +4,7 @@ title: Laterality description: The left, right, or unsided character of an anatomic structure or a finding, represented as a triad of linked variants and resolved by a stated precedence. tags: [glossary, semantic-foundation, anatomy] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: bpi resource: https://github.com/talkasab/BodyPartIndex.py/blob/388ae0a6da92f5ee4cf36620bbeeabe223938471/README.md @@ -24,7 +24,7 @@ sources: Whether a structure or a finding is left, right, or neither. The curated anatomic sets represent it structurally: "for cases where the body part is sided, the index contains three versions: an unsided version, a left-sided version, and a right-sided version. All of these are aware of each other."[^bpi] The newer package makes this an enumeration with four values, `generic` for a structure that has left and right variants, `left`, `right`, and `nonlateral` for a structure with no sides at all such as the heart or the spine.[^al-package] -Assigning laterality to a finding follows a stated precedence: explicit side in the text beats a sided exam, which beats the generic unsided structure. A non-sided exam never introduces a side. Laterality must be resolved "against the full report section, not the finding's isolated quote," because the side is often stated only in a section header or an earlier sentence, and a side is never inferred across exams or from clinical priors.[^rules] +Laterality assignment follows this precedence: explicit side in the text beats a sided exam, which beats the generic unsided structure. A non-sided exam never introduces a side. Laterality must be resolved "against the full report section, not the finding's isolated quote," because the side is often stated only in a section header or an earlier sentence, and a side is never inferred across exams or from clinical priors.[^rules] Bilateral findings split or do not split by a stated test. Discrete independent lesions per side become two findings; a single diffuse entity named as one, an "-osis" or a "disease," stays generic and unsided. The operational test is whether "you could meaningfully say the left one is larger or newer."[^rules] @@ -44,7 +44,7 @@ In the original set, sided variants take composite identifiers such as `RID294_R ## Conflicts -IHE IDR keeps laterality in a separate FHIR field on an unsided structure code, while OIDM's anatomy nodes are themselves sided. The IDR extract lists a stated mapping between the two, sided identifier and unsided identifier plus laterality, as something still needed so both directions round-trip.[^idr] A known defect in the `findingmodel` issue list also reports that laterality is assigned backwards during one database build step. +IHE IDR keeps laterality in a separate FHIR field on an unsided structure code, while OIDM's anatomy nodes are themselves sided. The IDR extract records a reversible mapping between sided identifiers and unsided identifiers with a laterality field as something still needed so both directions round-trip.[^idr] A known defect in the `findingmodel` issue list also reports that laterality is assigned backwards during one database build step. [^bpi]: BodyPartIndex.py README [^al-package]: Laterality enumeration in the anatomic-locations package diff --git a/knowledge/glossary/loinc-rsna-radiology-playbook.md b/knowledge/glossary/loinc-rsna-radiology-playbook.md index edf7ddf..0256ef4 100644 --- a/knowledge/glossary/loinc-rsna-radiology-playbook.md +++ b/knowledge/glossary/loinc-rsna-radiology-playbook.md @@ -4,7 +4,7 @@ title: LOINC/RSNA Radiology Playbook description: The jointly governed radiology part of LOINC that names imaging orderables along modality, anatomy, and technique axes. tags: [glossary, semantic-foundation, terminologies, exam-types] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: playbook resource: https://loinc.org/committee/radiology/ @@ -24,7 +24,7 @@ sources: The radiology portion of [LOINC](/glossary/loinc.md), developed jointly by the Regenstrief Institute and the RSNA, which names imaging orderables along axes such as modality, anatomy, and technique.[^playbook] It is "actively governed, and freely licensed for commercial and non-commercial use. The Playbook ships twice yearly under joint Regenstrief/RSNA governance, but it is a separate artifact" from [RadLex](/glossary/radlex.md).[^current-understanding] -In OIDM the Playbook is the stated basis for [exam types](/glossary/exam-type.md), and it appears only in design documents. The terminology tool's roadmap makes it "first-class in `radiology`," planning to detect both LOINC codes and legacy `RPID` Playbook identifiers, to rank orderable queries toward Playbook terms while ranking finding and anatomy queries toward RadLex, and to carry Playbook, RPID, and RadLex anatomy correspondences in crosswalk provenance.[^roadmap] The earliest statement of the idea is older still: the curated anatomic location set's roadmap calls for "a companion for exam types based on LOINC/RadLex Playbook exam definitions that specify all included body parts for the exam."[^al-site] +In OIDM the Playbook is the stated basis for [exam types](/glossary/exam-type.md), and it appears only in design documents. The terminology roadmap makes it "first-class in `radiology`," with planned detection of LOINC codes and legacy `RPID` Playbook identifiers. Orderable queries would favor Playbook terms, and finding and anatomy queries would favor RadLex. Crosswalk provenance would record Playbook, RPID, and RadLex anatomy correspondences.[^roadmap] The earliest statement of the idea is older still: the curated anatomic location set's roadmap calls for "a companion for exam types based on LOINC/RadLex Playbook exam definitions that specify all included body parts for the exam."[^al-site] ## Synonyms and near-synonyms diff --git a/knowledge/glossary/loinc.md b/knowledge/glossary/loinc.md index 16e5988..e1baf15 100644 --- a/knowledge/glossary/loinc.md +++ b/knowledge/glossary/loinc.md @@ -27,7 +27,7 @@ sources: Logical Observation Identifiers Names and Codes, the Regenstrief Institute's system for identifying laboratory and clinical observations, including imaging procedures.[^loinc] In OIDM, LOINC's job is [exam type](/glossary/exam-type.md) identification, not finding identification. -An [Exam Finding List](/glossary/exam-finding-list.md) carries the exam's LOINC code as `examInfo.studyLoincCode`, described as "LOINC codes: Used for exam type identification (e.g., '72133-2' = CT Abdomen and Pelvis Without Contrast)."[^ipl-claude] The specification says the structure "must also have basic information (keyed by a curated list of LOINC codes) about what exam this is."[^ipl-readme] The lineage FHIR sample codes its DiagnosticReport the same way, with `87279-6 CT Chest for Screening`.[^fhir-sample] +An [Exam Finding List](/glossary/exam-finding-list.md) carries the exam's LOINC code as `examInfo.studyLoincCode`, described as "LOINC codes: Used for exam type identification (e.g., '72133-2' = CT Abdomen and Pelvis Without Contrast)."[^ipl-claude] The imaging-problem-list README says the structure "must also have basic information (keyed by a curated list of LOINC codes) about what exam this is."[^ipl-readme] The lineage FHIR sample codes its DiagnosticReport the same way, with `87279-6 CT Chest for Screening`.[^fhir-sample] The division of labour is stated in the terminology roadmap: radiology "orderables live in the LOINC/RSNA Radiology Playbook, while findings, anatomy, and report language live in RadLex."[^roadmap] @@ -48,7 +48,7 @@ Digits, a hyphen, and a check digit, for example `72133-2`. The lookup tooling a ## Conflicts -The "curated list of LOINC codes" the specification refers to does not exist as an artifact. Exam types are documented as goals and as building blocks, not as a published catalog; see [Exam types](/roadmap/exam-types.md). +The "curated list of LOINC codes" that exam-type documents refer to does not exist as an artifact. Exam types are documented as goals and as building blocks, not as a published catalog; see [Exam types](/roadmap/exam-types.md). [^loinc]: LOINC, Regenstrief Institute [^ipl-claude]: imaging-problem-list domain model, dev branch diff --git a/knowledge/glossary/observation.md b/knowledge/glossary/observation.md index ea59576..21ed990 100644 --- a/knowledge/glossary/observation.md +++ b/knowledge/glossary/observation.md @@ -4,7 +4,7 @@ title: Observation description: The atomic unit of OIDM data, one finding seen or excluded on one exam, with its anatomic location and attribute values. tags: [glossary, data-structures] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: deck resource: https://gamma.app/docs/Open-Imaging-Data-Model-2026-Status-Update:-Realizing-Object-Oriented-Imaging-Results-yfxzx4q9zssafal @@ -29,7 +29,7 @@ The atomic unit of OIDM data: one finding, seen or explicitly excluded, on one e In the current [Exam Finding List](/glossary/exam-finding-list.md) format an observation is one entry in the `findings` array, with an `observationId`, a `findingCode` and description, an `attributes` array, an optional `anatomicLocation`, and an optional verbatim `reportText`. Repeat instances are separate observations: "the same finding type may appear multiple times, for example multiple kidney stones, and each gets its own entry with a unique `observationId`."[^ipl-claude] -The FHIR lineage is direct. The 2024 reference implementation's `Observation` class states "the Observation class is the model for FHIR Observation objects," with `code`, `status`, `subject`, `bodySite`, `derivedFrom`, and a discriminated union of components.[^lineage-obs] +The 2024 reference implementation's `Observation` class states "the Observation class is the model for FHIR Observation objects," with `code`, `status`, `subject`, `bodySite`, `derivedFrom`, and a discriminated union of components.[^lineage-obs] ## Synonyms and near-synonyms diff --git a/knowledge/glossary/oifm.md b/knowledge/glossary/oifm.md index 093dac8..6ba2bb8 100644 --- a/knowledge/glossary/oifm.md +++ b/knowledge/glossary/oifm.md @@ -4,7 +4,7 @@ title: OIFM description: Open Imaging Finding Model, the OIDM specification for a finding definition, and the prefix of the identifiers that specification mints. tags: [glossary, semantic-foundation, finding-models] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: fm-py resource: https://github.com/openimagingdata/findingmodel/blob/75afd39a400419dcfaf7c8d4a34f065b4d804e0d/packages/findingmodel/src/findingmodel/finding_model.py @@ -19,7 +19,7 @@ sources: # OIFM -**Open Imaging Finding Model (OIFM).** The OIDM specification that defines what a [finding model](/glossary/finding-model.md) is: a named radiology finding with a description, optional synonyms and tags, a list of characterizing [attributes](/glossary/attribute.md), optional [anatomic locations](/glossary/anatomic-location.md) and [index codes](/glossary/index-code.md), and optional [contributors](/glossary/contributor.md).[^fm-schema] The canonical statement of the format is the `FindingModelFull` Pydantic model in the `findingmodel` package.[^fm-py] +**Open Imaging Finding Model (OIFM).** The OIDM specification that defines what a [finding model](/glossary/finding-model.md) is: a named radiology finding with a description, optional synonyms and tags, a list of characterizing [attributes](/glossary/attribute.md), optional [anatomic locations](/glossary/anatomic-location.md) and [index codes](/glossary/index-code.md), and optional [contributors](/glossary/contributor.md).[^fm-schema] The format is defined by the `FindingModelFull` Pydantic model in the `findingmodel` package.[^fm-py] "OIFM" is also the literal prefix of the identifier minted for each finding model, which is why the two senses are easy to confuse. The deck expands the acronym as "Open Imaging Finding Models" when counting content, reporting nearly 3,000 definitions.[^deck] diff --git a/knowledge/glossary/presence.md b/knowledge/glossary/presence.md index 7f72679..57a1535 100644 --- a/knowledge/glossary/presence.md +++ b/knowledge/glossary/presence.md @@ -4,7 +4,7 @@ title: Presence description: The near-universal first attribute of a finding model, asserting that a finding was present, absent, indeterminate, or unknown, and the dot-code convention that encodes those values. tags: [glossary, semantic-foundation, data-structures] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: overview resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/notes/oifm-overview.md @@ -27,15 +27,15 @@ sources: The assertion that a finding was present, absent, indeterminate, or unknown on an exam. Authoring guidance makes it the required first [attribute](/glossary/attribute.md) of every [finding model](/glossary/finding-model.md), with the value set "absent, present, indeterminate, unknown."[^overview] -Presence carries the project's central claim that a negative is data. "Findings must cover negative assertions. When a radiologist states 'no fracture' or 'upper abdomen is unremarkable,' that's an active observation of absence that needs to be captured... The `presence: absent` observation is clinically meaningful, it means the finding was looked for and not found."[^overview] +"Findings must cover negative assertions. When a radiologist states 'no fracture' or 'upper abdomen is unremarkable,' that's an active observation of absence that needs to be captured... The `presence: absent` observation is clinically meaningful, it means the finding was looked for and not found."[^overview] -**The dot-code convention.** Value codes are generated by appending a dot and the value's zero-based position in the attribute's value list.[^fm-py] Where the standard ordering is used, that gives `.0` absent, `.1` present, `.2` indeterminate, `.3` unknown, which is the convention consuming code documents: "`.1` = present, `.0` = absent."[^ipl-claude] Across the 2,382 published definitions, 2,261 carry a presence attribute and 2,223 of those use that ordering. +Value codes append a dot and the value's zero-based position in the attribute's value list.[^fm-py] The standard ordering gives `.0` absent, `.1` present, `.2` indeterminate, `.3` unknown, which is the convention consuming code documents: "`.1` = present, `.0` = absent."[^ipl-claude] Across the 2,382 published definitions, 2,261 carry a presence attribute and 2,223 of those use that ordering. ## Synonyms and near-synonyms - **Presence or absence** and **present/absent** describe the same attribute. - **Detected** is IHE IDR's value for the same assertion.[^idr] -- **Indeterminate** means the exam could not determine it; **unknown** means it was not assessed. The two are distinct values, not spellings of one. +- **Indeterminate** means the exam could not determine it; **unknown** means it was not assessed. These are distinct values. - **[Change from prior](/glossary/change-from-prior.md)** is the companion second attribute, not part of presence. ## Identifier form diff --git a/knowledge/glossary/provenance.md b/knowledge/glossary/provenance.md index ff4e10f..5fe5ecf 100644 --- a/knowledge/glossary/provenance.md +++ b/knowledge/glossary/provenance.md @@ -4,7 +4,7 @@ title: Provenance description: The record of where an observation came from, a radiologist, an AI tool, or a language model reading a report, and of the text that supports it. tags: [glossary, data-structures, extraction] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: ipl-readme resource: https://github.com/openimagingdata/imaging-problem-list/blob/06f64a7893b444b761dc069ed86140a081195eac/README.md @@ -25,15 +25,15 @@ sources: # Provenance -The record of where an [observation](/glossary/observation.md) came from. The [Exam Finding List](/glossary/exam-finding-list.md) specification states the requirement directly: findings "can be generated by LLM from an existing report or generated live during exam time; each Observation should include some kind of provenance marker."[^ipl-readme] +The record of where an [observation](/glossary/observation.md) came from. The [Exam Finding List](/glossary/exam-finding-list.md) specification requires a marker: findings "can be generated by LLM from an existing report or generated live during exam time; each Observation should include some kind of provenance marker."[^ipl-readme] -Provenance matters because sources are not interchangeable. The deck lists AI validation as a stated ACR priority, specifically the ability to "correlate AI vs radiologist Observations," which is only possible if the two are distinguishable.[^deck] The lineage FHIR samples make the distinction with FHIR `status`: an AI-generated finding carries `preliminary` and the radiologist's carries `final`, with otherwise identical structure.[^fhir-ai] +The deck lists AI validation as a stated ACR priority, requiring the ability to "correlate AI vs radiologist Observations," which is only possible if the two are distinguishable.[^deck] The lineage FHIR samples make the distinction with FHIR `status`: an AI-generated finding carries `preliminary` and the radiologist's carries `final`, with otherwise identical structure.[^fhir-ai] -A second kind of provenance operates within a report. Every extracted finding carries a verbatim `report_text` quote, validated as verbatim rather than paraphrased, so a consumer can see the sentence the structure came from.[^extraction-plan] That quote is what the reviewing tools display and what the evaluation design keys on. +A second kind of provenance operates within a report. Each extracted finding carries a `report_text` quote, validated as verbatim rather than paraphrased, identifying its source sentence.[^extraction-plan] That quote is what the reviewing tools display and what the evaluation design keys on. ## Synonyms and near-synonyms -- **Provenance marker** is the specification's phrase for the field. +- **Provenance marker** is the imaging-problem-list README's phrase for the field. - **Source** and **attribution** are informal equivalents. - **`status`** in FHIR is the field the lineage samples use to carry it. - **Verbatim quote** is evidence for one observation, not a statement of who produced it. diff --git a/knowledge/glossary/radelement.md b/knowledge/glossary/radelement.md index 99af3ed..35f1b23 100644 --- a/knowledge/glossary/radelement.md +++ b/knowledge/glossary/radelement.md @@ -4,7 +4,7 @@ title: RadElement description: The ACR and RSNA registry that publishes common data element sets and elements, and the coding system their identifiers belong to. tags: [glossary, semantic-foundation, terminologies, cde] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: cde-repo resource: https://github.com/openimagingdata/common_data_elements/blob/35536d8c858bcd33e730a00c919edaef2e310a0b/README.md @@ -42,7 +42,7 @@ RadElement is downstream of authoring. Informal definitions are drafted in `CDES ## Conflicts -There is no settled coding-system URI for RadElement codes. IHE IDR asks the question directly, "What is the Coding System identifier for Radelement codes?", and the next-generation work records it as open.[^idr] In practice three forms are in use: `https://radelement.org` in FHIR samples, `RADELEMENT` as an index code system string, and a proposed `RDE2` base in the next-generation notes. Separately, RadElement coverage was found missing from ontology search during metadata enrichment, which made `index_codes` the weakest-scoring field in that pipeline.[^index-fixture] +There is no settled coding-system URI for RadElement codes. IHE IDR asks, "What is the Coding System identifier for Radelement codes?", and the next-generation work records it as open.[^idr] Three forms appear in the sources: `https://radelement.org` in FHIR samples, `RADELEMENT` as an index code system string, and a proposed `RDE2` base in the next-generation notes. Separately, RadElement coverage was found missing from ontology search during metadata enrichment, which made `index_codes` the weakest-scoring field in that pipeline.[^index-fixture] [^cde-repo]: common_data_elements repository README [^radelement]: RadElement registry diff --git a/knowledge/glossary/radlex.md b/knowledge/glossary/radlex.md index 5aa5bfb..f03ab33 100644 --- a/knowledge/glossary/radlex.md +++ b/knowledge/glossary/radlex.md @@ -4,7 +4,7 @@ title: RadLex description: The RSNA radiology lexicon, the ontology that supplies identifiers for anatomic locations and many finding and attribute codes. tags: [glossary, semantic-foundation, terminologies] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: radlex resource: https://radlex.org/ diff --git a/knowledge/glossary/snomed-ct.md b/knowledge/glossary/snomed-ct.md index 21aded2..198fa42 100644 --- a/knowledge/glossary/snomed-ct.md +++ b/knowledge/glossary/snomed-ct.md @@ -4,7 +4,7 @@ title: SNOMED CT description: The clinical terminology used in OIDM as a secondary coding system on findings, attribute values, and anatomic locations. tags: [glossary, semantic-foundation, terminologies] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: snomed resource: https://www.snomed.org/ @@ -25,7 +25,7 @@ sources: # SNOMED CT -The Systematized Nomenclature of Medicine Clinical Terms, the general clinical terminology.[^snomed] In OIDM it is a secondary coding system rather than a primary key. It appears in three places: as an [index code](/glossary/index-code.md) system on [finding models](/glossary/finding-model.md), [attributes](/glossary/attribute.md), and [attribute values](/glossary/attribute-value.md), listed alongside [RadLex](/glossary/radlex.md) and [Gamuts](/glossary/gamuts.md) as one of the common ontologies;[^claude-md] as a cross-reference on [anatomic locations](/glossary/anatomic-location.md), present on 1,732 of the 2,890 records in the curated set;[^al-code] and in the FHIR lineage samples as the code system for a report's category and its conclusion codes.[^fhir-sample] +The Systematized Nomenclature of Medicine Clinical Terms, the general clinical terminology.[^snomed] OIDM uses it for secondary codes, not primary keys. Alongside [RadLex](/glossary/radlex.md) and [Gamuts](/glossary/gamuts.md), it supplies [index codes](/glossary/index-code.md) on [finding models](/glossary/finding-model.md), [attributes](/glossary/attribute.md), and [attribute values](/glossary/attribute-value.md).[^claude-md] SNOMED CT cross-references appear on 1,732 of 2,890 curated [anatomic locations](/glossary/anatomic-location.md).[^al-code] FHIR lineage samples use it for report category and conclusion codes.[^fhir-sample] Typical use on a value is the qualifier hierarchy, for example `52101004` for Present and `2667000` for Absent, paired with the equivalent RadLex codes on the same value. @@ -45,7 +45,7 @@ A numeric concept identifier, for example `23043003` for uterine adnexa. ## Conflicts -SNOMED CT is licensed, which is why the lookup tooling treats it as a credentialed backend and keeps licensed behavior opt-in and visible rather than implicit.[^molu] The curated anatomic set also records "complete SNOMED identification" as unfinished roadmap work, so SNOMED coverage of anatomic locations is partial by design. +SNOMED CT requires a licence. The lookup tooling keeps licensed behavior opt-in and visible rather than implicit.[^molu] The curated anatomic set also records "complete SNOMED identification" as unfinished roadmap work, so SNOMED coverage of anatomic locations is partial by design. [^snomed]: SNOMED International [^molu]: med-ontology-lookup README diff --git a/knowledge/glossary/tag.md b/knowledge/glossary/tag.md index c79c5dc..0a09e80 100644 --- a/knowledge/glossary/tag.md +++ b/knowledge/glossary/tag.md @@ -4,7 +4,7 @@ title: Tag description: A free-text clinical category attached to a finding model for organization and retrieval, distinct from the typed structured metadata that is replacing it. tags: [glossary, semantic-foundation, finding-models] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: fm-py resource: https://github.com/openimagingdata/findingmodel/blob/75afd39a400419dcfaf7c8d4a34f065b4d804e0d/packages/findingmodel/src/findingmodel/finding_model.py @@ -21,7 +21,7 @@ sources: "Tags that might be used to categorize the finding among other findings."[^fm-py] Tags are an optional list of free-text strings on a [finding model](/glossary/finding-model.md). The authoring guidance describes them as "clinical categories (anatomy, modality, etiology) for organization and retrieval."[^overview] -Tags are untyped and unvalidated. A real definition in the corpus carries `["ultrasound", "CT", "US", "XR", "urological", "obstructive", "diagnosis"]` on one finding, mixing modality abbreviations, two spellings of the same modality, a subspecialty, an etiology, and an entity type in one list. That looseness is the reason the metadata rewrite exists. +Tags are untyped and unvalidated. A real definition in the corpus carries `["ultrasound", "CT", "US", "XR", "urological", "obstructive", "diagnosis"]`, mixing modality abbreviations, two spellings of the same modality, a subspecialty, an etiology, and an entity type in one list. The metadata rewrite addresses this inconsistency. ## Synonyms and near-synonyms @@ -40,7 +40,7 @@ None. Tags are bare strings with no registry. ## Conflicts -Tags and the new typed fields overlap: a tag reading `CT` and an `applicable_modalities` entry of `CT` say the same thing in two places. The rewrite states that structured metadata should be canonical model state rather than sidecar output, but it does not say what becomes of the existing tag lists, and nothing has landed on `main`.[^metadata-rewrite] +Tags and the new typed fields overlap: a tag reading `CT` and an `applicable_modalities` entry of `CT` say the same thing in two places. The rewrite specifies that structured metadata should be the model's own state rather than sidecar output, but it does not say what becomes of the existing tag lists, and nothing has landed on `main`.[^metadata-rewrite] [^fm-py]: TagSequence field description in the findingmodel package [^overview]: "Finding Models: Overview" diff --git a/knowledge/glossary/technical-finding.md b/knowledge/glossary/technical-finding.md index c383e5a..e319c2e 100644 --- a/knowledge/glossary/technical-finding.md +++ b/knowledge/glossary/technical-finding.md @@ -4,7 +4,7 @@ title: Technical finding description: A finding stated in modality-specific imaging language, such as a density or signal characteristic, without committing to an underlying diagnosis. tags: [glossary, semantic-foundation, data-structures] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: tech resource: https://github.com/openimagingdata/imaging-problem-list/blob/36fa30c7383bf687d7bc17815282a93e123a56cb/docs/technical-imaging-findings.md @@ -23,7 +23,7 @@ A finding stated in modality-specific imaging language. "'Technical findings' de The reference catalogs them by modality: CT attenuation terms such as hypodense lesion and ground-glass opacity; MR signal terms such as diffusion restriction and marrow signal abnormality; enhancement and opacification patterns such as washout and filling defect; ultrasound echogenicity terms such as anechoic structure and posterior acoustic shadowing; and nuclear medicine terms such as FDG-avid lesion and photopenic area.[^tech] -The distinction that matters for coding is observation versus interpretation. "The same imaging appearance can be described at observation level ('T2 hyperintense marrow signal') or interpretation level ('marrow edema'). Reports often mix both. The ontology needs entries at the observation level to capture what's actually seen." The guidance is specific: "marrow signal abnormality should be searched as exactly that, it is the observation. Do NOT reinterpret as 'bone marrow edema' or 'marrow infiltration', which are specific diagnoses that may or may not be the cause."[^tech] +The distinction that matters for coding is observation versus interpretation. "The same imaging appearance can be described at observation level ('T2 hyperintense marrow signal') or interpretation level ('marrow edema'). Reports often mix both. The ontology needs entries at the observation level to capture what's actually seen." The guidance states: "marrow signal abnormality should be searched as exactly that, it is the observation. Do NOT reinterpret as 'bone marrow edema' or 'marrow infiltration', which are specific diagnoses that may or may not be the cause."[^tech] ## Synonyms and near-synonyms diff --git a/knowledge/glossary/umls.md b/knowledge/glossary/umls.md index eca1749..beb6621 100644 --- a/knowledge/glossary/umls.md +++ b/knowledge/glossary/umls.md @@ -4,7 +4,7 @@ title: UMLS description: The Unified Medical Language System, used in OIDM as the hub for translating identifiers between terminologies and as a cross-reference on anatomic locations. tags: [glossary, semantic-foundation, terminologies] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: umls resource: https://www.nlm.nih.gov/research/umls/index.html @@ -22,11 +22,11 @@ sources: # UMLS -The Unified Medical Language System, the US National Library of Medicine's integration of many source vocabularies under shared concept identifiers.[^umls] OIDM uses it for two jobs. +The Unified Medical Language System, the US National Library of Medicine's integration of many source vocabularies under shared concept identifiers.[^umls] -The first is crosswalking. The `molu` lookup tool resolves a concept to its UMLS concept unique identifiers and then translates to codes in other vocabularies; the stated design makes "UMLS as the CUI hub" part of the default radiology profile, alongside [RadLex](/glossary/radlex.md), [LOINC](/glossary/loinc.md), [SNOMED CT](/glossary/snomed-ct.md), and [FMA](/glossary/fma.md).[^roadmap][^molu] The roadmap is explicit that a crosswalk is not an equivalence: translation should preserve "mapping direction, scope, provenance, and strength instead of treating every cross-reference as equivalence."[^roadmap] +The `molu` lookup tool resolves a concept to its UMLS concept unique identifiers and then translates to codes in other vocabularies. The design makes "UMLS as the CUI hub" part of the default radiology profile, alongside [RadLex](/glossary/radlex.md), [LOINC](/glossary/loinc.md), [SNOMED CT](/glossary/snomed-ct.md), and [FMA](/glossary/fma.md).[^roadmap][^molu] The roadmap is explicit that a crosswalk is not an equivalence: translation should preserve "mapping direction, scope, provenance, and strength instead of treating every cross-reference as equivalence."[^roadmap] -The second is as a cross-reference code on [anatomic locations](/glossary/anatomic-location.md), present on 578 of the 2,890 records in the curated set.[^al-code] +UMLS also supplies cross-reference codes on [anatomic locations](/glossary/anatomic-location.md), present on 578 of the 2,890 records in the curated set.[^al-code] ## Synonyms and near-synonyms @@ -45,7 +45,7 @@ The second is as a cross-reference code on [anatomic locations](/glossary/anatom ## Conflicts -UMLS requires a licence and an API key, so any OIDM tooling that depends on it fails differently for an unlicensed caller. The lookup tool's typed failure model exists partly for this reason, separating absence of a result from authentication, authorization, and licensing failures so the latter stay visible rather than silently falling back.[^molu] A tracked issue also records that co-occurring CUI ambiguity is currently lost rather than preserved. +UMLS requires a licence and API key. The lookup tool's typed failure model exists partly for this reason, separating absence of a result from authentication, authorization, and licensing failures, so the latter stay visible rather than silently falling back.[^molu] A tracked issue also records that co-occurring CUI ambiguity is currently lost rather than preserved. [^umls]: Unified Medical Language System [^molu]: med-ontology-lookup README diff --git a/knowledge/guides/authoring-guide.md b/knowledge/guides/authoring-guide.md index ce8e093..53f6a1b 100644 --- a/knowledge/guides/authoring-guide.md +++ b/knowledge/guides/authoring-guide.md @@ -4,7 +4,7 @@ title: Authoring guide description: How humans and agents write, migrate, link, and verify documents in this knowledgebase. tags: [meta, conventions, okf] status: draft -generated: { by: claude-fable-5-1/claude-code, at: 2026-09-21T01:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: okf-spec resource: https://github.com/GoogleCloudPlatform/open-knowledge-format/blob/main/SPEC.md @@ -16,9 +16,9 @@ sources: # Overview -This repository is the canonical, public, high-level documentation for the Open Imaging Data Model (OIDM). It is an Open Knowledge Format (OKF) 0.2 bundle: a directory of markdown files with YAML frontmatter that both people and agents read.[^okf-spec] The bundle lives in `knowledge/`. Everything in this guide is enforced by two checkers described at the end. +This repository holds the canonical public, high-level documentation for the Open Imaging Data Model (OIDM). The `knowledge/` directory is an Open Knowledge Format (OKF) 0.2 bundle of Markdown files with YAML frontmatter for people and agents.[^okf-spec] Everything in this guide is enforced by two checkers described at the end. -Three rules summarize the house style: +Follow these rules: 1. One concept per file, typed, described, and sourced. 2. Facts and stated goals only. Proposals belong to a separate workstream and are marked as such when they arrive. @@ -40,13 +40,14 @@ Three rules summarize the house style: | `guides/` | This guide and the migration ledger | | `plans/` | Plans for building and maintaining the knowledgebase | -Every directory has an `index.md` that lists each concept and subdirectory in it, one entry per line. Index entries use the `./` prefix so the site's absolute link resolution keeps them inside the directory: +Each directory needs an `index.md` listing its concepts and subdirectories, one per line. Index entries use the `./` prefix so the site's absolute link resolution keeps them inside the directory: ```markdown * [Title](./file.md) - description * [Subdirectory](./subdir/) - description ``` - Index files carry no frontmatter, except the bundle root, which declares `okf_version`. `log.md` at the root records changes newest first under `## YYYY-MM-DD` headings. + +Only the bundle-root index has frontmatter, declaring `okf_version`. Record changes newest first in root `log.md`, under `## YYYY-MM-DD` headings. # Frontmatter @@ -69,7 +70,7 @@ sources: --- ``` -**Types.** `type` must be one of the controlled vocabulary below. Inherited from the ACR-RSNA-CDEs next-gen bundle:[^cde-checker] Reference, Analysis, Decision Record, Proposal, Playbook, Worked Example, Presentation Extract, Meeting Notes, Draft Specification, Gap Log, Exploration. Added here: Overview, Concept, Glossary Term, Format Specification, Data Structure, Project Profile, Guide, Roadmap, History, Source Extract, Plan. Proposal and Decision Record are reserved for the proposals workstream. +**Types.** `type` must be one of the controlled vocabulary below. It inherits Reference, Analysis, Decision Record, Proposal, Playbook, Worked Example, Presentation Extract, Meeting Notes, Draft Specification, Gap Log, and Exploration from the ACR-RSNA-CDEs next-gen bundle.[^cde-checker] This repository adds Overview, Concept, Glossary Term, Format Specification, Data Structure, Project Profile, Guide, Roadmap, History, Source Extract, and Plan. Reserve Proposal and Decision Record for the proposals workstream. | Type | Use it for | |---|---| @@ -88,11 +89,11 @@ sources: | Worked Example | A concrete example with real data | | Plan | A plan for work on this knowledgebase | -**Status and trust.** Every agent-written document starts as `status: draft`. When the project lead reviews it, they add `verified: [{ by: human:talkasab, at: }]` and set `status: stable`. Deprecated documents keep their content, get `status: deprecated`, and are noted in `log.md`. Project profiles and roadmap documents set `stale_after` one year out. +**Status and trust.** Start agent-written documents as `status: draft`. After review, the project lead adds `verified: [{ by: human:talkasab, at: }]` and sets `status: stable`. Keep deprecated content, set `status: deprecated`, and note it in `log.md`. Set `stale_after` one year out for project profiles and roadmaps. -**Actors.** `generated.by` and `verified[].by` follow the OKF actor convention: `/` for an agent or tool, `human:` for a person, `process:` for automation. Use the `human:` prefix whenever a person authored or signed off; trust tiers key off it. +**Actors.** Use `/` for agents or tools, `human:` for people, and `process:` for automation in `generated.by` and `verified[].by`, following the OKF actor convention. Use the `human:` prefix whenever a person authored or signed off; trust tiers key off it. `generated` names the actor that last wrote the document's text; a copy-editing pass by another actor updates it, and the pass is recorded once in log.md. -**Sources.** List what you actually read. Pin GitHub links to a commit, not a branch, so a reader can tell what version was read. Attribute a specific claim in the body with a footnote whose label matches a source `id`, as this guide does. A migrated document lists its origin as its first source. +**Sources.** List what you actually read. Pin GitHub links to a commit, not a branch, so a reader can tell what version was read. Attribute claims with footnote labels matching source `id` values. Put a migrated document's origin first. # Writing @@ -108,11 +109,11 @@ sources: ``` - Link to code and content by commit-pinned GitHub URL, and to deployed tools by their live URL. -- Prefer short sections, tables for field lists, and fenced code for examples. No empty headings. Balanced code fences. +- Use short sections, tables for field lists, and fenced code for examples. Keep headings nonempty and code fences balanced. # Migrating a document from a working repository -1. Confirm it is documentation, not code documentation. Install steps, API usage, and developer workflow stay with the code. +1. Confirm it is documentation, not code documentation. Keep installation, API usage, and developer workflow with the code. 2. Copy the substance. Rewrite only for consistency of terms and to remove individual names. Keep the author's structure. 3. Add frontmatter: an appropriate type, `status: draft`, `generated` naming you, and `sources` whose first entry is the origin file at its commit. 4. Add glossary links on first use of terms, and links to related concepts. @@ -129,7 +130,7 @@ uv run .agents/skills/validate/scripts/okf_validate.py knowledge --strict uv run tools/check_bundle.py ``` -The first checks OKF 0.2 conformance and warns on legacy fields. The second enforces this guide: type vocabulary, required frontmatter, trust-signal shape, index coverage for every directory, link resolution, balanced fences, and a sweep for email addresses and denylisted names. The denylist lives at `tools/denylist.txt`, is ignored by git, and is maintained by the project lead. Continuous integration runs both on every push and pull request. +The first checks OKF 0.2 conformance and warns on legacy fields. The second enforces this guide: type vocabulary, required frontmatter, trust-signal shape, index coverage for every directory, link resolution, balanced fences, and a sweep for email addresses and denylisted names. The project lead maintains the gitignored `tools/denylist.txt`. Continuous integration runs both on pushes to `main` and pull requests. [^okf-spec]: Open Knowledge Format specification, version 0.2 [^cde-checker]: Bundle checker from the ACR-RSNA-CDEs next-gen-2026 branch diff --git a/knowledge/guides/migration-ledger.md b/knowledge/guides/migration-ledger.md index c927d5e..b83a7af 100644 --- a/knowledge/guides/migration-ledger.md +++ b/knowledge/guides/migration-ledger.md @@ -4,12 +4,12 @@ title: Migration ledger description: Every document migrated into this knowledgebase from a working repository, with its origin, commit, and destination. tags: [meta, migration] status: draft -generated: { by: claude-fable-5-1/claude-code, at: 2026-09-21T01:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } --- # Overview -This ledger records each document whose substance moved from a working repository into this bundle. It is the work list for the follow-up round in which working repositories replace migrated documents with links here. Add a row whenever you migrate, per the [authoring guide](/guides/authoring-guide.md). +This ledger records each document whose substance moved from a working repository into this bundle. It is the work list for the follow-up round in which working repositories replace migrated documents with links here. Add a row whenever you migrate, following the [authoring guide](/guides/authoring-guide.md). # Ledger diff --git a/knowledge/history/cde-template-rendering.md b/knowledge/history/cde-template-rendering.md index 34ddd47..5774619 100644 --- a/knowledge/history/cde-template-rendering.md +++ b/knowledge/history/cde-template-rendering.md @@ -1,10 +1,10 @@ --- type: History title: CDE template rendering -description: The 2023 CDETemplateDemo pattern that turned a CDE-labeled Observation into report prose through a Mustache template, and how it relates to the reporting SDK direction. +description: How CDETemplateDemo rendered structured Observations through Mustache templates in 2023, a precedent for the proposed reporting SDK. tags: [history, reporting, observation, cde] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T02:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: mapper resource: https://github.com/openimagingdata/CDETemplateDemo/blob/e09f2553de58b2c88ea26e9673750a62803d4dbc/mapper-logic/src/mappers/obsToMustache.ts @@ -28,15 +28,15 @@ sources: # What it was -`CDETemplateDemo` is a small full-stack demonstration written in 2023 and untouched since 2023-06-15. Its whole purpose was to show that structured data can be turned back into readable report prose without a language model, by rendering a [CDE](/glossary/cde.md)-labeled [Observation](/glossary/observation.md) through a text template. The demonstration was shown at SIIM in June 2023 as a web service that takes a radiology finding encoded as a FHIR Observation with CDE tags and generates customizable prose.[^siim-post] +`CDETemplateDemo` renders a [CDE](/glossary/cde.md)-labeled [Observation](/glossary/observation.md) as report prose through a text template, without a language model. Written in 2023 and unchanged since 2023-06-15, it was shown at SIIM in June 2023 as a web service that generated customizable prose from FHIR Observations.[^siim-post] -It is the earliest working structured-data-to-text generator in the project, and the direction it points is still live. See [lineage repositories](/history/lineage-repositories.md) for the repository's status. +It is the project's earliest working generator of prose from structured data. See [lineage repositories](/history/lineage-repositories.md) for the repository's status. # The pattern in three parts **The Observation.** A sample pneumothorax Observation carries `code` as the RadElement set code RDES44, a `bodySite` coded against the anatomic locations system, and a `component` array whose entries each carry an element code and a value.[^observation] Six components appear: lung tissue collapse, presence, pleural separation in millimeters, side, size, and associated chest tube, plus signs of tension. -**The mapper.** `obsToMustache.ts` flattens the Observation's components into a plain key-value dictionary keyed by the component display name.[^mapper] It then does two things that matter. It sets a boolean flag named after each value, so that any value can drive a template section. And it special-cases the presence component, deriving two explicit flags, one true when presence is present and one true when it is absent. +**The mapper.** `obsToMustache.ts` flattens the Observation's components into a plain key-value dictionary keyed by the component display name.[^mapper] It sets a boolean flag for each value to control template sections. Presence has two flags, one for present and one for absent. ```typescript if (key.toLowerCase() === "presence") { @@ -64,21 +64,21 @@ There is no pneumothorax. {{/presence_absent}} ``` -Rendered against the sample Observation, that produces: "There is a Medium Left pneumothorax (pleural separation: 28 mm). There is Partial lung tissue collapse." The absent branch would instead produce a single sentence, which is exactly the shape the negative-statement problem in [extraction approaches](/history/extraction-approaches.md) works in the opposite direction. +Rendered against the sample Observation, that produces: "There is a Medium Left pneumothorax (pleural separation: 28 mm). There is Partial lung tissue collapse." The absent branch produces a single sentence. [Extraction approaches](/history/extraction-approaches.md) describes the reverse task of extracting explicit negatives. # What the demo also shows by accident -The Observation class inside this repository is not the FHIR one. It models components as a flat record of string keys to string values, with the code and body site reduced to an identifier and a display string.[^obs-model] The sample JSON files on disk are full FHIR Observations, so the demo reads FHIR and works internally with something simpler. That divergence is why the repository is recorded as superseded: the FHIR-faithful Observation in `OpenImagingDataModel.py` became the reference shape, and the flat variant did not carry forward. The flattening itself did, as a rendering step rather than a data model. +The internal Observation class stores components as string key-value pairs and reduces the code and body site to an identifier and display string.[^obs-model] The sample files contain full FHIR Observations. The FHIR-based Observation in `OpenImagingDataModel.py` superseded this simplified internal model. Flattening remained a rendering step. -The mapper also has a hardcoded assumption worth naming: presence is the only attribute given special treatment, and every other value becomes a bare boolean flag. That works because presence is the one attribute the current [finding model format](/semantic-foundation/finding-models/finding-model-format.md) also treats as near-universal. +Only presence receives special treatment. Other values become boolean flags. Presence is also near-universal in the current [finding model format](/semantic-foundation/finding-models/finding-model-format.md). # Relation to the reporting SDK idea -The January 2026 status deck names an Open Imaging Reporting SDK under its applications pillar, positioned as the vendor-facing surface through which reporting tools consume OIDM structures.[^deck] No such artifact exists; see [the reporting SDK](/applications/reporting-sdk.md), which records it as stated direction only. +The January 2026 status deck names an Open Imaging Reporting SDK under its applications pillar, for vendors to use OIDM structures in reporting tools.[^deck] No such artifact exists; see [the reporting SDK](/applications/reporting-sdk.md), which records it as stated direction only. -This demonstration is the concrete precedent for one half of what such an SDK would have to do. The 2023 next-generation reporting assistance framework post described the other half, a plugin container in which assistance scripts run against standardized report context and can insert generated text into a report. Rendering a structured observation into a sentence is the operation those scripts would call; see [site articles](/history/site-articles.md) for that post. +The 2023 next-generation reporting assistance framework post described a plugin container whose scripts inspect standard report context and insert generated text. This demo provides a precedent for that rendering operation. See [site articles](/history/site-articles.md). -Three facts about the demonstration are worth carrying into any later work on this. The template is per-CDE-set, stored under a directory named for the set identifier, so the unit of authoring is the finding rather than the report. The template is data, not code, so a site can maintain its own phrasing without touching the renderer. And the renderer itself is about thirty lines, because all the semantics live in the codes. +Each CDE set has a template in a directory named for its identifier, so templates describe findings rather than reports. A site can change template wording without modifying the renderer. The renderer is about thirty lines because the codes carry the semantics. [^mapper]: CDETemplateDemo obsToMustache.ts, the Observation to template-data mapper [^template]: CDETemplateDemo pneumothorax Mustache template diff --git a/knowledge/history/extraction-approaches.md b/knowledge/history/extraction-approaches.md index 22c81c0..b661180 100644 --- a/knowledge/history/extraction-approaches.md +++ b/knowledge/history/extraction-approaches.md @@ -1,10 +1,10 @@ --- type: History title: Extraction approaches -description: Seven successive attempts at turning radiology report text into structured findings, from a template corpus in 2024 to the current extraction platform, and what each one established. +description: Seven report-extraction approaches, their results, and their contributions to the current platform. tags: [history, extraction, llm, findings] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T02:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: template-extraction resource: https://github.com/openimagingdata/template_extraction/tree/4d947d7e7557ce6187a35d592f8199d3abb673cf/templates @@ -43,31 +43,31 @@ sources: # The problem, restated each time -Every one of these efforts answers the same question: given free-text radiology report language, produce structured findings that carry standard codes. They differ in what they start from, what they produce, and how they judge whether the result is right. Read in order, they converge on three conclusions that the current platform treats as settled: extraction must work on real report prose rather than templates, it must produce explicit negatives as well as positives, and it must be judged on faithfulness to the source text rather than on how many findings it emits. +These efforts seek structured, coded findings from radiology reports. Their inputs, outputs, and evaluation methods differ. The current platform extracts from real report prose, includes explicit negatives, and evaluates faithfulness to the source text. # 1. Templates as the source, 2024 to 2025 **SARTemplatesToCDEs** (2023-12 to 2024-03) proposed using a language model to convert Society of Abdominal Radiology reporting templates into CDE sets, starting with rectal cancer staging.[^sar] No conversion code was committed. Its lasting artifact is a hand-written itemized redesign of one CDE set; see [lineage repositories](/history/lineage-repositories.md). -**template_extraction** (2025-06) took the same starting point at scale, accumulating 281 RadReport templates spanning CT, MR, ultrasound, nuclear medicine, and fluoroscopy across neuro, musculoskeletal, chest, abdomen, genitourinary, and cardiac imaging, plus oncology staging templates and two CDE-labeled test templates.[^template-extraction] The script that reads them is short. The corpus is the asset, and it remains unused: it is a candidate vocabulary for [exam types](/semantic-foundation/exam-types/overview.md) as much as for findings, since the templates are named by exam. +**template_extraction** (2025-06) took the same starting point at scale, accumulating 281 RadReport templates spanning CT, MR, ultrasound, nuclear medicine, and fluoroscopy across neuro, musculoskeletal, chest, abdomen, genitourinary, and cardiac imaging, plus oncology staging templates and two CDE-labeled test templates.[^template-extraction] A short script reads the corpus. It remains unused but could supply vocabulary for findings and [exam types](/semantic-foundation/exam-types/overview.md), since templates are named by exam. -What this line established: templates give you the vocabulary a specialty society has agreed on, but not the language radiologists actually dictate, and not the negatives. +Templates supply agreed specialty vocabulary but omit dictated language and negatives. # 2. Ontologies as the source, 2025 **get_ontology_findings** (2025-03) inverted the direction: look through an existing ontology for entries that correspond to imaging findings, so they can be turned into finding models or common data elements.[^get-ontology] It carries a RadLex export and a minimal script. Its narrow single-ontology scope was widened by `med-ontology-lookup`; see [that project profile](/semantic-foundation/terminologies/med-ontology-lookup.md). -What this line established: an ontology tells you what a finding could be called, not which findings are worth modeling or how they are characterized. +Ontologies supply finding names without deciding which findings to model or how to characterize them. # 3. Real report text, retrieval-augmented, 2024 to 2025 -**ReportFindingRefiner** (2024-12 to 2025-05) is the first pipeline built on real report prose.[^refiner] Its architecture is a privacy-first, locally hosted chain: ingest plain-text reports, split each into header, findings, and impression sections, embed the sections with sentence transformers, store them in a local vector database, expose basic, vector, and hybrid search over them, then use a locally run language model to generate a finding model outline from retrieved context and persist it. It separates a search service, a report service, a language model service, and a finding model service, and exposes each step as its own command-line script, including one that generates a finding outline with retrieved context and one without, so the two can be compared. +**ReportFindingRefiner** (2024-12 to 2025-05) is the first pipeline built on real report prose.[^refiner] It processes reports locally for privacy. The pipeline splits plain text into header, findings, and impression sections, embeds them with sentence transformers, and stores them in a local vector database. Basic, vector, and hybrid searches retrieve context for a local language model to generate and store finding model outlines. Separate search, report, language model, and finding model services have command-line scripts for each step. Two scripts compare outline generation with and without retrieved context. -What this line established: retrieval over a real corpus produces better finding definitions than a template does, local models make report text usable without sending it anywhere, and generating a definition is a different task from extracting an instance. +Retrieval over real reports produced better definitions than templates, while local models kept report text private. Definition generation remained distinct from instance extraction. # 4. Manual extraction as a specification, 2024 to 2025 -`CDEStaging` approached extraction by doing it by hand and writing down what broke. Its process document works a chest CT pulmonary angiogram report into a list of what it calls mini-observations, each a finding name with attribute and value lines.[^cde-process] The worked example is short enough to quote: +`CDEStaging` documented manual extraction and its failures. Its process document works a chest CT pulmonary angiogram report into a list of what it calls mini-observations, each a finding name with attribute and value lines.[^cde-process] Its worked example is: ```markdown - pulmonary embolism @@ -87,11 +87,11 @@ What this line established: retrieval over a real corpus produces better finding - side: left ``` -Two observations in that document set the agenda for everything after it. Finding, attribute, and value names have to match the project's own finding definitions, or the extraction is not interoperable. And blanket negative statements such as "Lungs are clear" need their own catalog, because they assert many findings absent in one phrase. +Interoperability requires finding, attribute, and value names to match the project's definitions. Blanket negatives such as "Lungs are clear" need a catalog because one phrase asserts several findings absent. -Three companion files hold the results of that cataloging work. `negative_statements.md` collects composite and negative report statements by organ system. `uncovered_findings.md` lists findings pulled out of reports with no matching definition, a standing gap log.[^cde-uncovered] `missing_attributes.md` collects report phrases whose attributes existing definitions cannot capture.[^cde-negatives] Fifty-seven worked structured extractions sit alongside them. The two branches that carried most of this work, a report-representation branch of 37 commits and a content branch of 33, were never merged; see the work edge section of [the repository map](/repositories/repository-map.md). +Three companion files catalog these gaps. `negative_statements.md` collects composite and negative report statements by organ system. `uncovered_findings.md` lists findings pulled out of reports with no matching definition, a standing gap log.[^cde-uncovered] `missing_attributes.md` collects report phrases whose attributes existing definitions cannot capture.[^cde-negatives] Fifty-seven worked structured extractions sit alongside them. The two branches that carried most of this work, a report-representation branch of 37 commits and a content branch of 33, were never merged; see the work edge section of [the repository map](/repositories/repository-map.md). -What this line established: the hard part is not parsing, it is the vocabulary gap and the treatment of negation. Both are still open; the extraction platform's own validator prompt names "incorrect representation of a blanket negative" as a re-extraction trigger. +Vocabulary gaps and negation remain unresolved. The extraction validator names "incorrect representation of a blanket negative" as a re-extraction trigger. # 5. Embedding similarity, 2025 @@ -104,23 +104,23 @@ What this line established: the hard part is not parsing, it is the vocabulary g | `step2_map.py` | Each extracted finding is embedded and matched by cosine similarity against 15 curated neuro finding models, with a configurable threshold of 0.70 | | `step3_review_mappings.py` | Produces a human-readable mapping summary | -Its output schema is deliberately thin: a finding is a name and a boolean presence; a mapping adds the matched finding model identifier, a confidence score, and a status. It produces neither an [Exam Finding List](/data-structures/exam-finding-list.md) nor an [Imaging Problem List](/data-structures/imaging-problem-list.md), and no FHIR output; the README lists FHIR Observation generation as a future enhancement. Evaluation was informal: 8 sample reports, 87 extracted findings, 5 matched above threshold, 82 flagged for manual review. +A finding contains a name and boolean presence. A mapping adds the matched model identifier, confidence score, and status. It produces neither an [Exam Finding List](/data-structures/exam-finding-list.md) nor an [Imaging Problem List](/data-structures/imaging-problem-list.md), and no FHIR output; the README lists FHIR Observation generation as a future enhancement. Evaluation was informal: 8 sample reports, 87 extracted findings, 5 matched above threshold, 82 flagged for manual review. Three single-commit branches pushed in one week extend it without merging: a longitudinal multiple sclerosis report series, a port of the extraction step to a typed agent framework, and a design note proposing persistent FHIR Observations with stable identifiers, so that repeat mentions of the same lesion across reports attach to one tracked entity with its own timeline. That note adds no code and names two modules that were never written. See [the project profile](/applications/ipl-mvp-extraction.md). -What this line established: a 6 percent match rate at a 0.70 similarity threshold against 15 models is not a mapping strategy. Code assignment needs the index, not the embedding alone. +The 6 percent match rate at a 0.70 threshold against 15 models shows the limits of embedding-only matching and the need for index-based code assignment. # 6. The current extraction platform, 2026 The `dev` branch of `imaging-problem-list` is a full extraction, coding, persistence, and review platform; see [the project profile](/applications/report-extraction-platform.md). Four things distinguish it from everything above. -**A richer extraction schema.** The original plan defines an extracted finding as a finding name, a presence drawn from present, absent, indeterminate, and possible, an optional location with body region, specific anatomy, and laterality, a list of attribute key and value pairs with standard keys for size, acuity, change from prior, severity, count, and morphology, and the verbatim report text it came from.[^ipl-initial-plan] The `possible` value exists specifically to hold hedged language such as "raising the possibility of" or "cannot exclude". +**A richer extraction schema.** The original plan records a finding name, presence, optional location, attributes, and verbatim report text.[^ipl-initial-plan] Presence can be present, absent, indeterminate, or possible. Location includes body region, specific anatomy, and laterality. Attribute key-value pairs use standard keys for size, acuity, change from prior, severity, count, and morphology. `possible` covers hedged language such as "raising the possibility of" or "cannot exclude". **Coding as a separate stage.** Assigning a finding code and a location code happens after extraction, not during it: a deterministic index lookup first, and only where that fails, three language model calls per report chunk to generate search terms, select a finding code from candidates, and select a location code from candidates. See [finding and location coding](/applications/finding-and-location-coding.md). **Verbatim-quote validation.** A validator reviews each extraction against the chunk it came from and names the failure modes that justify re-extraction: content unsupported by the chunk text, report text describing a finding that no structure represents, a finding marked present when it is not or absent when it is possible, a finding name more specific than the text supports, incorrect representation of a blanket negative, and wrong or misscoped location information.[^ipl-validator] -**Evaluation redesigned for honesty.** After three and a half months without implementation, the evaluation plan was cut down rather than abandoned. Version one scores quote-first matching and attribute values rather than raw finding yield, uses frozen run configurations with per-case artifacts, and adjudicates a ten-case gold set through the human review tool. The stated motivation is a specific failure: a model-selection round chose a local default on throughput and yield alone, which cannot distinguish a real recall gain from a fabricated finding.[^ipl-evals] +**Evaluation redesign.** After three and a half months without implementation, the evaluation plan was reduced. Version one scores quote-first matching and attribute values rather than raw finding yield, uses frozen run configurations with per-case artifacts, and adjudicates a ten-case gold set through the human review tool. The stated motivation is a specific failure: a model-selection round chose a local default on throughput and yield alone, which cannot distinguish a real recall gain from a fabricated finding.[^ipl-evals] # What carried forward diff --git a/knowledge/history/index.md b/knowledge/history/index.md index 439ce6a..80610c0 100644 --- a/knowledge/history/index.md +++ b/knowledge/history/index.md @@ -1,10 +1,10 @@ # History -What was tried before OIDM reached its current shape, what survives, and what superseded the rest. +Earlier OIDM work, its surviving contributions, and its successors. -* [Timeline](./timeline.md) - A dated record of the Open Imaging Data Model from its anatomic-location prologue through the January 2026 status update and the 2026 work edge. -* [Lineage repositories](./lineage-repositories.md) - The twelve early OIDM repositories, what each one was for, what survives into current work, and what superseded the rest. -* [Extraction approaches](./extraction-approaches.md) - Seven successive attempts at turning radiology report text into structured findings, from a template corpus in 2024 to the current extraction platform, and what each one established. -* [CDE template rendering](./cde-template-rendering.md) - The 2023 CDETemplateDemo pattern that turned a CDE-labeled Observation into report prose through a Mustache template, and how it relates to the reporting SDK direction. -* [Use case catalog](./use-cases.md) - The roughly 25 use case ideas collected in the UseCases repository, organized by category, with the six value categories used to tag them. +* [Timeline](./timeline.md) - Dated OIDM milestones from anatomic-location work in 2022 through current work in September 2026. +* [Lineage repositories](./lineage-repositories.md) - Twelve early OIDM repositories, their surviving contributions, and their successors. +* [Extraction approaches](./extraction-approaches.md) - Seven report-extraction approaches, their results, and their contributions to the current platform. +* [CDE template rendering](./cde-template-rendering.md) - How CDETemplateDemo rendered structured Observations through Mustache templates in 2023, a precedent for the proposed reporting SDK. +* [Use case catalog](./use-cases.md) - The roughly 25 ideas from UseCases, with source attribution and six value-category tags. * [Site articles](./site-articles.md) - The fifteen posts published on openimagingdata.org between June 2023 and March 2025, plus the About page, each dated, linked, and summarized. diff --git a/knowledge/history/lineage-repositories.md b/knowledge/history/lineage-repositories.md index 935ec80..515fa08 100644 --- a/knowledge/history/lineage-repositories.md +++ b/knowledge/history/lineage-repositories.md @@ -1,10 +1,10 @@ --- type: History title: Lineage repositories -description: The twelve early OIDM repositories, what each one was for, what survives into current work, and what superseded the rest. +description: Twelve early OIDM repositories, their surviving contributions, and their successors. tags: [history, lineage, repositories, fhir] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T02:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: oidm-py-observation resource: https://github.com/openimagingdata/OpenImagingDataModel.py/blob/455e5b68d730ea8829083d73064de0ec316d3c4a/openimagingdatamodel/observation/observation.py @@ -49,7 +49,7 @@ sources: # Why this document exists -Twelve repositories came before the current three-layer structure. Some are dead ends; several hold the precedent that later work still follows, and one of them is still the project's CDE data source. Each section below gives the repository's purpose, its dates, its status in [the repository map](/repositories/repository-map.md), what survives, and what replaced it. +Twelve repositories preceded the current three-layer structure. Several informed later work, and one remains the CDE data source. Their dates, status, and successors are described below and in [the repository map](/repositories/repository-map.md). # The FHIR precedent @@ -66,21 +66,21 @@ Two lineage repositories together define how OIDM maps onto FHIR, and nothing si | `example1OIDMradiologist.json` | Observation | The same finding as confirmed by a radiologist, distinguished only by `status` `final` | | `example1OIDMradiologistLungRADS.json` | Observation | A second-order assessment Observation that is `derivedFrom` both the ImagingStudy and the radiologist's finding Observation, carrying the Lung-RADS category (RDES267) as a component | -Three patterns come out of this example and recur throughout later work. The chain from CDE set code to element code to value code, all through the `radelement.org` coding system, is what "CDE-labeled FHIR Observation" means concretely. The `status` field is what separates a machine-produced finding from a radiologist-confirmed one, rather than a separate resource type. And the second-order observation, an assessment built on top of a finding observation, is the precedent for any later assessment or category modeling, including the reporting-system categories the [2026 roadmap](/roadmap/roadmap-2026.md) names. +A "CDE-labeled FHIR Observation" uses set, element, and value codes from `radelement.org`. Its `status` distinguishes machine-produced from radiologist-confirmed findings within the same resource type. The second-order observation, an assessment built on top of a finding observation, is the precedent for any later assessment or category modeling, including the reporting-system categories [the 2026 roadmap](/roadmap/roadmap-2026.md) names. -Two absences in the example are worth recording. No `bodySite` coding appears on the finding Observations, because the anatomy was implicit in the CDE definition rather than explicit on the resource. No Patient resource is included; `subject.reference` is a bare reference. Both gaps are addressed in the current model, where [anatomic location](/glossary/anatomic-location.md) is an explicit field. See [FHIR mapping](/data-structures/fhir-mapping.md) for where the current structures stand. +The finding Observations omit `bodySite` because anatomy is implicit in the CDE definition. There is no Patient resource, only `subject.reference`. Both gaps are addressed in the current model, where [anatomic location](/glossary/anatomic-location.md) is an explicit field. See [FHIR mapping](/data-structures/fhir-mapping.md) for where the current structures stand. # Reference implementations -**OpenImagingDataModel.ts.** Created 2023-04-27, last commit on the default branch 2023-10-22. A pnpm monorepo with `cde_set`, `observation`, and `findingModel` packages, all typed with Zod schemas.[^oidm-ts] Status: lineage. Its Zod schemas are the cleanest early type definitions for a CDE set, a CDE element, an index code, and a body part, and they are the only place the project expressed these shapes in TypeScript. No FHIR imports appear anywhere in it. Superseded by the Python implementation and then by the `findingmodel` package. +**OpenImagingDataModel.ts.** Created 2023-04-27, last commit on the default branch 2023-10-22. A pnpm monorepo with `cde_set`, `observation`, and `findingModel` packages, all typed with Zod schemas.[^oidm-ts] Status: lineage. Its Zod schemas define CDE sets, CDE elements, index codes, and body parts, the project's only TypeScript definitions of these shapes. No FHIR imports appear anywhere in it. Superseded by the Python implementation and then by the `findingmodel` package. -**OpenImagingDataModel.py.** Created 2024-03-08, last commit on the default branch 2024-11-13. Subpackages `cde_set` and `observation`.[^oidm-py-observation] Status: lineage, but the most consequential of the group. Besides the Observation class above, `finding_model.py` defines a `FindingModel` with a name, a description, and a list of attributes discriminated into choice and numeric types with a `required` flag.[^oidm-py-fm] Its docstring, "The definition of a radiology finding ... along with definitions of the relevant attributes that a radiologist might use to characterize the finding in a radiology report", survives verbatim into the current [finding model](/glossary/finding-model.md) class in `findingmodel`. What the early class lacked is exactly what the current format adds: identifiers, synonyms, tags, index codes, anatomic locations, and contributors. Its `set.py`, `element.py`, and `set_factory.py` mirror the RadElement schema. Superseded by the `findingmodel` package. +**OpenImagingDataModel.py.** Created 2024-03-08, last commit on the default branch 2024-11-13. Subpackages `cde_set` and `observation`.[^oidm-py-observation] Status: lineage. Besides the Observation class above, `finding_model.py` defines a `FindingModel` with a name, a description, and a list of attributes discriminated into choice and numeric types with a `required` flag.[^oidm-py-fm] Its docstring, "The definition of a radiology finding ... along with definitions of the relevant attributes that a radiologist might use to characterize the finding in a radiology report", survives verbatim into the current [finding model](/glossary/finding-model.md) class in `findingmodel`. The current format adds identifiers, synonyms, tags, index codes, anatomic locations, and contributors. Its `set.py`, `element.py`, and `set_factory.py` mirror the RadElement schema. Superseded by the `findingmodel` package. # Content and schema -**openimagingdata.org (the repository).** Created 2023-02-20, last commit 2023-06-27. Status: lineage. This is where the project's first name lives: the README titles it "Open Radiology Data Model" and points at a domain that no longer serves the project. Two things survive. The `schemas/` directory holds the CDE Set JSON schema and minimal sample CDE set and Observation fixtures. More useful is `schema_differences.md`, a precise gap analysis between the CDE Set RelaxNG schema and the RadElement JSON API: array wrapper naming, `index_code.url` against the API's `href`, a `system` enum constrained in the schema but not the API, authors interleaved in the schema but split into arrays in the API, and presence mismatches on modality, biological sex, age range, parent set, question, references, and body parts.[^old-site-schema] That analysis is still live; the same gap is the subject of an open issue in `CDEStaging`. See [CDEs and RadElement](/semantic-foundation/common-data-elements/cdes-and-radelement.md). Superseded as a site by the hosted blog at the same domain. +**openimagingdata.org (the repository).** Created 2023-02-20, last commit 2023-06-27. Status: lineage. The README titles it "Open Radiology Data Model" and points to a former project domain. `schemas/` holds the CDE Set JSON schema and sample CDE set and Observation fixtures. `schema_differences.md` compares the CDE Set RelaxNG schema with the RadElement JSON API: array wrapper naming, `index_code.url` against the API's `href`, a `system` enum constrained in the schema but not the API, authors interleaved in the schema but split into arrays in the API, and presence mismatches on modality, biological sex, age range, parent set, question, references, and body parts.[^old-site-schema] An open `CDEStaging` issue tracks the same gap. See [CDEs and RadElement](/semantic-foundation/common-data-elements/cdes-and-radelement.md). Superseded as a site by the hosted blog at the same domain. -**common_data_elements.** Created 2025-02-21, content uploaded 2025-06-04. Status: maintenance, not lineage: this is still the project's local snapshot of RadElement. It holds roughly 140 CDE set definitions as JSON, indexed in the README by clinical topic with their set identifiers, and the canonical `cde.schema-1.0.json` and `cde.schema-1.1.json` files that the gap analysis above refers to.[^cde-data] The README notes that the definitions conform to schema version 1.0, not the newer 1.1. +**common_data_elements.** Created 2025-02-21, content uploaded 2025-06-04. Status: maintenance. This remains the project's local RadElement snapshot. It holds roughly 140 CDE set definitions as JSON, indexed in the README by clinical topic with their set identifiers, and the canonical `cde.schema-1.0.json` and `cde.schema-1.1.json` files that the gap analysis above refers to.[^cde-data] The README notes that the definitions conform to schema version 1.0, not the newer 1.1. **UseCases.** Created 2023-09-07, last commit 2024-02-26. Status: lineage as an activity, but its content is the fullest enumeration of application ideas anywhere in the project.[^usecases] It holds roughly 25 one-line use case ideas and the six value categories used to tag them. Migrated in full to [the use case catalog](/history/use-cases.md). Nothing superseded it; the deck's application pillar and the [2026 roadmap](/roadmap/roadmap-2026.md) cover related ground without reusing the catalog. @@ -88,15 +88,15 @@ Two absences in the example are worth recording. No `bodySite` coding appears on **CDETemplateDemo.** Created 2023-05-31, last commit 2023-06-15, default branch `master`. Status: lineage. A working proof of concept that renders a structured Observation into report prose through a Mustache template.[^template-demo] The pattern survives as the clearest precedent for the reporting SDK direction; see [CDE template rendering](/history/cde-template-rendering.md). Its own Observation shape, a flat string-keyed record of components, is looser than the FHIR-based one and is superseded by it. -**SARTemplatesToCDEs.** Created 2023-12-30, last commit 2024-03-11. Status: lineage, stalled at proof of concept. The stated goal was to use a language model to convert Society of Abdominal Radiology reporting templates into CDE sets, starting with rectal cancer staging. No conversion code was committed. What survives is `Changes_vs_RDES11.md`, an itemized redesign of the MR rectal tumor imaging CDE set against a 2016 baseline: an element renamed, mucinous composition given finer granularity, T-category and sphincter-invasion elements restructured, and new elements for tumor morphology, extramural vascular invasion, tumor deposits, and lymph nodes, each with explicit value sets.[^sar] It remains the most detailed single-CDE-set redesign in the lineage. The conversion approach itself is superseded by the batch content pipelines in `findingmodels`; see [extraction approaches](/history/extraction-approaches.md). +**SARTemplatesToCDEs.** Created 2023-12-30, last commit 2024-03-11. Status: lineage, stalled at proof of concept. The stated goal was to use a language model to convert Society of Abdominal Radiology reporting templates into CDE sets, starting with rectal cancer staging. No conversion code was committed. `Changes_vs_RDES11.md` records an itemized redesign of the MR rectal tumor imaging CDE set against a 2016 baseline: an element renamed, mucinous composition given finer granularity, T-category and sphincter-invasion elements restructured, and new elements for tumor morphology, extramural vascular invasion, tumor deposits, and lymph nodes, each with explicit value sets.[^sar] It remains the most detailed single-CDE-set redesign in the lineage. The conversion approach itself is superseded by the batch content pipelines in `findingmodels`; see [extraction approaches](/history/extraction-approaches.md). # Extraction and ontology tooling These four are covered in depth in [extraction approaches](/history/extraction-approaches.md); their status is summarized here. -**template_extraction.** Created 2025-06-05, last commit 2025-06-16. Status: lineage. A short script and a corpus of 281 RadReport templates spanning CT, MR, ultrasound, nuclear medicine, and fluoroscopy across most body regions, plus two CDE-labeled test templates.[^template-extraction] The corpus is the asset; it is an unused candidate vocabulary for exam types as well as findings. Not superseded by anything; the work simply moved to converting CDE staging content instead. +**template_extraction.** Created 2025-06-05, last commit 2025-06-16. Status: lineage. A short script and a corpus of 281 RadReport templates spanning CT, MR, ultrasound, nuclear medicine, and fluoroscopy across most body regions, plus two CDE-labeled test templates.[^template-extraction] The corpus remains unused but could supply exam-type and finding vocabulary. No successor replaced it. Work moved to converting CDE staging content. -**ReportFindingRefiner.** Created 2024-12-31, last commit 2025-05-23. Status: lineage, and the most mature of the extraction family. A privacy-first pipeline running local models: ingest report text, split into header, findings, and impression sections, embed with sentence transformers, store in a vector database, search, then generate finding model outlines with a local language model and persist them.[^refiner] Superseded by the extraction platform on the `imaging-problem-list` `dev` branch, which pursues the same goal with a chunked, multi-provider, verbatim-quote-validated design. +**ReportFindingRefiner.** Created 2024-12-31, last commit 2025-05-23. Status: lineage. Its local-model pipeline protects report privacy: ingest report text, split into header, findings, and impression sections, embed with sentence transformers, store in a vector database, search, then generate finding model outlines with a local language model and persist them.[^refiner] Superseded by the extraction platform on the `imaging-problem-list` `dev` branch, which pursues the same goal with a chunked, multi-provider, verbatim-quote-validated design. **get_ontology_findings.** Created 2025-03-27, last commit 2025-03-27. Status: lineage. A minimal script plus a RadLex export, aimed at finding ontology entries that correspond to imaging findings so they can become finding models or CDEs.[^get-ontology] Superseded in scope by `med-ontology-lookup`. @@ -104,7 +104,7 @@ These four are covered in depth in [extraction approaches](/history/extraction-a # What connects them -No lineage repository depends on another as a package, and none names another by URL. The connective tissue is shared external vocabulary: RadElement set and element codes thread through the CDE snapshot, the FHIR samples, the TypeScript sample data, the template demo's sample observations, and the SAR redesign. The CDE set and element shape is independently re-implemented three times. The finding model concept is defined independently in the TypeScript and Python implementations with near-identical shape and reimplemented a third time inside `ReportFindingRefiner`. That independent convergence is why the current format could consolidate them without contradiction. +No lineage repository imports another as a package or names another by URL. They share RadElement set and element codes across the CDE snapshot, FHIR samples, TypeScript samples, template demo, and SAR redesign. Three implementations independently define the CDE set and element shape. That independent convergence is why the current format could consolidate them without contradiction. TypeScript and Python define near-identical finding model shapes; `ReportFindingRefiner` implements the concept separately. [^oidm-py-observation]: OpenImagingDataModel.py observation.py, the FHIR Observation model [^oidm-py-fm]: OpenImagingDataModel.py finding_model.py, the earliest FindingModel class diff --git a/knowledge/history/site-articles.md b/knowledge/history/site-articles.md index abd9373..4c047eb 100644 --- a/knowledge/history/site-articles.md +++ b/knowledge/history/site-articles.md @@ -4,7 +4,7 @@ title: Site articles description: The fifteen posts published on openimagingdata.org between June 2023 and March 2025, plus the About page, each dated, linked, and summarized. tags: [history, site, articles, reference] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T02:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: rss resource: https://openimagingdata.org/rss/ @@ -16,7 +16,7 @@ sources: # What the site is -`openimagingdata.org` is the project's public site, a hosted blog whose title is "Open Imaging Data Model" and whose tagline is "Defining unified data structures to integrate new functionality into imaging informatics platforms." It carries two static pages, Home and About, and fifteen posts running from 2023-06-24 to 2025-03-10.[^rss] Every date and summary below was verified against the live page on 2026-09-21. Individual authors are not named here, per the conventions in [the authoring guide](/guides/authoring-guide.md). +`openimagingdata.org` is the project's public site, a hosted blog whose title is "Open Imaging Data Model" and whose tagline is "Defining unified data structures to integrate new functionality into imaging informatics platforms." It has Home and About pages and fifteen posts dated 2023-06-24 to 2025-03-10.[^rss] Every date and summary below was verified against the live page on 2026-09-21. Individual authors are not named here, per the conventions in [the authoring guide](/guides/authoring-guide.md). The site replaced the earlier repository-hosted site in June 2023; see [lineage repositories](/history/lineage-repositories.md). @@ -24,7 +24,7 @@ The site replaced the earlier repository-hosted site in June 2023; see [lineage ## 2025-03-10, [Leveraging Common Data Elements (CDEs) to Enhance Radiology Reporting](https://www.openimagingdata.org/leveraging-common-data-elements-cdes-to-enhance-radiology-reporting/) -A guest post from a reporting software vendor arguing that standardized data points improve clinical decision-making and data quality in radiology reporting. It describes integrating CDEs with radiology information systems and PACS while adhering to HL7, FHIR, and FHIRcast. The stated payoff is efficiency, advanced analytics, and better outcomes from structured data. This is the most recent post on the site. +A guest post from a reporting software vendor arguing that standardized data points improve clinical decision-making and data quality in radiology reporting. It describes integrating CDEs with radiology information systems and PACS while adhering to HL7, FHIR, and FHIRcast. The stated payoff is efficiency, advanced analytics, and better outcomes from structured data. This is the latest site post. ## 2024-07-02, [SIIM 2024 Update: Hackathon Edition](https://www.openimagingdata.org/siim-2024-update-hackathon-edition/) @@ -32,7 +32,7 @@ Reports the completed hackathon tool, which automatically associates concepts fr ## 2024-07-01, [Benchmarking a Vision](https://www.openimagingdata.org/benchmarking-a-vision/) -Announces a manuscript in the Journal of the American Medical Informatics Association titled "Standardizing imaging findings representation: harnessing Common Data Elements semantics and Fast Healthcare Interoperability Resources structures." The paper presents the framework for representing findings as CDE-labeled FHIR Observations, with a pulmonary nodule case study. Its claim, quoted in the post, is that CDE-labeled Observations should be the universal representation for exchanging and consuming radiology report content. +Announces a manuscript in the Journal of the American Medical Informatics Association titled "Standardizing imaging findings representation: harnessing Common Data Elements semantics and Fast Healthcare Interoperability Resources structures." The paper presents the framework for representing findings as CDE-labeled FHIR Observations, with a pulmonary nodule case study. The post quotes its claim that CDE-labeled Observations should be the universal representation for exchanging and consuming radiology report content. ## 2024-06-20, [Attaching Ontology Links to Common Data Elements](https://www.openimagingdata.org/attaching-ontology-links-to-common-data-elements/) @@ -40,7 +40,7 @@ Describes the problem the hackathon set out to solve: matching CDEs to ontology ## 2024-06-18, [AI-Powered Chest CT Reporting: Transforming Radiologist Observations into Standardized Data](https://www.openimagingdata.org/creating-common-data-elements-for-chest-cts-how-ai-is-revolutionizing-radiology-reporting/) -Reports using a large language model to generate common data element definitions from anonymized chest CT reports, by converting report text into semantic vectors, ranking relevant sections, and having radiologists review the generated definitions. More than 200 CDE definitions came out of the pilot. They were published to GitHub for community review, which is the origin of the chest CT content later carried in `CDEStaging`. +Reports using a large language model to generate common data element definitions from anonymized chest CT reports, by converting report text into semantic vectors, ranking relevant sections, and having radiologists review the generated definitions. The pilot published more than 200 definitions to GitHub for community review, originating the chest CT content later held in `CDEStaging`. ## 2024-06-17, [Counting Down to SIIM](https://www.openimagingdata.org/counting-down-to-siim/) @@ -60,7 +60,7 @@ A summary of the 2024-01-26 meeting, covering how imaging data standards connect ## 2024-01-25, [Data Model: Structure and Function](https://www.openimagingdata.org/data-model-structure-and-function/) -The clearest statement of what OIDM is structurally. It describes the model as covering the whole reporting context, observations, patient data, imaging studies, and clinical history, and says the model makes extensive use of FHIR definitions while providing a superstructure on top for easier programmatic access, comparing that relationship to how a browser's document object model relates to HTML. It names two utility libraries: anatomic locations for standardized body part terminology, and an exam type library based on the LOINC and RSNA Playbook linked to anatomic locations. That exam type library has never been built; see [exam types](/semantic-foundation/exam-types/overview.md). +Describes OIDM as covering report context, observations, patient data, imaging studies, and clinical history. It proposes structures over FHIR definitions for programmatic access, comparing the relationship to a browser's document object model and HTML. It names two utility libraries: anatomic locations for standardized body part terminology, and an exam type library based on the LOINC and RSNA Playbook linked to anatomic locations. That exam type library has never been built; see [exam types](/semantic-foundation/exam-types/overview.md). ## 2024-01-12, [2024 New Year Update](https://www.openimagingdata.org/2024-new-year-update/) @@ -72,7 +72,7 @@ Lists six engagement channels: registering on the site for newsletters and comme ## 2023-07-16, [OIDM-Based Next-gen Reporting Assistance Framework](https://www.openimagingdata.org/oidm-based-next-gen-reporting-assistance/) -Proposes a plugin architecture in which developers write assistance scripts that run inside a reporting tool's container. A script reads standardized data structures holding the report context, and can insert generated text into the report, ask the radiologist for more information, alert the radiologist to a problem, or send data to an external system. The container re-runs the scripts whenever the report context changes, which makes the assistance continuous rather than one-shot. This is the earliest statement of the direction later named the reporting SDK; see [the reporting SDK](/applications/reporting-sdk.md). +Proposes a plugin architecture in which developers write assistance scripts that run inside a reporting tool's container. A script reads standardized data structures holding the report context, and can insert generated text into the report, ask the radiologist for more information, alert the radiologist to a problem, or send data to an external system. The container reruns scripts whenever report context changes. This is the earliest statement of the direction later named the reporting SDK; see [the reporting SDK](/applications/reporting-sdk.md). ## 2023-06-26, [SIIM Update](https://www.openimagingdata.org/siim-update/) @@ -80,7 +80,7 @@ Announces the site itself and summarizes an in-person SIIM meeting on cooperatio ## 2023-06-24, [Findings, CDEs, and Observations](https://www.openimagingdata.org/findings-cdes-and-observations/) -The founding post. It argues that a radiology finding can be standardized as a FHIR Observation labeled with ACR and RSNA common data element identifiers: the Observation's code carries the CDE set identifier naming the finding type, and each attribute becomes a component carrying a CDE element identifier and a value. Its worked example is a solid 6 mm nodule in the right lower lobe, labeled with the pulmonary nodule CDE set code and element codes for composition and size. Everything in [the data structures layer](/data-structures/hierarchy.md) descends from this claim. +The founding post. It argues that a radiology finding can be standardized as a FHIR Observation labeled with ACR and RSNA common data element identifiers: the Observation's code carries the CDE set identifier naming the finding type, and each attribute becomes a component carrying a CDE element identifier and a value. Its worked example is a solid 6 mm nodule in the right lower lobe, labeled with the pulmonary nodule CDE set code and element codes for composition and size. This claim underlies [the data structures layer](/data-structures/hierarchy.md). # The About page @@ -88,7 +88,7 @@ The About page states the mission: establish common data structures representing It also commits to programming interfaces in three languages, TypeScript and JavaScript, Python, and C#. Two of the three exist as lineage repositories and neither is current; no C# library was ever created. See [lineage repositories](/history/lineage-repositories.md). -The page was last modified 2023-06-21 and has not been revised since, so it predates finding models, the Exam Finding List, and the Imaging Problem List. Where it differs from current documents, the current documents govern. +The page was last modified 2023-06-21, before finding models, the Exam Finding List, and the Imaging Problem List. Where it differs from current documents, the current documents govern. [^rss]: openimagingdata.org RSS feed, 15 posts, fetched 2026-09-21 [^about]: openimagingdata.org About page, fetched 2026-09-21 diff --git a/knowledge/history/timeline.md b/knowledge/history/timeline.md index 8b8b92c..f9e3e34 100644 --- a/knowledge/history/timeline.md +++ b/knowledge/history/timeline.md @@ -1,10 +1,10 @@ --- type: History title: Timeline -description: A dated record of the Open Imaging Data Model from its anatomic-location prologue through the January 2026 status update and the 2026 work edge. +description: Dated OIDM milestones from anatomic-location work in 2022 through current work in September 2026. tags: [history, timeline] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T02:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: gh-org resource: https://github.com/openimagingdata @@ -37,7 +37,7 @@ sources: # Prologue: 2022 -The anatomic-location work predates the project's own name. The TypeScript wrapper repository was created on 2022-02-02, the Python wrapper on 2022-07-19, and the curated dataset and its site on 2022-12-14.[^gh-org] The dataset's own changelog records version `1.0.0-rc.1` in December 2022, adding a version field and SNOMED links. The curated set reached 2,890 records and its last substantive site commit, a hierarchy tree view, landed on 2023-01-10. See [the anatomic location lineage](/semantic-foundation/anatomic-locations/lineage-and-current-implementation.md). +Anatomic-location work began before OIDM. The TypeScript wrapper was created on 2022-02-02, the Python wrapper on 2022-07-19, and the curated dataset and site on 2022-12-14.[^gh-org] Version `1.0.0-rc.1` added a version field and SNOMED links in December 2022. The set reached 2,890 records. The last substantive site commit added a hierarchy tree view on 2023-01-10. See [the anatomic location lineage](/semantic-foundation/anatomic-locations/lineage-and-current-implementation.md). # 2023: naming, schema, and the first demonstrations diff --git a/knowledge/history/use-cases.md b/knowledge/history/use-cases.md index be7998c..02b8003 100644 --- a/knowledge/history/use-cases.md +++ b/knowledge/history/use-cases.md @@ -1,10 +1,10 @@ --- type: Reference title: Use case catalog -description: The roughly 25 use case ideas collected in the UseCases repository, organized by category, with the six value categories used to tag them. +description: The roughly 25 ideas from UseCases, with source attribution and six value-category tags. tags: [history, use-cases, reference] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T02:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: usecases-index resource: https://github.com/openimagingdata/UseCases/blob/71a90d2ab2efeee4c4303dc0aef27ed3d70a6c99/Index.md @@ -16,7 +16,7 @@ sources: # What this is -The `UseCases` repository was created in September 2023 to collect ideas for what an Open Imaging Data Model (OIDM) would make possible. Its index was meant to be a holding pen: a name and a one-sentence description each, with mature entries promoted to their own files.[^usecases-index] None were promoted, and the last commit is 2024-02-26. The catalog below is the whole of it, reorganized but not extended. +The `UseCases` repository began in September 2023 to collect Open Imaging Data Model (OIDM) application ideas. Each index entry had a name and one-sentence description, with mature ideas intended to become separate files.[^usecases-index] None did. The last commit was 2024-02-26. This catalog reorganizes all entries without additions. Entries marked as contributed by the RSNA Reporting Informatics Committee are so marked in the source. The numbers after each entry are the value categories defined in the next section, exactly as the source assigns them. Four of the repository's seven headings, Protocoling System, AI Pipeline, PACS Viewing, and Data Exploration, are placeholders with no entries. @@ -39,7 +39,7 @@ Six categories, taken from the RSNA Reporting Informatics Committee's use case w # Assisted reporting -Most entries in this section were contributed by the RSNA Reporting Informatics Committee, which is noted per entry below. +Most entries came from the RSNA Reporting Informatics Committee, as marked below. - **Stroke notification** (RSNA Reporting Informatics Committee). Automated communication to the stroke team when findings of stroke are reported. (2, 3) - **Problem list update** (RSNA Reporting Informatics Committee). Findings in a radiology report automatically update the electronic medical record problem list. (3) @@ -74,11 +74,11 @@ These entries carry no value category tags in the source. # How the catalog was meant to work -The repository's README sets out an intended process that was never completed: collect ideas in the index, then define metadata for each mature case and move it to its own file organized hierarchically as Markdown or JSON.[^usecases-readme] It asks three questions that remain unanswered in the repository: what information a use case should capture, whether the format should be prose or data, and whether specialized coded inputs such as LOINC for laboratory data are needed. +The unfinished process was to collect ideas, define metadata for mature cases, and store them in hierarchical Markdown or JSON files.[^usecases-readme] The README leaves three questions open: what information to capture, whether to use prose or data, and whether coded inputs such as laboratory LOINC codes are needed. The categories the README proposes for organizing cases are workflow and list oriented, AI pipeline oriented, reporting oriented, image-viewer oriented, data exploration and outcome oriented, multi-category, and miscellaneous. The index uses a slightly different set of headings, listed above. -For where this line of thinking went next, see [the 2026 roadmap](/roadmap/roadmap-2026.md), whose applications pillar and use-case pipeline to the CDE group cover related ground without reusing this catalog. +[The 2026 roadmap](/roadmap/roadmap-2026.md) describes related applications and use-case submissions to the CDE group without reusing this catalog. [^usecases-index]: UseCases Index.md, the living list of use case ideas [^usecases-readme]: UseCases README.md, the intended process and the six value categories diff --git a/knowledge/index.md b/knowledge/index.md index 6f38561..4f84c4b 100644 --- a/knowledge/index.md +++ b/knowledge/index.md @@ -6,7 +6,9 @@ okf_version: "0.2" Canonical high-level documentation for the Open Imaging Data Model (OIDM). -**Start here:** [What is OIDM](./overview/what-is-oidm.md), then [Architecture](./overview/architecture.md). Look terms up in the [glossary](./glossary/), find where code and content live in the [repository map](./repositories/repository-map.md), and see what is settled versus open in the [roadmap](./roadmap/) and [open questions](./roadmap/open-questions.md). Every document's frontmatter states its type, status, sources, and who generated and verified it; agents should read that before relying on a page. +**Status: pre-review draft.** Every document was generated by agents from the source repositories and has `status: draft` until the project lead verifies it. Do not treat any page as authoritative until it carries a `verified` entry and `status: stable`. + +Start with [What is OIDM](./overview/what-is-oidm.md) and [Architecture](./overview/architecture.md). Use the [glossary](./glossary/) for terms, the [repository map](./repositories/repository-map.md) for code and content, and the [roadmap](./roadmap/) and [open questions](./roadmap/open-questions.md) for plans and unresolved issues. Check each page's frontmatter for its type, sources, authorship, and review status. * [overview](./overview/) - What OIDM is, the vision, and how the pieces fit @@ -20,3 +22,4 @@ Canonical high-level documentation for the Open Imaging Data Model (OIDM). * [references](./references/) - Verbatim and near-verbatim source material * [guides](./guides/) - Authoring conventions and the migration ledger * [plans](./plans/) - Plans for building and maintaining this knowledgebase +* [drafts](./drafts/) - Staging area for the restructured pillar pages (in progress, 2026-09-22) diff --git a/knowledge/log.md b/knowledge/log.md index ee6957b..b620a5a 100644 --- a/knowledge/log.md +++ b/knowledge/log.md @@ -1,6 +1,12 @@ # Update Log +## 2026-09-22 + +* Completed Codex's source-fidelity review of seven companion drafts and corrected Data Structures, Use Cases, and Sample Applications against the incoming reviews. Added the deck's graph example and live application links; clarified proposal status and demonstrated capabilities. Draft replacement remains pending. +* Added staged drafts for Data Structures, Use Cases, and Sample Applications, with source citations, dated representations, and session authorship. Source cross-review and replacement of the current pages remain pending. + ## 2026-09-21 +* 2026-09-21 - Prose tightened across 112 concept documents by codex/gpt-6 (two passes); reviewed by five claude-opus-5 reviewers; reverts and substantive fixes applied. Sources, links, and footnotes unchanged. * 2026-09-21 - Added `roadmap/open-questions.md`, 90 numbered entries deduplicated from all ten collecting agents and grouped into finding models, common data elements, anatomic locations, exam types and terminologies, data structures, applications, and the project narrative, each with the sources on each side and an owner where a source names one, plus a separate table of 21 source-document defects with repository and path so they can become issues. Rewritten after the five Phase 2 and 3 agents appended their sections. * 2026-09-21 - Corrected three roadmap documents against those late sections: the med-ontology-lookup backlog is eleven of twelve issues open rather than nine open and unstarted; findingmodels issue 15 is answered by unmerged work rather than merely overlapping it; the two framings of the RadLex relationship and the 1,016 composite sided identifiers were added to the anatomy roadmap; an identifier lifecycle section covering the absence of any deprecation mechanism and findingmodel issue 42 was added to format evolution. * 2026-09-21 - Added `roadmap/roadmap-2026.md`, the project-level direction from the January 2026 deck: the three strategic pillars, the ACR-OIDM Structured Imaging Results Working Group proposal with its structure-first and vendor-driven conditions, the four ACR priorities it says the work supports, the three next steps including the use-case pipeline to the CDE group, a per-repository work edge table linking each area roadmap, and the three deck items with no artifact behind them. diff --git a/knowledge/overview/architecture.excalidraw b/knowledge/overview/architecture.excalidraw new file mode 100644 index 0000000..f097d57 --- /dev/null +++ b/knowledge/overview/architecture.excalidraw @@ -0,0 +1,1823 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "oidm-knowledge/tools/diagrams", + "elements": [ + { + "type": "text", + "id": "band_app", + "x": 80, + "y": 16, + "width": 97.44, + "height": 17.5, + "strokeColor": "#3b82f6", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1001, + "version": 1, + "versionNonce": 1002, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "APPLICATIONS", + "originalText": "APPLICATIONS", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "forge", + "x": 0, + "y": 40, + "width": 190, + "height": 100, + "strokeColor": "#1e3a5f", + "backgroundColor": "#60a5fa", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1003, + "version": 1, + "versionNonce": 1004, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "forge_t", + "type": "text" + }, + { + "id": "a_forge_fm", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "forge_t", + "x": 10, + "y": 50, + "width": 170, + "height": 80, + "strokeColor": "#1e3a5f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1005, + "version": 1, + "versionNonce": 1006, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Finding Model Forge\nauthoring wizard\nfmf.oidm.org", + "originalText": "Finding Model Forge\nauthoring wizard\nfmf.oidm.org", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "forge", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "extract", + "x": 296, + "y": 40, + "width": 190, + "height": 100, + "strokeColor": "#1e3a5f", + "backgroundColor": "#60a5fa", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1007, + "version": 1, + "versionNonce": 1008, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "extract_t", + "type": "text" + }, + { + "id": "a_extract_efl", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "extract_t", + "x": 306, + "y": 50, + "width": 170, + "height": 80, + "strokeColor": "#1e3a5f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1009, + "version": 1, + "versionNonce": 1010, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Report extraction\nplatform\nLLM extraction\nand coding (dev)", + "originalText": "Report extraction\nplatform\nLLM extraction\nand coding (dev)", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "extract", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "viewer", + "x": 512, + "y": 40, + "width": 190, + "height": 100, + "strokeColor": "#1e3a5f", + "backgroundColor": "#60a5fa", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1011, + "version": 1, + "versionNonce": 1012, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "viewer_t", + "type": "text" + }, + { + "id": "a_ipl_viewer", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "viewer_t", + "x": 522, + "y": 50, + "width": 170, + "height": 80, + "strokeColor": "#1e3a5f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1013, + "version": 1, + "versionNonce": 1014, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Imaging Problem\nList viewer\nimaging-problem-\nlist.pages.dev", + "originalText": "Imaging Problem\nList viewer\nimaging-problem-\nlist.pages.dev", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "viewer", + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "div1", + "x": 0, + "y": 224, + "width": 702, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1015, + "version": 1, + "versionNonce": 1016, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 702, + 0 + ] + ] + }, + { + "type": "text", + "id": "band_data", + "x": 80, + "y": 230, + "width": 121.8, + "height": 17.5, + "strokeColor": "#3b82f6", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1017, + "version": 1, + "versionNonce": 1018, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "DATA STRUCTURES", + "originalText": "DATA STRUCTURES", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "obs", + "x": 80, + "y": 315, + "width": 190, + "height": 80, + "strokeColor": "#1e3a5f", + "backgroundColor": "#3b82f6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1019, + "version": 1, + "versionNonce": 1020, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "obs_t", + "type": "text" + }, + { + "id": "a_obs_efl", + "type": "arrow" + }, + { + "id": "a_fm_obs", + "type": "arrow" + }, + { + "id": "a_al_obs", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "obs_t", + "x": 90, + "y": 325, + "width": 170, + "height": 60, + "strokeColor": "#ffffff", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1021, + "version": 1, + "versionNonce": 1022, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Observation\nfinding + location\n+ attributes", + "originalText": "Observation\nfinding + location\n+ attributes", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "obs", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "efl", + "x": 296, + "y": 315, + "width": 190, + "height": 80, + "strokeColor": "#1e3a5f", + "backgroundColor": "#3b82f6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1023, + "version": 1, + "versionNonce": 1024, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "efl_t", + "type": "text" + }, + { + "id": "a_obs_efl", + "type": "arrow" + }, + { + "id": "a_efl_ipl", + "type": "arrow" + }, + { + "id": "a_extract_efl", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "efl_t", + "x": 306, + "y": 325, + "width": 170, + "height": 60, + "strokeColor": "#ffffff", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1025, + "version": 1, + "versionNonce": 1026, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Exam Finding List\nall observations\nof one exam", + "originalText": "Exam Finding List\nall observations\nof one exam", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "efl", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "ipl", + "x": 512, + "y": 315, + "width": 190, + "height": 80, + "strokeColor": "#1e3a5f", + "backgroundColor": "#3b82f6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1027, + "version": 1, + "versionNonce": 1028, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "ipl_t", + "type": "text" + }, + { + "id": "a_efl_ipl", + "type": "arrow" + }, + { + "id": "a_ipl_viewer", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "ipl_t", + "x": 522, + "y": 325, + "width": 170, + "height": 60, + "strokeColor": "#ffffff", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1029, + "version": 1, + "versionNonce": 1030, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Imaging Problem List\none patient, grouped\nby finding", + "originalText": "Imaging Problem List\none patient, grouped\nby finding", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "ipl", + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "a_obs_efl", + "x": 270, + "y": 355.0, + "width": 26, + "height": 0.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1031, + "version": 1, + "versionNonce": 1032, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 26, + 0.0 + ] + ], + "startBinding": { + "elementId": "obs", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "efl", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "id": "a_obs_efl_l", + "x": 250.52, + "y": 267.0, + "width": 64.96, + "height": 17.5, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1033, + "version": 1, + "versionNonce": 1034, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "per exam", + "originalText": "per exam", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "a_efl_ipl", + "x": 486, + "y": 355.0, + "width": 26, + "height": 0.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1035, + "version": 1, + "versionNonce": 1036, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 26, + 0.0 + ] + ], + "startBinding": { + "elementId": "efl", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "ipl", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "id": "a_efl_ipl_l", + "x": 454.34000000000003, + "y": 267.0, + "width": 89.32, + "height": 17.5, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1037, + "version": 1, + "versionNonce": 1038, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "per patient", + "originalText": "per patient", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "a_extract_efl", + "x": 391.0, + "y": 140, + "width": 0.0, + "height": 175, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1039, + "version": 1, + "versionNonce": 1040, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.0, + 175 + ] + ], + "startBinding": { + "elementId": "extract", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "efl", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "id": "a_extract_efl_l", + "x": 338.22, + "y": 177.5, + "width": 105.55999999999999, + "height": 35.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1041, + "version": 1, + "versionNonce": 1042, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "extracts from\nreports", + "originalText": "extracts from\nreports", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "a_ipl_viewer", + "x": 607.0, + "y": 315, + "width": 0.0, + "height": -175, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1043, + "version": 1, + "versionNonce": 1044, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.0, + -175 + ] + ], + "startBinding": { + "elementId": "ipl", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "viewer", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "id": "a_ipl_viewer_l", + "x": 578.58, + "y": 195.5, + "width": 56.839999999999996, + "height": 17.5, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1045, + "version": 1, + "versionNonce": 1046, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "renders", + "originalText": "renders", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "persona", + "x": 512, + "y": 455, + "width": 190, + "height": 80, + "strokeColor": "#64748b", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1047, + "version": 1, + "versionNonce": 1048, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "persona_t", + "type": "text" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "persona_t", + "x": 522, + "y": 465, + "width": 170, + "height": 60, + "strokeColor": "#475569", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1049, + "version": 1, + "versionNonce": 1050, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Imaging Persona\nplus clinical\ncontext (concept)", + "originalText": "Imaging Persona\nplus clinical\ncontext (concept)", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "persona", + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "persona_note", + "x": 512, + "y": 549, + "width": 188.5, + "height": 32.5, + "strokeColor": "#475569", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1051, + "version": 1, + "versionNonce": 1052, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "goal: extends the Imaging\nProblem List with context", + "originalText": "goal: extends the Imaging\nProblem List with context", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "line", + "id": "div2", + "x": 0, + "y": 619, + "width": 702, + "height": 0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1053, + "version": 1, + "versionNonce": 1054, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 702, + 0 + ] + ] + }, + { + "type": "text", + "id": "band_found", + "x": 80, + "y": 625, + "width": 154.28, + "height": 17.5, + "strokeColor": "#3b82f6", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1055, + "version": 1, + "versionNonce": 1056, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "SEMANTIC FOUNDATION", + "originalText": "SEMANTIC FOUNDATION", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "fm", + "x": 80, + "y": 649, + "width": 190, + "height": 80, + "strokeColor": "#1e3a5f", + "backgroundColor": "#93c5fd", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1057, + "version": 1, + "versionNonce": 1058, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "fm_t", + "type": "text" + }, + { + "id": "a_fm_obs", + "type": "arrow" + }, + { + "id": "a_forge_fm", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "fm_t", + "x": 90, + "y": 659, + "width": 170, + "height": 60, + "strokeColor": "#1e3a5f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1059, + "version": 1, + "versionNonce": 1060, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Finding models\nOIFM_ / OIFMA_\ncodes", + "originalText": "Finding models\nOIFM_ / OIFMA_\ncodes", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "fm", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "al", + "x": 296, + "y": 649, + "width": 190, + "height": 80, + "strokeColor": "#1e3a5f", + "backgroundColor": "#93c5fd", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1061, + "version": 1, + "versionNonce": 1062, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "al_t", + "type": "text" + }, + { + "id": "a_al_obs", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "al_t", + "x": 306, + "y": 659, + "width": 170, + "height": 60, + "strokeColor": "#1e3a5f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1063, + "version": 1, + "versionNonce": 1064, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Anatomic locations\nRadLex RID codes", + "originalText": "Anatomic locations\nRadLex RID codes", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "al", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "et", + "x": 512, + "y": 649, + "width": 190, + "height": 80, + "strokeColor": "#64748b", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1065, + "version": 1, + "versionNonce": 1066, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "et_t", + "type": "text" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "et_t", + "x": 522, + "y": 659, + "width": 170, + "height": 60, + "strokeColor": "#475569", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1067, + "version": 1, + "versionNonce": 1068, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Exam types\nLOINC / Playbook\n(planned)", + "originalText": "Exam types\nLOINC / Playbook\n(planned)", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "et", + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "et_note", + "x": 512, + "y": 743, + "width": 135.72, + "height": 48.75, + "strokeColor": "#475569", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1069, + "version": 1, + "versionNonce": 1070, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "supplies the LOINC\nexam code on the\nExam Finding List", + "originalText": "supplies the LOINC\nexam code on the\nExam Finding List", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "a_fm_obs", + "x": 254.8, + "y": 649, + "width": 0.0, + "height": -254, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1071, + "version": 1, + "versionNonce": 1072, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.0, + -254 + ] + ], + "startBinding": { + "elementId": "fm", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "obs", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "id": "a_fm_obs_l", + "x": 140.14000000000001, + "y": 482.0, + "width": 89.32, + "height": 35.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1073, + "version": 1, + "versionNonce": 1074, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "OIFM and\nOIFMA codes", + "originalText": "OIFM and\nOIFMA codes", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "a_al_obs", + "x": 391.0, + "y": 649, + "width": -159.0, + "height": -254, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1075, + "version": 1, + "versionNonce": 1076, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -159.0, + -254 + ] + ], + "startBinding": { + "elementId": "al", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "obs", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "id": "a_al_obs_l", + "x": 343.32, + "y": 482.0, + "width": 24.36, + "height": 17.5, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1077, + "version": 1, + "versionNonce": 1078, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "RID", + "originalText": "RID", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "a_forge_fm", + "x": 19.0, + "y": 140, + "width": 61.0, + "height": 549.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1079, + "version": 1, + "versionNonce": 1080, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 549.0 + ], + [ + 61.0, + 549.0 + ] + ], + "startBinding": { + "elementId": "forge", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "fm", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "id": "a_forge_fm_l", + "x": 11.080000000000002, + "y": 434.5, + "width": 56.839999999999996, + "height": 17.5, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1081, + "version": 1, + "versionNonce": 1082, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "authors", + "originalText": "authors", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "cde", + "x": 80, + "y": 789, + "width": 190, + "height": 100, + "strokeColor": "#c2410c", + "backgroundColor": "#fed7aa", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1083, + "version": 1, + "versionNonce": 1084, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "cde_t", + "type": "text" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "cde_t", + "x": 90, + "y": 799, + "width": 170, + "height": 80, + "strokeColor": "#7c2d12", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1085, + "version": 1, + "versionNonce": 1086, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "ACR/RSNA CDEs at\nRadElement\nRDES / RDE codes\n(allied project)", + "originalText": "ACR/RSNA CDEs at\nRadElement\nRDES / RDE codes\n(allied project)", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "cde", + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "cde_note", + "x": 296, + "y": 807, + "width": 263.9, + "height": 32.5, + "strokeColor": "#7c2d12", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1087, + "version": 1, + "versionNonce": 1088, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "finding models graduate to CDEs;\nCDE definitions seed finding models", + "originalText": "finding models graduate to CDEs;\nCDE definitions seed finding models", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "terms", + "x": 0, + "y": 929, + "width": 603.1999999999999, + "height": 32.5, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1089, + "version": 1, + "versionNonce": 1090, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Terminologies underneath: RadLex, SNOMED CT, FMA, UMLS, MeSH, LOINC and the RSNA\nRadiology Playbook. Looked up through med-ontology-lookup.", + "originalText": "Terminologies underneath: RadLex, SNOMED CT, FMA, UMLS, MeSH, LOINC and the RSNA\nRadiology Playbook. Looked up through med-ontology-lookup.", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "legend_t", + "x": 0, + "y": 983.5, + "width": 45.239999999999995, + "height": 16.25, + "strokeColor": "#3b82f6", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1091, + "version": 1, + "versionNonce": 1092, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Legend", + "originalText": "Legend", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "lg0", + "x": 0, + "y": 1007.5, + "width": 18, + "height": 14, + "strokeColor": "#1e3a5f", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1093, + "version": 1, + "versionNonce": 1094, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "lg0_t", + "x": 26, + "y": 1005.5, + "width": 203.57999999999998, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1095, + "version": 1, + "versionNonce": 1096, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "solid outline: exists today", + "originalText": "solid outline: exists today", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "lg1", + "x": 0, + "y": 1029.5, + "width": 18, + "height": 14, + "strokeColor": "#64748b", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1097, + "version": 1, + "versionNonce": 1098, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "lg1_t", + "x": 26, + "y": 1027.5, + "width": 316.67999999999995, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1099, + "version": 1, + "versionNonce": 1100, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "dashed outline: documented or planned only", + "originalText": "dashed outline: documented or planned only", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "lg2", + "x": 0, + "y": 1051.5, + "width": 18, + "height": 14, + "strokeColor": "#c2410c", + "backgroundColor": "#fed7aa", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1101, + "version": 1, + "versionNonce": 1102, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "lg2_t", + "x": 26, + "y": 1049.5, + "width": 233.73999999999998, + "height": 16.25, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1103, + "version": 1, + "versionNonce": 1104, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "orange: allied external project", + "originalText": "orange: allied external project", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + } + ], + "appState": { + "viewBackgroundColor": "#ffffff", + "gridSize": null + }, + "files": {} +} \ No newline at end of file diff --git a/knowledge/overview/architecture.md b/knowledge/overview/architecture.md index 5c34683..93c8a9a 100644 --- a/knowledge/overview/architecture.md +++ b/knowledge/overview/architecture.md @@ -4,7 +4,7 @@ title: Architecture description: How the semantic foundation, data structures, and applications fit together, which identifier system joins each pair, and what is actually built. tags: [overview, architecture, identifiers] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T15:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:34:50Z } sources: - id: deck resource: https://gamma.app/docs/Open-Imaging-Data-Model-2026-Status-Update:-Realizing-Object-Oriented-Imaging-Results-yfxzx4q9zssafal @@ -49,57 +49,29 @@ sources: # The shape of the system -OIDM is three layers stacked on each other, and the joints between them are identifiers. The semantic foundation defines what things are and gives each one a code. The data structures carry instances of those things, referring to them only by code. The applications create and read those structures. Nothing in the upper layers embeds a definition; everything points. - -This is what makes the system work across organizations. Two systems can agree that a finding is `OIFM_GMTS_016552` located at `RID42239` without sharing any code, any database, or any vendor. - -```mermaid -flowchart TB - subgraph SF["Semantic foundation: what things are"] - FM["Finding models
OIFM_XXXX_###### / OIFMA_XXXX_######"] - AL["Anatomic locations
RadLex RIDs"] - CDE["Common data elements
RDES### sets / RDE#### elements"] - ET["Exam types
LOINC codes"] - end - subgraph DS["Data structures: what was seen"] - OBS["Observation
finding + location + attribute values"] - EFL["Exam Finding List
one exam"] - IPL["Imaging Problem List
one patient, grouped by finding"] - IP["Imaging Persona
clinical context around the IPL"] - end - subgraph APP["Applications: what makes and reads them"] - FORGE["Finding Model Forge"] - CAT["Finding model catalog site"] - EXTR["Report extraction and coding platform"] - VIEW["IPL viewer"] - MOLU["molu terminology lookup"] - end - FM -->|findingCode, attributeCode| OBS - AL -->|anatomicLocation.locationId| OBS - ET -->|examInfo.studyLoincCode| EFL - CDE -.->|graduation target| FM - OBS --> EFL --> IPL --> IP - FORGE -->|authors| FM - CAT -->|browses| FM - EXTR -->|produces| EFL - VIEW -->|renders| IPL - MOLU -->|resolves codes for| FM - MOLU -->|resolves codes for| AL -``` +OIDM has three layers joined by identifiers. The semantic foundation defines concepts and assigns codes. Data structures hold instances that reference those definitions by code. Applications create and read the structures without embedding definitions. + +Shared identifiers let systems agree that a finding is `OIFM_GMTS_016552` at `RID42239` without sharing code, databases, or vendors. + +[![Open Imaging Data Model: three layers joined by identifiers. Applications on top, data structures in the middle, semantic foundation below, with arrows showing which codes join them.](./architecture.svg)](./architecture.svg) + +Also in the applications layer, not drawn: the finding model catalog site, the terminology lookup library, and the Open Imaging Reporting SDK, which remains a concept with no artifact. + +*Diagram source: `architecture.excalidraw` beside this document (click the image for full size), generated by `tools/diagrams/build_architecture.py`.* # The semantic foundation -A [finding model](/glossary/finding-model.md) is the definition of one radiology finding: a name, a description, synonyms, tags, optional anatomic locations, optional [index codes](/glossary/index-code.md) into external ontologies, and a list of [attributes](/glossary/attribute.md) that a radiologist would use to characterize it. Each carries an [OIFM identifier](/glossary/oifm.md) matching `OIFM_[A-Z]{3,4}_[0-9]{6}`, where the letter block identifies the contributing organization. Each attribute carries an `OIFMA_[A-Z]{3,4}_[0-9]{6}` identifier, and each choice value extends its attribute identifier with a dot suffix, so `OIFMA_GMTS_707209.1` is a specific value of a specific attribute of a specific finding.[^fm-model] A flat registry file maps every issued identifier to its definition file, which is how duplicates are caught.[^fm-ids] +A [finding model](/glossary/finding-model.md) defines one radiology finding with a name, description, synonyms, tags, and [attributes](/glossary/attribute.md) that characterize it. It can include anatomic locations and [index codes](/glossary/index-code.md) into external ontologies. Its [OIFM identifier](/glossary/oifm.md) matches `OIFM_[A-Z]{3,4}_[0-9]{6}`, with the letter block identifying the contributing organization. Attribute identifiers match `OIFMA_[A-Z]{3,4}_[0-9]{6}`. Choice values add a dot suffix to the attribute identifier, as in `OIFMA_GMTS_707209.1`.[^fm-model] A flat registry maps issued identifiers to definition files to detect duplicates.[^fm-ids] -[Anatomic locations](/glossary/anatomic-location.md) are keyed by RadLex identifiers of the form `RID####`. Sided structures are composite, as in `RID294_RID5824` for the left variant of the uterine adnexa. Two hierarchies are carried, ["contained by" and "part of"](/glossary/contained-by-and-part-of.md), together with a [laterality](/glossary/laterality.md) triad linking unsided, left, and right variants, and cross-references to SNOMED CT, FMA, UMLS, and MESH.[^anat-docs] +[Anatomic locations](/glossary/anatomic-location.md) use RadLex identifiers of the form `RID####`. Sided structures use composite identifiers, such as `RID294_RID5824` for the left uterine adnexa. Locations have ["contained by" and "part of"](/glossary/contained-by-and-part-of.md) hierarchies, [laterality](/glossary/laterality.md) links between unsided, left, and right variants, and cross-references to SNOMED CT, FMA, UMLS, and MESH.[^anat-docs] -[Common data elements](/glossary/cde.md) are the formally governed counterpart, published by the ACR and RSNA through RadElement with `RDES###` set identifiers and `RDE####` element identifiers. They are external to OIDM. The relationship runs the other way from the one people expect: finding models are the fast-moving workbench, and proven definitions are candidates to graduate into common data elements.[^deck] +[Common data elements](/glossary/cde.md) are external to OIDM, governed by the ACR and RSNA, and published through RadElement. Sets use `RDES###` identifiers, and elements use `RDE####`. Finding models support experimentation, with proven definitions becoming candidates for common data elements.[^deck] -[Exam types](/glossary/exam-type.md) are coded with LOINC. The Exam Finding List requires a LOINC code on its exam header, and the only written design for a richer exam-type capability, one that would weight the LOINC and RSNA Radiology Playbook vocabulary for orderables and carry Playbook correspondences in crosswalk provenance, lives in the terminology lookup roadmap.[^molu-roadmap] +[Exam types](/glossary/exam-type.md) use LOINC codes, which the Exam Finding List requires in its exam header. The terminology lookup roadmap contains the only written design for richer exam-type support. It proposes weighting LOINC and RSNA Radiology Playbook vocabulary for orderables and recording Playbook correspondences in crosswalk provenance.[^molu-roadmap] # The data structures -An [Observation](/glossary/observation.md) is the atomic unit: what, where, and how. The deck states it as a finding tag plus an anatomic location plus lesion characteristics, carrying presence indicators, change from prior, and measurements.[^deck] In the Exam Finding List JSON this appears as a `findingCode` with its `findingDescription`, an optional `anatomicLocation` object holding a RadLex identifier and display text, and an `attributes` array of attribute code, value code, and descriptions. +An [Observation](/glossary/observation.md) records a finding tag, anatomic location, and lesion characteristics, including presence, change from prior, and measurements.[^deck] The Exam Finding List JSON represents these as `findingCode` and `findingDescription`, an optional `anatomicLocation` with a RadLex identifier and display text, and an `attributes` array with attribute codes, value codes, and descriptions. ```json { @@ -118,17 +90,19 @@ An [Observation](/glossary/observation.md) is the atomic unit: what, where, and } ``` -An [Exam Finding List](/glossary/exam-finding-list.md) wraps all observations from one exam with a report identifier, patient information, and exam information including the LOINC-coded exam type. Repeated instances of the same finding get separate entries, each with its own observation identifier, so three kidney stones are three observations rather than one with a count.[^ipl-main] +An [Exam Finding List](/glossary/exam-finding-list.md) collects an exam's observations with a report identifier, patient information, and exam information, including the LOINC-coded exam type. Repeated instances of the same finding get separate entries, each with its own observation identifier, so three kidney stones are three observations rather than one with a count.[^ipl-main] -An [Imaging Problem List](/glossary/imaging-problem-list.md) reorganizes observations across a patient's exams by finding rather than by date, which is what makes the question "was finding X present on the most recent study" a lookup instead of a search.[^deck] An [Imaging Persona](/glossary/imaging-persona.md) is the stated goal of surrounding that with clinical context, medical baseline, specialized history, and surgical history. It exists in the deck and nowhere else. +An [Imaging Problem List](/glossary/imaging-problem-list.md) groups observations across a patient's exams by finding to answer "was finding X present on the most recent study" with a lookup.[^deck] An [Imaging Persona](/glossary/imaging-persona.md) would add clinical context, medical baseline, specialized history, and surgical history. It is a goal recorded only in the deck. -The 2024 site post describes the surrounding model in wider terms, listing observations, current report text, imaging studies, patient, order, prior studies, tracked observations, and electronic health record data as the elements OIDM organizes over FHIR.[^site-structure] +The 2024 site post describes a broader model organized over FHIR. It includes observations, current report text, imaging studies, patient, order, prior studies, tracked observations, and electronic health record data.[^site-structure] # The applications -Finding Model Forge is the authoring front end: sign in, name a finding, generate a description, review it, generate attributes, and save a draft that moves through a submission and review lifecycle.[^forge] The catalog site reads finding model definitions directly out of the content repository at build time and renders browsable pages. The report extraction and coding platform takes narrative report text, extracts findings in chunks, validates against verbatim quotes, and assigns finding and location codes in a separate post-extraction coding pass.[^ipl-dev] The viewer renders Imaging Problem Lists, with a second-generation anatomy-aware dashboard. The `molu` terminology lookup library resolves terms and codes across RadLex, SNOMED CT, FMA, LOINC, and UMLS, which is the infrastructure the enrichment and coding work depends on. +Finding Model Forge supports authoring and review. Authors sign in, name a finding, generate and review a description, generate attributes, and save a draft for submission and review.[^forge] The catalog site reads definitions from the content repository at build time and creates browsable pages. + +The report extraction and coding platform extracts findings from chunks of narrative report text and validates them against verbatim quotes. A separate pass assigns finding and location codes.[^ipl-dev] The rule that keeps the coding honest is stated in the assignment rules document on the extraction platform's development branch: an anatomic location is attached only when the report localizes the finding, and is omitted rather than guessed when it does not.[^ipl-anat-rules] -The rule that keeps the coding honest is stated in the assignment rules document on the extraction platform's development branch: an anatomic location is attached only when the report localizes the finding, and is omitted rather than guessed when it does not.[^ipl-anat-rules] +The viewer displays Imaging Problem Lists and has a second-generation anatomy-aware dashboard. The `molu` library supports enrichment and coding through term and code lookup across RadLex, SNOMED CT, FMA, LOINC, and UMLS. # Implementation status @@ -158,7 +132,7 @@ The layers are at very different stages. This table states where each piece actu | Open Imaging Reporting SDK | Concept only | Named as a strategic pillar in the deck; no repository or artifact exists[^deck] | | ACR-OIDM working group | Proposed | Stated as a call to action in the deck; not recorded as convened[^deck] | -Per-area goals and the sources that state them are collected under [roadmap](/roadmap/). Every repository, its role, and its branch of record are listed in [the repository map](/repositories/repository-map.md). +See [roadmap](/roadmap/) for goals and their sources, and [the repository map](/repositories/repository-map.md) for repository roles and branches of record. [^deck]: Open Imaging Data Model 2026 Status Update, January 2026 [^fm-model]: FindingModelFull definition, findingmodel repository, main diff --git a/knowledge/overview/architecture.svg b/knowledge/overview/architecture.svg new file mode 100644 index 0000000..2676e81 --- /dev/null +++ b/knowledge/overview/architecture.svg @@ -0,0 +1,2 @@ +APPLICATIONSFinding Model Forgeauthoring wizardfmf.oidm.orgReport extractionplatformLLM extractionand coding (dev)Imaging ProblemList viewerimaging-problem-list.pages.devDATA STRUCTURESObservationfinding + location+ attributesExam Finding Listall observationsof one examImaging Problem Listone patient, groupedby findingper examper patientextracts fromreportsrendersImaging Personaplus clinicalcontext (concept)goal: extends the ImagingProblem List with contextSEMANTIC FOUNDATIONFinding modelsOIFM_ / OIFMA_codesAnatomic locationsRadLex RID codesExam typesLOINC / Playbook(planned)supplies the LOINCexam code on theExam Finding ListOIFM andOIFMA codesRIDauthorsACR/RSNA CDEs atRadElementRDES / RDE codes(allied project)finding models graduate to CDEs;CDE definitions seed finding modelsTerminologies underneath: RadLex, SNOMED CT, FMA, UMLS, MeSH, LOINC and the RSNARadiology Playbook. Looked up through med-ontology-lookup.Legendsolid outline: exists todaydashed outline: documented or planned onlyorange: allied external project \ No newline at end of file diff --git a/knowledge/overview/getting-involved.md b/knowledge/overview/getting-involved.md index ca3f7c0..5e6de68 100644 --- a/knowledge/overview/getting-involved.md +++ b/knowledge/overview/getting-involved.md @@ -4,7 +4,7 @@ title: Getting involved description: Where the OIDM community gathers, which repositories to start with, how to file issues, how content is contributed, and how this knowledgebase is edited. tags: [overview, community, contributing] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T15:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:34:50Z } sources: - id: site-involved resource: https://www.openimagingdata.org/how-to-get-involved/ @@ -25,7 +25,7 @@ sources: # Where the project gathers -Everything OIDM produces is public. The four durable entry points are the GitHub organization, the project site, the Slack channel, and the deployed tools. +OIDM's work is public. These channels provide access to its code, content, tools, and discussions. | Channel | Where | What it is for | |---|---|---| @@ -35,13 +35,13 @@ Everything OIDM produces is public. The four durable entry points are the GitHub | Finding Model Forge | | Authoring finding models through a browser | | IPL viewer demo | | Seeing an Imaging Problem List rendered from real sample data | -The site's participation post also invites registration for newsletter updates and article comments, describes working groups on use cases and standards work, and asks for help identifying related projects and venues where the work would have impact.[^site-involved] That post dates from August 2023 and parts of it have aged: it advertises a working group on the TypeScript reference implementation, which is now a lineage repository rather than active work, and its meeting section is a placeholder. Treat the GitHub organization and the Slack channel as the current live channels. The site also carries a contact link for general inquiries. +Use GitHub and Slack for current discussions. The site's August 2023 participation post invites newsletter registration and article comments, describes use-case and standards working groups, and seeks related projects and venues.[^site-involved] Some details have aged. The advertised working group on the TypeScript reference implementation concerns a repository now kept for lineage. The meeting section remains a placeholder. The site also has a contact link for general inquiries. -The largest stated organizational goal is not yet a channel you can join. The January 2026 deck proposes an "ACR-OIDM Structured Imaging Results Working Group" co-hosted with the ACR, bringing expert and vendor participants into one venue, with a use-case pipeline feeding the ACR and RSNA common data element group.[^deck] It is a proposal, not a convened body. +The January 2026 deck proposes an "ACR-OIDM Structured Imaging Results Working Group" co-hosted with the ACR. It would bring together experts and vendors, with a use-case pipeline feeding the ACR and RSNA common data element group.[^deck] The group is not recorded as convened. # Repositories to start with -Pick by what you want to do. Every repository, including the lineage ones, is listed with its status and branch of record in [the repository map](/repositories/repository-map.md). +Choose a repository by task. [The repository map](/repositories/repository-map.md) lists all repositories, including lineage projects, with their status and branches of record. | If you want to | Start at | |---|---| @@ -52,36 +52,36 @@ Pick by what you want to do. Every repository, including the lineage ones, is li | Look up codes across terminologies | `openimagingdata/med-ontology-lookup`, the `molu` library and CLI | | Work on the authoring application | `openimagingdata/FindingModelForge` | -Several of these repositories have their current state on a branch other than `main`. Check the repository map before assuming the default branch is the live one. +Check the repository map before starting. Several repositories keep current work on branches other than `main`. # Filing issues -Each repository carries its own issue tracker, and issues are where the work edge is visible. File against the repository that owns the thing you are reporting. +File issues in the repository that owns the affected content or code. -- **A wrong, missing, or badly scoped finding model** goes to `openimagingdata/findingmodels`. The public catalog site routes its "Submit Issue" link there.[^catalog-site] -- **A bug or gap in the library, CLI, or anatomic location data** goes to `openimagingdata/findingmodel`. -- **A question about the data structures** goes to `openimagingdata/imaging-problem-list`. Its issue #1, asking for a formal model layer with JSON Schema export for Observation, Exam Finding List, and Imaging Problem List, is open and unclaimed. -- **Terminology lookup behavior** goes to `openimagingdata/med-ontology-lookup`. +- Report wrong, missing, or badly scoped finding models to `openimagingdata/findingmodels`. The public catalog's "Submit Issue" link goes there.[^catalog-site] +- Report library, CLI, or anatomic location data problems to `openimagingdata/findingmodel`. +- Ask data structure questions in `openimagingdata/imaging-problem-list`. Its open, unclaimed issue #1 requests a formal model layer with JSON Schema export for Observation, Exam Finding List, and Imaging Problem List. +- Report terminology lookup problems to `openimagingdata/med-ontology-lookup`. -Existing open issues are the best statement of what the project knows is missing. They are summarized by area under [roadmap](/roadmap/). +See [roadmap](/roadmap/) for open issues by area. # Contributing content -Content means [finding models](/glossary/finding-model.md) and the [anatomic locations](/glossary/anatomic-location.md) they reference. There are three routes, and they differ in how much of the work you do by hand. +Content includes [finding models](/glossary/finding-model.md) and their [anatomic locations](/glossary/anatomic-location.md). Choose one of three contribution routes. -**Through Finding Model Forge.** The browser application is the supported route for authoring a single finding model without cloning anything. You sign in with GitHub, name the finding, generate and edit a description and synonyms, generate the attributes, and the draft autosaves. Submitting locks the draft for review, and a reviewer moves it through under review to added or declined.[^forge] Editing a model after creation is an open issue on that repository, not yet available. +**Finding Model Forge.** To author a single model in the browser, sign in with GitHub and name the finding. Generate and edit its description and synonyms, then generate attributes. The draft autosaves. Submission locks it for review, and a reviewer moves it through under review to added or declined.[^forge] Editing a model after creation is an open issue on that repository, not yet available. -**Through the content repository.** Definitions live as one JSON file per finding, validated on commit, with identifiers issued from a registry that detects duplicates. Batch authoring and review run through agent skills held in that repository. Contributing this way means working with the schema directly; the prose mirror of the schema is the reference.[^fm-content] +**The content repository.** Definitions are JSON files, one per finding, validated on commit. A registry issues identifiers and detects duplicates. Repository agent skills support batch authoring and review. Use the prose schema mirror when editing definitions directly.[^fm-content] -**Through staged common data elements.** Candidate definitions authored informally, ahead of formal review, are staged in `openimagingdata/CDEStaging` before entering the ACR and RSNA review pipeline that publishes through RadElement. That path is a manual curation workflow rather than an automated one. +**Staged common data elements.** Informal candidate definitions go into `openimagingdata/CDEStaging` before formal ACR and RSNA review and publication through RadElement. This is a manual curation workflow. -Identifier discipline matters in all three routes. An [OIFM identifier](/glossary/oifm.md) encodes its contributing organization in its letter block, and identifiers are never reissued or regenerated on a round trip. The authoring conventions are covered in [the authoring workflow](/semantic-foundation/finding-models/authoring-workflow.md). +Identifier discipline matters in all three routes. An [OIFM identifier](/glossary/oifm.md) encodes its contributing organization in its letter block, and identifiers are never reissued or regenerated on a round trip. See [the authoring workflow](/semantic-foundation/finding-models/authoring-workflow.md) for conventions. # Contributing to this knowledgebase -This repository is the canonical high-level documentation, written as an Open Knowledge Format bundle so that both people and agents can read it. It describes and links to catalogs; it does not copy them. Code documentation, install steps, and developer workflow stay with the code. +This repository provides canonical high-level documentation as an Open Knowledge Format bundle for people and agents. It describes and links to catalogs; it does not copy them. Keep installation instructions, API usage, and developer workflows with the code. -Before editing anything here, read [the authoring guide](/guides/authoring-guide.md). It sets the document types, the required frontmatter, the trust workflow by which a draft becomes verified, the linking conventions, and the procedure for migrating a document out of a working repository. Two checkers run on every push and must pass: an Open Knowledge Format conformance validator and a house-rules checker that enforces the type vocabulary, index coverage, link resolution, and a sweep for names and email addresses. +Read [the authoring guide](/guides/authoring-guide.md) before editing. It covers document types, frontmatter, draft verification, links, and document migration. Two checkers must pass on every push: the Open Knowledge Format validator and a house checker for types, index coverage, links, names, and email addresses. Two house rules catch newcomers. Facts and stated goals only, with every goal citing the deck, issue, or plan that states it, because design proposals belong to a separate workstream. And organizations, not individuals: the project lead is named as such and nobody else is named. diff --git a/knowledge/overview/vision.md b/knowledge/overview/vision.md index 7f1f41c..4e6adb2 100644 --- a/knowledge/overview/vision.md +++ b/knowledge/overview/vision.md @@ -4,7 +4,7 @@ title: Vision description: Why OIDM pursues object-oriented imaging results, what that unlocks across the imaging life cycle, and what the project has proposed next. tags: [overview, vision, strategy] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T15:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:34:50Z } sources: - id: deck resource: https://gamma.app/docs/Open-Imaging-Data-Model-2026-Status-Update:-Realizing-Object-Oriented-Imaging-Results-yfxzx4q9zssafal @@ -28,31 +28,31 @@ sources: # Object-oriented imaging results -The January 2026 status deck frames the project's goal as "standardizing the DNA of imaging IT" and titles itself "Realizing Object-Oriented Imaging Results."[^deck] The metaphor is deliberate. An imaging result today is a document. The proposition is that it should instead be a set of objects: each finding an addressable thing with a type, a location, attributes, and an identity that persists across exams. +The January 2026 status deck calls OIDM's goal "standardizing the DNA of imaging IT" and titles itself "Realizing Object-Oriented Imaging Results."[^deck] It proposes representing each finding as an object with a type, location, attributes, and an identity that persists across exams. -The earlier site posts set the technical form of that proposition. A finding is "a standard format based on FHIR Observations semantically labeled with ACR/RSNA Common Data Element identifiers."[^site-findings] The wider model is described as "a superstructure on top of these FHIR definitions to both organize them and enable more straightforward programmatic access to the data," with an explicit analogy: "the relationship between OIDM and FHIR might be that between the browser's DOM and HTML."[^site-structure] FHIR supplies the resources; OIDM supplies the object model over them that software can actually program against. +The site posts describe a finding as "a standard format based on FHIR Observations semantically labeled with ACR/RSNA Common Data Element identifiers."[^site-findings] The wider model is "a superstructure on top of these FHIR definitions to both organize them and enable more straightforward programmatic access to the data." The post compares the layers: "the relationship between OIDM and FHIR might be that between the browser's DOM and HTML."[^site-structure] FHIR supplies resources, and OIDM supplies an object model for programmatic access. # What object-oriented results unlock -The deck names three consequences.[^deck] +The deck names three benefits.[^deck] -**A unified reading toolset.** Picture archiving and communication systems, reporting software, and artificial intelligence tools currently each hold their own partial, private representation of what an exam showed. A shared object model lets one representation serve all three, so a finding created in one tool is legible in the next. +**A unified reading toolset.** Picture archiving and communication systems, reporting software, and artificial intelligence tools each hold partial, private representations of exam results. A shared object model would make findings created in one tool readable by the others. -**Integrated data sources.** Radiologists, the electronic medical record, and artificial intelligence tools all produce statements about a patient's imaging. When each produces the same kind of object, they can be merged, compared, and attributed rather than kept in separate lanes. The deck lists correlating artificial intelligence observations against radiologist observations as an explicit validation use case. +**Integrated data sources.** A common representation would let systems merge, compare, and attribute statements from radiologists, electronic medical records, and artificial intelligence tools. The deck proposes validating artificial intelligence tools by correlating their observations with radiologist observations. -**Downstream longitudinal utility.** Once findings are objects with identity, a patient's imaging history becomes queryable. The core query the deck names for the [Imaging Problem List](/glossary/imaging-problem-list.md) is whether a given finding was present on the most recent study, with dynamic tracking of appearance, disappearance, and change. +**Downstream longitudinal utility.** Findings with persistent identities would make imaging histories queryable. The deck's core query for the [Imaging Problem List](/glossary/imaging-problem-list.md) is whether a finding was present on the most recent study, with tracking of appearance, disappearance, and change. # The workbench relationship between finding models and CDEs -The deck's most specific strategic claim concerns the relationship between [finding models](/glossary/finding-model.md) and formal [common data elements](/glossary/cde.md). It calls the Open Imaging Finding Model corpus "the CDE workbench."[^deck] +The deck calls the [finding models](/glossary/finding-model.md) corpus "the CDE workbench."[^deck] [Common data elements](/glossary/cde.md) published through RadElement undergo formal ACR and RSNA review, versioning, and governance. That process supports adoption but slows creation. -The reasoning is about velocity and governance. Common data elements published through RadElement are formally reviewed, versioned, and governed by the ACR and RSNA, which is what makes them worth adopting and also what makes them slow to create. Finding models are authored quickly, with language model assistance, through [Finding Model Forge](https://fmf.oidm.org) and agent-driven batch workflows. The deck positions that speed as a feature: finding models are a "rapid innovation / proving ground before ACR/RSNA CDE adoption," carrying "exploratory metadata" in the form of "rich definitions w/ embedded relationships and semantic tags that can graduate to standards."[^deck] +[Finding Model Forge](https://fmf.oidm.org) and agent-driven batch workflows support faster authoring with language model assistance. The deck describes finding models as a "rapid innovation / proving ground before ACR/RSNA CDE adoption." Their "exploratory metadata" includes "rich definitions w/ embedded relationships and semantic tags that can graduate to standards."[^deck] -The finding model corpus therefore serves two purposes at once. It is programmatic knowledge, described in the deck as "ground-level info for tool access + LLM context engineering," usable today by extraction and reporting tools. And it is a staging ground whose proven definitions become candidates for formal common data elements. The relationship is treated in depth in [Finding models and CDEs](/semantic-foundation/finding-models/finding-models-and-cdes.md). +The corpus supplies knowledge for extraction and reporting tools, described in the deck as "ground-level info for tool access + LLM context engineering." Proven definitions become candidates for formal common data elements. See [Finding models and CDEs](/semantic-foundation/finding-models/finding-models-and-cdes.md). # The Imaging Problem List across the imaging life cycle -The deck argues that structured results pay off at every stage of an imaging encounter, not only at reporting.[^deck] +The deck proposes uses for structured results throughout an imaging encounter.[^deck] | Stage | Stated application | |---|---| @@ -61,31 +61,31 @@ The deck argues that structured results pay off at every stage of an imaging enc | Interpretation | Findings-oriented views in the picture archiving system, real-time quality control | | Post-interpretation | Passive screening, research cohorts, outcomes tracking | -The same point appears in the 2023 framework post, which proposes a plugin-container architecture in which a reporting tool hosts small programs, supplies them with "all the relevant contextual information, about the findings in the current report, about prior reports, about the exams that were being reported on," re-runs them whenever the report context changes, and lets them issue commands back to insert text, request input, raise alerts, or send data onward.[^site-plugin] That architecture only works if the context handed to the plugins is structured, which is what the data structures layer provides. +The 2023 framework post proposes a reporting tool that hosts plugins and supplies "all the relevant contextual information, about the findings in the current report, about prior reports, about the exams that were being reported on." The tool reruns plugins when context changes. Plugins can insert text, request input, raise alerts, or send data onward.[^site-plugin] The data structures layer provides the structured context those plugins need. # Why not just let the language model read the report -Large language models can read narrative reports well, which raises the obvious objection that structure is unnecessary. The deck answers it with three arguments.[^deck] +Large language models can read narrative reports, but the deck gives three reasons to retain structured results.[^deck] -**Context engineering.** A model answers better when given the relevant findings directly than when given a stack of prior reports to re-read. Structured results are how the right context gets selected and delivered. +**Context engineering.** Models answer better when given relevant findings directly. Structured results let systems select that context from prior reports. -**Deterministic logic.** Some decisions must not be probabilistic. MRI safety checks and protocol selection are rule evaluations over facts. They need facts with known types and known codes, not an inference drawn fresh from prose on each run. +**Deterministic logic.** MRI safety checks and protocol selection require rules over facts with known types and codes. Reinterpreting prose on each run does not provide that consistency. -**Citable common context.** When several systems act on the same patient, they need to be acting on the same stated facts, with a shared reference that can be pointed at and audited. A model's private reading of a report is neither shared nor citable. +**Citable common context.** Systems acting on the same patient need shared, auditable facts. A model's private interpretation of a report provides no shared reference. -The argument is not that language models are unsuited to the work. They do the extraction: the deck's own premise is that the Imaging Problem List is "automatically extractable from narrative report text via LLMs."[^deck] The argument is about where the model sits. It converts prose into objects once, and everything downstream operates on the objects. +The deck describes the Imaging Problem List as "automatically extractable from narrative report text via LLMs."[^deck] Language models convert prose into objects once for downstream systems to use. # The proposed working group -The deck's call to action is a proposal, not an existing body. It proposes that the ACR co-host an "ACR-OIDM Structured Imaging Results Working Group," bringing together expert and vendor participants.[^deck] Three principles are stated for it: structure first, with mapping to FHIR and other standards following rather than leading; vendor-driven innovation, with reporting software vendors building on the result; and an academic-vendor "big tent" that the project would host and moderate. +The deck's call to action is a proposal, not an existing body. The deck proposes an "ACR-OIDM Structured Imaging Results Working Group," co-hosted with the ACR and bringing together expert and vendor participants.[^deck] Its principles are to define structures before mapping them to FHIR and other standards, support innovation by reporting software vendors, and host an academic-vendor "big tent" moderated by the project. -The deck lists four ACR priorities the working group would serve: recommendation tracking, validation of artificial intelligence tools by correlating their observations against radiologist observations, quality metrics, and support for the *-RADS reporting systems. The stated next steps are to convene that group, run a use-case pipeline feeding the CDE group, and standardize the result. +The proposed group would address four ACR priorities: recommendation tracking, artificial intelligence validation against radiologist observations, quality metrics, and support for the *-RADS reporting systems. The next steps are to convene the group, run a use-case pipeline feeding the CDE group, and standardize the result. -As of this writing the working group is a proposal recorded in the deck. Nothing in the source repositories records it as convened. Stated goals for each area are collected under [roadmap](/roadmap/). +As of this writing the working group is a proposal recorded in the deck. Nothing in the source repositories records it as convened. Area-specific goals appear under [roadmap](/roadmap/). # Evidence offered so far -The vision has been argued in a peer-reviewed venue. A 2024 site post announces a manuscript in the Journal of the American Medical Informatics Association titled "Standardizing imaging findings representation: harnessing Common Data Elements semantics and Fast Healthcare Interoperability Resources structures," whose position the post summarizes as "CDE-labeled Observations should be the universal representation for exchanging and consuming content in radiology reports," worked through a pulmonary nodule case study together with guidance on adoption challenges.[^site-benchmark] +A 2024 site post announces a manuscript in the peer-reviewed Journal of the American Medical Informatics Association titled "Standardizing imaging findings representation: harnessing Common Data Elements semantics and Fast Healthcare Interoperability Resources structures." The post summarizes its position as "CDE-labeled Observations should be the universal representation for exchanging and consuming content in radiology reports." The manuscript presents a pulmonary nodule case study and guidance on adoption challenges.[^site-benchmark] [^deck]: Open Imaging Data Model 2026 Status Update, January 2026 [^site-structure]: "Data Model: Structure and Function", 2024-01-25 diff --git a/knowledge/overview/what-is-oidm.md b/knowledge/overview/what-is-oidm.md index 2623b21..9042524 100644 --- a/knowledge/overview/what-is-oidm.md +++ b/knowledge/overview/what-is-oidm.md @@ -4,7 +4,7 @@ title: What is OIDM description: The mission of the Open Imaging Data Model, the problem it addresses, its three layers, who it serves, and where its work lives. tags: [overview, orientation] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T15:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:34:50Z } sources: - id: deck resource: https://gamma.app/docs/Open-Imaging-Data-Model-2026-Status-Update:-Realizing-Object-Oriented-Imaging-Results-yfxzx4q9zssafal @@ -25,46 +25,46 @@ sources: # What OIDM is -The [Open Imaging Data Model (OIDM)](/glossary/oidm.md) is an open project that defines how the results of an imaging exam are represented as data rather than as prose. Its stated purpose, in the words of the project site, is "defining unified data structures to integrate new functionality into imaging informatics platforms."[^site-about] The January 2026 status deck puts the same ambition more bluntly: standardizing "the DNA of imaging IT."[^deck] +The [Open Imaging Data Model (OIDM)](/glossary/oidm.md) is an open project that represents imaging exam results as structured data. The project site describes its purpose as "defining unified data structures to integrate new functionality into imaging informatics platforms."[^site-about] The January 2026 status deck calls this standardizing "the DNA of imaging IT."[^deck] -Concretely, OIDM supplies three things. It supplies a controlled vocabulary of imaging findings and the attributes that characterize them, each carrying a stable identifier. It supplies a small hierarchy of data structures that carry those findings from a single [observation](/glossary/observation.md) up to a longitudinal view of one patient. And it supplies working tools that produce and consume those structures, so that the vocabulary and the structures are exercised against real reports rather than only specified. +OIDM provides a controlled vocabulary, data structures, and tools that produce and consume them. Stable identifiers connect findings and their attributes across individual [observations](/glossary/observation.md) and longitudinal patient records. The tools apply the vocabulary and structures to real reports. # The problem: results locked in narrative -An imaging report is the product of the exam, and it is almost always a block of narrative text. That text is readable by a clinician and opaque to everything else. A downstream system that wants to know whether a pulmonary nodule was present on the most recent chest CT, how large it was, and whether it grew, has to re-read the prose every time, and each system re-reads it differently. +Imaging reports are usually narrative text. To determine whether a pulmonary nodule was present on the latest chest CT, how large it was, or whether it grew, downstream systems must interpret that text. Each system interprets it differently. -The consequences compound across the imaging life cycle. Prior findings cannot be retrieved reliably at interpretation time, so radiologists reconstruct history by reading old reports. Recommendations made in a report cannot be tracked to completion. Quality metrics and registry submissions require manual abstraction. Findings produced by artificial intelligence tools and findings produced by radiologists cannot be compared, because they are not expressed in the same terms. Each vendor that solves part of this solves it privately, in its own schema, which means the solution does not travel. +Radiologists reconstruct finding histories from old reports because prior findings cannot be retrieved reliably. Recommendations cannot be tracked to completion. Quality metrics and registry submissions require manual abstraction. Artificial intelligence tools and radiologists express findings differently, preventing comparison. Vendors address these problems with private schemas that other systems cannot reuse. -OIDM's response is to make the finding, not the report, the unit of data. A finding gets a coded identity, a coded location, coded attributes, and a place in a structure that other systems can query. The 2023 site post that set the direction states it as: "Radiology findings can be represented in a standard format based on FHIR Observations semantically labeled with ACR/RSNA Common Data Element identifiers."[^site-findings] +OIDM gives each finding a coded identity, location, and attributes in a queryable structure. The 2023 site post states the approach: "Radiology findings can be represented in a standard format based on FHIR Observations semantically labeled with ACR/RSNA Common Data Element identifiers."[^site-findings] # Three layers -The project organizes its work into three layers, and this knowledgebase follows that organization. +The project and this knowledgebase organize the work into three layers. -**Semantic foundation.** The vocabulary layer. It holds [finding models](/glossary/finding-model.md), each a named finding with a description, synonyms, and a list of attributes, identified by an [Open Imaging Finding Model (OIFM)](/glossary/oifm.md) identifier.[^fm-schema] It holds [anatomic locations](/glossary/anatomic-location.md) keyed by RadLex identifiers, [common data elements](/glossary/cde.md) published through RadElement, [exam types](/glossary/exam-type.md), and the external terminologies all of these draw on. See [semantic-foundation](/semantic-foundation/). +**Semantic foundation.** [Finding models](/glossary/finding-model.md) define findings with descriptions, synonyms, and attributes. Each has an [Open Imaging Finding Model (OIFM)](/glossary/oifm.md) identifier.[^fm-schema] The layer also includes [anatomic locations](/glossary/anatomic-location.md) keyed by RadLex identifiers, [common data elements](/glossary/cde.md) published through RadElement, [exam types](/glossary/exam-type.md), and external terminologies. See [semantic-foundation](/semantic-foundation/). -**Data structures.** The container layer. An [Observation](/glossary/observation.md) is one finding in one exam, with its location and attribute values. An [Exam Finding List](/glossary/exam-finding-list.md) is every observation from one exam in one queryable structure.[^ipl-readme] An [Imaging Problem List](/glossary/imaging-problem-list.md) reorganizes observations across a patient's exams by finding rather than by date. An [Imaging Persona](/glossary/imaging-persona.md) is the stated goal of surrounding that with clinical context. See [data-structures](/data-structures/). +**Data structures.** An [Observation](/glossary/observation.md) records one finding in one exam, with its location and attribute values. An [Exam Finding List](/glossary/exam-finding-list.md) collects an exam's observations in one queryable structure.[^ipl-readme] An [Imaging Problem List](/glossary/imaging-problem-list.md) groups observations across a patient's exams by finding. An [Imaging Persona](/glossary/imaging-persona.md) is the stated goal of adding clinical context. See [data-structures](/data-structures/). -**Applications.** The tools that make the first two layers real: an authoring application for finding models, a catalog site, a viewer for Imaging Problem Lists, a report extraction and coding platform, and a terminology lookup library. See [applications](/applications/). +**Applications.** Tools include a finding model authoring application, a catalog site, an Imaging Problem List viewer, a report extraction and coding platform, and a terminology lookup library. See [applications](/applications/). -Each layer depends on the one below it, and the identifiers are what join them. How the layers and identifier systems connect is laid out in [Architecture](/overview/architecture.md), and the reasoning behind the whole design in [Vision](/overview/vision.md). +Each layer depends on the one below it through shared identifiers. [Architecture](/overview/architecture.md) explains those connections. [Vision](/overview/vision.md) explains the design rationale. # Who this is for -- **Developers** building imaging informatics software who need formats to read and write, and libraries that already speak them. -- **Informaticists** who need to know what a finding model is, how it relates to a common data element, and what identifier to use for an anatomic structure. -- **Standards bodies and committees** evaluating the vocabulary and data structures, and deciding what should graduate into formal standards. -- **Agents** doing extraction, coding, or authoring work, which is why this knowledgebase is an Open Knowledge Format bundle with machine-readable frontmatter on every document. +- Developers building imaging informatics software need formats and libraries to read and write them. +- Informaticists need to understand finding models, their relationship to common data elements, and identifiers for anatomic structures. +- Standards bodies and committees evaluate vocabulary and data structures for formal standardization. +- Agents extract, code, or author content. This knowledgebase is an Open Knowledge Format bundle with machine-readable frontmatter to support that work. # Where things live -The work is spread across repositories in the `openimagingdata` GitHub organization plus several allied external projects. Content, code, specifications, and in-flight work do not all live in the same place, and several repositories have their current state on a branch other than `main`. [The repository map](/repositories/repository-map.md) lists every source repository, its role, its status, and its branch of record. +OIDM spans repositories in the `openimagingdata` GitHub organization and allied projects. Several repositories keep current work on branches other than `main`. [The repository map](/repositories/repository-map.md) lists their roles, status, and branches of record. -This knowledgebase is the high-level documentation. It describes and links to catalogs; it does not copy them. Installation instructions, API usage, and developer workflow stay with the code. +It describes and links to catalogs; it does not copy them. Installation instructions, API usage, and developer workflows stay with the code. # Getting involved -Participation channels, the repositories to start with, how to file issues, and how content is contributed are covered in [Getting involved](/overview/getting-involved.md). Conventions for editing this knowledgebase itself are in [the authoring guide](/guides/authoring-guide.md). +See [Getting involved](/overview/getting-involved.md) for participation channels, repositories, issues, and content contributions. See [the authoring guide](/guides/authoring-guide.md) for knowledgebase conventions. [^deck]: Open Imaging Data Model 2026 Status Update, January 2026 [^site-about]: openimagingdata.org, project site and tagline diff --git a/knowledge/plans/2026-09-20-knowledgebase-build-plan.md b/knowledge/plans/2026-09-20-knowledgebase-build-plan.md index a45c065..5e666f7 100644 --- a/knowledge/plans/2026-09-20-knowledgebase-build-plan.md +++ b/knowledge/plans/2026-09-20-knowledgebase-build-plan.md @@ -4,7 +4,7 @@ title: Knowledgebase build plan description: How the oidm-knowledge repository is scaffolded, populated from the source repositories, cross-linked, validated, and published. tags: [plan, meta] status: draft -generated: { by: claude-fable-5-1/claude-code, at: 2026-09-20T22:30:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: charter resource: scope:grilling-session-2026-09-20 @@ -16,9 +16,9 @@ sources: # Purpose -Build `oidm-knowledge` as the canonical, public, high-level documentation for the Open Imaging Data Model (OIDM). Non-code documentation migrates here from the working repositories; those repositories will later reference this one. The bundle follows the Open Knowledge Format (OKF) 0.2 so that people and agents can both read it. +Build `oidm-knowledge` as canonical public, high-level documentation for the Open Imaging Data Model (OIDM) in Open Knowledge Format (OKF) 0.2. Migrate non-code documentation here and replace it with links in the source repositories. -This plan is itself part of the bundle. It is updated as phases complete and marked complete at the end. +This plan is itself part of the bundle. Update this plan as phases finish and mark it complete when all work is done. # Decisions already made @@ -40,7 +40,7 @@ These were settled with the project lead on 2026-09-20 and are not re-opened her # The project lead's stated goals -Recorded verbatim from the 2026-09-20 request that started this work, so that documents citing `scope:grilling-session-2026-09-20` have a written source. Wording lightly normalized for spelling only. +Recorded verbatim from the 2026-09-20 request that started this work, so that documents citing `scope:grilling-session-2026-09-20` have a written source. Only spelling was normalized. - **Open Imaging Finding Models.** "Definition formats, needs overhaul for increased metadata and interesting relationship/graph work coming from CDEs." "Tooling for working with these, using them, probably needs corresponding overhaul." "Actual content efforts." - **ACR/RSNA Common Data Elements.** "Should dovetail with the OIFM work." @@ -52,7 +52,7 @@ Recorded verbatim from the 2026-09-20 request that started this work, so that do # Source map -Inventory reports for every source live in the session scratchpad and are summarized here. "Read from" names the branch that represents current state. +Inventory reports for every source live in the session scratchpad and are summarized here. "Read from" names the branch used for current state. | Source | Role | Read from | Key migration candidates | |---|---|---|---| @@ -74,10 +74,12 @@ Inventory reports for every source live in the session scratchpad and are summar | openimagingdata.org (Ghost site) | 15 posts (2023-06 to 2025-03) and an About page | live | "Findings, CDEs, and Observations", "Data Model: Structure and Function", "Benchmarking a Vision", "OIDM-Based Next-gen Reporting Assistance Framework", the SIIM 2024 posts | | CDETemplateDemo, SARTemplatesToCDEs, template_extraction, ReportFindingRefiner, get_ontology_findings, ontology_tools, common_data_elements | Lineage | `main` | `SARTemplatesToCDEs/RectalCAStaging/Changes_vs_RDES11.md`, `ReportFindingRefiner/README.md`, `common_data_elements/README.md` and schema versions; the rest as one-paragraph history entries | | Gamma deck, January 2026 | Vision and roadmap | live | Whole deck as a Presentation Extract | +| SIIM 2026 deck, June 2026 ("Reports of the Future") | The framing: Patient Context and Foundation Context; the three axes (Observation Type, Anatomic Location, Exam Type) as OIDM layers over CDE/OIFM, RadLex, and the Playbook; relationships and external citations; SDKs that resolve codes; the ask | `sources/bucket/siim2026/` (public talk) | Whole deck; the slide 7 table and the foundation-context graph as figures, at the project lead's discretion | +| oidm-knowledge-sources bucket folder | Manuscripts (JACR IPL; two JDIM under review), the AI-evolution essay, the reporting-schema deck, the July 2026 SIIM webinar deck | `sources/bucket/REPORT.md` | Paraphrase and cite per the manuscripts rule; reviewer correspondence never used | # The work edge -The project lead asked that the knowledgebase reflect the entire work edge, not only default branches. Branch-level inventories on 2026-09-21 established the following. Documents that describe current state cite the branch and pin the commit they read. +The project lead asked that the knowledgebase reflect the entire work edge, not only default branches. Cite the branch and pin the commit they read for each account of current state. - **findingmodels.** The MGB exam-oriented sub-taxonomies on `taxonomy-export-2026-08-15` are the immediate direction for all content and are expected to replace many of the Gamuts-derived models, which make up 1,933 of the 2,382 current definitions. Rows without a matched OIFM ID are the next triage task. Three content pipelines (`content/chestcts` as the live CT-chest front, `content/headcts`, `km`) and a metadata-enrichment branch touching 78 models are in flight, none merged. The finding model schema is being extended on three uncoordinated branches with nothing landed on `main`. - **findingmodel.** The live thread is the canonical structured-metadata rewrite on `feature/metadata-cleanup` and `dev`: eight new optional fields (body regions, subspecialties, etiologies, entity type, applicable modalities, expected time course, age profile, sex specificity), a multi-agent enrichment architecture, and a dual-database release plan. The older eight-facet specification is superseded. The branch's own readiness assessment is not yet passing. Twenty-four open issues map one-to-one onto task plans. @@ -237,7 +239,7 @@ Remaining: ## Phase 1: Spine -Overview, glossary, repository map, history, references. These are written first because every later document links into them. +Write the overview, glossary, repository map, history, and references first so later documents can link to them. - Opus synthesis agents, one per directory, each given the relevant inventory reports, the source file paths, the authoring guide, and the deck extract. - The glossary harvests every definition-like statement the inventories quoted and flags conflicts for the project lead in `roadmap/open-questions.md`. @@ -265,7 +267,7 @@ Goals and open questions per area, drawn from the deck, GitHub issues, and plan 2. Both validators pass under strict mode. Site builds and deploys. Link checker passes. 3. The project lead reviews document by document. Each accepted document gains `verified` and `status: stable`. Rejections go back to the phase's agent with notes. 4. Documentation review: this plan marked complete, `CHANGELOG.md` reflecting the first release, `DEV_LOG.md` current, migration ledger complete. -5. Follow-ups filed as issues: source-repo pull requests replacing migrated docs with links; manuscripts to integrate; the proposals workstream (finding model format evolution, exam types, IPL data model system). +5. Follow-ups filed as issues: source-repo pull requests replacing migrated docs with links; manuscripts to integrate; the proposals workstream (finding model format evolution, exam types, IPL data model system); production custom domain knowledge.openimagingdata.org for the oidm-knowledge Worker (not urgent); off-the-shelf page feedback and comments (Hypothesis or Giscus); a Quartz plugin rendering OKF `sources` and `verified` as typed graph edges. # Phase status @@ -289,6 +291,34 @@ Answers can come at approval time or during Phase 1. 4. Answered 2026-09-21: publish the next-generation vocabulary document as draft, sourced to the branch, no committee material. 5. Answered 2026-09-21: publish the use case catalog with the committee credit. + +# Decisions added 2026-09-21 + +| Topic | Decision | +|---|---| +| Manuscripts in the bucket | Paraphrase facts, structures, and numbers; cite as "manuscript under review at JDIM, 2026" or "prepared for submission"; never quote; reviewer correspondence never reproduced or paraphrased. | +| Excalidraw boards | Publish the public-facing boards (object model, structured report sections, outcome tracking, exhibit figures, lineage, use-case notes). From internal boards, publish only schema and data-model ideas with organizations named; people, meeting histories, and vendor demo logistics omitted; the rest recorded as reviewed and held. | +| Diagrams | No Mermaid. Excalidraw files rendered to SVG beside each document. Per diagram, a builder is the source until the file is hand-edited, after which the builder is retired (tools/diagrams/README.md). | +| Vendor name in the deck extract | Generalized to "a reporting vendor". | +| Remote | openimagingdata/oidm-knowledge created public; site deploy workflow disabled until the site generator is settled; the project lead pushes main (agent pushes are blocked by a local guard). | +| Upstream defects | Drafted for the project lead's review before any issue is filed. | +| No specification exists | The project is in a coalescing phase; nothing is formally defined. The knowledgebase presents each source's current version of a structure side by side (repo branch and commit, manuscript under review, deck or webinar, board), dated and attributed, and states disagreements (for example the three Imaging Problem List status vocabularies) without resolving them. Words like "specification" or "canonical model" are not used for any of them. | +| Data structures versus transport | Per the project lead's 2026-09-19 manuscript notes: OIDM defines a system of data structures for imaging exam result information used inside applications; FHIR and DICOM are transport expressions designed separately and guided by the structures. The data-structure documents are to be reframed accordingly. | +| Page feedback (later) | Wanted: off-the-shelf page comments and suggested changes, possibly dictation; candidates Hypothesis or Giscus. Not this iteration. | +| Site generator and host | Decided 2026-09-21 after a survey of wiki and knowledge-graph tools (sources/site-tools-comparison.md): Quartz stays, on Cloudflare Workers static assets, which serve its clean URLs natively. Three targets: oidm-knowledge-dev (default, `task deploy`), oidm-knowledge-staging (`task deploy:staging`, also the push-to-main workflow), oidm-knowledge (`task deploy:prod`). Typed-edge graph from OKF frontmatter is a Quartz plugin to write later. The object-storage pipeline was removed. | + + +# Decisions added 2026-09-22 + +| Topic | Decision | +|---|---| +| Structure | Five named pillars, always by name: Foundation Context (schema and meta-definitions plus the content build-out), Data Structures (especially the Observation layer and how the patient graph and the foundation graph work together), SDKs, Use Cases (the team's documented possible applications, tools, plugins, and outputs), Sample Applications (what was actually built). The earlier three-layer and four-pillar organizations are superseded. Ideas mined from repository documents, plans, prompts, skills, and ADRs are the team's own ideas and enter as content. | +| CDEs and finding models | The same content in two collections: the inclusive OIDM-maintained finding models and the well-reviewed ACR/RSNA CDEs. Both are intended to use the schema and classes of the CDE schema rewrite (FindingClass, DataElement, Measurement, and the rest). Explained once as a common model, then the two collections and their relationship. Collection expectations are not per-item facts; migration is intended, not complete. | +| OIFM reorganization | Reorganizing the finding models around the graph-based approach of the CDE next-generation schema effort is an immediate priority, stated as direction under Foundation Context with current implementation kept distinct. No storage, schema, or migration design beyond the source work. | +| Source eligibility | Repository documents, prompts, plans, skills, ADRs, and code are team artifacts eligible for substantive content, not demoted for being agent-assisted. Each claim carries its source's status, date, and any provenance label the source supplies. Differences and later corrections are preserved, not reconciled. | +| Terminology | Foundation Context and Patient Context from the SIIM 2026 deck. The CDE report graph and the Imaging Problem List representations are related representations of the Observation idea. Retained artifact names are used where a source's files are cited. | +| Restructure record | The operating record is `docs/plans/restructure-joint-notes.md` (decisions, agreed outline, next steps) with `docs/plans/idea-placement.md` mapping every inventoried idea to its section. | + # Risks - **Drift while writing.** Source repos are active. Every `sources` entry pins a commit so a reader can tell what version was read. diff --git a/knowledge/references/anatomic-location-json-schema.md b/knowledge/references/anatomic-location-json-schema.md index f373ea4..46b7f25 100644 --- a/knowledge/references/anatomic-location-json-schema.md +++ b/knowledge/references/anatomic-location-json-schema.md @@ -1,10 +1,10 @@ --- type: Reference title: Anatomic location record format -description: The two JSON record formats for anatomic locations, the original anatomiclocations.org body part schema and the current anatomic-locations package format, with a real record from each. +description: The original and current anatomic location formats, with field tables and sample records. tags: [references, anatomic-locations, schema, radlex] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: al-schema resource: https://github.com/talkasab/anatomiclocations.org/blob/1f39fa45f621cef947a3f3ef1f869334cfa5c841/data/body_parts_schema.json @@ -31,7 +31,7 @@ sources: # Provenance and status -Two record formats for [anatomic locations](/glossary/anatomic-location.md) coexist in OIDM, and this document holds both. The first is the original schema from the `anatomiclocations.org` repository, read at commit `1f39fa4`, which validates a curated set of 2,890 body parts keyed by [RadLex](/glossary/radlex.md) identifier. The second is the format used by the `anatomic-locations` package inside the `findingmodel` repository, read at commit `75afd39` on `main`, which covers 2,926 records and adds classification, dual hierarchies, and explicit [laterality](/glossary/laterality.md). The build plan names the newer package and its dataset as the current anatomic data, and the older set as lineage.[^build-plan] Field tables here are compiled from the schema file and the model source; the records shown are copied unchanged from the published data. +OIDM has two [anatomic location](/glossary/anatomic-location.md) formats. The original `anatomiclocations.org` schema at `1f39fa4` validates 2,890 body parts keyed by [RadLex](/glossary/radlex.md) identifiers. The `anatomic-locations` package in `findingmodel/main` at `75afd39` covers 2,926 records with classification, dual hierarchies, and explicit [laterality](/glossary/laterality.md). The build plan identifies the newer package as current and the older set as lineage.[^build-plan] Tables derive from the schemas and model source. Example records are unchanged. # Lineage A: the anatomiclocations.org body part schema @@ -90,7 +90,7 @@ The entry for uterine adnexa shows containment, part-of, a laterality pair, sex # Lineage B: the anatomic-locations package format, current -This lineage has two representations of the same information. The curation format is the JSON file that editors change, documented in the repository's own field reference.[^fm-json-schema] The runtime format is the `AnatomicLocation` Pydantic model that the package returns from its index.[^fm-location-model] +Editors use the JSON curation format documented in the field reference.[^fm-json-schema] The package index returns the runtime `AnatomicLocation` Pydantic model.[^fm-location-model] ## Curation format fields @@ -117,7 +117,7 @@ The source file `notebooks/data/anatomic_locations_noembed.json` is a flat JSON Two fields appear in the data but not in the field reference: `sexSpecific`, on 110 records, and `anatomicLocationsId`, on a single record. The field reference also lists `"Spine"` among the common `region` values, but no record in the data uses it and the runtime enumeration has no spine member. The nine region values actually present are Head (869), Upper Extremity (582), Lower Extremity (579), Neck (235), Thorax (226), Abdomen (212), Pelvis (152), Breast (46), and Body (25). -The two hierarchy relations are kept deliberately distinct, as documented in the field reference: `containedByRef` is spatial, meaning X is inside Y, while `partOfRef` is mereological, meaning X is a component of Y. See [contained-by and part-of](/glossary/contained-by-and-part-of.md). SNOMED coding follows one rule without exception: of the Structure, Entire, and Part concepts in a SNOMED anatomy triad, always use the "Structure of" concept, because that is what SNOMED intends for finding sites and procedure sites. +The two hierarchy relations are kept deliberately distinct, as documented in the field reference: `containedByRef` is spatial, meaning X is inside Y, while `partOfRef` is mereological, meaning X is a component of Y. See [contained-by and part-of](/glossary/contained-by-and-part-of.md). SNOMED coding follows one rule without exception: from the Structure, Entire, and Part triad, always use the "Structure of" concept, because that is what SNOMED intends for finding sites and procedure sites. Laterality is expressed as a triad. The generic entry carries `leftRef` and `rightRef`; each sided entry carries `unsidedRef` back to the generic. 827 distinct left-sided and 827 distinct right-sided entries are referenced, and every reference resolves to a record in the file. 1,597 records carry an `unsidedRef`. @@ -147,7 +147,7 @@ The hypopharynx entry, unchanged from the data file and used as the worked examp ## Runtime model fields -`AnatomicLocation` is the object the package hands back. It renames the curation fields, resolves the reference objects into a lightweight `AnatomicRef` of `id` and `display`, and adds classification and materialized paths. +`AnatomicLocation` renames curation fields, represents references as `AnatomicRef` objects with `id` and `display`, and adds classification and materialized paths. | Field | Type | Default | Notes | |---|---|---|---| @@ -177,13 +177,13 @@ The hypopharynx entry, unchanged from the data file and used as the worked examp Two computed fields are serialized with the record: `is_bilateral`, true when `laterality` is generic, and `is_lateralized`, true when it is left or right. `LocationType` is a coarse split modeled on the top level of the Foundational Model of Anatomy, separating discrete structures from spaces, regions, macro body parts, organ systems, and named groups. `StructureType` is the finer classification, with members grouped as musculoskeletal, vascular, peripheral neural, brain-specific, organs, lymphatic, anatomical organization, and spatial.[^fm-enums] -The materialized paths are what make hierarchy queries cheap. Containment ancestry, descendants, and the "is X inside Y" test all read `containment_path` rather than walking parent links, and the part-of hierarchy works the same way through `partof_path`. +The materialized paths are what make hierarchy queries cheap. Containment ancestry, descendants, and the "is X inside Y" test all read `containment_path` rather than walking parent links. Part-of queries use `partof_path` the same way. A location converts to an `IndexCode` with `system` set to `anatomic_locations`, its RadLex identifier as the code, and its description as the display. That is the form an anatomic location takes when it is attached to a [finding model](/glossary/finding-model.md). # Which is current -The `anatomic-locations` package format is current. It is the format the OIDM tooling reads, it carries the larger and more recently curated dataset, and it adds the classification axes and explicit laterality that the original schema left implicit. The `anatomiclocations.org` schema remains the published format of the original curated set and of the wrapper libraries built on it, and is documented here because that data and those libraries are still reachable. +OIDM tooling uses the current `anatomic-locations` format, with its larger, more recently curated dataset, classification, and explicit laterality. The original `anatomiclocations.org` set and wrapper libraries remain available, and are documented here because that data and those libraries are still reachable. [^al-schema]: body_parts_schema.json, anatomiclocations.org repository [^al-data]: body_parts.json, anatomiclocations.org curated body part set diff --git a/knowledge/references/cde-schema-differences.md b/knowledge/references/cde-schema-differences.md index b5d4a56..6962f5b 100644 --- a/knowledge/references/cde-schema-differences.md +++ b/knowledge/references/cde-schema-differences.md @@ -1,10 +1,10 @@ --- type: Source Extract title: CDE set schema versus the RadElement API -description: Near-verbatim extract of the note cataloguing where the CDE set RelaxNG schema and the RadElement API disagree, with the later JSON Schema versions that partly close the gap. +description: A 2023 CDE schema and API comparison, with notes on later JSON Schema changes. tags: [references, cde, radelement, schema, source-extract] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: differences resource: https://github.com/openimagingdata/openimagingdata.org/blob/fb431dfc81801a5a8e621c0e8bf2acd20f74be7d/schemas/schema_differences.md @@ -26,9 +26,9 @@ sources: # Provenance and status -The catalogue below is migrated from `schemas/schema_differences.md` in the `openimagingdata.org` repository, last changed on 2023-03-28 and read at commit `fb431df`. Its structure and wording are the author's; only dash punctuation was normalized. It compares two descriptions of the same object, a [CDE set](/glossary/cde-set.md): the RelaxNG schema kept alongside it as `original_cde_set_schema.rnc`, and the de facto JSON shape returned by the [RadElement](/glossary/radelement.md) API. +This extract preserves `schemas/schema_differences.md` from `openimagingdata.org` at `fb431df`, last changed 2023-03-28. It compares the [CDE set](/glossary/cde-set.md) format in `original_cde_set_schema.rnc` with the JSON returned by the [RadElement](/glossary/radelement.md) API. Its structure and wording are the author's; only dash punctuation was normalized. -It is a 2023 snapshot and should be read as one. Since it was written, the schema has been reissued as JSON Schema in two versions, and the closing section records what those versions changed. No individual names appeared in the source. +The extract is a 2023 snapshot. The closing section compares two later JSON Schema versions. The source contains no individual names. # Differences between Defined CDE Set Schema and RadElement API @@ -69,9 +69,9 @@ The CDE Set Schema is a RelaxNG schema that defines the structure of a CDE Set. # What the JSON Schema versions changed -The `common_data_elements` repository, which mirrors the [common data element](/glossary/cde.md) definitions published on RadElement, carries two JSON Schema drafts in `schema/`, read at commit `35536d8`. Both are JSON Schema draft-07. The repository's README states that the definitions currently conform to version 1.0, not the newer version 1.1.[^cde-readme] Version 1.1 is therefore published but not in force. +The `common_data_elements` repository mirrors RadElement's [common data element](/glossary/cde.md) definitions. At `35536d8`, its `schema/` directory contains versions 1.0 and 1.1, both using JSON Schema draft-07. The README states that definitions conform to 1.0, so 1.1 is published but not in force.[^cde-readme] -Both files declare the same `$id`, `https://github.com/ACR-RSNA-CDEs/blob/v1.0.0/cde.schema.json`. Version 1.1 did not update it, so the two schemas are not distinguishable by identifier. +Both files declare `$id` as `https://github.com/ACR-RSNA-CDEs/blob/v1.0.0/cde.schema.json`, so the identifier does not distinguish them. ## Changes from 1.0 to 1.1 in the set definition @@ -94,13 +94,13 @@ At the definitions level, 1.1 drops `event`, `biological_sex`, and `boolean_valu ## How this bears on the 2023 catalogue -Three of the gaps the note recorded look different once the JSON Schema versions are taken into account. +The JSON Schema versions change three comparisons: - **`images` and `modality`.** The note lists both as present in the RelaxNG schema and missing from the API. Version 1.1 adds `images` and `modalities` to both the set and the element, moving the JSON side toward the RelaxNG side rather than away from it. - **`url` and `body_parts`.** The note lists both as API-only. Both are properties of the set in JSON Schema 1.0 and 1.1, and `body_parts` is added to the element in 1.1. - **`biological_sex` and `age_range`.** These remain unreconciled. `biological_sex` has a definition in 1.0 and is dropped in 1.1; `age_range` appears in neither JSON Schema version. Both were RelaxNG-only in 2023 and are now absent from the schema in force. -One constraint moved the other way. The note records the RelaxNG schema as allowing `RADLEX`, `SNOMEDCT`, and `LOINC` for an [index code](/glossary/index-code.md) system. Both JSON Schema versions constrain the same field to `RADLEX`, `SNOMEDCT`, `LOINC`, and `ACRCOMMON`, and both keep `url` on the index code rather than the API's `href`. +One constraint moved the other way. The note records the RelaxNG schema as allowing `RADLEX`, `SNOMEDCT`, and `LOINC` for an [index code](/glossary/index-code.md) system. Both JSON Schema versions add `ACRCOMMON` to that enumeration. Both use `url` on index codes where the API uses `href`. [^differences]: Differences between Defined CDE Set Schema and RadElement API, openimagingdata.org repository [^rnc]: original_cde_set_schema.rnc, the RelaxNG CDE set schema the note compares diff --git a/knowledge/references/finding-model-schema.md b/knowledge/references/finding-model-schema.md index ba110fd..3e40522 100644 --- a/knowledge/references/finding-model-schema.md +++ b/knowledge/references/finding-model-schema.md @@ -1,10 +1,10 @@ --- type: Reference title: Finding model schema -description: The Open Imaging Finding Model record format as specified in the findingmodels repository, reconciled field by field against the Pydantic definitions that validate it. +description: The finding model prose schema, compared with released and unreleased Pydantic models. tags: [references, oifm, finding-models, schema] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: fm-schema resource: https://github.com/openimagingdata/findingmodels/blob/4475ac1bcb591f1a0951b2082b59208def173a5d/schema/finding_model_schema.md @@ -32,7 +32,7 @@ sources: # Provenance and status -The specification below is migrated near-verbatim from `schema/finding_model_schema.md` in the `findingmodels` repository, last changed on 2025-06-17 and read here at commit `4475ac1` on `main`.[^fm-schema] Its structure and wording are the author's; only dash punctuation was normalized to house style and the term "user" was left as written. That file is a prose mirror, not an executable schema. The record format that software actually enforces is the set of Pydantic models in the `findingmodel` repository, and the two have drifted. The reconciliation section states every difference. A third section records fields that exist only on the `feature/metadata-cleanup` work-edge branch and are not in any released version. +The extract preserves `findingmodels/schema/finding_model_schema.md` from `main` at `4475ac1`, last changed 2025-06-17.[^fm-schema] Its structure and wording are the author's; only dash punctuation was normalized to house style and the term "user" was left as written. That file is a prose mirror, not an executable schema; `findingmodel`'s Pydantic classes enforce it, and the two have drifted. The reconciliation section records differences, followed by unreleased fields on `feature/metadata-cleanup`. # Finding Model Schema @@ -149,7 +149,7 @@ Contributor details. # Reconciliation with the Pydantic source of truth -The released definitions live in `packages/findingmodel/src/findingmodel/finding_model.py`, read at commit `75afd39` on `main`.[^fm-pydantic] Two classes matter. `FindingModelBase` is a definition without registry identifiers, used while authoring. `FindingModelFull` is the registered form, and it is what the prose specification above describes. The tables record what the code enforces and mark each difference from the prose. +`packages/findingmodel/src/findingmodel/finding_model.py` on `main` at `75afd39` defines both classes.[^fm-pydantic] Authors use `FindingModelBase` before identifier assignment. `FindingModelFull` is the registered form described above. The tables compare the code's constraints with the prose. ## FindingModelFull @@ -240,7 +240,7 @@ The six digits are generated at random by `generate_oifm_id` and `generate_oifma # On the work edge, not released -Everything in this section is on the `feature/metadata-cleanup` branch of `findingmodel`, read at commit `1942b06`. None of it is on `main`, and none of it appears in the prose specification. It is recorded here because it is the stated direction for the format, not because it is in effect. +This section describes unreleased work on `findingmodel/feature/metadata-cleanup` at `1942b06`. These changes are absent from `main` and the prose above. It is recorded here because it is the stated direction for the format, not because it is in effect. The branch splits `finding_model.py` into `types/models.py`, `types/attributes.py`, and `types/metadata.py`. Attribute and `IndexCode` definitions are unchanged by the split. The design document that governs the work states the goal as making structured metadata "canonical `FindingModel` state rather than disposable enrichment output".[^edge-rewrite] @@ -263,7 +263,7 @@ Three further changes ride along.[^edge-metadata] - **Model-level codes must carry a display value.** A validator on `FindingModelFull` rejects any entry in `index_codes` or `anatomic_locations` whose `display` is empty. - **Canonical `index_codes` are narrowed.** The branch restricts them to exact matches or clinically substitutable near-equivalents, and sends broader, narrower, and merely related candidates to a separate enrichment review artifact rather than to the model. -The branch's own readiness assessment is not yet passing, so the field list above should be read as the current shape of unmerged work. +The branch's own readiness assessment is not yet passing. These fields remain unmerged. [^fm-schema]: Finding Model Schema, prose specification, findingmodels repository [^fm-pydantic]: finding_model.py, released Pydantic definitions, findingmodel main branch diff --git a/knowledge/references/index.md b/knowledge/references/index.md index ea29d55..1b9b26d 100644 --- a/knowledge/references/index.md +++ b/knowledge/references/index.md @@ -1,12 +1,12 @@ # References -Verbatim and near-verbatim source material: migrated specifications, extracted notes, and worked examples built from real data. Each document says where it came from, when, and whether it is current. +Source extracts, format references, and worked examples. Each page states its origin, date, and status. * [Status update, January 2026](./status-update-2026-01.md) - A faithful extract of the January 2026 OIDM status deck, "Realizing Object-Oriented Imaging Results", slide by slide. -* [Finding model schema](./finding-model-schema.md) - The Open Imaging Finding Model record format as specified in the findingmodels repository, reconciled field by field against the Pydantic definitions that validate it. -* [Anatomic location record format](./anatomic-location-json-schema.md) - The two JSON record formats for anatomic locations, the original anatomiclocations.org body part schema and the current anatomic-locations package format, with a real record from each. +* [Finding model schema](./finding-model-schema.md) - The finding model prose schema, compared with released and unreleased Pydantic models. +* [Anatomic location record format](./anatomic-location-json-schema.md) - The original and current anatomic location formats, with field tables and sample records. * [Exam Finding List example](./exam-finding-list-example.md) - A real Exam Finding List from the imaging-problem-list sample data, trimmed to five findings, with a field-by-field walkthrough. * [Imaging Problem List example](./imaging-problem-list-example.md) - Two findings from a real Imaging Problem List in the imaging-problem-list sample data, with the grouping key and the temporal status derivation as the dev branch implements them. * [Finding models: overview](./oifm-overview-extract.md) - Near-verbatim extract of the OIFM overview note explaining why finding models exist, what counts as an imaging finding, and how a finding model is structured. * [Finding model structured metadata fields](./oifm-metadata-fields-extract.md) - Near-verbatim extract of the reference for the structured metadata fields on FindingModelBase and FindingModelFull, with the points where it differs from the branch code it describes. -* [CDE set schema versus the RadElement API](./cde-schema-differences.md) - Near-verbatim extract of the note cataloguing where the CDE set RelaxNG schema and the RadElement API disagree, with the later JSON Schema versions that partly close the gap. +* [CDE set schema versus the RadElement API](./cde-schema-differences.md) - A 2023 CDE schema and API comparison, with notes on later JSON Schema changes. diff --git a/knowledge/references/oifm-metadata-fields-extract.md b/knowledge/references/oifm-metadata-fields-extract.md index ae42612..aec48ef 100644 --- a/knowledge/references/oifm-metadata-fields-extract.md +++ b/knowledge/references/oifm-metadata-fields-extract.md @@ -4,7 +4,7 @@ title: Finding model structured metadata fields description: Near-verbatim extract of the reference for the structured metadata fields on FindingModelBase and FindingModelFull, with the points where it differs from the branch code it describes. tags: [references, oifm, finding-models, metadata, source-extract] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: note resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/notes/oifm-metadata-fields.md @@ -25,9 +25,9 @@ sources: # Provenance and status -This is a near-verbatim extract of `notes/oifm-metadata-fields.md` from the `next-gen-2026` branch of the `ACR-RSNA-CDEs` repository, read at commit `44836c1`. That file is a copy: its own frontmatter records it as fetched on 2026-07-29 from a gist published by the project lead, and describes itself as intended for review with colleagues who are not reading the code. The only change made here is that dash punctuation was normalized to house style. No individual names appeared in the source. +This near-verbatim extract comes from `ACR-RSNA-CDEs/notes/oifm-metadata-fields.md` on `next-gen-2026` at `44836c1`. The note records a 2026-07-29 copy of the project lead's gist for review by colleagues who are not reading the code. Only dash punctuation was normalized. The source contains no individual names. -The fields it documents are **not released**. They exist on the `feature/metadata-cleanup` branch of the `findingmodel` repository and on `dev`, and none of them are on `main`. The released record format, and a field-by-field reconciliation against it, is in [the finding model schema](/references/finding-model-schema.md). Terms used below have glossary entries: [finding model](/glossary/finding-model.md), [attribute](/glossary/attribute.md), [index code](/glossary/index-code.md), [anatomic location](/glossary/anatomic-location.md), and [measurement](/glossary/measurement.md). +The metadata fields are unreleased, present on `findingmodel`'s `feature/metadata-cleanup` and `dev` branches but absent from `main`. See the [finding model schema](/references/finding-model-schema.md) for the released format and comparison. Related terms are [finding model](/glossary/finding-model.md), [attribute](/glossary/attribute.md), [index code](/glossary/index-code.md), [anatomic location](/glossary/anatomic-location.md), and [measurement](/glossary/measurement.md). ## Where this differs from the branch code diff --git a/knowledge/references/oifm-overview-extract.md b/knowledge/references/oifm-overview-extract.md index d21882e..7292500 100644 --- a/knowledge/references/oifm-overview-extract.md +++ b/knowledge/references/oifm-overview-extract.md @@ -4,7 +4,7 @@ title: "Finding models: overview" description: Near-verbatim extract of the OIFM overview note explaining why finding models exist, what counts as an imaging finding, and how a finding model is structured. tags: [references, oifm, finding-models, source-extract] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T16:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: note resource: https://github.com/RSNA/ACR-RSNA-CDEs/blob/44836c19f4e025cf1684a015ed5cc63c29eaf7f3/notes/oifm-overview.md @@ -17,7 +17,9 @@ sources: # Provenance and status -This is a near-verbatim extract of `notes/oifm-overview.md` from the `next-gen-2026` branch of the `ACR-RSNA-CDEs` repository, read at commit `44836c1`. That file is itself a copy: its own frontmatter records it as fetched from `prompts/overview.md` in the `findingmodels` repository on 2026-07-29, and the two are byte-identical to the version of that file at commit `2267d5d`, last changed on 2026-04-18. The upstream file is an authoring prompt, which is why it reads as guidance to whoever or whatever is writing a [finding model](/glossary/finding-model.md). It is current: the upstream file is live on the `main` branch of `findingmodels` and the note carries `status: stable`. The only change made here is that dash punctuation was normalized to house style. No names appeared in the source. Glossary links are not inserted into the extract body; the terms it uses are [finding model](/glossary/finding-model.md), [attribute](/glossary/attribute.md), [presence](/glossary/presence.md), [index code](/glossary/index-code.md), and [Observation](/glossary/observation.md). +This near-verbatim extract comes from `notes/oifm-overview.md` on `ACR-RSNA-CDEs`'s `next-gen-2026` branch at `44836c1`. The note records a 2026-07-29 copy of `findingmodels/prompts/overview.md`, byte-identical to commit `2267d5d`, last changed 2026-04-18. At review, the authoring prompt was current on `findingmodels/main`, and the note had `status: stable`. The upstream file is an authoring prompt, which is why it reads as guidance to whoever or whatever is writing a [finding model](/glossary/finding-model.md). + +Only dash punctuation was normalized in the extract. It contains no individual names or added glossary links. Related terms are [finding model](/glossary/finding-model.md), [attribute](/glossary/attribute.md), [presence](/glossary/presence.md), [index code](/glossary/index-code.md), and [Observation](/glossary/observation.md). # Finding Models: Overview diff --git a/knowledge/references/status-update-2026-01.md b/knowledge/references/status-update-2026-01.md index c6a5351..8fcdc62 100644 --- a/knowledge/references/status-update-2026-01.md +++ b/knowledge/references/status-update-2026-01.md @@ -4,7 +4,7 @@ title: Status update, January 2026 description: A faithful extract of the January 2026 OIDM status deck, "Realizing Object-Oriented Imaging Results", slide by slide. tags: [references, deck, vision, roadmap] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T15:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: deck resource: https://gamma.app/docs/Open-Imaging-Data-Model-2026-Status-Update:-Realizing-Object-Oriented-Imaging-Results-yfxzx4q9zssafal @@ -13,9 +13,9 @@ sources: # About this extract -This is an extract of the January 2026 Open Imaging Data Model (OIDM) status deck, presented by the project lead under the running subtitle "Standardizing the DNA of Imaging IT."[^deck] Sections below follow the deck's slides in order and keep its wording and emphasis. Two departures from the source are noted where they occur: the collaborators slide is reduced to organizations, per this knowledgebase's convention of naming organizations and not individuals, and screenshots are described rather than reproduced. +This extract follows the January 2026 Open Imaging Data Model (OIDM) status deck, presented by the project lead under the subtitle "Standardizing the DNA of Imaging IT."[^deck] Sections below follow the deck's slides in order and keep its wording and emphasis. Two departures from the source are noted where they occur: the collaborators slide is reduced to organizations, per this knowledgebase's convention of naming organizations and not individuals, and screenshots are described rather than reproduced. -The deck is the primary statement of OIDM's direction as of early 2026. Where it names something that does not yet exist, this extract keeps the claim as the deck makes it; [Architecture](/overview/architecture.md) states the implementation status of each piece, and [Vision](/overview/vision.md) works through the reasoning. +The deck is the primary statement of OIDM's direction as of early 2026. Where it names something that does not yet exist, this extract keeps the claim as the deck makes it. See [Architecture](/overview/architecture.md) for implementation status and [Vision](/overview/vision.md) for the rationale. # Title diff --git a/knowledge/repositories/index.md b/knowledge/repositories/index.md index c7d810c..b686278 100644 --- a/knowledge/repositories/index.md +++ b/knowledge/repositories/index.md @@ -1,5 +1,5 @@ # Repositories -Where the code and content live. One document, covering every source repository behind OIDM. +Source repositories for OIDM code and content. -* [Repository map](./repository-map.md) - Every source repository behind OIDM, with its organization, role, status, branch of record, last activity, deployed URL, and the documents in this bundle that cover it. +* [Repository map](./repository-map.md) - OIDM source repositories, their roles, branches, activity, deployments, and related documentation. diff --git a/knowledge/repositories/repository-map.excalidraw b/knowledge/repositories/repository-map.excalidraw new file mode 100644 index 0000000..0fe47b2 --- /dev/null +++ b/knowledge/repositories/repository-map.excalidraw @@ -0,0 +1,2024 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "oidm-knowledge/tools/diagrams", + "elements": [ + { + "type": "text", + "id": "hdr_cde_stage", + "x": 0, + "y": 16, + "width": 89.32, + "height": 17.5, + "strokeColor": "#3b82f6", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1001, + "version": 1, + "versionNonce": 1002, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "CDE STAGING", + "originalText": "CDE STAGING", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "hdr_fm_pipeline", + "x": 0, + "y": 186, + "width": 113.67999999999999, + "height": 17.5, + "strokeColor": "#3b82f6", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1003, + "version": 1, + "versionNonce": 1004, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "FINDING MODELS", + "originalText": "FINDING MODELS", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "hdr_apps", + "x": 0, + "y": 356, + "width": 97.44, + "height": 17.5, + "strokeColor": "#3b82f6", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1005, + "version": 1, + "versionNonce": 1006, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "APPLICATIONS", + "originalText": "APPLICATIONS", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "hdr_anatomy", + "x": 0, + "y": 526, + "width": 56.839999999999996, + "height": 17.5, + "strokeColor": "#3b82f6", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1007, + "version": 1, + "versionNonce": 1008, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "ANATOMY", + "originalText": "ANATOMY", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "hdr_terms", + "x": 0, + "y": 696, + "width": 146.16, + "height": 17.5, + "strokeColor": "#3b82f6", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1009, + "version": 1, + "versionNonce": 1010, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "TERMINOLOGY LOOKUP", + "originalText": "TERMINOLOGY LOOKUP", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "cdesnap", + "x": 0, + "y": 40, + "width": 190, + "height": 80, + "strokeColor": "#1e3a5f", + "backgroundColor": "#93c5fd", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1011, + "version": 1, + "versionNonce": 1012, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "cdesnap_t", + "type": "text" + }, + { + "id": "f3", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "cdesnap_t", + "x": 10, + "y": 50, + "width": 170, + "height": 60, + "strokeColor": "#1e3a5f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1013, + "version": 1, + "versionNonce": 1014, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "common_data_elements\nRadElement snapshot", + "originalText": "common_data_elements\nRadElement snapshot", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "cdesnap", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "cdes", + "x": 305, + "y": 40, + "width": 190, + "height": 80, + "strokeColor": "#1e3a5f", + "backgroundColor": "#93c5fd", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1015, + "version": 1, + "versionNonce": 1016, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "cdes_t", + "type": "text" + }, + { + "id": "f4", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "cdes_t", + "x": 315, + "y": 50, + "width": 170, + "height": 60, + "strokeColor": "#1e3a5f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1017, + "version": 1, + "versionNonce": 1018, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "CDEStaging\n259 draft CDE\ndefinitions", + "originalText": "CDEStaging\n259 draft CDE\ndefinitions", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "cdes", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "radelement", + "x": 0, + "y": 210, + "width": 190, + "height": 80, + "strokeColor": "#c2410c", + "backgroundColor": "#fed7aa", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1019, + "version": 1, + "versionNonce": 1020, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "radelement_t", + "type": "text" + }, + { + "id": "f1", + "type": "arrow" + }, + { + "id": "f3", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "radelement_t", + "x": 10, + "y": 220, + "width": 170, + "height": 60, + "strokeColor": "#7c2d12", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1021, + "version": 1, + "versionNonce": 1022, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "RadElement (ACR/RSNA)\nRDES and RDE codes", + "originalText": "RadElement (ACR/RSNA)\nRDES and RDE codes", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "radelement", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "fms", + "x": 305, + "y": 210, + "width": 190, + "height": 80, + "strokeColor": "#1e3a5f", + "backgroundColor": "#93c5fd", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1023, + "version": 1, + "versionNonce": 1024, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "fms_t", + "type": "text" + }, + { + "id": "f1", + "type": "arrow" + }, + { + "id": "f2", + "type": "arrow" + }, + { + "id": "f4", + "type": "arrow" + }, + { + "id": "f5", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "fms_t", + "x": 315, + "y": 220, + "width": 170, + "height": 60, + "strokeColor": "#1e3a5f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1025, + "version": 1, + "versionNonce": 1026, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "findingmodels\n2,382 finding models", + "originalText": "findingmodels\n2,382 finding models", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "fms", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "fm", + "x": 610, + "y": 210, + "width": 190, + "height": 80, + "strokeColor": "#1e3a5f", + "backgroundColor": "#60a5fa", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1027, + "version": 1, + "versionNonce": 1028, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "fm_t", + "type": "text" + }, + { + "id": "f2", + "type": "arrow" + }, + { + "id": "f6", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "fm_t", + "x": 620, + "y": 220, + "width": 170, + "height": 60, + "strokeColor": "#1e3a5f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1029, + "version": 1, + "versionNonce": 1030, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "findingmodel\nOIFM format, index,\nCLIs, MCP", + "originalText": "findingmodel\nOIFM format, index,\nCLIs, MCP", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "fm", + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "f1", + "x": 190, + "y": 250.0, + "width": 115, + "height": 0.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1031, + "version": 1, + "versionNonce": 1032, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 115, + 0.0 + ] + ], + "startBinding": { + "elementId": "radelement", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "fms", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "id": "f1_l", + "x": 202.84, + "y": 228.0, + "width": 89.32, + "height": 17.5, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1033, + "version": 1, + "versionNonce": 1034, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "CDE-derived", + "originalText": "CDE-derived", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "f2", + "x": 495, + "y": 250.0, + "width": 115, + "height": 0.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1035, + "version": 1, + "versionNonce": 1036, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 115, + 0.0 + ] + ], + "startBinding": { + "elementId": "fms", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "fm", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "id": "f2_l", + "x": 507.84000000000003, + "y": 228.0, + "width": 89.32, + "height": 17.5, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1037, + "version": 1, + "versionNonce": 1038, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "definitions", + "originalText": "definitions", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "f3", + "x": 95.0, + "y": 210, + "width": 0.0, + "height": -90, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1039, + "version": 1, + "versionNonce": 1040, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.0, + -90 + ] + ], + "startBinding": { + "elementId": "radelement", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "cdesnap", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "id": "f3_l", + "x": 62.52, + "y": 143.0, + "width": 64.96, + "height": 17.5, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1041, + "version": 1, + "versionNonce": 1042, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "snapshot", + "originalText": "snapshot", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "f4", + "x": 400.0, + "y": 120, + "width": 0.0, + "height": 90, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1043, + "version": 1, + "versionNonce": 1044, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.0, + 90 + ] + ], + "startBinding": { + "elementId": "cdes", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "fms", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "id": "f4_l", + "x": 339.1, + "y": 143.0, + "width": 121.8, + "height": 17.5, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1045, + "version": 1, + "versionNonce": 1046, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "content batches", + "originalText": "content batches", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "ipl", + "x": 0, + "y": 380, + "width": 190, + "height": 80, + "strokeColor": "#1e3a5f", + "backgroundColor": "#3b82f6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1047, + "version": 1, + "versionNonce": 1048, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "ipl_t", + "type": "text" + }, + { + "id": "f9", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "ipl_t", + "x": 10, + "y": 390, + "width": 170, + "height": 60, + "strokeColor": "#ffffff", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1049, + "version": 1, + "versionNonce": 1050, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "imaging-problem-list\nuses models +\nlocations", + "originalText": "imaging-problem-list\nuses models +\nlocations", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "ipl", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "site", + "x": 305, + "y": 380, + "width": 190, + "height": 80, + "strokeColor": "#1e3a5f", + "backgroundColor": "#3b82f6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1051, + "version": 1, + "versionNonce": 1052, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "site_t", + "type": "text" + }, + { + "id": "f5", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "site_t", + "x": 315, + "y": 390, + "width": 170, + "height": 60, + "strokeColor": "#ffffff", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1053, + "version": 1, + "versionNonce": 1054, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "finding-models-site\ncorpus catalog", + "originalText": "finding-models-site\ncorpus catalog", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "site", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "forge", + "x": 610, + "y": 380, + "width": 190, + "height": 80, + "strokeColor": "#1e3a5f", + "backgroundColor": "#3b82f6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1055, + "version": 1, + "versionNonce": 1056, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "forge_t", + "type": "text" + }, + { + "id": "f6", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "forge_t", + "x": 620, + "y": 390, + "width": 170, + "height": 60, + "strokeColor": "#ffffff", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1057, + "version": 1, + "versionNonce": 1058, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Finding Model Forge\nfmf.oidm.org", + "originalText": "Finding Model Forge\nfmf.oidm.org", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "forge", + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "f5", + "x": 400.0, + "y": 290, + "width": 0.0, + "height": 90, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1059, + "version": 1, + "versionNonce": 1060, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.0, + 90 + ] + ], + "startBinding": { + "elementId": "fms", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "site", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "id": "f5_l", + "x": 347.22, + "y": 313.0, + "width": 105.55999999999999, + "height": 17.5, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1061, + "version": 1, + "versionNonce": 1062, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "git submodule", + "originalText": "git submodule", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "f6", + "x": 705.0, + "y": 290, + "width": 0.0, + "height": 90, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1063, + "version": 1, + "versionNonce": 1064, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.0, + 90 + ] + ], + "startBinding": { + "elementId": "fm", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "forge", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "id": "f6_l", + "x": 680.64, + "y": 313.0, + "width": 48.72, + "height": 17.5, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1065, + "version": 1, + "versionNonce": 1066, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "engine", + "originalText": "engine", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "cdes_note", + "x": 0, + "y": 302, + "width": 190, + "height": 32.5, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1067, + "version": 1, + "versionNonce": 1068, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "(CDEStaging also has an\ninformal path to RadElement)", + "originalText": "(CDEStaging also has an\ninformal path to RadElement)", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "radlex", + "x": 0, + "y": 550, + "width": 190, + "height": 80, + "strokeColor": "#c2410c", + "backgroundColor": "#fed7aa", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1069, + "version": 1, + "versionNonce": 1070, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "radlex_t", + "type": "text" + }, + { + "id": "f7", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "radlex_t", + "x": 10, + "y": 560, + "width": 170, + "height": 60, + "strokeColor": "#7c2d12", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1071, + "version": 1, + "versionNonce": 1072, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "RadLex (RSNA)\nRID codes", + "originalText": "RadLex (RSNA)\nRID codes", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "radlex", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "alorg", + "x": 305, + "y": 550, + "width": 190, + "height": 80, + "strokeColor": "#1e3a5f", + "backgroundColor": "#93c5fd", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1073, + "version": 1, + "versionNonce": 1074, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "alorg_t", + "type": "text" + }, + { + "id": "f7", + "type": "arrow" + }, + { + "id": "f8", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "alorg_t", + "x": 315, + "y": 560, + "width": 170, + "height": 60, + "strokeColor": "#1e3a5f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1075, + "version": 1, + "versionNonce": 1076, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "anatomiclocations.org\n+ BodyPartIndex", + "originalText": "anatomiclocations.org\n+ BodyPartIndex", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "alorg", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "alpkg", + "x": 610, + "y": 550, + "width": 190, + "height": 80, + "strokeColor": "#1e3a5f", + "backgroundColor": "#60a5fa", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1077, + "version": 1, + "versionNonce": 1078, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "alpkg_t", + "type": "text" + }, + { + "id": "f8", + "type": "arrow" + }, + { + "id": "f9", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "alpkg_t", + "x": 620, + "y": 560, + "width": 170, + "height": 60, + "strokeColor": "#1e3a5f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1079, + "version": 1, + "versionNonce": 1080, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "anatomic-locations pkg\ninside findingmodel", + "originalText": "anatomic-locations pkg\ninside findingmodel", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "alpkg", + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "f7", + "x": 190, + "y": 590.0, + "width": 115, + "height": 0.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1081, + "version": 1, + "versionNonce": 1082, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 115, + 0.0 + ] + ], + "startBinding": { + "elementId": "radlex", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "alorg", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "id": "f7_l", + "x": 223.14, + "y": 568.0, + "width": 48.72, + "height": 17.5, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1083, + "version": 1, + "versionNonce": 1084, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "subset", + "originalText": "subset", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "f8", + "x": 495, + "y": 590.0, + "width": 115, + "height": 0.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1085, + "version": 1, + "versionNonce": 1086, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 115, + 0.0 + ] + ], + "startBinding": { + "elementId": "alorg", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "alpkg", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "id": "f8_l", + "x": 524.08, + "y": 568.0, + "width": 56.839999999999996, + "height": 17.5, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1087, + "version": 1, + "versionNonce": 1088, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "lineage", + "originalText": "lineage", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "f9", + "x": 705.0, + "y": 550, + "width": -610.0, + "height": -90, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1089, + "version": 1, + "versionNonce": 1090, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -610.0, + -90 + ] + ], + "startBinding": { + "elementId": "alpkg", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "ipl", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "id": "f9_l", + "x": 371.58, + "y": 483.0, + "width": 56.839999999999996, + "height": 17.5, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1091, + "version": 1, + "versionNonce": 1092, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "used by", + "originalText": "used by", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "others", + "x": 0, + "y": 720, + "width": 190, + "height": 80, + "strokeColor": "#c2410c", + "backgroundColor": "#fed7aa", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1093, + "version": 1, + "versionNonce": 1094, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "others_t", + "type": "text" + }, + { + "id": "f10", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "others_t", + "x": 10, + "y": 730, + "width": 170, + "height": 60, + "strokeColor": "#7c2d12", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1095, + "version": 1, + "versionNonce": 1096, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "SNOMED CT, FMA,\nLOINC, UMLS", + "originalText": "SNOMED CT, FMA,\nLOINC, UMLS", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "others", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "molu", + "x": 305, + "y": 720, + "width": 190, + "height": 80, + "strokeColor": "#1e3a5f", + "backgroundColor": "#60a5fa", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1097, + "version": 1, + "versionNonce": 1098, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "molu_t", + "type": "text" + }, + { + "id": "f10", + "type": "arrow" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "molu_t", + "x": 315, + "y": 730, + "width": 170, + "height": 60, + "strokeColor": "#1e3a5f", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1099, + "version": 1, + "versionNonce": 1100, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "med-ontology-lookup\nmolu", + "originalText": "med-ontology-lookup\nmolu", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "molu", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "id": "mvp", + "x": 610, + "y": 720, + "width": 190, + "height": 80, + "strokeColor": "#64748b", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1101, + "version": 1, + "versionNonce": 1102, + "isDeleted": false, + "groupIds": [], + "boundElements": [ + { + "id": "mvp_t", + "type": "text" + } + ], + "link": null, + "locked": false, + "roundness": { + "type": 3 + } + }, + { + "type": "text", + "id": "mvp_t", + "x": 620, + "y": 730, + "width": 170, + "height": 60, + "strokeColor": "#475569", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1103, + "version": 1, + "versionNonce": 1104, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "IPL-MVP-\nExtractionAndLabeling\n(superseded)", + "originalText": "IPL-MVP-\nExtractionAndLabeling\n(superseded)", + "fontSize": 16, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "mvp", + "lineHeight": 1.25 + }, + { + "type": "arrow", + "id": "f10", + "x": 190, + "y": 760.0, + "width": 115, + "height": 0.0, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1105, + "version": 1, + "versionNonce": 1106, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 115, + 0.0 + ] + ], + "startBinding": { + "elementId": "others", + "focus": 0, + "gap": 2 + }, + "endBinding": { + "elementId": "molu", + "focus": 0, + "gap": 2 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "id": "f10_l", + "x": 219.08, + "y": 738.0, + "width": 56.839999999999996, + "height": 17.5, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1107, + "version": 1, + "versionNonce": 1108, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "lookups", + "originalText": "lookups", + "fontSize": 14, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "molu_note", + "x": 305, + "y": 814, + "width": 286.52, + "height": 32.5, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1109, + "version": 1, + "versionNonce": 1110, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "molu also enriches findingmodel\nmetadata by ontology search (see text)", + "originalText": "molu also enriches findingmodel\nmetadata by ontology search (see text)", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + }, + { + "type": "text", + "id": "legend", + "x": 0, + "y": 860, + "width": 565.5, + "height": 32.5, + "strokeColor": "#64748b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 1111, + "version": 1, + "versionNonce": 1112, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "text": "Orange: external terminology. Light blue: content repository.\nMid blue: library. Dark blue: application. Dashed: lineage or superseded.", + "originalText": "Orange: external terminology. Light blue: content repository.\nMid blue: library. Dark blue: application. Dashed: lineage or superseded.", + "fontSize": 13, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "lineHeight": 1.25 + } + ], + "appState": { + "viewBackgroundColor": "#ffffff", + "gridSize": null + }, + "files": {} +} \ No newline at end of file diff --git a/knowledge/repositories/repository-map.md b/knowledge/repositories/repository-map.md index 0d1068f..18e4763 100644 --- a/knowledge/repositories/repository-map.md +++ b/knowledge/repositories/repository-map.md @@ -1,10 +1,10 @@ --- type: Reference title: Repository map -description: Every source repository behind OIDM, with its organization, role, status, branch of record, last activity, deployed URL, and the documents in this bundle that cover it. +description: OIDM source repositories, their roles, branches, activity, deployments, and related documentation. tags: [repositories, index, meta] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T02:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } stale_after: 2027-09-21 sources: - id: oidm-org @@ -26,7 +26,7 @@ sources: # How to read this map -Twenty-six repositories carry the Open Imaging Data Model (OIDM). Twenty-one belong to the `openimagingdata` GitHub organization, three anatomic-location repositories belong to the project lead's personal account, and two belong to RSNA as allied external projects. +Open Imaging Data Model (OIDM) sources span twenty-six repositories. Twenty-one belong to `openimagingdata`, three anatomic-location repositories belong to the project lead's personal account, and two allied projects to RSNA. Four status values are used. @@ -37,7 +37,7 @@ Four status values are used. | lineage | Superseded by later work; kept for history | | dead | Never completed and superseded by nothing | -"Branch of record" names the branch that represents current state for readers of this bundle. Where a repository's released state and its work edge differ, both are named. "Last activity" is the repository-wide push date reported by GitHub on 2026-09-21, which can be later than the tip commit on the branch of record when the most recent push landed on another branch. +"Branch of record" names the branch that represents current state for readers of this bundle. Where a repository's released state and its work edge differ, both are named. "Last activity" is the repository-wide push date reported by GitHub on 2026-09-21. A push to another branch can make it later than the branch-of-record tip. # The repositories @@ -74,71 +74,26 @@ Four status values are used. Content repositories hold definitions and data. Library repositories turn those definitions into typed objects and searchable indexes. Application repositories consume both. Two external terminologies, RadElement and RadLex, sit outside the project and are referenced by code, not vendored into it. -```mermaid -flowchart TD - subgraph external[External terminologies] - RE[RadElement
RDES and RDE codes] - RL[RadLex
RID codes] - SN[SNOMED CT, FMA,
LOINC, UMLS] - end - - subgraph content[Content repositories] - CDS[CDEStaging
259 draft CDE definitions] - CDE[common_data_elements
RadElement snapshot] - FMS[findingmodels
2,382 finding models] - AL[anatomiclocations.org
2,890 anatomic locations] - end - - subgraph libs[Libraries] - FM[findingmodel
OIFM format, index, CLIs, MCP] - ALP[anatomic-locations package
inside findingmodel] - MOLU[med-ontology-lookup
molu] - BPI[BodyPartIndex.py and .ts] - end - - subgraph apps[Applications] - FMF[FindingModelForge
fmf.oidm.org] - FSITE[finding-models-site] - IPL[imaging-problem-list
extraction, coding, viewers] - MVP[IPL-MVP-ExtractionAndLabeling] - end - - CDS --> RE - CDE --> RE - FMS --> FM - AL --> BPI - AL --> ALP - RL --> ALP - RL --> MOLU - SN --> MOLU - RE --> FMS - MOLU --> FM - ALP --> FM - FM --> FMF - FMS --> FSITE - FM --> IPL - ALP --> IPL - FMS --> IPL - FMS --> MVP - CDS --> FMS -``` - -Three edges deserve a note. The `findingmodels` corpus is pulled into `finding-models-site` as a git submodule and resolved by `imaging-problem-list` through the published `ids.json` file, so the content repository is the single source of finding model identity. The newer anatomic data lives inside `findingmodel` as the `anatomic-locations` package rather than in the original `anatomiclocations.org` repository, and the two lineages are not synchronized. RSNA/RadLex issue 3, "Add Anatomic Locations", opened 2026-08-10, tracks folding the curated anatomic location set into RadLex itself with an exit criterion of full coverage; that is a GitHub tracking issue, not a code dependency. +[![How the repositories relate: read each row left to right, from an external terminology or content repository, through the library that packages it, to the application that uses it. RadElement feeds findingmodels and CDEStaging; findingmodels feeds findingmodel; findingmodel feeds Finding Model Forge and imaging-problem-list. RadLex feeds anatomiclocations.org, which feeds the anatomic-locations package inside findingmodel. SNOMED CT, FMA, LOINC, and UMLS feed med-ontology-lookup, which enriches findingmodel. findingmodels also feeds finding-models-site via a git submodule and the superseded IPL-MVP-ExtractionAndLabeling.](./repository-map.svg)](./repository-map.svg) + +*Diagram source: `repository-map.excalidraw` beside this document (click the image for full size), generated by `tools/diagrams/build_repository_map.py`.* + +Three edges deserve a note. The `findingmodels` corpus is pulled into `finding-models-site` as a git submodule and resolved by `imaging-problem-list` through the published `ids.json` file, so the content repository is the single source of finding model identity. Current anatomic data lives in `findingmodel`'s `anatomic-locations` package, unsynchronized with `anatomiclocations.org`. RSNA/RadLex issue 3, "Add Anatomic Locations", opened 2026-08-10, tracks folding the curated anatomic location set into RadLex itself with an exit criterion of full coverage. It creates no code dependency. # Work edge -Branch inventories taken on 2026-09-21 established what follows. None of the unmerged branches named here has an open pull request. +These branch inventories date to 2026-09-21. None of the unmerged branches below has an open pull request. -**findingmodel.** The live thread is the canonical structured-metadata rewrite, on `feature/metadata-cleanup` (tip `1942b06`, 2026-06-29) and its base `dev` (tip `504a42a`, 2026-04-11). It adds eight optional fields to the finding model base class, splits metadata assignment across seven typed agents, and plans a dual-database release so existing consumers do not break. The branch's own readiness assessment still reports a failure: two fields remain below the quality floor. The earlier eight-facet specification on `main` is superseded by this field set. Twenty-four open issues map one to one onto task plans in the repository. +**findingmodel.** The canonical metadata rewrite uses `feature/metadata-cleanup` (tip `1942b06`, 2026-06-29) and its base `dev` (tip `504a42a`, 2026-04-11). It adds eight optional fields to the finding model base class, splits metadata assignment across seven typed agents, and plans a dual-database release so existing consumers do not break. The branch's own readiness assessment still reports a failure: two fields remain below the quality floor. The earlier eight-facet specification on `main` is superseded by this field set. Twenty-four open issues map one to one onto task plans in the repository. **findingmodels.** Six branches carry unmerged work. `taxonomy-export-2026-08-15` (tip `a30c3c9`) replaces the legacy `lists/` directory with the six MGB exam-oriented sub-taxonomies as CSVs totaling 3,789 rows, of which 1,028 already match an existing finding model identifier by exact name; the remaining rows are named as the next triage task. Two content pipelines add large batches that have never merged: a CT chest conversion branch with 1,822 new definitions and a three-agent merge, create, and review pipeline of which one of twenty-one chunks is complete, and a head CT branch with 419 new definitions plus an overlapping review branch with 76 more. A metadata branch applies an approved enrichment baseline to 78 existing definitions and adds no new ones. A clinician-request branch adds 59 definitions for an intracranial problem list application. The finding model JSON schema is being extended on three of these branches independently, and none of those changes has landed on `main`. -**imaging-problem-list.** `dev` (tip `36fa30c`, 2026-07-22) is 258 commits ahead of `main` (tip `06f64a7`, 2025-11-18) and is current state. Anatomic-location coding of findings has landed, and the Imaging Problem List grouping key changed from finding code alone to finding code plus location. Eight active plans center on human-review tooling, an evaluation redesign that scores quote-first matching rather than raw finding yield, an anatomy-aware viewer, and a reassessment of local model choice. The only open issue, number 1, asks for a formal Pydantic model layer for Observation, Exam Finding List, and Imaging Problem List with JSON Schema export; it is broader than any current plan and unclaimed. The one open pull request is empty after its design document was moved to a separate repository. +**imaging-problem-list.** `dev` (tip `36fa30c`, 2026-07-22) is 258 commits ahead of `main` (tip `06f64a7`, 2025-11-18) and represents current state. Anatomic-location coding of findings has landed, and the Imaging Problem List grouping key changed from finding code alone to finding code plus location. Eight active plans center on human-review tooling, an evaluation redesign that scores quote-first matching rather than raw finding yield, an anatomy-aware viewer, and a reassessment of local model choice. The only open issue, number 1, asks for a formal Pydantic model layer for Observation, Exam Finding List, and Imaging Problem List with JSON Schema export; it is broader than any current plan and unclaimed. The one open pull request is empty after its design document was moved to a separate repository. **med-ontology-lookup.** No branch is ahead of `main`. A twelve-issue backlog follows the six-phase design in the repository's review and proposal document; nine of those issues are open and unstarted. Offline continuous integration is implemented but sits uncommitted in a working tree, pending authorization to publish. **CDEStaging.** All current work lands directly on `main`; the most recent commit is 2025-11-25. Fourteen topic branches exist and eleven are unmerged, the largest being a 2024 report-representation branch of 37 commits and a content branch of 33 commits. No branch has a commit after 2025-03-22, and no pull request proposes merging any of them. -**IPL-MVP-ExtractionAndLabeling.** Three single-commit experiment branches pushed within one week of each other in October 2025, none merged: a longitudinal multiple sclerosis sample dataset, a port of the extraction step to a typed agent, and a design note proposing persistent FHIR Observations with stable identifiers so repeat mentions of a finding across reports link to one entity. That design note carries no file extension and adds no code. +**IPL-MVP-ExtractionAndLabeling.** Three single-commit experiment branches pushed within one week of each other in October 2025, none merged: a longitudinal multiple sclerosis sample dataset, a port of the extraction step to a typed agent, and a design note proposing persistent FHIR Observations with stable identifiers so repeat mentions of a finding across reports link to one entity. The extensionless design note adds no code. **FindingModelForge.** Both `dev` (96 commits ahead of `main`, 2026-01-02) and `feature/model-editing` (60 commits ahead, 2025-11-28) are unmerged. The editing branch implements AI-assisted iteration of published models rather than manual editing; its first sprint is complete and two later sprints are not started. A peer-review workflow with public drafts and comments is finished on `dev` and absent from `main`. diff --git a/knowledge/repositories/repository-map.svg b/knowledge/repositories/repository-map.svg new file mode 100644 index 0000000..bc5b2fe --- /dev/null +++ b/knowledge/repositories/repository-map.svg @@ -0,0 +1,2 @@ +CDE STAGINGFINDING MODELSAPPLICATIONSANATOMYTERMINOLOGY LOOKUPcommon_data_elementsRadElement snapshotCDEStaging259 draft CDEdefinitionsRadElement (ACR/RSNA)RDES and RDE codesfindingmodels2,382 finding modelsfindingmodelOIFM format, index,CLIs, MCPCDE-deriveddefinitionssnapshotcontent batchesimaging-problem-listuses models +locationsfinding-models-sitecorpus catalogFinding Model Forgefmf.oidm.orggit submoduleengine(CDEStaging also has aninformal path to RadElement)RadLex (RSNA)RID codesanatomiclocations.org+ BodyPartIndexanatomic-locations pkginside findingmodelsubsetlineageused bySNOMED CT, FMA,LOINC, UMLSmed-ontology-lookupmoluIPL-MVP-ExtractionAndLabeling(superseded)lookupsmolu also enriches findingmodelmetadata by ontology search (see text)Orange: external terminology. Light blue: content repository.Mid blue: library. Dark blue: application. Dashed: lineage or superseded. \ No newline at end of file diff --git a/knowledge/roadmap/anatomic-locations-and-radlex.md b/knowledge/roadmap/anatomic-locations-and-radlex.md index 7cbd5b9..a8c8f2a 100644 --- a/knowledge/roadmap/anatomic-locations-and-radlex.md +++ b/knowledge/roadmap/anatomic-locations-and-radlex.md @@ -1,10 +1,10 @@ --- type: Roadmap title: Anatomic locations and RadLex -description: "The stated goals for the anatomic location set: incorporation into RadLex as an overlay, the node requests owed to the RadLex anatomy track, the two unreconciled datasets, the tooling items carried forward from the original libraries, and the body region enumerations that disagree." +description: RadLex incorporation, anatomy node requests, dataset differences, tooling goals, and conflicting body regions. tags: [roadmap, anatomic-locations, radlex, laterality, tooling] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T19:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } stale_after: 2027-09-21 sources: - id: radlex-issue-3 @@ -50,35 +50,35 @@ No code, commit message, or document inside the `RSNA/RadLex` repository mention # The overlay agreement -A more specific agreement, dated 13 September 2026, is recorded in the next-generation vocabulary work on the `next-gen-2026` branch of `ACR-RSNA-CDEs`. The anatomic locations file is **an overlay on [RadLex](/glossary/radlex.md)**, not a replacement and not the sole source: RadLex concepts and predicates sit underneath, and the file adds identifiers RadLex lacks, its own containment and part-of hierarchies, and [laterality](/glossary/laterality.md).[^cde-axis] +A 13 September 2026 agreement on `ACR-RSNA-CDEs`'s `next-gen-2026` branch defines the anatomic locations file as an overlay on [RadLex](/glossary/radlex.md). It adds missing identifiers, containment and part-of hierarchies, and [laterality](/glossary/laterality.md) to RadLex concepts and predicates. It does not replace RadLex or supply all anatomy content.[^cde-axis] -Two consequences are already written into that vocabulary. An anatomic location carries one identifier, its [RadLex identifier](/glossary/radlex-id.md), and a RadLex code is never shown beside it, because the location code is the RadLex code. And the compound identifiers for sided variants that RadLex lacks, such as `RID1363_RID5825`, are an acknowledged exception the RadLex track is expected to remove by minting real identifiers.[^cde-axis] +An anatomic location carries one identifier, its [RadLex identifier](/glossary/radlex-id.md), and a RadLex code is never shown beside it, because the location code is the RadLex code. And the compound identifiers for sided variants that RadLex lacks, such as `RID1363_RID5825`, are an acknowledged exception the RadLex track is expected to remove by minting real identifiers.[^cde-axis] The same record states that the overlay file is "the basis of the RadLex anatomy axis going forward," because the RadLex anatomy track is editing it rather than the published release.[^cde-axis] Two framings of the relationship are therefore in force, and nobody has reconciled them. The issue's exit criterion, full coverage of the terminology in RadLex, reads as absorption. The September agreement describes an overlay that RadLex edits in place. The two are compatible but not identical, and no source says which governs. It is carried in [open questions](/roadmap/open-questions.md). -The scale of the sided-variant exception is worth stating with it: 1,016 of the 2,926 records carry a composite identifier, so more than a third of the set is not resolvable as a RadLex identifier until real ones are minted. +Composite identifiers occur on 1,016 of 2,926 records. More than a third of the set therefore awaits resolvable RadLex identifiers. # What is owed in each direction -The gap log on that branch is the tracking artifact, kept deliberately separate from the wider design discussion so it can move independently.[^cde-gaps] The full list of node requests, with the reason and date for each, is reproduced in [RadLex integration](/semantic-foundation/anatomic-locations/radlex-integration.md). Two items are worth naming here because they are structural rather than individual concepts. +The branch's gap log tracks requests independently of design discussions.[^cde-gaps] [RadLex integration](/semantic-foundation/anatomic-locations/radlex-integration.md) lists each request, reason, and date. Two requests affect the structure of the dataset. **From OIDM to RadLex: real identifiers for sided variants.** Raised 2026-09-13, needed by every sided [Observation](/glossary/observation.md). -**From RadLex to OIDM: an is-a relation and structure-type nodes.** Raised 2026-08-19 and restated 2026-09-13 as the top priority. The curated set has no is-a relation and no structure-type nodes, which is recorded as its major shortcoming, because it blocks any scope statement of the form "applies to tendons." RadLex 4.3 has an is-a chain for every one of the 1,910 plain-identifier locations, and the stated work item is a derived, pinned overlay file handed to the anatomic locations track. Two cautions accompany it: RadLex's own release note warns that some is-a categorizations were converted from part-of and may be wrong, and the FMA-style chain is not the clinically useful layer.[^cde-axis] +**From RadLex to OIDM: an is-a relation and structure-type nodes.** Raised 2026-08-19 and restated 2026-09-13 as the top priority. The curated set has no is-a relation and no structure-type nodes, which is recorded as its major shortcoming, because it blocks any scope statement of the form "applies to tendons." RadLex 4.3 has an is-a chain for every one of the 1,910 plain-identifier locations, and the stated work item is a derived, pinned overlay file handed to the anatomic locations track. The record gives two cautions: RadLex's own release note warns that some is-a categorizations were converted from part-of and may be wrong, and the FMA-style chain is not the clinically useful layer.[^cde-axis] -Coverage of external codes is uneven and is recorded as a gap rather than assigned as work: [SNOMED CT](/glossary/snomed-ct.md) on 1,782 of 2,926 records, with 608 records carrying no codes at all.[^cde-gaps] +External-code coverage remains an unassigned gap: [SNOMED CT](/glossary/snomed-ct.md) on 1,782 of 2,926 records, with 608 records carrying no codes at all.[^cde-gaps] # The two datasets -Two lineages coexist and are not synchronized: the original 2,890-node set published at anatomiclocations.org with its two wrapper libraries, and the 2,926-record dataset inside the `anatomic-locations` package in `findingmodel`, which the build plan names as current.[^plan] The differences and the open questions between them are set out in [lineage and current implementation](/semantic-foundation/anatomic-locations/lineage-and-current-implementation.md). +Two datasets are unsynchronized: the original 2,890-node set published at anatomiclocations.org with its two wrapper libraries, and the 2,926-record dataset inside the `anatomic-locations` package in `findingmodel`, which the build plan names as current.[^plan] The differences and the open questions between them are set out in [lineage and current implementation](/semantic-foundation/anatomic-locations/lineage-and-current-implementation.md). Reconciling the record counts is stated nowhere as work. No document says what the extra 36 records are, and no process syncs edits in either direction. # Items carried forward from the original libraries -The clearest statement of intent for the original lineage is the TODO list added to `BodyPartIndex.py` on 2024-02-03. None of its items is done in that repository, and several were done independently in the current package.[^bpi-todo] +The `BodyPartIndex.py` TODO list dates to 2024-02-03. None of its items was completed there, though the current package independently completed several.[^bpi-todo] | Item | Status | |---|---| @@ -96,7 +96,7 @@ The site roadmap additionally lists finishing `BodyPartIndex.py` and publishing The project lead stated in the 2026-09-20 planning interview that the area needs tooling for the people who work with anatomic locations, meaning curators and coders rather than library consumers.[^plan] What exists today, the package, its command-line interface, the curation skill, and the older wrappers, is described in [tooling](/semantic-foundation/anatomic-locations/tooling.md). -Four concrete items sit in the `findingmodel` repository against that surface. +Four `findingmodel` items address this tooling. - **Hierarchy-aware related models.** A task on `dev` records that `related_models()` requires an exact identifier match today and therefore misses hierarchy-aware relations.[^hierarchy-related] - **Graph representation research.** A note on `main` works through representing the containment and laterality graph in DuckDB and records why the adjacency-list plus recursive-query alternative was not chosen for a read-only database.[^graph-research] @@ -107,7 +107,7 @@ Search quality is not a side issue for the RadLex relationship. The search and c # Four body region enumerations -[Body region](/glossary/body-region.md) is enumerated four incompatible ways across OIDM: in the anatomic locations package, in the finding model metadata rewrite, in the extraction schema, and in the viewer's filter. Thorax against chest, and whether spine is a region at all, are the recurring mismatches. No document reconciles them and no source assigns the reconciliation. It is carried, with the rest of the area's unresolved items, in [open questions](/roadmap/open-questions.md). +[Body region](/glossary/body-region.md) is enumerated four incompatible ways across OIDM: in the anatomic locations package, in the finding model metadata rewrite, in the extraction schema, and in the viewer's filter. Thorax against chest, and whether spine is a region at all, are the recurring mismatches. Reconciliation is undocumented and unassigned. See [open questions](/roadmap/open-questions.md). [^radlex-issue-3]: RSNA/RadLex issue 3, "Add Anatomic Locations" [^cde-axis]: The anatomy axis, current state, next-gen-2026 branch diff --git a/knowledge/roadmap/exam-types.md b/knowledge/roadmap/exam-types.md index 1a6d290..526fdf8 100644 --- a/knowledge/roadmap/exam-types.md +++ b/knowledge/roadmap/exam-types.md @@ -1,10 +1,10 @@ --- type: Roadmap title: Exam types roadmap -description: The goals stated for an OIDM exam type layer, by whom and when, the one written design that exists, the building blocks a future effort would start from, and the questions no source answers. +description: Exam type goals, the unimplemented Playbook profile design, and unresolved ownership and data questions. tags: [roadmap, exam-types, loinc, playbook, anatomy] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T19:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } stale_after: 2027-09-21 sources: - id: plan @@ -35,9 +35,9 @@ sources: # The state of the area -There is no [exam type](/glossary/exam-type.md) artifact. No registry, no curated code list, no exam-to-body-part mapping, and no code anywhere in the Open Imaging Data Model (OIDM) repositories that parses an exam name into modality and anatomy axes. What exists is a goal stated three times across four years, one written design that has not been implemented, and three places where a bare [LOINC](/glossary/loinc.md) code does real work today. +Open Imaging Data Model (OIDM) has no [exam type](/glossary/exam-type.md) registry, curated code list, exam-to-body-part map, or code that parses exam names into modality and anatomy. The goal appears three times across four years. One design is unimplemented, and three existing uses rely on bare [LOINC](/glossary/loinc.md) codes. -The area as it stands is described in [exam types](/semantic-foundation/exam-types/overview.md), and the inventory of what a future effort would start from is in [existing building blocks](/semantic-foundation/exam-types/existing-building-blocks.md). This document collects the goals and the open questions. +See [exam types](/semantic-foundation/exam-types/overview.md) and [existing building blocks](/semantic-foundation/exam-types/existing-building-blocks.md) for current capabilities. # The goal as the project lead states it @@ -47,7 +47,7 @@ In the 2026-09-20 planning interview recorded in [the knowledgebase build plan]( 2. **A set of preferred high-level entries**, at the granularity clinicians and systems actually use, the examples given being CT Chest, MRI Brain, and X-ray Knee, each marked as the preferred entry among the many Playbook codes describing variants of the same study. 3. **Tight coupling to [anatomic locations](/glossary/anatomic-location.md)**, with typed edges from an exam type to the structures it covers, distinguishing anatomy that is **always included**, which may be expressed as a hierarchy rather than a flat list, anatomy that is **usually included**, and anatomy that is **possibly included and must be checked**. -The third part is what would make the artifact more than a code list. It answers the question both a report reader and an extraction pipeline need answered: given this study, what could have been assessed? +The anatomy links would tell readers and extraction tools what a study could have assessed. # The same goal, stated earlier @@ -59,13 +59,13 @@ The site post "Data Model: Structure and Function" of 2024-01-25 names two utili # The one written design -The most developed written design is in the terminology tool's product roadmap, which proposes replacing an ever-growing default search with named, inspectable domain profiles. Its `radiology` profile makes the Playbook first-class: RadLex, LOINC weighted toward the Playbook, [SNOMED CT](/glossary/snomed-ct.md), and [FMA](/glossary/fma.md), with [UMLS](/glossary/umls.md) as the crosswalk hub.[^molu-roadmap] +The terminology tool's product roadmap proposes named, inspectable domain profiles in place of a growing default search. Its `radiology` profile makes the Playbook first-class: RadLex, LOINC weighted toward the Playbook, [SNOMED CT](/glossary/snomed-ct.md), and [FMA](/glossary/fma.md), with [UMLS](/glossary/umls.md) as the crosswalk hub.[^molu-roadmap] Four Playbook-specific implications are stated in it: rank procedure and orderable queries toward Playbook terms and finding queries toward the other vocabularies; teach the crosswalk the Playbook correspondences, linking a LOINC code to its historic `RPID` and to RadLex anatomy and modality attributes, recording that in the mapping provenance; detect `RPID` codes as well as LOINC-shaped codes; and do not treat every LOINC hit as radiology.[^molu-roadmap] None of it is built. The repository's issue backlog follows a six-phase design as one tracking issue plus eleven focused ones, of which only typed provider failures is closed; the profile mechanism is part of that backlog, not a released capability.[^molu-backlog] See [med-ontology-lookup](/semantic-foundation/terminologies/med-ontology-lookup.md). -Two facts from the next-generation vocabulary analysis constrain any such effort and are worth stating with the goals. The Playbook is "actively governed, and freely licensed for commercial and non-commercial use," shipping twice yearly under joint Regenstrief Institute and RSNA governance, and it "is a separate artifact" from RadLex.[^current-understanding] Current Playbook content carries ordinary LOINC codes; `RPID` identifiers are legacy and appear only as historical codes a crosswalk would need to recognize.[^molu-roadmap] +The next-generation vocabulary analysis records two constraints. The Playbook is "actively governed, and freely licensed for commercial and non-commercial use," shipping twice yearly under joint Regenstrief Institute and RSNA governance, and it "is a separate artifact" from RadLex.[^current-understanding] Current Playbook content carries ordinary LOINC codes; `RPID` identifiers are legacy and appear only as historical codes a crosswalk would need to recognize.[^molu-roadmap] # What is unanswered diff --git a/knowledge/roadmap/finding-model-content-direction.md b/knowledge/roadmap/finding-model-content-direction.md index 81dd343..cf53a03 100644 --- a/knowledge/roadmap/finding-model-content-direction.md +++ b/knowledge/roadmap/finding-model-content-direction.md @@ -1,10 +1,10 @@ --- type: Roadmap title: Finding model content direction -description: "Where the finding model corpus is going: the MGB exam-oriented sub-taxonomies as the content spine, the expected supersession of Gamuts-derived models, the triage of unmatched rows, the content batches in flight, the definition cleanup plan, and the open content issues." +description: Exam-oriented content priorities, unmatched taxonomy rows, unmerged batches, and corpus cleanup plans. tags: [roadmap, finding-models, content, taxonomy, gamuts, cleanup] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T19:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } stale_after: 2027-09-21 sources: - id: plan @@ -69,7 +69,7 @@ The sub-taxonomy export minted no identifiers. Rows were matched by exact name a | Carrying an existing OIFM identifier | 1,028 | | Blank, awaiting triage | 2,761 | -The README names the next task in one sentence: "Blank rows are the ones needing triage."[^lists-readme] Match rates are uneven, from 86 percent on head CT and 76 percent on chest radiography down to 10 percent on the combined chest, abdomen, and pelvis CT file and 3 percent on mammography. No plan document assigns the triage work, and no issue tracks it. +The README states: "Blank rows are the ones needing triage."[^lists-readme] Match rates are uneven, from 86 percent on head CT and 76 percent on chest radiography down to 10 percent on the combined chest, abdomen, and pelvis CT file and 3 percent on mammography. No plan document assigns the triage work, and no issue tracks it. # Content batches in flight @@ -83,7 +83,7 @@ Five `findingmodels` branches carry unmerged content work. None has an open pull | a clinician-request branch | 2025-12-12 | 59 | A requested batch for an intracranial problem list application | | `findingmodels-metadata` | 2026-06-01 | 0, modifies 78 | Applies an approved metadata enrichment baseline to existing definitions | -The CT chest branch is the live front of that pipeline. Its plan records the refactor from one monolithic agent into three focused ones with Python-level orchestration, with phases 1 through 3 complete and two follow-ups open: the create agent extracts fewer attributes than the single-agent version did, and the sub-findings schema is unresolved.[^chest-plan] Its progress document is explicit about how far the batch has run: 205 total sources, chunked into 21 groups of 10, with chunk 1 complete and chunks 2 through 21 pending.[^chest-progress] +Its plan records the refactor from one monolithic agent into three focused ones with Python-level orchestration, with phases 1 through 3 complete and two follow-ups open: the create agent extracts fewer attributes than the single-agent version did, and the sub-findings schema is unresolved.[^chest-plan] Its progress document is explicit about how far the batch has run: 205 total sources, chunked into 21 groups of 10, with chunk 1 complete and chunks 2 through 21 pending.[^chest-progress] The head CT branch's one plan document is marked complete for the soft tissue category: four new models created, nine mappings made to existing models, review done, identifiers written back, validator clean.[^headct-plan] @@ -93,7 +93,7 @@ An earlier CT chest branch, `cde_to_finding`, holds 1,915 definitions from the s A draft plan on `main`, still marked "DRAFT - for review," covers cleaning the existing corpus against the authoring conventions. It scopes 2,379 models: 1,934 Gamuts, 264 OIDM already reviewed, 115 from the common data element work, 47 from MassGeneral Brigham, and 19 from Microsoft.[^cleanup] -It gives an ordered execution sequence with counts. +The plan orders the work as follows. | Order | Category | Models | Nature of the work | |---:|---|---:|---| @@ -131,7 +131,7 @@ Five of the ten open `findingmodels` issues are content batches. None is closed Two further open issues, 17 and 32, ask for a static marketing site and a static catalog site for the content; the catalog site exists and is profiled in [the finding models site](/applications/finding-models-site.md). -How the corpus is organized and browsed today is in [the content catalog](/semantic-foundation/finding-models/content-catalog.md), and the identifier scheme that governs writebacks is in [identifiers](/semantic-foundation/finding-models/identifiers.md).[^ids-json] Where sources disagree about corpus counts and content classification, see [open questions](/roadmap/open-questions.md). +See [the content catalog](/semantic-foundation/finding-models/content-catalog.md) for organization and browsing, and [identifiers](/semantic-foundation/finding-models/identifiers.md) for writeback rules.[^ids-json] Where sources disagree about corpus counts and content classification, see [open questions](/roadmap/open-questions.md). [^plan]: Knowledgebase build plan, recording the project lead's statement of 2026-09-21 [^lists-readme]: MGB exam-oriented sub-taxonomies README, taxonomy-export-2026-08-15 branch diff --git a/knowledge/roadmap/finding-model-format-evolution.md b/knowledge/roadmap/finding-model-format-evolution.md index 389d93f..663adae 100644 --- a/knowledge/roadmap/finding-model-format-evolution.md +++ b/knowledge/roadmap/finding-model-format-evolution.md @@ -1,10 +1,10 @@ --- type: Roadmap title: Finding model format evolution -description: "The stated goals for where the Open Imaging Finding Model record format is going: the canonical structured-metadata rewrite, the source schema version 2 draft, relationship and graph ideas from the next-generation CDE work, versioning, and the discrepancies a revision would have to settle." +description: Proposed metadata, schema, relationship, and versioning changes to the finding model format. tags: [roadmap, finding-models, schema, metadata, relationships, versioning] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T19:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } stale_after: 2027-09-21 sources: - id: rewrite @@ -59,9 +59,9 @@ sources: # What this document collects -The released Open Imaging Finding Model (OIFM) record format is described in [the finding model format](/semantic-foundation/finding-models/finding-model-format.md). This document collects the goals that have been stated for changing it, with the source that states each one. Nothing here is implemented on `main` of any repository, and nothing here is a proposal by this knowledgebase. +The released Open Imaging Finding Model (OIFM) format is described in [the finding model format](/semantic-foundation/finding-models/finding-model-format.md). This document collects the goals that have been stated for changing it, with the source that states each one. Nothing here is implemented on `main` of any repository, and nothing here is a proposal by this knowledgebase. -Four separate threads are in play, and they are not coordinated with each other: a metadata rewrite on a `findingmodel` branch, a source schema version 2 draft circulating in the common data element work, relationship and graph ideas coming out of the next-generation CDE vocabulary, and a versioning plan for packages and database artifacts. +Four efforts remain uncoordinated: a metadata rewrite on a `findingmodel` branch, a source schema version 2 draft circulating in the common data element work, relationship and graph ideas coming out of the next-generation CDE vocabulary, and a versioning plan for packages and database artifacts. # The canonical structured-metadata rewrite @@ -69,13 +69,13 @@ The most advanced thread. The design document on `feature/metadata-cleanup` stat It adds eight optional fields to both finding model classes: `body_regions`, `subspecialties`, `etiologies`, `entity_type`, `applicable_modalities`, `expected_time_course`, `age_profile`, and `sex_specificity`. Their permitted values are listed in [the format document](/semantic-foundation/finding-models/finding-model-format.md); the pipeline that populates them is described in [the enrichment pipeline](/semantic-foundation/finding-models/enrichment-pipeline.md). -Two constraints ride with it. Canonical `index_codes` are narrowed to exact or clinically substitutable matches, with broader, narrower, and merely related candidates diverted to a separate review artifact. And model-level entries in `index_codes` and `anatomic_locations` are rejected when `display` is empty.[^rewrite] +Canonical `index_codes` allow only exact or clinically substitutable matches. Broader, narrower, and related candidates go to a review artifact. Model-level `index_codes` and `anatomic_locations` entries require a nonempty `display`.[^rewrite] **Status as the branch reports it.** The execution plan on `dev` records slices 1 through 8 and 9-A complete, with slice 9-B, migrating the MCP and command-line callers plus a bulk backfill, and slice 10, backfill, fixtures, and final documentation, remaining.[^impl-plan] The branch's own readiness assessment fails: the 2026-06-03 prompt-improvement document raises expected time course to between 0.76 and 0.78 and etiologies to between 0.91 and 0.93, then states that overall readiness remains a failure because age profile and index codes are below the quality floor.[^tempo] # The source schema version 2 draft -A separate and broader draft, dated 2026-04-20 and marked "a proposed authoring schema, not an implementation-complete contract yet," is kept in the `next-gen-2026` branch of `ACR-RSNA-CDEs` as a copy of an upstream gist.[^v2-draft] It proposes a different decomposition of the format than the metadata rewrite does, and the two have not been reconciled. +A broader draft, dated 2026-04-20 and marked "a proposed authoring schema, not an implementation-complete contract yet," is kept in the `next-gen-2026` branch of `ACR-RSNA-CDEs` as a copy of an upstream gist.[^v2-draft] Its format differs from the metadata rewrite and remains unreconciled with it. | Proposal | What the draft says | |---|---| @@ -87,7 +87,7 @@ A separate and broader draft, dated 2026-04-20 and marked "a proposed authoring | Registries | `relationship_types.json` and `quantity_kinds.json` alongside the corpus | | `schema_version` on the record | Required, `"2.0"` for version 2 source files | -The draft also lists explicit removals and changes against the current shape: drop `required`; replace the numeric `unit` with `quantity_kind` plus optional `common_units`; add `synonyms` to attributes and choice values; add model-level `references`; add `lifecycle` and `related_models`; allow canonical attribute references; and keep hydrated output close to the current structure.[^v2-draft] +The draft also proposes these changes: drop `required`; replace the numeric `unit` with `quantity_kind` plus optional `common_units`; add `synonyms` to attributes and choice values; add model-level `references`; add `lifecycle` and `related_models`; allow canonical attribute references; and keep hydrated output close to the current structure.[^v2-draft] Five decisions are left open in the draft itself, including whether runtime APIs expose both the authored and the effective relationship views, where registry files live, and whether canonical attributes may be numeric or carry index codes.[^v2-draft] @@ -95,7 +95,7 @@ Five decisions are left open in the draft itself, including whether runtime APIs The project lead's stated goal for the format, recorded in [the knowledgebase build plan](/plans/2026-09-20-knowledgebase-build-plan.md), is increased metadata plus the relationship and graph work coming out of the common data element effort.[^plan] -That effort is described in [the next-generation vocabulary](/semantic-foundation/common-data-elements/next-generation-vocabulary.md). Three of its ideas bear directly on the finding model format. +[The next-generation vocabulary](/semantic-foundation/common-data-elements/next-generation-vocabulary.md) contributes three relevant ideas. - **Typed, identified relationships.** Eight relationship pairs plus a catch-all, each carrying its own identifier so a report-level assertion can cite the standing potential it expresses.[^doc07] - **The differential as a derived view.** Computed by traversing manifestation edges and filtering by context, with no `DIFFERENTIAL_OF` edge type.[^doc07] @@ -115,7 +115,7 @@ Record-format versioning appears only in the version 2 draft's `schema_version` # Superseded, and still open as an issue -The original eight-facet classification specification is superseded. Two task documents on `main` carry it, the task status summary marks it "Blocked - needs 4 design decisions" covering scope, required against optional, markdown representation, and search indexing,[^status] and the canonical metadata implementation plan states that it supersedes the facets plan for this workstream.[^impl-plan] Issue 25 remains open against the old design.[^issue-25] +Two `main` task documents describe the superseded eight-facet specification. The status summary marks it "Blocked - needs 4 design decisions" on scope, required versus optional fields, markdown representation, and search indexing.[^status] The canonical metadata implementation plan supersedes it for this workstream.[^impl-plan] Issue 25 remains open against the old design.[^issue-25] Four other open `findingmodel` issues shape the format rather than the tooling. Issue 5 asks for three model variants: a content-only form for language model extraction, a draft form carrying everything but identifiers and contributors, and the full saveable form.[^issue-5] Issue 3 asks for a human-editable markdown form without identifiers or codes, issue 4 for a tool that folds edits to that markdown back into the JSON while preserving identifiers, and issue 8 for a `FindingObservation` concept holding worked examples of a finding model in use. @@ -136,7 +136,7 @@ Two are recorded in the format documentation and are carried in [open questions] - **Choice value code indexing.** The prose mirror on `main` numbers the first choice value `.1`; the validator in the released code writes `.0`, and the stored corpus follows the code.[^prose-schema] - **Omissions in the prose mirror.** It omits `anatomic_locations` from the full model entirely, and states none of the length and cardinality constraints the code enforces.[^prose-schema] -The content-side direction, which is separate from the format, is in [the content direction roadmap](/roadmap/finding-model-content-direction.md). +See [the content direction roadmap](/roadmap/finding-model-content-direction.md) for corpus work. [^rewrite]: Canonical Structured Metadata and Enrichment Rewrite, feature/metadata-cleanup branch [^impl-plan]: Canonical structured metadata implementation plan, findingmodel dev branch diff --git a/knowledge/roadmap/index.md b/knowledge/roadmap/index.md index a6c6465..9680eac 100644 --- a/knowledge/roadmap/index.md +++ b/knowledge/roadmap/index.md @@ -2,10 +2,10 @@ Stated goals and direction, area by area, with the source that states each one. Everything here is a fact about what a deck, an issue, a plan document, or the project lead has said. Nothing here is a design proposal by this knowledgebase; proposals are a separate workstream. Where sources disagree, the disagreement is recorded rather than resolved, and collected in open questions. -* [Roadmap 2026](./roadmap-2026.md) - The project-level direction stated in the January 2026 status deck, the working group and use-case pipeline it proposes, and a per-repository summary of what is currently in flight. -* [Finding model format evolution](./finding-model-format-evolution.md) - The stated goals for where the Open Imaging Finding Model record format is going: the canonical structured-metadata rewrite, the source schema version 2 draft, relationship and graph ideas from the next-generation CDE work, versioning, and the discrepancies a revision would have to settle. -* [Finding model content direction](./finding-model-content-direction.md) - Where the finding model corpus is going: the MGB exam-oriented sub-taxonomies as the content spine, the expected supersession of Gamuts-derived models, the triage of unmatched rows, the content batches in flight, the definition cleanup plan, and the open content issues. -* [Imaging Problem List data model system](./ipl-data-model-system.md) - The stated goals for the Observation, Exam Finding List, and Imaging Problem List layer: the formal model system asked for in issue 1, the eight active plans on the development branch, the anatomic-compatibility follow-on, and the FHIR and IHE alignments that are documented but unimplemented. -* [Exam types roadmap](./exam-types.md) - The goals stated for an OIDM exam type layer, by whom and when, the one written design that exists, the building blocks a future effort would start from, and the questions no source answers. -* [Anatomic locations and RadLex](./anatomic-locations-and-radlex.md) - The stated goals for the anatomic location set: incorporation into RadLex as an overlay, the node requests owed to the RadLex anatomy track, the two unreconciled datasets, the tooling items carried forward from the original libraries, and the body region enumerations that disagree. -* [Open questions](./open-questions.md) - Every conflict between sources and every unverified fact found while building this knowledgebase, grouped by area, with the sources on each side and the owner where one is indicated. +* [Roadmap 2026](./roadmap-2026.md) - The January 2026 project goals, proposed working group, use-case pipeline, and current repository work. +* [Finding model format evolution](./finding-model-format-evolution.md) - Proposed metadata, schema, relationship, and versioning changes to the finding model format. +* [Finding model content direction](./finding-model-content-direction.md) - Exam-oriented content priorities, unmatched taxonomy rows, unmerged batches, and corpus cleanup plans. +* [Imaging Problem List data model system](./ipl-data-model-system.md) - Formal data model goals, eight active plans, anatomy reconciliation, and unimplemented FHIR and IHE mappings. +* [Exam types roadmap](./exam-types.md) - Exam type goals, the unimplemented Playbook profile design, and unresolved ownership and data questions. +* [Anatomic locations and RadLex](./anatomic-locations-and-radlex.md) - RadLex incorporation, anatomy node requests, dataset differences, tooling goals, and conflicting body regions. +* [Open questions](./open-questions.md) - Every conflict between sources and every unverified fact found while building this knowledgebase, grouped by area, with the sources on each side and the owner where one is indicated, plus the defects found in source documents. diff --git a/knowledge/roadmap/ipl-data-model-system.md b/knowledge/roadmap/ipl-data-model-system.md index 8fcc0cf..96ac5b0 100644 --- a/knowledge/roadmap/ipl-data-model-system.md +++ b/knowledge/roadmap/ipl-data-model-system.md @@ -1,10 +1,10 @@ --- type: Roadmap title: Imaging Problem List data model system -description: "The stated goals for the Observation, Exam Finding List, and Imaging Problem List layer: the formal model system asked for in issue 1, the eight active plans on the development branch, the anatomic-compatibility follow-on, and the FHIR and IHE alignments that are documented but unimplemented." +description: Formal data model goals, eight active plans, anatomy reconciliation, and unimplemented FHIR and IHE mappings. tags: [roadmap, data-structures, ipl, observation, fhir, ihe] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T19:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } stale_after: 2027-09-21 sources: - id: issue-1 @@ -46,7 +46,7 @@ sources: In the 2026-09-20 planning interview that produced [the knowledgebase build plan](/plans/2026-09-20-knowledgebase-build-plan.md), the project lead described the Imaging Problem List work in four parts: define data structures for [Observations](/glossary/observation.md) and their relationships; manage and collate those observations across a patient's history; design the applications that use them; and publish the result as standard formats.[^plan] -The January 2026 deck states the same layer as the second strategic pillar, an ordered hierarchy from the atomic Observation through the [Exam Finding List](/glossary/exam-finding-list.md) and the [Imaging Problem List](/glossary/imaging-problem-list.md) to the [Imaging Persona](/glossary/imaging-persona.md), and names the Imaging Problem List as "a standard format for structured imaging results, automatically extractable from narrative report text."[^deck] The structures as they exist today are documented under [data structures](/data-structures/); what follows is what has been stated about where they go. +The January 2026 deck makes this hierarchy its second strategic pillar: Observation, [Exam Finding List](/glossary/exam-finding-list.md), [Imaging Problem List](/glossary/imaging-problem-list.md), and [Imaging Persona](/glossary/imaging-persona.md). It calls the Imaging Problem List "a standard format for structured imaging results, automatically extractable from narrative report text."[^deck] The structures as they exist today are documented under [data structures](/data-structures/); what follows is what has been stated about where they go. # Issue 1: a formal system of data models @@ -57,9 +57,9 @@ The one open issue in the `imaging-problem-list` repository, opened 2026-01-28, - With **extensive annotation to generate JSON schemas**. - Using **camelCase aliases in export** against **snake_case object attributes** internally. -Each element of that corresponds to a gap that exists today. There is no Observation model, no JSON Schema, and no standalone Observation record; the structure exists only inside the Exam Finding List JSON and, separately, inside the extraction pipeline's own models. Both the Exam Finding List and Imaging Problem List sample files carry a `$schema` URL that resolves to nothing. And the camelCase against snake_case split is the convention the existing sample data already follows without a model to enforce it. +There is no formal Observation model, JSON Schema, or standalone record. Observations exist within Exam Finding List JSON and separate extraction models. Both list formats have sample `$schema` URLs that resolve to nothing. Sample data follows the camelCase and snake_case convention without a model enforcing it. -The Extracted Observation subtype the issue floats maps onto a distinction the pipeline already makes in practice, between what a language model produced and what has been coded. See [Observation](/data-structures/observation.md). +The proposed subtype reflects the pipeline's distinction between language model output and coded findings. See [Observation](/data-structures/observation.md). # The eight active plans as direction @@ -87,11 +87,11 @@ This is a data model question, not a display question, because the grouping key The mapping is stated in the specification on `main`: a report containing a list of [FHIR Condition](/glossary/fhir-condition.md) objects labeled with the finding identifier, each containing FHIR Observations documenting which exams the finding was recorded on, with exam date and LOINC-coded exam type.[^ipl-main] -No code in any repository produces a Condition resource, and no current plan claims to. The full picture, including the lineage precedents that do implement a FHIR encoding, is in [FHIR mapping](/data-structures/fhir-mapping.md). One lineage experiment states an adjacent goal: a design note on an unmerged `IPL-MVP-ExtractionAndLabeling` branch proposes persistent FHIR Observations with stable identifiers, so repeated mentions of a finding across reports link to one entity rather than creating new ones.[^fhir-design-note] It carries no file extension and adds no code. +No code in any repository produces a Condition resource, and no current plan claims to. See implemented lineage precedents in [FHIR mapping](/data-structures/fhir-mapping.md). One lineage experiment states an adjacent goal: a design note on an unmerged `IPL-MVP-ExtractionAndLabeling` branch proposes persistent FHIR Observations with stable identifiers, so repeated mentions of a finding across reports link to one entity rather than creating new ones.[^fhir-design-note] The extensionless note adds no code. # IHE Imaging Diagnostic Report alignment -The deck states that the Exam Finding List "connects to the IHE Imaging Diagnostic Report (IDR) FHIR representation."[^deck] That connection is a goal. No OIDM repository implements or references the profile; what exists is a full extract of the Phase II public comment draft on the `next-gen-2026` branch of `ACR-RSNA-CDEs`.[^idr-extract] +The deck states that the Exam Finding List "connects to the IHE Imaging Diagnostic Report (IDR) FHIR representation."[^deck] The connection remains a goal. No OIDM repository implements or references the profile. `ACR-RSNA-CDEs`'s `next-gen-2026` branch holds a full Phase II public comment draft extract.[^idr-extract] Four differences between the profile and current OIDM encodings are recorded in that extract, all listed as items to raise during public comment and none resolved: whether attributes ride in `Observation.component` or in `hasMember`; a vocabulary collision on the words "finding" and "observation"; whether a diagnosis is a FHIR Observation or a FHIR Condition; and whether [laterality](/glossary/laterality.md) lives in the location identifier or in a separate field. The profile also puts three questions back to the RadElement side, including what the coding system identifier for RadElement codes is. All are carried in [IHE IDR alignment](/data-structures/ihe-idr-alignment.md) and in [open questions](/roadmap/open-questions.md). diff --git a/knowledge/roadmap/open-questions.md b/knowledge/roadmap/open-questions.md index f66d959..3a19b2c 100644 --- a/knowledge/roadmap/open-questions.md +++ b/knowledge/roadmap/open-questions.md @@ -1,10 +1,10 @@ --- type: Reference title: Open questions -description: Every conflict between sources and every unverified fact found while building this knowledgebase, grouped by area, with the sources on each side and the owner where one is indicated. +description: Every conflict between sources and every unverified fact found while building this knowledgebase, grouped by area, with the sources on each side and the owner where one is indicated, plus the defects found in source documents. tags: [roadmap, open-questions, conflicts, gaps] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T19:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: deck resource: https://gamma.app/docs/Open-Imaging-Data-Model-2026-Status-Update:-Realizing-Object-Oriented-Imaging-Results-yfxzx4q9zssafal diff --git a/knowledge/roadmap/roadmap-2026.md b/knowledge/roadmap/roadmap-2026.md index 4b38e82..ae6d4dc 100644 --- a/knowledge/roadmap/roadmap-2026.md +++ b/knowledge/roadmap/roadmap-2026.md @@ -1,10 +1,10 @@ --- type: Roadmap title: Roadmap 2026 -description: The project-level direction stated in the January 2026 status deck, the working group and use-case pipeline it proposes, and a per-repository summary of what is currently in flight. +description: The January 2026 project goals, proposed working group, use-case pipeline, and current repository work. tags: [roadmap, deck, working-group, acr, work-edge] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T19:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } stale_after: 2027-09-21 sources: - id: deck @@ -32,9 +32,9 @@ sources: # What this document is -This is the project-level direction for the Open Imaging Data Model (OIDM), as stated by its sources. The single most complete statement is the January 2026 status deck, extracted in full at [status update, January 2026](/references/status-update-2026-01.md).[^deck] Below the deck sit the working repositories, whose direction is visible in their unmerged branches, plan documents, and open issues. +The January 2026 status deck states the Open Imaging Data Model (OIDM) direction. See [the full extract](/references/status-update-2026-01.md).[^deck] Repository branches, plans, and issues record work toward it. -Nothing here is a proposal. Each goal is attributed to the deck, an issue, or a plan document that states it. Where a goal has no artifact behind it, that is said. Per-area goals live in the five area roadmaps linked from [the roadmap index](/roadmap/); unresolved conflicts between sources are collected in [open questions](/roadmap/open-questions.md). +Nothing here is a proposal. Each goal is attributed to the deck, an issue, or a plan document that states it. Where a goal has no artifact behind it, that is said. Per-area goals live in the five [area roadmaps](/roadmap/); unresolved conflicts between sources are collected in [open questions](/roadmap/open-questions.md). # The three strategic pillars @@ -65,11 +65,11 @@ No record of the working group being convened exists in any repository read for Three, in the deck's own words: host and moderate an academic and vendor "big tent"; run a **use-case pipeline feeding the CDE group**; standardize the result.[^deck] -The use-case pipeline is the one of the three with existing material behind it. The lineage `UseCases` repository holds roughly 25 use case ideas organized against the RSNA value categories, described in [use cases](/history/use-cases.md). The direction the deck states is that such use cases feed the ACR and RSNA common data element group, which is the same direction as the workbench relationship described in [finding models and CDEs](/semantic-foundation/finding-models/finding-models-and-cdes.md). +The use-case pipeline is the one of the three with existing material behind it. The lineage `UseCases` repository provides roughly 25 ideas tagged with RSNA value categories. See [use cases](/history/use-cases.md). The deck would send such cases to the ACR and RSNA CDE group, consistent with the process described in [finding models and CDEs](/semantic-foundation/finding-models/finding-models-and-cdes.md). # The work edge, repository by repository -Branch inventories taken on 2026-09-21 established what follows; the full detail is in [the repository map](/repositories/repository-map.md).[^repo-map] None of the unmerged branches named here has an open pull request. +These inventories date to 2026-09-21. See [the repository map](/repositories/repository-map.md).[^repo-map] None of the unmerged branches named here has an open pull request. | Repository | Live thread | In flight | Area roadmap | |---|---|---|---| @@ -92,7 +92,7 @@ Three items in the deck have no artifact in any repository. They are direction, A fourth item, [exam types](/glossary/exam-type.md), is not in the deck at all but has been stated as a goal in three places since 2022 with no artifact produced; see [the exam types roadmap](/roadmap/exam-types.md). -The implementation status of every piece of the system, built and unbuilt, is tabulated in [architecture](/overview/architecture.md). +See implementation status in [architecture](/overview/architecture.md). [^deck]: "Open Imaging Data Model 2026 Status Update: Realizing Object-Oriented Imaging Results", January 2026 [^plan]: Knowledgebase build plan diff --git a/knowledge/semantic-foundation/anatomic-locations/data-model.md b/knowledge/semantic-foundation/anatomic-locations/data-model.md index 3518e0d..a4b504a 100644 --- a/knowledge/semantic-foundation/anatomic-locations/data-model.md +++ b/knowledge/semantic-foundation/anatomic-locations/data-model.md @@ -1,10 +1,10 @@ --- type: Format Specification title: Anatomic location data model -description: The record model for an anatomic location in both lineages, its identifier scheme, its two hierarchies, its laterality triads, its classification fields, and its external codes, with verified counts. +description: Anatomic location identifiers, fields, hierarchies, classification, and code coverage in both datasets. tags: [semantic-foundation, anatomic-locations, schema, radlex, laterality] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: al-schema resource: https://github.com/talkasab/anatomiclocations.org/blob/1f39fa45f621cef947a3f3ef1f869334cfa5c841/data/body_parts_schema.json @@ -37,7 +37,7 @@ sources: # Scope -This document describes the record: what an [anatomic location](/glossary/anatomic-location.md) carries and what each field means. The verbatim JSON Schema and the full runtime field list live in [the anatomic location record format reference](/references/anatomic-location-json-schema.md). Two datasets exist and are not reconciled with each other, so both are described here; [lineage and current implementation](/semantic-foundation/anatomic-locations/lineage-and-current-implementation.md) says which is current and why. +An [anatomic location](/glossary/anatomic-location.md) record has two unreconciled formats. This page describes both. See [the record format reference](/references/anatomic-location-json-schema.md) for the verbatim JSON Schema and runtime fields, and [lineage and current implementation](/semantic-foundation/anatomic-locations/lineage-and-current-implementation.md) for their status. | Dataset | Records | Version | Field naming | |---|---|---|---| @@ -76,11 +76,11 @@ Every record carries a containment parent. The distinction between the two hiera The original set stores parent pointers only and lets a library derive children. The current set stores both directions as `{id, display}` reference objects, so a consumer can read a node's children without indexing the whole file. Containment is a rooted tree from `RID39569`, whole body. The part-of relation covers fewer than half the records and is not a tree. -Two data defects are visible in the current file and are worth knowing before traversing it. 111 records carry a `partOfRef` pointing at themselves, and one carries a self-referential `leftRef`. The build process already expects self-referential containment at the root, which is legitimate, but self-referential part-of on 111 nodes is not.[^fm-normalized] +The current file has 111 self-referential `partOfRef` values and one self-referential `leftRef`. The build already expects self-referential containment at the root, which is legitimate, but self-referential part-of is a defect.[^fm-normalized] # Laterality triads -A sided structure is represented by three records, not by a flag on one. The generic record carries `leftRef` and `rightRef`; each sided record carries `unsidedRef` back to the generic one and a reference to its counterpart. The full convention, including the containment and synonym rules for sided entries, is in [laterality conventions](/semantic-foundation/anatomic-locations/laterality-conventions.md). See also [laterality](/glossary/laterality.md). +A sided structure uses generic, left, and right records. The generic record has `leftRef` and `rightRef`. Each sided record has `unsidedRef` and a counterpart reference. See [laterality conventions](/semantic-foundation/anatomic-locations/laterality-conventions.md) for containment and synonym rules, and [laterality](/glossary/laterality.md) for the term. | Field | Original set | Current set | |---|---|---| @@ -145,7 +145,7 @@ The current format, unchanged from the data file. It shows containment, part-of, # From record to usable object -The curation format is what an editor changes. The package that consumes it normalizes each record into an `AnatomicLocation` object, resolves the reference objects, adds a laterality enum, and precomputes a materialized containment path and part-of path so that ancestry, descendants, and the "is X inside Y" test are string comparisons rather than recursive walks.[^fm-normalized] A location converts to an [index code](/glossary/index-code.md) with system `anatomic_locations`, its RadLex identifier as the code, and its description as the display, which is the form it takes when attached to a [finding model](/glossary/finding-model.md).[^fm-location-model] +The curation format is what an editor changes. The package that consumes it normalizes each record into an `AnatomicLocation` object, resolves references, and adds a laterality enum. Precomputed containment and part-of paths make ancestry, descendants, and "is X inside Y" tests string comparisons.[^fm-normalized] A location becomes an [index code](/glossary/index-code.md) with system `anatomic_locations`, its RadLex identifier as code, and its description as display. [Finding models](/glossary/finding-model.md) use this form.[^fm-location-model] [^al-schema]: body_parts_schema.json, anatomiclocations.org [^al-data]: body_parts.json, release 1.0.0-rc.1 diff --git a/knowledge/semantic-foundation/anatomic-locations/index.md b/knowledge/semantic-foundation/anatomic-locations/index.md index 8a1ea35..8ce05cf 100644 --- a/knowledge/semantic-foundation/anatomic-locations/index.md +++ b/knowledge/semantic-foundation/anatomic-locations/index.md @@ -1,8 +1,8 @@ # Anatomic locations -* [Why anatomic locations](./why-anatomic-locations.md) - Why OIDM curates its own anatomic location set instead of pointing at an existing ontology, and every place those identifiers are used across the model. -* [Anatomic location data model](./data-model.md) - The record model for an anatomic location in both lineages, its identifier scheme, its two hierarchies, its laterality triads, its classification fields, and its external codes, with verified counts. -* [Laterality conventions](./laterality-conventions.md) - How sided anatomic locations are identified, linked, contained, and named in the curated set, and how a side is assigned to a finding at coding time. -* [Lineage and current implementation](./lineage-and-current-implementation.md) - The two anatomic location lineages, the original curated set with its wrapper libraries and the anatomic-locations package inside findingmodel, which one is current, and what remains unreconciled between them. -* [RadLex integration](./radlex-integration.md) - What RadLex is, how the curated anatomic location set relates to it as an overlay, the open RSNA tracking issue for folding the set into RadLex, and the running list of node requests. -* [Anatomic location tooling](./tooling.md) - How to look up, search, and traverse anatomic locations with the anatomic-locations package and CLI, the older wrapper libraries, and the raw JSON download. +* [Why anatomic locations](./why-anatomic-locations.md) - Why OIDM curates anatomic identifiers and where the model uses them. +* [Anatomic location data model](./data-model.md) - Anatomic location identifiers, fields, hierarchies, classification, and code coverage in both datasets. +* [Laterality conventions](./laterality-conventions.md) - Sided location identifiers and references, with rules for assigning laterality to findings. +* [Lineage and current implementation](./lineage-and-current-implementation.md) - The original and current anatomic location datasets, their consumers, and unresolved differences. +* [RadLex integration](./radlex-integration.md) - RadLex integration, the anatomy overlay agreement, search limitations, and pending node requests. +* [Anatomic location tooling](./tooling.md) - Lookup, search, and hierarchy traversal through current and older anatomic location tools. diff --git a/knowledge/semantic-foundation/anatomic-locations/laterality-conventions.md b/knowledge/semantic-foundation/anatomic-locations/laterality-conventions.md index c9e2b27..db5ba05 100644 --- a/knowledge/semantic-foundation/anatomic-locations/laterality-conventions.md +++ b/knowledge/semantic-foundation/anatomic-locations/laterality-conventions.md @@ -1,10 +1,10 @@ --- type: Reference title: Laterality conventions -description: How sided anatomic locations are identified, linked, contained, and named in the curated set, and how a side is assigned to a finding at coding time. +description: Sided location identifiers and references, with rules for assigning laterality to findings. tags: [semantic-foundation, anatomic-locations, laterality, reference, migrated] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: fm-laterality resource: https://github.com/openimagingdata/findingmodel/blob/75afd39a400419dcfaf7c8d4a34f065b4d804e0d/.claude/skills/manage-anatomic-locations/reference/laterality-conventions.md @@ -25,7 +25,7 @@ sources: # Two questions -[Laterality](/glossary/laterality.md) is decided twice in OIDM, and the rules are different. Curation decides how a sided structure is represented in the [anatomic location](/glossary/anatomic-location.md) set. Coding decides which of those records a given finding in a given report gets. The first half of this document is the curation convention, migrated from the finding model repository's curation skill.[^fm-laterality] The second half is the assignment rule from the extraction platform.[^ipl-rules] +[Laterality](/glossary/laterality.md) has two sets of rules. Curation defines sided records in the [anatomic location](/glossary/anatomic-location.md) set, as described in the migrated curation convention below.[^fm-laterality] Coding assigns those records to findings using the extraction platform's rules.[^ipl-rules] # Compound identifier pattern @@ -90,9 +90,9 @@ Identifier `{base}_RID5825`. Has `leftRef`, its counterpart, and `unsidedRef`. ` | `unsidedRef` only | `generic` | Maps to generic | | None | `nonlateral` | Not a lateralized structure | -The key insight is that a reference points at the counterpart, not at itself. A left entry has `rightRef` and `unsidedRef`. It does not have `leftRef`, because it is the left variant. +A reference points to the counterpart. A left entry has `rightRef` and `unsidedRef`, but no `leftRef`. -This inversion is easy to get wrong, and it has been got wrong: open issue 39 in the finding model repository reports that the build's `determine_laterality()` assigns left and right backwards.[^fm-issues] +Open issue 39 in the finding model repository reports that the build's `determine_laterality()` assigns left and right backwards.[^fm-issues] # Containment and synonyms for sided entries @@ -102,7 +102,7 @@ Synonyms follow a consistent pattern. Generic `["hilum", "lung hilum", "hilum of # Assigning a side to a finding -Curation says which records exist. Assignment says which one a given observation gets. The precedence is stated as explicit text side, then sided-exam side, then generic unsided.[^ipl-rules] +The precedence is stated as explicit text side, then sided-exam side, then generic unsided.[^ipl-rules] - **A non-sided exam never introduces a side.** On a CT abdomen, "adrenal glands unremarkable" resolves to the generic adrenal gland, not to a left one. "No hydronephrosis" with no side stated resolves to the generic kidney. - **A sided exam sides the finding.** A left shoulder radiograph plus "humerus fracture" resolves to the left humerus. @@ -120,7 +120,7 @@ Curation says which records exist. Assignment says which one a given observation The operational test for separable against inseparable: if you could meaningfully say "the left one is larger or newer," it is separable; if it is a named diffuse entity, it is inseparable.[^ipl-rules] -The full ladder, including the specificity and exam-region rules that surround these laterality rules, is in [anatomic location assignment rules](/data-structures/anatomic-location-assignment-rules.md). +See [anatomic location assignment rules](/data-structures/anatomic-location-assignment-rules.md) for the full precedence, specificity, and exam-region rules. # Known limitation diff --git a/knowledge/semantic-foundation/anatomic-locations/lineage-and-current-implementation.md b/knowledge/semantic-foundation/anatomic-locations/lineage-and-current-implementation.md index e668c93..0f09360 100644 --- a/knowledge/semantic-foundation/anatomic-locations/lineage-and-current-implementation.md +++ b/knowledge/semantic-foundation/anatomic-locations/lineage-and-current-implementation.md @@ -1,10 +1,10 @@ --- type: Concept title: Lineage and current implementation -description: The two anatomic location lineages, the original curated set with its wrapper libraries and the anatomic-locations package inside findingmodel, which one is current, and what remains unreconciled between them. +description: The original and current anatomic location datasets, their consumers, and unresolved differences. tags: [semantic-foundation, anatomic-locations, lineage, status] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: al-site resource: https://github.com/talkasab/anatomiclocations.org/blob/1f39fa45f621cef947a3f3ef1f869334cfa5c841/docs/index.markdown @@ -40,7 +40,7 @@ sources: # Two lineages -[Anatomic locations](/glossary/anatomic-location.md) exist twice in OIDM. The first lineage is the original curated set published at anatomiclocations.org with two wrapper libraries. The second is the `anatomic-locations` package inside the `findingmodel` repository, with its own data file. They descend from the same curation effort and hold nearly the same concepts, but they are separate artifacts with different field names, different record counts, and no synchronization between them. +OIDM has two [anatomic location](/glossary/anatomic-location.md) datasets from the same curation effort. The original, published at anatomiclocations.org, has two wrapper libraries. The current `anatomic-locations` package in `findingmodel` uses a separate file. They contain nearly the same concepts, with different field names and counts, and no synchronization. | | Original lineage | Current lineage | |---|---|---| @@ -59,7 +59,7 @@ Three repositories under the project lead's personal account, all under the ISC `BodyPartIndex.ts` is the TypeScript wrapper, published to npm as `@talkasab/body_part_index` with the data bundled in the package. It is the richer of the two wrappers, documenting local-code mapping and every hierarchy accessor.[^bpi-ts] Its last commit on `main` is 2022-12-18. -`BodyPartIndex.py` is the Python wrapper. Its README says installation from PyPI is pending, and the site roadmap still lists "finish BodyPartIndex.py and publish to PyPI" as an open item.[^al-site] Its last commit on `main`, 2024-02-03, added a TODO list that remains the clearest statement of what that lineage intended next: move the repository to the `openimagingdata` organization, adopt ACR Common codes, acknowledge DICOM codes, track URLs, rewrite `BodyPart` as a Pydantic model, and on the website build a better tree browser and a way for people to submit suggestions about a specific node.[^bpi-todo] None of those items is done in that repository. Several were done independently in the other lineage. +`BodyPartIndex.py` is the Python wrapper. Its README says installation from PyPI is pending, and the site lists "finish BodyPartIndex.py and publish to PyPI" as open.[^al-site] Its last `main` commit, 2024-02-03, added these TODOs: move to `openimagingdata`, adopt ACR Common codes, acknowledge DICOM codes, track URLs, and rewrite `BodyPart` in Pydantic. It also requested a better website tree browser and suggestions for specific nodes.[^bpi-todo] None is complete in that repository. The current lineage independently completed several. # The current lineage @@ -74,7 +74,7 @@ The JSON source data is hosted outside the repository, with the migration tool r # Which is current -The build plan states it plainly: the `anatomic-locations` package inside `findingmodel` and its 2,926-record dataset are the current anatomic data, and the original set with its wrapper libraries is lineage.[^build-plan] Everything built since uses the package. The extraction and coding platform resolves locations through it, the finding model tooling attaches its identifiers to definitions, and the next-generation vocabulary work points at its data file pinned to a commit rather than at the older one.[^cde-axis] +The build plan identifies `anatomic-locations` and its 2,926-record dataset as current.[^build-plan] The extraction platform resolves locations through it, finding model tools attach its identifiers, and the next-generation vocabulary work cites its data at a pinned commit.[^cde-axis] The original lineage is not dead content. Its data file is still the download the public site offers, its npm package still installs, and both are still reachable at the addresses published in 2022. It is superseded as the working set, not withdrawn. diff --git a/knowledge/semantic-foundation/anatomic-locations/radlex-integration.md b/knowledge/semantic-foundation/anatomic-locations/radlex-integration.md index a130a49..bc6b6ed 100644 --- a/knowledge/semantic-foundation/anatomic-locations/radlex-integration.md +++ b/knowledge/semantic-foundation/anatomic-locations/radlex-integration.md @@ -1,10 +1,10 @@ --- type: Concept title: RadLex integration -description: What RadLex is, how the curated anatomic location set relates to it as an overlay, the open RSNA tracking issue for folding the set into RadLex, and the running list of node requests. +description: RadLex integration, the anatomy overlay agreement, search limitations, and pending node requests. tags: [semantic-foundation, anatomic-locations, radlex, rsna, integration] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: radlex-issue-3 resource: https://github.com/RSNA/RadLex/issues/3 @@ -39,23 +39,23 @@ Three features of its structure matter to OIDM: - **Provenance is carried on the concept.** A `RID:Source` annotation records free text such as "Playbook", "LOINC", or "LI-RADS 2020", saying where a concept came from. - **Obsolescence is explicit.** `RID:Replaced_by` points a retired concept at its successor. -The `RSNA/RadLex` repository is not a copy of the ontology alone. Its working branches hold a concept search and curation pipeline that parses the OWL with `rdflib`, writes Parquet triples, builds a DuckDB graph of nodes, edges, and search documents, and drives an agent harness that matches report findings to RadLex concepts and proposes candidate new concepts for review.[^radlex-repo] +The `RSNA/RadLex` working branches contain a search and curation pipeline. It parses OWL with `rdflib`, writes Parquet triples, and builds a DuckDB graph of nodes, edges, and search documents. An agent harness matches report findings to concepts and proposes new concepts for review.[^radlex-repo] # Why search quality is the gating problem -The pipeline's search plan is worth reading because it names the failure mode that any integration has to avoid. Concept lookup failed "silently": a term that should match returned nothing or returned noise, and the consuming agent concluded the concept was missing from RadLex. That false-gap outcome is called the worst failure mode of the project, because it flows straight into proposing a concept and pollutes the candidate file with duplicates of concepts RadLex already has.[^radlex-search] +The search plan describes lookup failing "silently": known terms returned no matches or noise. Agents then proposed duplicates as new concepts, the plan's worst failure mode.[^radlex-search] -Two defects produced it. The graph query ranked alphabetically rather than by relevance, so searching `LUL` returned 69 rows with the correct concept, `RID1327` upper lobe of left lung, sorting 67th behind concepts that merely contain the letters. A replacement scorer fixed ranking but matched literal words only, so `part-solid nodule`, `hilar adenopathy`, and `enlarged lymph nodes` all missed.[^radlex-search] +Alphabetical ranking put `RID1327`, upper lobe of left lung, 67th among 69 results for `LUL`. A replacement scorer fixed ranking but matched only literal words, missing `part-solid nodule`, `hilar adenopathy`, and `enlarged lymph nodes`.[^radlex-search] -The design keeps exact matching as the confidence signal and adds BM25 underneath as a recall layer, with a per-query relative cutoff because BM25 scores are not comparable across queries. The stated goal is "recall good enough that a MISS is real evidence of an ontology gap rather than evidence of unlucky phrasing." The plan is marked complete, shipped 2026-08-20.[^radlex-search] For OIDM this matters because a gap list handed to RadLex is only as trustworthy as the search that produced it. +The design combines exact matching for confidence with BM25 for recall. A per-query relative cutoff accounts for scores being incomparable across queries. Its goal is "recall good enough that a MISS is real evidence of an ontology gap rather than evidence of unlucky phrasing." The plan is marked complete and shipped 2026-08-20.[^radlex-search] # The tracking point `RSNA/RadLex` issue 3, "Add Anatomic Locations", was opened on 2026-08-10 by RSNA and is open. Its exit criterion is one line: "100% coverage of the Anatomic Locations terminology in RadLex."[^radlex-issue-3] -That issue is the whole of the integration as recorded in the RadLex repository. No code, commit message, or document inside the repository mentions anatomic locations, body parts, or OIDM. The relationship exists at the issue level, not yet in the ontology file. +The issue is the only integration record in the `RSNA/RadLex` repository. No code, commit message, or repository document mentions anatomic locations, body parts, or OIDM. The integration is not in the ontology file. -The January 2026 status update states the direction more simply, saying the anatomic locations are "being formally incorporated into RadLex by RSNA committee."[^deck] The issue is the evidence for that statement; the ontology content is not there yet. +The January 2026 update says the locations are "being formally incorporated into RadLex by RSNA committee."[^deck] The issue supports this direction, but the ontology content is pending. # The overlay agreement @@ -70,13 +70,13 @@ Two consequences are already written into that vocabulary: # What RadLex can supply in return -The traffic is not one way. The curated set has no is-a relation and no structure-type nodes, which is recorded as its major shortcoming. RadLex 4.3 has an is-a chain for every one of the 1,910 plain-identifier locations, up to "anatomical entity," and walking it yields a first structure-type layer without inventing anything: 352 locations under muscle organ, 221 under artery, 137 under vein, 115 under tendon, 101 under bone organ, 28 each under joint and nerve, and 26 under lymph node.[^cde-axis] +The curated set has no is-a relation and no structure-type nodes, which is recorded as its major shortcoming. All 1,910 plain-identifier locations have a RadLex 4.3 is-a chain to "anatomical entity," yielding 352 locations under muscle organ, 221 under artery, 137 under vein, 115 under tendon, 101 under bone organ, 28 each under joint and nerve, and 26 under lymph node, without inventing anything.[^cde-axis] Two cautions are recorded with that finding. RadLex's own release note warns that some of its is-a categorizations were converted from part-of and may be wrong, so a derived layer needs a clinical skim. And the FMA-style chain, in which a lung is a "lobular organ," is not the clinically useful layer. The work item is a derived, pinned overlay file handed to the anatomic locations track.[^cde-axis] # The node request list -The gap log on the same branch keeps a running list of specific "we need this node" changes to carry to the RadLex anatomy track, kept deliberately separate from the wider design discussion so it can move independently.[^cde-gaps] +The branch's gap log tracks "we need this node" requests separately from broader design work.[^cde-gaps] | Request | Needed by | Raised | |---|---|---| @@ -87,7 +87,7 @@ The gap log on the same branch keeps a running list of specific "we need this no | Real RadLex identifiers for the compound sided variants | every sided [Observation](/glossary/observation.md) | 2026-09-13 | | An is-a relation and structure-type nodes | scope of the form "applies to tendons" | 2026-08-19, restated 2026-09-13 as the top priority | -The log also records closures and oddities, which is what makes it useful as a status document rather than a wish list. `pleural space` was found present as `RID1363` with both sided forms and is marked closed. External-code coverage is uneven, with SNOMED CT on 1,782 of 2,926 records and 608 records carrying no codes at all. And `lung` is contained by `pleural space` in the data, which is anatomically odd and which any check that walks containment from a lung location will pass through.[^cde-gaps] +The `pleural space` request is closed because `RID1363` and both sided forms exist. SNOMED CT covers 1,782 of 2,926 records, while 608 have no external codes. The data also places `lung` inside `pleural space`, an anatomic oddity that affects containment traversal.[^cde-gaps] Goals for this area, and who has stated them, are collected in [the anatomic locations and RadLex roadmap](/roadmap/anatomic-locations-and-radlex.md). RadLex's place among the terminologies OIDM uses is described in [ontologies used](/semantic-foundation/terminologies/ontologies-used.md). diff --git a/knowledge/semantic-foundation/anatomic-locations/tooling.md b/knowledge/semantic-foundation/anatomic-locations/tooling.md index e3f7f13..4563911 100644 --- a/knowledge/semantic-foundation/anatomic-locations/tooling.md +++ b/knowledge/semantic-foundation/anatomic-locations/tooling.md @@ -1,10 +1,10 @@ --- type: Guide title: Anatomic location tooling -description: How to look up, search, and traverse anatomic locations with the anatomic-locations package and CLI, the older wrapper libraries, and the raw JSON download. +description: Lookup, search, and hierarchy traversal through current and older anatomic location tools. tags: [semantic-foundation, anatomic-locations, tooling, cli, guide] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } stale_after: 2027-09-21 sources: - id: fm-docs @@ -45,7 +45,7 @@ sources: | The raw data, no dependency | The JSON download from the project site | | To curate the set itself | The `manage-anatomic-locations` skill in `findingmodel`, and [laterality conventions](/semantic-foundation/anatomic-locations/laterality-conventions.md) | -Installation and configuration detail belongs with the code and is not repeated here. The package README and the anatomic locations guide in `findingmodel` are the reference.[^fm-pkg-readme][^fm-docs] +See the package README and guide for installation and configuration.[^fm-pkg-readme][^fm-docs] # The anatomic-locations package @@ -62,9 +62,9 @@ print(location.description) # "kidney" print(location.region.value) # "Abdomen" ``` -Four capabilities matter in practice. +The package provides four capabilities. -**Direct lookup and code lookup.** `get()` for the three forms above, and `find_by_code(system, code)` to come in from [SNOMED CT](/glossary/snomed-ct.md), [FMA](/glossary/fma.md), or RadLex. The assignment rules for the extraction platform tell coders to prefer direct lookup over search for a named target organ, because search is less reliable and produces retrieval misses such as "prostate" returning salivary glands.[^ipl-rules] +**Direct lookup and code lookup.** `get()` accepts identifiers, descriptions, or synonyms. `find_by_code(system, code)` accepts [SNOMED CT](/glossary/snomed-ct.md), [FMA](/glossary/fma.md), or RadLex codes. Assignment rules prefer direct lookup for a named organ to avoid search misses such as "prostate" returning salivary glands.[^ipl-rules] **Hierarchy traversal.** `get_containment_ancestors()` and `get_containment_descendants()` on a location, plus `get_children_of()` on the index. Both the containment and the part-of hierarchies are backed by materialized paths, so these are not recursive queries. @@ -107,7 +107,7 @@ whole body - RID39569 # Where the database comes from -The DuckDB file is built separately from the JSON source, published to remote storage, and referenced from a central `manifest.json` that also carries the finding model index. On first use the package fetches it, checks the manifest for a newer version on later runs, and caches it locally.[^fm-normalized] The path can be overridden with the `ANATOMIC_DB_PATH` environment variable or a `db_path` constructor argument, which is how a pinned build or a locally rebuilt database is used.[^fm-pkg-readme] +The JSON source is built into a DuckDB file published to remote storage. A central `manifest.json` references it alongside the finding model index. The package downloads and caches the database on first use, then checks the manifest for updates.[^fm-normalized] Use `ANATOMIC_DB_PATH` or the `db_path` constructor argument for a pinned or locally rebuilt database.[^fm-pkg-readme] # What is not exposed @@ -129,13 +129,13 @@ bodyPart?.getPartOf(); // RID270, female genital system const left = bodyPart?.getLeft(); // RID294_RID5824 ``` -It carries the fullest hierarchy surface of any of the libraries: `isContained` and `isPartOf` tests, immediate and full children in both hierarchies, and full ancestors in both.[^bpi-ts] +The TypeScript library provides `isContained`, `isPartOf`, immediate and full children, and full ancestors for both hierarchies.[^bpi-ts] `BodyPartIndex.py` is the Python counterpart. Its README states that installation from PyPI is pending, so it is used from source or with a local data file. It offers `get()` by identifier or code, `get_by_code()`, `search()` over names and synonyms, `is_contained()`, the laterality triad through `left`, `right`, and `unsided`, and a `snomed_code` property that falls back to the unsided version and then the immediate parent when the sided record carries no code of its own.[^bpi-py] # The raw data -The project site publishes the curated set as a single JSON file with its JSON Schema and a changelog beside it, under the ISC license.[^al-code] That is the zero-dependency path, and the field meanings are in [the data model](/semantic-foundation/anatomic-locations/data-model.md) and, verbatim, in [the record format reference](/references/anatomic-location-json-schema.md). +The project site publishes a JSON file, JSON Schema, and changelog under the ISC license.[^al-code] This requires no library dependency. See [the data model](/semantic-foundation/anatomic-locations/data-model.md) and [the verbatim record format reference](/references/anatomic-location-json-schema.md). [^fm-docs]: Anatomic locations guide, findingmodel main [^fm-pkg-readme]: anatomic-locations package README diff --git a/knowledge/semantic-foundation/anatomic-locations/why-anatomic-locations.md b/knowledge/semantic-foundation/anatomic-locations/why-anatomic-locations.md index 8369c4e..41f0e2e 100644 --- a/knowledge/semantic-foundation/anatomic-locations/why-anatomic-locations.md +++ b/knowledge/semantic-foundation/anatomic-locations/why-anatomic-locations.md @@ -1,10 +1,10 @@ --- type: Concept title: Why anatomic locations -description: Why OIDM curates its own anatomic location set instead of pointing at an existing ontology, and every place those identifiers are used across the model. +description: Why OIDM curates anatomic identifiers and where the model uses them. tags: [semantic-foundation, anatomic-locations, radlex, rationale] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: al-site resource: https://github.com/talkasab/anatomiclocations.org/blob/1f39fa45f621cef947a3f3ef1f869334cfa5c841/docs/index.markdown @@ -28,9 +28,9 @@ sources: # The problem the set solves -The premise is stated in one sentence on the project site: "Standard identifiers for discrete anatomic locations would enable numerous levels of interoperability if applied broadly."[^al-site] Two systems that agree a lesion sits at `RID2772` agree on the kidney without sharing a database, a vendor, or a schema. +The project site states: "Standard identifiers for discrete anatomic locations would enable numerous levels of interoperability if applied broadly."[^al-site] Systems using `RID2772` agree on the kidney without sharing a database, vendor, or schema. -The obvious way to get such identifiers is to adopt an existing anatomy ontology whole. The site says why that was rejected. Attempts to use [RadLex](/glossary/radlex.md) or [SNOMED CT](/glossary/snomed-ct.md) directly run into three problems:[^al-site] +The site identifies three problems with adopting [RadLex](/glossary/radlex.md) or [SNOMED CT](/glossary/snomed-ct.md) directly:[^al-site] - **Lack of numerous desired terms.** Structures radiologists name every day are missing. - **Too many unnecessary or degenerate terms.** Several concepts denote the same structure, so a coder has no principled way to choose one and a consumer cannot tell two records mean the same place. @@ -38,15 +38,15 @@ The obvious way to get such identifiers is to adopt an existing anatomy ontology # Curation as the answer -The response is a curated subset rather than a new ontology: "We are curating a subset of anatomic concepts from existing ontologies and shaping them into a usable collection of anatomic identifiers for informatics interoperability."[^al-site] The method was to start from RadLex terms already recognized in radiology reports, keep the used and useful ones, place each in an anatomic hierarchy, attach cross-references to other ontologies, and record [laterality](/glossary/laterality.md) and sex phenotype.[^al-site] +"We are curating a subset of anatomic concepts from existing ontologies and shaping them into a usable collection of anatomic identifiers for informatics interoperability."[^al-site] The project selected useful RadLex terms from radiology reports, organized them in an anatomic hierarchy, and added ontology cross-references, [laterality](/glossary/laterality.md), and sex phenotype.[^al-site] -Two properties are claimed for the result and are the point of the exercise. It is complete enough, containing "almost all clinically used anatomic terms." It is non-degenerate, with "no uncertainty as to which node represents a structure."[^al-site] Non-degeneracy is what makes the identifier usable as a join key. See [anatomic location](/glossary/anatomic-location.md) for the term itself and [the data model](/semantic-foundation/anatomic-locations/data-model.md) for the record shape. +The site claims coverage of "almost all clinically used anatomic terms." It also claims "no uncertainty as to which node represents a structure."[^al-site] Unambiguous identifiers can serve as join keys. See [anatomic location](/glossary/anatomic-location.md) and [the data model](/semantic-foundation/anatomic-locations/data-model.md). # Separable identity -Anatomy is one of the two axes of an [Observation](/glossary/observation.md), and the model keeps it separate from the other. The January 2026 status update states the atomic unit as "what plus where plus attributes: finding tag plus anatomic location plus lesion characteristics," and says anatomy is "baked into OIFM definitions and Observation objects."[^deck] The set is "curated to identify where findings are visualized on imaging exams," which is a narrower target than anatomy in general and explains why structures with no imaging appearance are absent.[^deck] +An [Observation](/glossary/observation.md) separates the finding from its location. The January 2026 update describes "what plus where plus attributes: finding tag plus anatomic location plus lesion characteristics," with anatomy "baked into OIFM definitions and Observation objects."[^deck] The set is "curated to identify where findings are visualized on imaging exams," excluding structures with no imaging appearance.[^deck] -Separating what from where is what lets a single [finding model](/glossary/finding-model.md) for a cyst serve the kidney, the liver, and the breast, and what lets the [Imaging Problem List](/glossary/imaging-problem-list.md) offer "precision filtering via anatomy-embedded definitions."[^deck] +A single [finding model](/glossary/finding-model.md) for a cyst can therefore apply to the kidney, liver, or breast. The [Imaging Problem List](/glossary/imaging-problem-list.md) uses this separation for "precision filtering via anatomy-embedded definitions."[^deck] # Where the identifiers are used @@ -58,11 +58,11 @@ Separating what from where is what lets a single [finding model](/glossary/findi | Finding and location [coding](/glossary/coding.md) | The coding pass generates search terms, searches the location index, and has a selector choose from the returned candidates, with assignment governed by a stated precedence ladder[^ipl-rules] | | Imaging Problem List viewer | Region and organ-cluster filters, and a body schematic whose zones are driven by the location's region and laterality[^viewer-plan] | -The rule that keeps this honest is stated with the assignment rules: every assigned identifier must exist in the set, and a structure absent from it is left unassigned rather than forced to a wrong code.[^ipl-rules] That discipline turns missing terms into a visible list of requests rather than silent mis-coding. See [RadLex integration](/semantic-foundation/anatomic-locations/radlex-integration.md) for where those requests go. +Every assigned identifier must exist in the set. Missing structures stay unassigned to avoid incorrect codes.[^ipl-rules] See [RadLex integration](/semantic-foundation/anatomic-locations/radlex-integration.md) for term requests. # What curation costs -A curated set is a maintained artifact, not a free one. The site's own roadmap names the standing content work: review the hierarchy, add, prune, and modify; edit and improve synonyms; complete SNOMED identification.[^al-site] It also names the companion effort that has not been built, "a companion for exam types based on LOINC/RadLex Playbook exam definitions that specify all included body parts for the exam," which remains the earliest written statement of the [exam type](/glossary/exam-type.md) goal.[^al-site] See [exam types](/semantic-foundation/exam-types/overview.md). +The site's roadmap calls for reviewing, adding, pruning, and modifying hierarchy nodes, improving synonyms, and completing SNOMED identification.[^al-site] It also proposes "a companion for exam types based on LOINC/RadLex Playbook exam definitions that specify all included body parts for the exam," the earliest written [exam type](/glossary/exam-type.md) goal.[^al-site] It remains unbuilt. See [exam types](/semantic-foundation/exam-types/overview.md). [^al-site]: anatomiclocations.org site homepage, rationale, approach, and roadmap [^deck]: Open Imaging Data Model 2026 Status Update, January 2026 diff --git a/knowledge/semantic-foundation/common-data-elements/cde-staging.md b/knowledge/semantic-foundation/common-data-elements/cde-staging.md index 6c6e2d8..f59abeb 100644 --- a/knowledge/semantic-foundation/common-data-elements/cde-staging.md +++ b/knowledge/semantic-foundation/common-data-elements/cde-staging.md @@ -1,10 +1,10 @@ --- type: Project Profile title: CDE staging -description: The CDEStaging repository, where informally authored candidate common data element definitions collect before the formal review pipeline, and how its content feeds finding models. +description: Candidate CDE definitions, report coverage gaps, and their conversion into finding models. tags: [semantic-foundation, cde, radelement, repositories, content] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T18:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } stale_after: 2027-09-21 sources: - id: readme @@ -50,7 +50,7 @@ sources: # What it is -`CDEStaging` is where candidate [common data element](/glossary/cde.md) definitions collect before anyone tries to make them official. Its README states the purpose in one line: "a staging area for definitions of radiology common data elements (CDEs) in JSON format ... prior to their entering the review pipeline."[^readme] The banner above that line gives the concrete goal: "A multi-vendor project to generate a near-complete set of CDE Sets to represent the findings in chest CT reports."[^readme] +`CDEStaging` collects candidate [common data element](/glossary/cde.md) definitions before formal review. Its README calls it "a staging area for definitions of radiology common data elements (CDEs) in JSON format ... prior to their entering the review pipeline."[^readme] The stated goal is "A multi-vendor project to generate a near-complete set of CDE Sets to represent the findings in chest CT reports."[^readme] Contributions are organized by contributor. The README says provisional definitions go in the `definitions` directory "with separate folders for participating vendors."[^readme] Three folders are named after participating vendors, five carry a contributor prefix combined with a modality and body region (CT chest, CT abdomen and pelvis, chest radiograph, knee MRI, and O-RADS), and one holds location value lists. @@ -69,11 +69,11 @@ The `definitions/` tree holds 463 files at that commit. The largest single collection is the CT chest folder, with 206 markdown files and 103 JSON files. -The JSON files are worth a note, because the README's framing suggests otherwise. They do not follow the ACR and RSNA `cde.schema.json`. They carry a finding name, a description, and a list of attributes typed as `choice` or `numeric` with named values, which is the shape a [finding model](/glossary/finding-model.md) uses rather than the shape a [CDE set](/glossary/cde-set.md) uses. Everything in this repository is a pre-submission draft in whatever form its author found convenient. +The JSON files use a name, description, and `choice` or `numeric` attributes with named values. This resembles a [finding model](/glossary/finding-model.md), rather than a [CDE set](/glossary/cde-set.md) conforming to `cde.schema.json`. All content is a pre-submission draft in its author's chosen format. # Two authoring conventions -The markdown definitions were written under two conventions that coexist and were never reconciled. +The markdown definitions use two unreconciled conventions. **Coded `.cde.md` files.** Fourteen files in one vendor folder follow a structured convention: a `# Finding:` heading, a `source` and a `coding` bullet carrying a [RadLex identifier](/glossary/radlex-id.md), then one `##` section per [attribute](/glossary/attribute.md), with coded values, numeric attributes declared as `float` with a unit, and multi-select attributes marked in the heading.[^cardiomegaly] @@ -114,15 +114,15 @@ The markdown definitions were written under two conventions that coexist and wer - **Course**: Retroesophageal / Pretracheal / Other ``` -Some of these folders hold only bare finding lists with no attributes at all, one line per finding name, which is how the chest radiograph and knee MRI folders are organized. +The chest radiograph and knee MRI folders contain bare finding lists, one name per line, without attributes. -`docs/Authoring.md` was meant to reconcile them. It is two sentences long, points at the upstream schema, and says "the authoring guide will be hosted here as well."[^authoring] It was never written. +`docs/Authoring.md` is a two-sentence stub pointing to the upstream schema. It says "the authoring guide will be hosted here as well."[^authoring] The guide was never written. # The report representation work -A second body of work in the repository asks a different question: given real report text, what does the existing definition set fail to capture? Four documents record the answers. +Four documents record what the definitions fail to capture from report text. -**The extraction process.** `docs/report_extraction_process.md` works one chest CT report end to end, turning its prose into "a list of mini-observations" of the form finding, attribute, value.[^extraction-process] It closes with two notes to self: finding, attribute, and value names need to match the project's own finding definitions, and blanket negative statements such as "Lungs are clear" need separate cataloguing. Both notes became the next two documents. +**The extraction process.** `docs/report_extraction_process.md` converts a chest CT report into "a list of mini-observations" containing a finding, attribute, and value.[^extraction-process] Its closing notes call for matching names to the definitions and cataloguing blanket negatives such as "Lungs are clear". The next two documents address those tasks. **Composite negative statements.** A corpus of roughly 830 words of real negative and composite report sentences, grouped by organ system, collected to work out how absent findings should be modeled.[^negatives] Many are not simple negations. "Absence of intravenous contrast limits sensitivity for detecting solid organ findings" is a statement about the exam, not about a finding, and it recurs throughout the abdomen section. @@ -136,19 +136,19 @@ Alongside them, `report_representation/structured_extractions/` holds 52 worked One vendor folder holds a roadmap table covering chest CT findings across nine organ-system sections: pulmonary, pleura, cardiovascular, lymphatic and endocrine, musculoskeletal, abdominal, lines and tubes, devices, and post-operative or treatment changes.[^roadmap] It has 100 finding rows. Each row carries the finding name, a frequency judgment of common, uncommon, or rare, a priority column, a status column holding links to any RadElement sets that already cover the finding, an "in V1" flag, and a RadLex identifier. -At the read commit, 22 rows are flagged for version 1, 18 distinct `RDES` sets are referenced, and 19 distinct RadLex identifiers appear. The table is the clearest single artifact tying informal staged content to the published [RadElement](/glossary/radelement.md) catalog and to [RadLex](/glossary/radlex.md), and it is where the project recorded which findings already had a governed definition and which did not. +At the read commit, 22 rows are flagged for version 1, 18 distinct `RDES` sets are referenced, and 19 distinct RadLex identifiers appear. It records which staged findings have governed definitions in [RadElement](/glossary/radelement.md) and mappings to [RadLex](/glossary/radlex.md). # The path to RadElement -There is no automated pipeline. The README and the authoring stub both point at `RSNA/ACR-RSNA-CDEs` for the canonical `cde.schema.json` and a sample set,[^readme][^authoring] and the roadmap links findings to the RadElement sets that cover them, but nothing in the repository describes a mechanical route from a staged definition to a submitted one. The process is manual curation: draft informally here, harmonize, then submit through the ACR and RSNA review pipeline. See [CDEs and RadElement](/semantic-foundation/common-data-elements/cdes-and-radelement.md). +The README and authoring stub point to `RSNA/ACR-RSNA-CDEs` for `cde.schema.json` and a sample set.[^readme][^authoring] The roadmap links existing RadElement sets, but no automated submission pipeline exists. Authors draft, harmonize, and submit through ACR and RSNA review. See [CDEs and RadElement](/semantic-foundation/common-data-elements/cdes-and-radelement.md). # How it feeds finding models -The staged content is an input to the finding model corpus, and this connection is more developed than the one to RadElement. +Finding model conversion is more developed than RadElement submission. `findingmodels` issue 15, "Bring in CDE Staging MD content," opened 2025-05-28 and still open, asks for a script that takes a markdown file, checks whether a definition already exists for that finding, and either converts it or merges it into the existing definition, reusing element identifiers and synonyms where possible, and adding the appropriate contributor.[^fm-issue-15] -That work exists on the `content/chestcts` branch of `findingmodels`, unmerged at commit `0472a46`. A triage script reads the CT chest folder of `CDEStaging` and compares each source against the finding model search index;[^chestcts-triage] a conversion script then runs the survivors through a multi-agent pipeline of merge, create, and review steps and writes validated finding model JSON.[^chestcts-convert] Both scripts default to the same `CDEStaging` CT chest directory as input. The content direction is covered in [finding model content direction](/roadmap/finding-model-content-direction.md). +That work exists on the `content/chestcts` branch of `findingmodels`, unmerged at commit `0472a46`. A triage script compares CT chest sources with the finding model search index.[^chestcts-triage] A conversion script uses merge, create, and review agents to write validated JSON.[^chestcts-convert] Both default to the `CDEStaging` CT chest directory. See [finding model content direction](/roadmap/finding-model-content-direction.md). # Branch state and open issues diff --git a/knowledge/semantic-foundation/common-data-elements/cdes-and-radelement.md b/knowledge/semantic-foundation/common-data-elements/cdes-and-radelement.md index e980fb2..8339273 100644 --- a/knowledge/semantic-foundation/common-data-elements/cdes-and-radelement.md +++ b/knowledge/semantic-foundation/common-data-elements/cdes-and-radelement.md @@ -1,10 +1,10 @@ --- type: Concept title: CDEs and RadElement -description: What ACR and RSNA common data elements are, where they are published and schematized, where the two published schema descriptions disagree, and how the Open Imaging Data Model uses them today. +description: Governed CDE definitions, RadElement publication, schema differences, and OIDM usage. tags: [semantic-foundation, cde, radelement, schema, fhir] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T18:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: radelement-site resource: https://radelement.org/ @@ -61,16 +61,16 @@ The public API at `api3.rsna.org/radelement/v1/sets` listed 281 sets on 2026-09- The `common_data_elements` repository is the Open Imaging Data Model (OIDM) local snapshot of that registry. Its README describes it as "a periodically updated version of the Common Data Element definitions as stored and maintained in the ACR/RSNA RadElement web site," formatted as JSON for easy consumption.[^cde-readme] At commit `35536d8` it holds 145 set definitions under `definitions/`, one file per set named `RDES###.cde.json`, and the README indexes all 145 alphabetically by clinical topic with their set identifiers. -The snapshot is data, not code. It is used as a reference corpus rather than as a dependency, and it is not regenerated automatically. See [the repository map](/repositories/repository-map.md) for its status. +The snapshot is a reference corpus, not a code dependency. It is not regenerated automatically. See [the repository map](/repositories/repository-map.md). # The schema, and the two places that claim it -Stated plainly: the canonical CDE JSON Schema exists in two repositories, under three filenames, and all three declare the same identifier. +Three CDE JSON Schema files in two repositories declare the same identifier. - `RSNA/ACR-RSNA-CDEs` carries `cde.schema.json` at its repository root. `CDEStaging` names this file as the canonical schema and points authors at it.[^staging-readme] The file is byte-identical on the `master` branch and on the `next-gen-2026` branch, so the next-generation work has not changed it.[^acr-schema][^acr-schema-ng] - `common_data_elements` carries `schema/cde.schema-1.0.json` and `schema/cde.schema-1.1.json`, and its README says the schemas are the ones "maintained at the development repo."[^cde-readme] -The upstream `cde.schema.json` is byte-identical to `cde.schema-1.1.json`, the newer of the two local copies. The definitions in the snapshot conform to version 1.0, which the README states explicitly.[^cde-readme] So the schema published as canonical upstream is a version ahead of the data published beside it. +The upstream `cde.schema.json` is byte-identical to local version 1.1. The snapshot definitions conform to 1.0, one version behind the upstream schema.[^cde-readme] All three files are JSON Schema draft-07 and all three declare the same `$id`: @@ -96,11 +96,11 @@ The JSON Schema versions close part of the gap and leave part of it open. `image # CDE-labeled FHIR Observations -The idea that ties CDEs to the rest of OIDM is the [CDE-labeled FHIR Observation](/glossary/cde-labeled-fhir-observation.md): one radiology finding expressed as a FHIR [Observation](/glossary/observation.md) whose codes come from a CDE set, its elements, and their values. +A [CDE-labeled FHIR Observation](/glossary/cde-labeled-fhir-observation.md) expresses one finding as a FHIR [Observation](/glossary/observation.md), coded using a CDE set, its elements, and their values. `FHIRSamples` implements the pattern concretely in a lung cancer screening scenario.[^fhirsamples] An AI-produced finding Observation carries `code.coding` pointing at the `radelement.org` system with the set code `RDES195` for pulmonary nodule; each `component` entry carries an element code such as `RDE1717` with the chosen value code, for example `RDE1717.1`, as `valueCodeableConcept`. A second Observation repeats the same finding with `status` changed from `preliminary` to `final` to mark radiologist confirmation, and a third is `derivedFrom` both the imaging study and the radiologist's finding, carrying a Lung-RADS category (`RDES267`) as a component. -That chain, set code to element code to value code, all through one coding system, is what "CDE-labeled" means in practice. See [FHIR mapping](/data-structures/fhir-mapping.md) for where the current data structures stand against it, and [lineage repositories](/history/lineage-repositories.md) for the full example. +"CDE-labeled" refers to this chain of set, element, and value codes within one coding system. See [FHIR mapping](/data-structures/fhir-mapping.md) for current mappings and [lineage repositories](/history/lineage-repositories.md) for the full example. # How OIDM uses CDEs today @@ -126,7 +126,7 @@ Across the corpus, `RADELEMENT` is the smallest of the index code systems in use **As the standards-track counterpart of finding models.** Finding models are authored quickly and are not balloted; CDEs are governed and are. [Finding models and CDEs](/semantic-foundation/finding-models/finding-models-and-cdes.md) covers the relationship. -One thing worth recording because it is easy to assume otherwise: the current extraction prototypes do not label with RadElement codes. `IPL-MVP-ExtractionAndLabeling` maps extracted findings to a curated list of 15 finding models keyed by OIFM identifier, with no `RDES` or `RDE` code anywhere in the repository,[^ipl-mvp] and the `imaging-problem-list` repository contains no RadElement codes either. The CDE-labeled Observation pattern is implemented in the lineage samples and documented, not in the working extraction pipelines. +Current extraction prototypes use OIFM identifiers. `IPL-MVP-ExtractionAndLabeling` maps findings to 15 curated models and contains no `RDES` or `RDE` codes.[^ipl-mvp] Neither does `imaging-problem-list`. The CDE-labeled pattern remains in documentation and lineage samples. # The next generation diff --git a/knowledge/semantic-foundation/common-data-elements/index.md b/knowledge/semantic-foundation/common-data-elements/index.md index 9dd3c6f..1c50d39 100644 --- a/knowledge/semantic-foundation/common-data-elements/index.md +++ b/knowledge/semantic-foundation/common-data-elements/index.md @@ -1,5 +1,5 @@ # Common data elements -* [CDEs and RadElement](./cdes-and-radelement.md) - What ACR and RSNA common data elements are, where they are published and schematized, where the two published schema descriptions disagree, and how the Open Imaging Data Model uses them today. -* [CDE staging](./cde-staging.md) - The CDEStaging repository, where informally authored candidate common data element definitions collect before the formal review pipeline, and how its content feeds finding models. +* [CDEs and RadElement](./cdes-and-radelement.md) - Governed CDE definitions, RadElement publication, schema differences, and OIDM usage. +* [CDE staging](./cde-staging.md) - Candidate CDE definitions, report coverage gaps, and their conversion into finding models. * [Next-generation CDE vocabulary](./next-generation-vocabulary.md) - What the next-gen-2026 branch of the ACR-RSNA-CDEs repository defines, covering the working vocabulary, the graph shape, the anatomy axis, the display grammar, and the alpha implementation, recorded as in-progress design work in an allied project. diff --git a/knowledge/semantic-foundation/exam-types/overview.md b/knowledge/semantic-foundation/exam-types/overview.md index 9e57c87..1f08e4d 100644 --- a/knowledge/semantic-foundation/exam-types/overview.md +++ b/knowledge/semantic-foundation/exam-types/overview.md @@ -74,7 +74,7 @@ Two consequences matter for anyone reading exam type material in these repositor Three uses exist now. All three run on a bare LOINC code with no exam type object behind it. -**As the exam header of an [Exam Finding List](/glossary/exam-finding-list.md).** The specification requires that the structure "must also have basic information (keyed by a curated list of LOINC codes) about what exam this is."[^ipl-readme] In the data this is `examInfo.studyLoincCode` beside `studyIdentifier`, `studyDateTime`, and a free-text `studyDescription`; the domain notes give `72133-2` for CT Abdomen and Pelvis Without Contrast as the worked example.[^ipl-claude] The [Imaging Problem List](/glossary/imaging-problem-list.md) carries the same pair forward on every observation as `exam_type_code` and `exam_type_display`, which is how a finding's time course is labelled by study. The curated list of LOINC codes that the specification refers to has never been published. +**As the exam header of an [Exam Finding List](/glossary/exam-finding-list.md).** The imaging-problem-list README requires that the structure "must also have basic information (keyed by a curated list of LOINC codes) about what exam this is."[^ipl-readme] In the data this is `examInfo.studyLoincCode` beside `studyIdentifier`, `studyDateTime`, and a free-text `studyDescription`; the domain notes give `72133-2` for CT Abdomen and Pelvis Without Contrast as the worked example.[^ipl-claude] The [Imaging Problem List](/glossary/imaging-problem-list.md) carries the same pair forward on every observation as `exam_type_code` and `exam_type_display`, which is how a finding's time course is labelled by study. The curated list of LOINC codes that the README refers to has never been published. **As the fallback [body region](/glossary/body-region.md) for a finding with no anatomy.** The anatomic location assignment rules used by the extraction and coding platform put the exam at the bottom of a three-step precedence ladder. Explicit anatomy in the report text or section context wins; otherwise the finding's own target organ; otherwise, for findings with no anatomic noun at all such as "soft tissue mass" or "generalized osteoporosis," the rules "fall back to the exam-scoped coarse region (thorax, abdomen, head, ...), sided only if the exam is sided."[^ipl-rules] The exam also supplies [laterality](/glossary/laterality.md) under a stated source priority of explicit text side, then sided-exam side, then generic, so that a left shoulder radiograph sides its findings while an abdominal CT never introduces a side. The rules carry a small exam-to-region table of RadLex identifiers, reproduced in [existing building blocks](/semantic-foundation/exam-types/existing-building-blocks.md). diff --git a/knowledge/semantic-foundation/finding-models/authoring-workflow.md b/knowledge/semantic-foundation/finding-models/authoring-workflow.md index b2f1386..6aeaf40 100644 --- a/knowledge/semantic-foundation/finding-models/authoring-workflow.md +++ b/knowledge/semantic-foundation/finding-models/authoring-workflow.md @@ -1,10 +1,10 @@ --- type: Guide title: Authoring workflow -description: How finding models are created and reviewed today, through the Forge web application, the findingmodel-ai command line, the three agent skills, and the validator that gates every commit. +description: Finding model authoring, review, and validation through Forge, the CLI, and repository skills. tags: [semantic-foundation, finding-models, authoring, workflow, guide] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: forge-workflow resource: https://github.com/openimagingdata/FindingModelForge/blob/15d9ebcf64734b889081feed4d645a0afca67e61/docs/finding-model-creation-workflow.md @@ -40,7 +40,7 @@ sources: # Two front doors -A [finding model](/glossary/finding-model.md) reaches the corpus through one of two routes. A web application handles one finding at a time with a person driving. A set of agent skills in the content repository handles conversational and bulk authoring with a person reviewing. Both produce the same JSON, and both end at the same validator. +Authors create [finding models](/glossary/finding-model.md) through Forge or repository agent skills. Forge handles one finding with a person driving. Skills support conversational and bulk authoring with human review. Both produce JSON checked by the same validator. # Finding Model Forge @@ -55,7 +55,7 @@ A draft carries the user, the name, the raw inputs, the server-generated JSON, a # The findingmodel-ai command line -The `findingmodel-ai` package is the scriptable half of the same capability, installable from PyPI and configured with an API key for at least one model provider.[^ai-readme] Three commands cover the common path. +Install `findingmodel-ai` from PyPI and configure an API key for at least one provider.[^ai-readme] Its main authoring commands are: ```bash findingmodel-ai make-info "pneumothorax" # name to description and synonyms @@ -67,7 +67,7 @@ The same functions are available as a Python API, and an optional web-search key # Agent skills in the content repository -Three skills live under `.claude/skills/` in `findingmodels` and divide the work by shape of the job. +Three skills in `findingmodels/.claude/skills/` handle authoring and review. | Skill | Use it when | Shape | |---|---|---| @@ -75,7 +75,7 @@ Three skills live under `.claude/skills/` in `findingmodels` and divide the work | `finding-batch` | a list, CSV, or directory of source content | triage the whole batch, then draft each finding in an isolated sub-agent | | `finding-review` | existing definition files named by path, glob, or directory | lint, then review each file in an isolated sub-agent, then human sign-off | -Each skill file is deliberately thin. All rules, command cheatsheets, and procedures live in `prompts/fragments/`, and the skill loads the fragment named at each step rather than carrying the rules itself.[^skill-author] Sixteen fragments cover naming, synonym rules, scope and specificity, presence and change, the associated-versus-component distinction, search and triage, mechanical lint, the quality checklist, review file generation, CSV writeback, and handoff to the review interface. `core_concept.md` is the orientation fragment every skill reads first; it states the two guiding principles as "a finding is a noun phrase; everything else is an attribute" and "findings exist in time."[^core-concept] A companion `defaults.yml` holds the contributor and organization defaults, the permitted source codes for identifier minting, and suggested tag sets per campaign, which the skill confirms with the user at session start. +Skills load rules, command cheatsheets, and procedures from `prompts/fragments/` as needed.[^skill-author] Sixteen fragments cover naming, synonyms, scope, presence, change, associated versus component findings, search, triage, lint, quality review, review files, CSV writeback, and review-interface handoff. Every skill starts with `core_concept.md`, whose principles are "a finding is a noun phrase; everything else is an attribute" and "findings exist in time."[^core-concept] At session start, the skill confirms defaults from `defaults.yml` for contributor, organization, identifier source codes, and campaign tags. Three constraints run through all three skills. @@ -87,9 +87,9 @@ Review runs mechanical lint first, with auto-fix for trivially fixable errors su # The gate every route passes -Whatever produced the JSON, it lands in `defs/` and is committed. A pre-commit hook runs `uv run scripts/validator.py --with-git-adds` on every commit, serially, whether or not a definition was staged.[^precommit] The validator validates every definition against the format, fails on a duplicate finding or attribute identifier, reformats the JSON in place, regenerates the markdown render in `text/`, rewrites the corpus index, rewrites `ids.json`, and stages all of it. See [identifiers](/semantic-foundation/finding-models/identifiers.md) for what the duplicate check protects. +A pre-commit hook runs `uv run scripts/validator.py --with-git-adds` serially on every commit, even without staged definitions.[^precommit] It validates all `defs/` files, rejects duplicate finding or attribute identifiers, reformats JSON, rebuilds `text/`, the corpus index, and `ids.json`, then stages the results. See [identifiers](/semantic-foundation/finding-models/identifiers.md). -The practical consequence is that the generated artifacts cannot drift from the source. It is also why the repository's guidance forbids editing them by hand. +Regeneration keeps derived files consistent with definitions. Repository guidance prohibits editing them by hand. # Requests and cleanup diff --git a/knowledge/semantic-foundation/finding-models/content-catalog.md b/knowledge/semantic-foundation/finding-models/content-catalog.md index afce140..26bc061 100644 --- a/knowledge/semantic-foundation/finding-models/content-catalog.md +++ b/knowledge/semantic-foundation/finding-models/content-catalog.md @@ -1,10 +1,10 @@ --- type: Project Profile title: Finding model content catalog -description: "The findingmodels repository: what is in the corpus, where its identifiers and generated renders live, the conventions that govern it, how to browse it, and the content batches in flight on unmerged branches." +description: Published finding model content, repository conventions, browsing tools, and unmerged batches. tags: [semantic-foundation, finding-models, content, repository, project-profile] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } stale_after: 2027-09-21 sources: - id: fm-claude @@ -38,7 +38,7 @@ sources: # What the repository is -`findingmodels` is the content repository of the Open Imaging Data Model (OIDM). It holds finding model definitions and nothing that executes them. The format those definitions obey lives in a different repository, `findingmodel`, and is described in [the format document](/semantic-foundation/finding-models/finding-model-format.md). +`findingmodels` holds Open Imaging Data Model (OIDM) definitions. The separate `findingmodel` repository defines their format, described in [the format document](/semantic-foundation/finding-models/finding-model-format.md). Read at commit `4475ac1` on `main`, dated 2026-04-28, the repository contains 2,382 definitions. @@ -65,13 +65,13 @@ Every identifier carries a three-or-four-letter organization segment recording w | `MGB` | MassGeneral Brigham | 47 | | `MSFT` | Microsoft | 31 | -Four in five definitions are Gamuts-derived. That fact shapes everything about the corpus's current state: the [Radiology Gamuts Ontology](/glossary/gamuts.md) is a differential-diagnosis resource rather than a finding vocabulary, so its imported entries carry patterns that do not sit comfortably as findings. The [content direction roadmap](/roadmap/finding-model-content-direction.md) records the stated intent that the [MGB exam-oriented sub-taxonomies](/semantic-foundation/finding-models/finding-taxonomies.md) replace many of them. +Four in five definitions derive from the [Radiology Gamuts Ontology](/glossary/gamuts.md); the Radiology Gamuts Ontology is a differential-diagnosis resource rather than a finding vocabulary, so its imported entries carry patterns that do not sit comfortably as findings. The [content direction roadmap](/roadmap/finding-model-content-direction.md) records the stated intent that the [MGB exam-oriented sub-taxonomies](/semantic-foundation/finding-models/finding-taxonomies.md) replace many of them. Two further organizations, `RSNA` and `ACR`, are registered in the package's seeded organization list but have contributed no definitions under their own codes.[^base-orgs] Individual contributors appear on definitions as `Person` records with a GitHub username, an email address, and an organization code; organizations appear as `Organization` records with a name, a code, and a URL. # Conventions -The repository's own guidance file states the rules that govern changes.[^fm-claude] +The repository guidance sets these rules.[^fm-claude] - Three artifacts are auto-generated and must never be hand-edited: `text/*.md`, `index.md`, and `ids.json`. They are rebuilt from `defs/` by `uv run scripts/validator.py`. - Every finding identifier must be unique, and every attribute identifier must be unique across all files, not merely within one. The validator fails the commit if either check fails. @@ -85,7 +85,7 @@ A separate open plan, the definition cleanup plan, catalogs the conventions the # How to browse -Three routes exist, at different levels of convenience. +Browse through the repository, catalog site, or search tools. - **The repository.** Read `index.md` for the whole corpus as one table, then follow its links into `text/` for a rendered definition or `defs/` for the JSON. - **The catalog site.** `finding-models-site` is a static Astro site that pulls the content repository in as a git submodule and renders `/models/` and `/models/[slug]` pages at build time. It is published at [openimagingdata.github.io/finding-models-site](https://openimagingdata.github.io/finding-models-site/) and profiled in [applications](/applications/finding-models-site.md). @@ -93,7 +93,7 @@ Three routes exist, at different levels of convenience. # Content in flight -Six branches carry unmerged content work. None has an open pull request, and none is on `main`. The figures below are branch-to-`main` differences as of the dates given. +Six content branches remain unmerged with no open pull requests. Counts compare each branch with `main` at the stated dates. | Branch | Tip | New definitions | What it is | |---|---|---:|---| @@ -104,9 +104,9 @@ Six branches carry unmerged content work. None has an open pull request, and non | `findingmodels-metadata` | 2026-06-01 | 0 | Applies an approved enrichment baseline to 78 existing definitions and adds no new ones. | | `taxonomy-export-2026-08-15` | 2026-08-15 | 0 | Replaces `lists/` with the six MGB exam-oriented sub-taxonomy files. | -The chest CT branch is the largest by far and the least complete: its own progress document records 205 source items split into 21 chunks of ten, with chunk 1 done and chunks 2 through 21 pending.[^chestcts] The head CT branch's plan document is marked complete for the soft tissue category, which produced four new models and nine mappings onto existing ones, with identifiers written back to the source list and the validator run clean.[^headcts] +The chest CT progress document lists 205 sources in 21 chunks of ten. Chunk 1 is done, with 2 through 21 pending.[^chestcts] The head CT soft-tissue plan is complete, with four new models and nine mappings to existing models. Identifiers were written back to the source list and validation passed.[^headcts] -Two consequences follow. First, the published corpus of 2,382 understates by roughly 2,400 the number of definitions that have been drafted somewhere. Second, the JSON schema file in `schema/` is being extended independently on three of these branches, with nothing landed on `main`. +Roughly 2,400 definitions have been drafted beyond the 2,382 published models. Three branches also extend `schema/` independently, with no changes merged into `main`. Ten issues are open on the repository. Five request further content batches, including RadElement-derived definitions, chest CT and chest radiograph device lists, abdomen CT findings, knee MRI findings, and CDEStaging markdown content. Four cover tooling, including running the validator as a GitHub action and locking `main`. One asks for a static site with a landing page. diff --git a/knowledge/semantic-foundation/finding-models/enrichment-pipeline.md b/knowledge/semantic-foundation/finding-models/enrichment-pipeline.md index aa731a4..c23dc92 100644 --- a/knowledge/semantic-foundation/finding-models/enrichment-pipeline.md +++ b/knowledge/semantic-foundation/finding-models/enrichment-pipeline.md @@ -4,7 +4,7 @@ title: Metadata enrichment pipeline description: How finding model definitions get structured metadata assigned by language models, what shipped, what the canonical rewrite on the work edge changes, and why it has not been released. tags: [semantic-foundation, finding-models, enrichment, metadata, concept] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: prd resource: https://github.com/openimagingdata/findingmodel/blob/75afd39a400419dcfaf7c8d4a34f065b4d804e0d/docs/finding-enrichment-prd.md @@ -46,7 +46,7 @@ sources: # The problem -A [finding model](/glossary/finding-model.md) definition written by a person carries a name, a description, synonyms, and [attributes](/glossary/attribute.md). It usually does not carry ontology codes, anatomic locations, or the classification facts that make a corpus of 2,382 definitions browsable: which body region, which subspecialty reads it, which modalities show it, whether it is a finding or a diagnosis. Assigning those by hand across the corpus is not practical, so the project built a language-model pipeline to propose them. +Authors supply [finding model](/glossary/finding-model.md) names, descriptions, synonyms, and [attributes](/glossary/attribute.md). Ontology codes, locations, body regions, subspecialties, modalities, and finding-versus-diagnosis classification are often missing. A language-model pipeline proposes these metadata across the 2,382-definition corpus. Two generations of that pipeline exist. The first shipped and is on `main`. The second is a rewrite on the work edge that has not been released. @@ -68,11 +68,11 @@ The goal is stated as making structured metadata "canonical `FindingModel` state ## Seven agents, not one -Where the optimization proposal recommended one unified classifier, the rewrite went the other way. A decision record on the branch states that assignment is performed by seven focused agents, each with a lean external prompt and each emitting a typed decision: entity type, etiology and tempo, patient applicability, subspecialty domain, modality applicability, ontology decision, and anatomy decision. The reason given is that "focused agents allow concise/clean prompts, per-field evaluation, and targeted tuning of weak fields," accepting more model calls per finding as the cost.[^adr2] +Where the optimization proposal recommended one unified classifier, the rewrite went the other way. The rewrite uses seven agents with external prompts and typed outputs: entity type, etiology and tempo, patient applicability, subspecialty domain, modality applicability, ontology decision, and anatomy decision. ADR 0002 states that "focused agents allow concise/clean prompts, per-field evaluation, and targeted tuning of weak fields," at the cost of more calls.[^adr2] -An orchestrator, `assign_metadata()`, gathers candidates and assembles the decisions but "never decides a field value itself."[^agent-arch] It runs in stages: candidate gathering from ontology search and the anatomic index, bounded by a configurable limit defaulting to 15; then the ontology and anatomy agents, which select among those candidates rather than generating values; then entity type, patient applicability, subspecialty, and modality in parallel; then etiology and tempo, which runs last because it depends on entity type and is validated against it. Two search-agent pairs feed candidates and never set final metadata. An auditor is advisory only. +`assign_metadata()` assembles decisions but "never decides a field value itself."[^agent-arch] It gathers ontology and anatomy candidates with a configurable limit defaulting to 15, then asks ontology and anatomy agents to select from them. Entity type, patient applicability, subspecialty, and modality run in parallel. Etiology and tempo run last, depending on and validated against entity type. Two search-agent pairs supply candidates without setting metadata. An auditor provides advice only. -Each agent has its own component evaluation, which is what makes per-field tuning possible. +Each agent has a component evaluation for tuning its fields. ## Releasing without breaking anyone @@ -80,13 +80,13 @@ A third decision record covers distribution. Two DuckDB artifacts are published # Why it has not shipped -The branch measures itself and reports failure. A prompt-improvement document dated 2026-06-03 records raising the expected time course score from 0.69 to between 0.76 and 0.78, and the etiologies score from 0.74 to between 0.91 and 0.93 by scoring errors asymmetrically according to clinical consequence. It then states that overall readiness remains a failure because age profile and index codes are still below the quality floor.[^tempo] +The 2026-06-03 prompt-improvement document reports expected time course scores rising from 0.69 to between 0.76 and 0.78 and etiology from 0.74 to between 0.91 and 0.93. Scoring weighted errors asymmetrically by clinical consequence. Age profile and index codes still failed the quality floor, so overall readiness failed.[^tempo] -The index codes weakness was traced separately. At roughly 0.674 against a floor of 0.85 it was the weakest field, and the cause was missing RadElement coverage in the ontology search. Adding that coverage alone reached about 0.736, which the document calls insufficient; the approach that followed splits searchable source codes from codes carried forward.[^index-codes] +Index codes scored about 0.674 against a 0.85 floor, the weakest field, and the cause was missing RadElement coverage in the ontology search. Adding it raised the score to about 0.736, still insufficient. Subsequent work separates searchable source codes from carried-forward codes.[^index-codes] The active plan on the branch is therefore not a corpus run. Its stated goal is to get the branch and the sibling data repository "to a coherent, reviewable, git-clean state so we can move toward supervised corpus enrichment," and it says so explicitly: "The immediate milestone is not a broad corpus run."[^current-plan] Five ordered commits cover documentation consolidation, review-evidence fixtures and gate validation tests, tool and prompt refactoring, data-repository apply tooling, and the approved baseline. The plan also records "No commits are made without explicit permission." -The human review evidence it protects is specific: 150 unique reviewed records and 180 review events, with a latest effective status of 67 approved and 83 requiring feedback, up from an original 46 approved after a targeted follow-up pass updated 21 records. +Review evidence covers 150 unique records and 180 events. Current effective statuses are 67 approved and 83 requiring feedback. A follow-up pass updated 21 records, increasing approvals from 46 to 67. # The data side diff --git a/knowledge/semantic-foundation/finding-models/finding-model-format.md b/knowledge/semantic-foundation/finding-models/finding-model-format.md index d113a6e..a928a4a 100644 --- a/knowledge/semantic-foundation/finding-models/finding-model-format.md +++ b/knowledge/semantic-foundation/finding-models/finding-model-format.md @@ -1,10 +1,10 @@ --- type: Format Specification title: Finding model format -description: The released Open Imaging Finding Model record format, class by class and field by field, with a real example and the unreleased metadata fields on the work edge. +description: Released finding model fields, validation rules, examples, and unreleased metadata extensions. tags: [semantic-foundation, finding-models, oifm, schema, format] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: fm-model resource: https://github.com/openimagingdata/findingmodel/blob/75afd39a400419dcfaf7c8d4a34f065b4d804e0d/packages/findingmodel/src/findingmodel/finding_model.py @@ -84,7 +84,7 @@ An [attribute](/glossary/attribute.md) is one characterization axis. Two variant | `unit` | no | yes | no | string or null | | `index_codes` | yes | yes | no, `Ided` variants only | non-empty if present | -Three behaviors are enforced by validators rather than by field declarations. A choice attribute must carry at least two values. `max_selected` is repaired on input: it becomes 1 when missing or falsy, and is clamped to the number of values when larger or when the literal string `"all"` is supplied. And value codes are generated rather than supplied. +Validators require at least two choice values and generate value codes. They also repair `max_selected`: missing or falsy values become 1. Values above the number of choices, or the literal string `"all"`, become the number of choices. A `ChoiceValueIded` has `value_code` matching `^OIFMA_[A-Z]{3,4}_[0-9]{6}\.\d+$`, a `name`, an optional `description`, and optional `index_codes`. A validator overwrites each `value_code` with `.` counting from zero, so the first value of an attribute ends in `.0`, the second in `.1`, and so on. The prose mirror's example numbers values from `.1`, which does not match what the code writes or what the stored corpus contains. Real presence attributes carry `.0` for absent and `.1` for present. @@ -128,7 +128,7 @@ Contributors are `Person` or `Organization`.[^fm-contributor] An `Organization` } ``` -The `Laterality` attribute is elided here for length. Serialization conventions follow from the repository's validator: files are rewritten with consistent formatting on every commit, null and absent optional fields are omitted rather than written as `null`, and the generated markdown render, the repository index, and the identifier registry are regenerated from `defs/` and must never be hand-edited.[^fm-claude] +The example omits the `Laterality` attribute. On every commit, the validator reformats JSON, omits null and absent optional fields, and regenerates markdown, the corpus index, and the identifier registry from `defs/`. Generated files must not be edited manually.[^fm-claude] # On the work edge, not released @@ -147,9 +147,11 @@ The branch splits `finding_model.py` into `types/models.py`, `types/attributes.p | `age_profile` | `AgeProfile` | `applicability` is `all_ages` or a list of nine MeSH-derived age stages; `more_common_in` is an optional list of the same | | `sex_specificity` | `SexSpecificity` | male-specific, female-specific, sex-neutral | -Three changes ride along. Legacy values normalize on input, so title-cased body regions lowercase themselves, `Arm` and `Leg` become `upper_extremity` and `lower_extremity`, `ALL` becomes `whole_body`, modalities `CR` and `DX` become `XR`, and free-text age labels expand into an `AgeProfile`. Model-level entries in `index_codes` and `anatomic_locations` are rejected if `display` is empty. And canonical `index_codes` are narrowed to exact matches or clinically substitutable near-equivalents, with broader, narrower, and merely related candidates diverted to a separate review artifact. +The branch also normalizes legacy input. Body regions become lowercase, `Arm` and `Leg` become `upper_extremity` and `lower_extremity`, and `ALL` becomes `whole_body`. Modalities `CR` and `DX` become `XR`, and free-text ages expand into `AgeProfile`. -The branch's own readiness assessment does not pass. The prose reference for these fields, and the three places where it disagrees with the branch code, is in [the metadata fields extract](/references/oifm-metadata-fields-extract.md). The pipeline that populates them is described in [the enrichment pipeline](/semantic-foundation/finding-models/enrichment-pipeline.md), and the direction as a stated goal is in [format evolution](/roadmap/finding-model-format-evolution.md). +Model-level `index_codes` and `anatomic_locations` require nonempty `display`. Canonical `index_codes` accept exact or clinically substitutable matches. Broader, narrower, and related candidates go to a separate review artifact. + +The branch fails its readiness assessment. [The metadata fields extract](/references/oifm-metadata-fields-extract.md) records three disagreements between its code and prose. See [the enrichment pipeline](/semantic-foundation/finding-models/enrichment-pipeline.md) for assignment and [format evolution](/roadmap/finding-model-format-evolution.md) for planned work. [^fm-model]: finding_model.py, findingmodel main branch [^fm-contributor]: contributor.py, findingmodel main branch diff --git a/knowledge/semantic-foundation/finding-models/finding-taxonomies.md b/knowledge/semantic-foundation/finding-models/finding-taxonomies.md index 610f9c7..74cc18d 100644 --- a/knowledge/semantic-foundation/finding-models/finding-taxonomies.md +++ b/knowledge/semantic-foundation/finding-models/finding-taxonomies.md @@ -1,10 +1,10 @@ --- type: Reference title: MGB exam-oriented sub-taxonomies -description: The six exam-oriented finding hierarchies contributed by MassGeneral Brigham, their columns and hierarchy semantics, their row and match counts, and the triage they call for. +description: Six MGB exam-oriented finding hierarchies, their fields, counts, model matches, and pending triage. tags: [semantic-foundation, finding-models, taxonomy, content, reference] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: lists-readme resource: https://github.com/openimagingdata/findingmodels/blob/a30c3c95fa3943e7340ce87575f4b1b926987eb8/lists/README.md @@ -25,7 +25,7 @@ sources: # What they are -The MGB exam-oriented sub-taxonomies are six hierarchies of radiology finding names, contributed by MassGeneral Brigham and exported into the `findingmodels` repository on 2026-08-15. They live on the branch `taxonomy-export-2026-08-15`, read here at commit `a30c3c9`, which replaces the repository's earlier `lists/` directory wholesale and adds no finding model definitions of its own.[^lists-readme] +MassGeneral Brigham contributed six finding hierarchies, exported to `findingmodels` on 2026-08-15. The `taxonomy-export-2026-08-15` branch, read at `a30c3c9`, replaces `lists/` and adds no model definitions.[^lists-readme] Each file is a comma-separated table. Together they hold 3,789 rows, of which 1,028 already carry the identifier of an existing [finding model](/glossary/finding-model.md). @@ -69,7 +69,7 @@ Two columns sit deliberately outside that tree. `category` groups rows anatomica | `diagnosis` | 932 | | blank | 414 | -That split mirrors the distinction the finding model work elsewhere calls entity type, where a finding is what you see and a diagnosis is what you conclude. Blank rows are mostly the generic parents, which exist to hold a subtree rather than to be reported. +The values correspond to entity type elsewhere in the finding model work. The `finding_type` column's values are `observation` and `diagnosis`, where a finding is what you see and a diagnosis is what you conclude. Blank rows are mostly generic parents that group children without being reported. Two real rows show the shape: @@ -79,23 +79,23 @@ airway_abnormality,airway,,,,,OIFM_OIDM_449436 airspace_opacity,lung,lung_abnormality,"Air space opacity,Infiltrate,Airspace disease",observation,,OIFM_CDE_000225 ``` -The first is a top-level parent with no `finding_type`. The second is a child of `lung_abnormality`, typed as an observation, carrying three synonyms and matched to a definition that entered the corpus from the common data element work. +The first row is an untyped root. The second is an observation under `lung_abnormality`, with three synonyms and a CDE-derived model identifier. # Matching status and the triage task No identifiers were minted during the export. Filled rows were matched by exact name against `ids.json` across all branches, plus identifiers previously written back into the old lists.[^lists-readme] The README records a consequence of those earlier writebacks: "An ID can appear on two rows where those earlier writebacks mapped two findings onto one model." -The match rate varies enormously by file. Head CT is 86 percent matched and chest radiography 76 percent, because both areas have had content batches run against them. Mammography is 3 percent matched and the combined chest, abdomen, and pelvis CT file 10 percent, against 2,064 rows. +Head CT is 86 percent matched and chest radiography 76 percent after content batches in both areas. Mammography is 3 percent matched, and the 2,064-row combined CT file is 10 percent matched. -The README names the next task in one sentence: "Blank rows are the ones needing triage." That is 2,761 rows. Triage means deciding, for each, whether an existing model covers it under a different name, whether it needs a new model, or whether it is not a finding at all. No plan document in the repository yet assigns that work. +The README states: "Blank rows are the ones needing triage." Each of the 2,761 unmatched rows needs classification as an existing model under another name, a new model, or something other than a finding. No plan document in the repository yet assigns that work. # Why this matters The project lead stated on 2026-09-21 that the sub-taxonomies are the immediate direction for all finding model content, and that they are expected to replace many of the Gamuts-derived models that currently make up 1,933 of the corpus's 2,382 definitions. That statement is recorded in [the knowledgebase build plan](/plans/2026-09-20-knowledgebase-build-plan.md).[^build-plan] -This is a change in how content gets chosen. The Gamuts import brought in whatever the source ontology contained. The sub-taxonomies instead enumerate what a radiologist reading a particular exam type actually reports, organized by the exam type. A finding model corpus built against them would be scoped to assessable anatomy per modality, which is the scoping rule the authoring guidance already states. The stated direction, and what depends on it, is in [the content direction roadmap](/roadmap/finding-model-content-direction.md). +This is a change in how content gets chosen. The Gamuts import brought in whatever the source ontology contained. The sub-taxonomies instead enumerate what a radiologist reading a particular exam type actually reports, organized by the exam type. They would scope the corpus to anatomy assessable by modality, as authoring guidance requires. See [the content direction roadmap](/roadmap/finding-model-content-direction.md). -The glossary entry for the artifact type is [finding taxonomy](/glossary/finding-taxonomy.md). The files themselves are on the branch and are not copied into this knowledgebase. +See [finding taxonomy](/glossary/finding-taxonomy.md) for the artifact type. Source CSVs remain on the branch. [^lists-readme]: MGB exam-oriented sub-taxonomies README, taxonomy-export-2026-08-15 branch [^xr-chest]: xr_chest_findings.csv, taxonomy-export-2026-08-15 branch diff --git a/knowledge/semantic-foundation/finding-models/identifiers.md b/knowledge/semantic-foundation/finding-models/identifiers.md index 20a8d3d..ecb5d89 100644 --- a/knowledge/semantic-foundation/finding-models/identifiers.md +++ b/knowledge/semantic-foundation/finding-models/identifiers.md @@ -1,10 +1,10 @@ --- type: Reference title: Finding model identifiers -description: The OIFM and OIFMA identifier grammar, the organization-code segment and its registered values, value codes, how identifiers are minted and checked, and what stability is guaranteed. +description: Finding, attribute, and value identifier formats, generation, validation, and stability limits. tags: [semantic-foundation, finding-models, oifm, identifiers, reference] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: fm-model resource: https://github.com/openimagingdata/findingmodel/blob/75afd39a400419dcfaf7c8d4a34f065b4d804e0d/packages/findingmodel/src/findingmodel/finding_model.py @@ -28,7 +28,7 @@ sources: # The grammar -Three identifier forms carry the whole referencing scheme. Each is enforced by a regular expression on the Pydantic field that holds it.[^fm-model] +Pydantic fields enforce three identifier formats.[^fm-model] | Identifier | Regular expression | Example | Enforced on | |---|---|---|---| @@ -38,7 +38,7 @@ Three identifier forms carry the whole referencing scheme. Each is enforced by a The digit count is a module constant, `ID_LENGTH`, set to 6 and interpolated into all three patterns, so the three move together if it ever changes. -Reading one of these left to right gives you the whole address. `OIFMA_CDE_000632.1` is value 1 of attribute `000632`, contributed under organization code `CDE`. Because the attribute identifier is globally unique rather than scoped to its finding, an attribute code alone identifies the finding it belongs to, which is what makes the registry lookup in the next section possible. +`OIFMA_CDE_000632.1` identifies value 1 of attribute `000632` under organization `CDE`. A globally unique attribute identifier also identifies its parent finding through the registry. # The organization segment @@ -88,24 +88,24 @@ Identifiers are never written by hand. The authoring tools call the generators; `oifm_ids` maps each finding identifier to the file that defines it. `attribute_ids` maps each attribute identifier to a pair of file name and attribute name. Value codes are not registered separately, because they are derived from the attribute identifier. -The registry is rebuilt from `defs/` by `scripts/validator.py`, which walks every definition file, validates it, and fails if a finding identifier or an attribute identifier is seen twice.[^validator] That check is the only thing standing between random minting and a collision. A pre-commit hook runs the validator on every commit and stages the regenerated `ids.json`, the markdown renders, and the repository index, so a definition cannot land without the registry landing with it. +`scripts/validator.py` rebuilds the registry from `defs/`, validates each file, and rejects repeated finding or attribute identifiers.[^validator] This is the sole collision check. Every commit's pre-commit hook runs it and stages the registry, markdown renders, and corpus index. # Round-trip regeneration, issue 42 -The one documented way to lose an identifier is to round-trip a registered model through `FindingModelBase`. That class has no `oifm_id` field, so validating a stored definition against it silently discards the finding identifier and every attribute identifier. The helper that adds identifiers then sees none present and mints new ones.[^issue42] +Validating a registered model through `FindingModelBase`, which has no `oifm_id`, silently drops its finding and attribute identifiers. The helper then generates new ones.[^issue42] The issue, open since 2026-04-18, describes this as "a silent data-integrity hazard for any workflow that loads an existing `.fm.json` as a dict, needs to mutate it, and wants ID allocation for just the new part." It was hit in a review flow that added a change-from-prior attribute to a legacy model carrying only presence; the published finding identifier and the existing attribute identifier were both regenerated, and external references to them would have become dangling. The workaround shipped in the content work operates on the dictionary directly and allocates only the identifiers genuinely missing, building value codes from the attribute identifier by hand. Four candidate fixes are enumerated in the issue and none has been chosen. # Stability -What is documented amounts to this. +The documented stability rules are: - An identifier, once minted and committed, names one definition file, and the validator enforces that no second file claims it. - The registry admits that an identifier can legitimately appear on more than one row of an external list. The [MGB exam-oriented sub-taxonomies](/semantic-foundation/finding-models/finding-taxonomies.md) note that "an ID can appear on two rows where those earlier writebacks mapped two findings onto one model." That is a property of those files, not of the registry. - Nothing in the repository documents a deprecation, retirement, or supersession mechanism for an identifier. There is no version field on a finding model in the released format, and schema versioning is an open task rather than a shipped feature. - The round-trip defect above is the known exception to stability in practice, and it is unresolved. -Downstream systems rely on this. Exam Finding Lists store nothing but the identifier and a display string, so a changed identifier breaks the link between a stored [Observation](/glossary/observation.md) and its definition. The content repository is the single source of finding model identity for the catalog site, which consumes `defs/` as a git submodule, and for the extraction platform, which resolves identifiers through the published registry. See [the repository map](/repositories/repository-map.md). +Exam Finding Lists reference definitions by identifier and display string, so identifier changes break stored [Observation](/glossary/observation.md) links. The content repository supplies identity to the catalog site, which reads `defs/` through a git submodule, and to the extraction platform's registry lookups. See [the repository map](/repositories/repository-map.md). [^fm-model]: finding_model.py, findingmodel main branch [^base-orgs]: base_organizations.jsonl, findingmodel main branch diff --git a/knowledge/semantic-foundation/finding-models/index.md b/knowledge/semantic-foundation/finding-models/index.md index 697d949..b1e3a27 100644 --- a/knowledge/semantic-foundation/finding-models/index.md +++ b/knowledge/semantic-foundation/finding-models/index.md @@ -1,10 +1,10 @@ # Finding models -* [Why finding models](./why-finding-models.md) - Why the finding is OIDM's unit of data, what a finding model definition carries, what it deliberately is not, and how downstream structures consume it. -* [Finding model format](./finding-model-format.md) - The released Open Imaging Finding Model record format, class by class and field by field, with a real example and the unreleased metadata fields on the work edge. -* [Finding model identifiers](./identifiers.md) - The OIFM and OIFMA identifier grammar, the organization-code segment and its registered values, value codes, how identifiers are minted and checked, and what stability is guaranteed. -* [Finding model content catalog](./content-catalog.md) - The findingmodels repository: what is in the corpus, where its identifiers and generated renders live, the conventions that govern it, how to browse it, and the content batches in flight on unmerged branches. -* [MGB exam-oriented sub-taxonomies](./finding-taxonomies.md) - The six exam-oriented finding hierarchies contributed by MassGeneral Brigham, their columns and hierarchy semantics, their row and match counts, and the triage they call for. -* [Authoring workflow](./authoring-workflow.md) - How finding models are created and reviewed today, through the Forge web application, the findingmodel-ai command line, the three agent skills, and the validator that gates every commit. +* [Why finding models](./why-finding-models.md) - Why OIDM defines findings, what a finding model contains, and how observations use it. +* [Finding model format](./finding-model-format.md) - Released finding model fields, validation rules, examples, and unreleased metadata extensions. +* [Finding model identifiers](./identifiers.md) - Finding, attribute, and value identifier formats, generation, validation, and stability limits. +* [Finding model content catalog](./content-catalog.md) - Published finding model content, repository conventions, browsing tools, and unmerged batches. +* [MGB exam-oriented sub-taxonomies](./finding-taxonomies.md) - Six MGB exam-oriented finding hierarchies, their fields, counts, model matches, and pending triage. +* [Authoring workflow](./authoring-workflow.md) - Finding model authoring, review, and validation through Forge, the CLI, and repository skills. * [Metadata enrichment pipeline](./enrichment-pipeline.md) - How finding model definitions get structured metadata assigned by language models, what shipped, what the canonical rewrite on the work edge changes, and why it has not been released. * [Finding models and common data elements](./finding-models-and-cdes.md) - The workbench relationship: finding models as fast exploratory definitions that can graduate into governed ACR and RSNA common data elements, and the vocabularies both have to fit. diff --git a/knowledge/semantic-foundation/finding-models/why-finding-models.md b/knowledge/semantic-foundation/finding-models/why-finding-models.md index efff0f3..f3fe0c6 100644 --- a/knowledge/semantic-foundation/finding-models/why-finding-models.md +++ b/knowledge/semantic-foundation/finding-models/why-finding-models.md @@ -1,10 +1,10 @@ --- type: Concept title: Why finding models -description: Why the finding is OIDM's unit of data, what a finding model definition carries, what it deliberately is not, and how downstream structures consume it. +description: Why OIDM defines findings, what a finding model contains, and how observations use it. tags: [semantic-foundation, finding-models, oifm, concept] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:00:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:34:50Z } sources: - id: oifm-overview resource: https://github.com/openimagingdata/findingmodels/blob/2267d5d0b430ec7117a6da91efe6069da38c0056/prompts/overview.md @@ -26,39 +26,39 @@ sources: # The finding is the unit -A radiology report is prose. Somewhere inside it a radiologist has asserted that a thing is there, or is not there, or is bigger than it was. The Open Imaging Data Model (OIDM) takes that assertion as its atom, and a [finding model](/glossary/finding-model.md) is the reusable definition of one such assertion type. +A radiology report records assertions about findings, including their presence, absence, and change. The Open Imaging Data Model (OIDM) represents each finding type with a reusable [finding model](/glossary/finding-model.md). -The reason to define findings rather than reports is stated plainly in the overview note that governs authoring: finding models "turn that unstructured language into structured, machine-accessible observation objects, each linked to a rich knowledge base of clinical context."[^oifm-overview] An agent reads a report, matches each finding it recognizes to a definition, and emits an [Observation](/glossary/observation.md) tagged with the finding type and the values of its [attributes](/glossary/attribute.md). +Finding models "turn that unstructured language into structured, machine-accessible observation objects, each linked to a rich knowledge base of clinical context."[^oifm-overview] An agent matches report findings to definitions and emits an [Observation](/glossary/observation.md) with a finding type and [attribute](/glossary/attribute.md) values. -The second reason is time. "A radiology report is a snapshot, but the findings it describes persist across exams. A pleural effusion seen today may be the same one from last week, now larger."[^oifm-overview] Two reports written a year apart by two radiologists at two institutions can only be compared if both name the same thing the same way. That shared naming is what a finding model supplies, and it is why the [Imaging Problem List](/glossary/imaging-problem-list.md) can organize a patient's history by finding rather than by date. +"A radiology report is a snapshot, but the findings it describes persist across exams. A pleural effusion seen today may be the same one from last week, now larger."[^oifm-overview] Shared definitions let the [Imaging Problem List](/glossary/imaging-problem-list.md) group observations by finding across exams and institutions. # What a finding is, and is not -The scope is broader than pathology. The overview note counts as findings: pathologic entities, physiologic observations, devices and hardware, postsurgical states, anatomic variants, and image quality problems. It also refuses to separate description from diagnosis. "Diagnostic terms are first-class findings, do not question whether a diagnosis 'should' be a finding."[^oifm-overview] Both "bilateral perihilar opacities" and "pulmonary edema" are modeled, because radiologists write both. +Findings include pathologic entities, physiologic observations, devices and hardware, postsurgical states, anatomic variants, and image quality problems. The authoring overview includes diagnoses: "Diagnostic terms are first-class findings, do not question whether a diagnosis 'should' be a finding."[^oifm-overview] Both "bilateral perihilar opacities" and "pulmonary edema" qualify. -The test is whether a radiologist would write "there is X" or "no X" as a standalone statement. That test excludes a state of a finding ("stable cardiac silhouette"), a qualified version of one ("large pleural effusion"), normal anatomy, radiographic signs and interpretation techniques, exam metadata, clinical history, and recommendations. The guiding principle is that "a finding is a noun phrase; everything else is an attribute."[^oifm-overview] The full treatment, with its worked examples of too broad, too narrow, and right level, is in [the overview extract](/references/oifm-overview-extract.md). +The test is whether a radiologist would write "there is X" or "no X" as a standalone statement. It excludes finding states such as "stable cardiac silhouette", qualified findings such as "large pleural effusion", normal anatomy, radiographic signs, interpretation techniques, exam metadata, clinical history, and recommendations. The principle is that "a finding is a noun phrase; everything else is an attribute."[^oifm-overview] The [overview extract](/references/oifm-overview-extract.md) has examples of appropriate scope. -Negative assertions are inside the scope, not outside it. When a report says "no fracture," that is an active observation recorded as [presence](/glossary/presence.md) absent, which means the finding was looked for and not found. Models therefore have to exist at the breadth where radiologists make those sweeping statements, which is why "chest wall fracture" and "upper abdominal abnormality" are legitimate models. +"No fracture" records an observation with [presence](/glossary/presence.md) absent. The finding was looked for and not found. Broad models such as "chest wall fracture" and "upper abdominal abnormality" support these negative assertions. # What the definition carries -A finding model is a knowledge base entry, not a label. Each definition carries a canonical name, a description written for a radiologist audience, synonyms covering the ways the same observation gets expressed, [tags](/glossary/tag.md) for browsing, [index codes](/glossary/index-code.md) linking to SNOMED CT, RadLex, and the Radiology Gamuts Ontology, optional [anatomic locations](/glossary/anatomic-location.md), [contributors](/glossary/contributor.md), and the attribute list.[^oifm-overview][^fm-model] +A definition contains a canonical name, a description for radiologists, synonyms, [tags](/glossary/tag.md), [index codes](/glossary/index-code.md), optional [anatomic locations](/glossary/anatomic-location.md), [contributors](/glossary/contributor.md), and attributes. Tags support browsing; index codes link to SNOMED CT, RadLex, and the Radiology Gamuts Ontology.[^oifm-overview][^fm-model] -Attributes are the characterization axes. Two are near-universal and come first by convention: presence, with the values absent, present, indeterminate, and unknown, then [change from prior](/glossary/change-from-prior.md). After those come the domain-specific axes, size, severity, density, morphology, enhancement pattern, and whatever else the finding needs. Each choice value gets its own code, so a stored Observation can cite not just the finding and the attribute but the specific value chosen. Every identifier in that chain is machine-generated and never written by hand. The field-level specification is in [the format document](/semantic-foundation/finding-models/finding-model-format.md). +Attributes characterize a finding. By convention, most models start with presence, whose values are absent, present, indeterminate, and unknown, then [change from prior](/glossary/change-from-prior.md). Finding-specific attributes follow, such as size, severity, density, morphology, and enhancement pattern. Each choice value has a code so an Observation can identify the finding, attribute, and selected value. Tools generate all identifiers. Authors do not assign them by hand. See the [format document](/semantic-foundation/finding-models/finding-model-format.md). -Quality in these definitions is load-bearing rather than cosmetic. "A sloppy synonym maps the wrong concept to an observation; a nonsensical attribute propagates meaningless data; a poorly scoped model conflates distinct clinical entities. Errors here don't just look bad, they cause incorrect downstream reasoning about patient care."[^oifm-overview] +Definition errors affect downstream interpretation: "A sloppy synonym maps the wrong concept to an observation; a nonsensical attribute propagates meaningless data; a poorly scoped model conflates distinct clinical entities. Errors here don't just look bad, they cause incorrect downstream reasoning about patient care."[^oifm-overview] # What a finding model is not -It is not a report template. Templates were the earlier approach to structured reporting, and a finding model does not prescribe what a report contains or in what order. It defines one finding and leaves composition to whatever produces the report. +A finding model defines one finding. Earlier structured-reporting approaches used templates to prescribe report content and order; finding models leave report composition to the application. -It is not a common data element, at least not yet. The January 2026 status deck frames finding models as "the CDE workbench": rapid, language-model-assisted content creation acting as "a proving ground for formal common data elements," carrying "rich definitions with embedded relationships and semantic tags that can graduate to standards."[^deck] The relationship runs from finding model toward [common data element](/glossary/cde.md), not the other way, and it is worked through in [finding models and CDEs](/semantic-foundation/finding-models/finding-models-and-cdes.md). +It is not a common data element, at least not yet. The January 2026 deck calls them "the CDE workbench" and "a proving ground for formal common data elements".[^deck] The relationship runs from finding model toward [common data element](/glossary/cde.md), not the other way, and it is worked through in [finding models and CDEs](/semantic-foundation/finding-models/finding-models-and-cdes.md). -It is also not an instance. The definition says what a pleural effusion is and how one is characterized. It says nothing about any particular patient. That separation is the whole point of the layering described in [architecture](/overview/architecture.md). +A definition describes a finding type, such as pleural effusion. Patient-specific observations reference that definition, as described in the [architecture](/overview/architecture.md). # How the definitions get used -Downstream structures reference finding models only by identifier. An [Exam Finding List](/glossary/exam-finding-list.md) entry carries a `findingCode` holding the model's OIFM identifier, an optional anatomic location, and an `attributes` array in which each element pairs an OIFMA attribute identifier with a value code drawn from that attribute's permitted values.[^efl-example] Nothing in the Exam Finding List repeats the definition; a reader that wants to know what `OIFM_GMTS_016552` means resolves it against the content repository. +An [Exam Finding List](/glossary/exam-finding-list.md) entry references the model by its OIFM identifier in `findingCode`. Downstream structures reference finding models only by identifier. It adds an optional anatomic location and an `attributes` array pairing OIFMA attribute identifiers with permitted value codes.[^efl-example] Nothing in the Exam Finding List repeats the definition; a reader that wants to know what `OIFM_GMTS_016552` means resolves it against the content repository. ```json { @@ -74,9 +74,9 @@ Downstream structures reference finding models only by identifier. An [Exam Find } ``` -The same identifiers flow upward into the Imaging Problem List, which groups a patient's observations by finding code across exams. The details of both structures are in [the Exam Finding List document](/data-structures/exam-finding-list.md). +The Imaging Problem List groups a patient's observations across exams using the same identifiers. See the [Exam Finding List document](/data-structures/exam-finding-list.md). -An older statement of the same idea, from the 2023 site post that predates the finding model format, describes a radiology finding as a FHIR Observation "semantically labeled with ACR/RSNA Common Data Element identifiers," with the set identifier naming the finding type and element identifiers naming the attributes.[^site-post] The shape survived; what changed is that OIDM now mints its own identifiers for the definitions that no common data element covers. +The 2023 site post described a FHIR Observation "semantically labeled with ACR/RSNA Common Data Element identifiers", with a set identifier for the finding type and element identifiers for its attributes.[^site-post] OIDM now also mints its own identifiers for definitions that no common data element covers. [^oifm-overview]: "Finding Models: Overview", findingmodels repository [^deck]: Open Imaging Data Model 2026 Status Update, January 2026 diff --git a/knowledge/semantic-foundation/index.md b/knowledge/semantic-foundation/index.md index c44b3d3..5586ac5 100644 --- a/knowledge/semantic-foundation/index.md +++ b/knowledge/semantic-foundation/index.md @@ -1,8 +1,7 @@ # Semantic foundation - -* [finding-models](./finding-models/) - Open Imaging Finding Models: format, identifiers, content, authoring -* [common-data-elements](./common-data-elements/) - ACR/RSNA common data elements and how finding models relate to them -* [anatomic-locations](./anatomic-locations/) - The curated anatomic location set, its data model, and RadLex integration -* [exam-types](./exam-types/) - Exam types: goals and existing building blocks -* [terminologies](./terminologies/) - External terminologies and the lookup tooling +* [Finding models](./finding-models/) - Open Imaging Finding Models: format, identifiers, content, authoring +* [Common data elements](./common-data-elements/) - ACR/RSNA common data elements and how finding models relate to them +* [Anatomic locations](./anatomic-locations/) - The curated anatomic location set, its data model, and RadLex integration +* [Exam types](./exam-types/) - Exam types: goals and existing building blocks +* [Terminologies](./terminologies/) - External terminologies and the lookup tooling diff --git a/knowledge/semantic-foundation/terminologies/index.md b/knowledge/semantic-foundation/terminologies/index.md index 76f1206..4e2052d 100644 --- a/knowledge/semantic-foundation/terminologies/index.md +++ b/knowledge/semantic-foundation/terminologies/index.md @@ -1,6 +1,6 @@ # Terminologies -The external vocabularies OIDM points at rather than reinvents, and the tooling that resolves them. +External vocabularies referenced by OIDM and tools for resolving their codes. -* [Ontologies used](./ontologies-used.md) - Every external terminology OIDM touches, who governs it, the shape of its identifiers, the field and structure that carries it, and which lookup tool resolves it. -* [med-ontology-lookup](./med-ontology-lookup.md) - The molu library and command line tool that resolves medical terms and codes across RadLex, SNOMED CT, FMA, LOINC, and UMLS, its current capabilities, its stated direction, and its status. +* [Ontologies used](./ontologies-used.md) - External terminology identifiers, OIDM fields, code counts, and lookup support. +* [med-ontology-lookup](./med-ontology-lookup.md) - Medical terminology lookup, crosswalks, provider failures, planned features, and integration status. diff --git a/knowledge/semantic-foundation/terminologies/med-ontology-lookup.md b/knowledge/semantic-foundation/terminologies/med-ontology-lookup.md index 1e671c9..cbb85f0 100644 --- a/knowledge/semantic-foundation/terminologies/med-ontology-lookup.md +++ b/knowledge/semantic-foundation/terminologies/med-ontology-lookup.md @@ -1,10 +1,10 @@ --- type: Project Profile title: med-ontology-lookup -description: The molu library and command line tool that resolves medical terms and codes across RadLex, SNOMED CT, FMA, LOINC, and UMLS, its current capabilities, its stated direction, and its status. +description: Medical terminology lookup, crosswalks, provider failures, planned features, and integration status. tags: [semantic-foundation, terminologies, tooling, project-profile] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:30:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } stale_after: 2027-09-21 sources: - id: readme @@ -44,11 +44,11 @@ sources: # What it is -`med-ontology-lookup` is a Python library and command line tool, `molu`, that looks up medical terms and codes in [RadLex](/glossary/radlex.md), [SNOMED CT](/glossary/snomed-ct.md), [FMA](/glossary/fma.md), [LOINC](/glossary/loinc.md), and [UMLS](/glossary/umls.md) through the BioPortal and UMLS Terminology Services REST APIs.[^readme] It is the infrastructure layer under every other piece of OIDM work that needs to turn a phrase into a code: [index code](/glossary/index-code.md) assignment on [finding models](/glossary/finding-model.md), anatomic coding, and the enrichment pipeline. +`med-ontology-lookup` is a Python library and CLI, `molu`, for medical terms and codes in [RadLex](/glossary/radlex.md), [SNOMED CT](/glossary/snomed-ct.md), [FMA](/glossary/fma.md), [LOINC](/glossary/loinc.md), and [UMLS](/glossary/umls.md). It calls BioPortal and UMLS Terminology Services REST APIs.[^readme] Its role is phrase-to-code lookup for tasks such as [index code](/glossary/index-code.md) assignment to [finding models](/glossary/finding-model.md), anatomic coding, and enrichment. Package integration remains pending, as described below. -Its stated purpose is broader than a search box. The roadmap describes it as "the small, dependable layer that lets people and agents resolve medical language to versioned concepts, inspect the clinically relevant part of an ontology graph, and translate identifiers without learning each terminology provider's API."[^roadmap] +The roadmap calls it "the small, dependable layer that lets people and agents resolve medical language to versioned concepts, inspect the clinically relevant part of an ontology graph, and translate identifiers without learning each terminology provider's API."[^roadmap] -The repository is `openimagingdata/med-ontology-lookup`. Install and API key instructions are in its README and are not repeated here.[^readme] +See `openimagingdata/med-ontology-lookup`'s README for installation and API keys.[^readme] # Providers and credentials @@ -80,11 +80,11 @@ Results are typed. A `Concept` carries `concept_id`, `code`, `ontology`, `pref_l The distinguishing design decision is that a failure is a result, not a silent fallback. A `ProviderFailure` carries a `FailureCategory`, including `not_found`, `authentication`, `authorization`, `licensing`, `rate_limited`, `timeout`, `unavailable`, and `invalid_response`, and a `ProviderOperation` naming which call failed.[^models] The policy is that only absence of a result or an unsupported operation may trigger a fallback to another provider; authentication, licensing, rate limit, timeout, and upstream unavailability stay visible instead of being disguised as an empty answer.[^failures] -This matters to callers because SNOMED CT and UMLS are licensed. An unlicensed caller gets a licensing failure rather than a result that looks like the concept does not exist. +An unlicensed SNOMED CT or UMLS caller gets a licensing failure rather than an apparent missing concept. # Agent skill -The repository ships an agent skill under `skills/med-ontology-lookup/`, portable across agent runtimes, that tells an agent to classify the input, search first for free text, and use the CLI rather than scraping the BioPortal or UMLS web interfaces.[^skill] It is the reason this tool appears in coding workflows across the other repositories. +The portable skill at `skills/med-ontology-lookup/` instructs agents to classify input, search free text first, and use the CLI instead of scraping BioPortal or UMLS.[^skill] Coding workflows in other repositories use it. # Stated direction @@ -108,9 +108,9 @@ Read at `main`, commit `a1fd3ae`, dated 2026-09-20. # Relation to the rest of OIDM -The relationship is real in practice and thin in the documentation. The enrichment pipeline in `findingmodel` runs ontology search concurrently with anatomic location lookup to propose index codes for a finding model, and that phase is recorded as complete.[^enrichment-plan] But that pipeline calls a BioOntology client of its own, and `findingmodel` issue 34 asks for that client and its ontology search protocol to move into the shared `oidm-common` package as infrastructure, described as a hard break requiring an environment-only API key.[^fm-issue-34] +The `findingmodel` enrichment pipeline performs ontology and anatomic searches concurrently, a completed phase.[^enrichment-plan] It uses its own BioOntology client. Issue 34 requests moving that client and search protocol to `oidm-common`, with a hard break requiring an environment-only API key.[^fm-issue-34] -No document in `findingmodel` or `findingmodels` links to this repository, and no OIDM package depends on it today. It is best read as the layer that the coding and enrichment work is converging toward rather than one it already runs on. See [the repository map](/repositories/repository-map.md) for where it sits among the other repositories. +Neither `findingmodel` nor `findingmodels` links to this repository, and no OIDM package depends on it. Integration is a direction, not an implemented dependency. See [the repository map](/repositories/repository-map.md). [^readme]: med-ontology-lookup README [^models]: Concept and provider failure models, med-ontology-lookup diff --git a/knowledge/semantic-foundation/terminologies/ontologies-used.md b/knowledge/semantic-foundation/terminologies/ontologies-used.md index d44032d..9a9cbc6 100644 --- a/knowledge/semantic-foundation/terminologies/ontologies-used.md +++ b/knowledge/semantic-foundation/terminologies/ontologies-used.md @@ -1,10 +1,10 @@ --- type: Reference title: Ontologies used -description: Every external terminology OIDM touches, who governs it, the shape of its identifiers, the field and structure that carries it, and which lookup tool resolves it. +description: External terminology identifiers, OIDM fields, code counts, and lookup support. tags: [semantic-foundation, terminologies, reference, coding] status: draft -generated: { by: claude-opus-5/claude-code, at: 2026-09-21T17:30:00Z } +generated: { by: codex/gpt-6, at: 2026-09-21T20:53:02Z } sources: - id: radlex resource: https://radlex.org/ @@ -67,7 +67,7 @@ sources: # How to read this -OIDM mints its own identifiers for two things only: [finding models](/glossary/finding-model.md) and their [attributes](/glossary/attribute.md), under the `OIFM` and `OIFMA` schemes. Everything else it points at. This page lists every external terminology that appears somewhere in the OIDM repositories, says who governs it, what its identifiers look like, which field carries it, and whether the [`molu`](/semantic-foundation/terminologies/med-ontology-lookup.md) lookup tool can resolve it. +OIDM assigns `OIFM` identifiers to [finding models](/glossary/finding-model.md) and `OIFMA` identifiers to their [attributes](/glossary/attribute.md). Other codes come from external terminologies. This inventory records their governance, formats, uses, and [`molu`](/semantic-foundation/terminologies/med-ontology-lookup.md) support. Counts are from the corpus and datasets at the commits pinned in the sources. Finding model counts are occurrences of an [index code](/glossary/index-code.md) across all 2,382 definitions, not distinct concepts. @@ -87,7 +87,7 @@ Counts are from the corpus and datasets at the commits pinned in the sources. Fi # RadLex -The radiology lexicon published by the RSNA, and the terminology OIDM leans on hardest. It supplies the primary key for [anatomic locations](/glossary/anatomic-location.md) in the form of a [RadLex ID](/glossary/radlex-id.md), and it is the second most common index code system in the finding model corpus, with 25,765 occurrences.[^fm-corpus] Presence values across the corpus are coded with it, for example `RID28472` for present and `RID28473` for absent. +RSNA's radiology lexicon supplies primary [anatomic location](/glossary/anatomic-location.md) keys as [RadLex IDs](/glossary/radlex-id.md). With 25,765 occurrences, it is the corpus's second most common index code system.[^fm-corpus] Presence values include `RID28472` for present and `RID28473` for absent. The ontology ships as an OWL file in the RSNA repository, which the next-generation vocabulary analysis identifies as the authoritative artifact going forward.[^radlex-owl][^current-understanding] That analysis also records the licence position: RadLex is "actively governed, and freely licensed for commercial and non-commercial use."[^current-understanding] In OIDM data the `system` string is `RADLEX`; in FHIR encodings the system URI is `http://www.radlex.org`.[^fhir-sample] Details of the relationship in both directions, including the open RSNA issue to fold the OIDM anatomic set into RadLex, are in [RadLex integration](/semantic-foundation/anatomic-locations/radlex-integration.md). @@ -129,7 +129,7 @@ RadElement is the one terminology in this table that OIDM both consumes and feed # Radiology Gamuts Ontology -An ontology of radiologic differential diagnosis lists, published at gamuts.net.[^gamuts] It plays two roles at once. As a coding system, `GAMUTS` appears 1,935 times in the corpus, essentially once per Gamuts-derived definition.[^fm-corpus] As a contributing organization it holds the [organization code](/glossary/oidm-organization-code.md) `GMTS`, which is the middle segment of 1,933 of the 2,382 finding model identifiers. See [content catalog](/semantic-foundation/finding-models/content-catalog.md) for what that content is and [finding model content direction](/roadmap/finding-model-content-direction.md) for where it is headed. +Published at gamuts.net, the Radiology Gamuts Ontology contains differential diagnosis lists.[^gamuts] `GAMUTS` occurs 1,935 times as an index code system, about once per derived definition.[^fm-corpus] Its [organization code](/glossary/oidm-organization-code.md), `GMTS`, appears in 1,933 of 2,382 finding identifiers. See [content catalog](/semantic-foundation/finding-models/content-catalog.md) and [finding model content direction](/roadmap/finding-model-content-direction.md). # DICOM Controlled Terminology diff --git a/site/README.md b/site/README.md index 4cbcf02..6fcbd33 100644 --- a/site/README.md +++ b/site/README.md @@ -2,8 +2,8 @@ Renders `knowledge/` (the OKF bundle) as a static [Quartz](https://quartz.jzhao.xyz) site. -Quartz itself is not vendored in this repository — only our config and one small plugin -live here. `build.sh` clones Quartz at a pinned commit into `site/.quartz-src/` +Quartz itself is not vendored in this repository — only our config and two small +plugins live here. `build.sh` clones Quartz at a pinned commit into `site/.quartz-src/` (gitignored) at build time and points it at `knowledge/`. ## What's here @@ -12,11 +12,20 @@ live here. `build.sh` clones Quartz at a pinned commit into `site/.quartz-src/` |---|---| | `quartz.config.yaml` | Site config: theme, plugins, layout | | `okf-meta-plugin/` | Component that renders OKF frontmatter as a badge row | -| `build.sh` | Clones Quartz, wires up the plugin, builds | +| `okf-lightbox-plugin/` | Component that adds a click-to-zoom image viewer | +| `build.sh` | Clones Quartz, wires up the plugins, builds | `site/.quartz-src/` (the Quartz checkout), `public/` (the build output), and any `node_modules/` under `site/` are gitignored. +## Brand assets + +OIDM and Anatomic Locations logos are in `knowledge/assets/brand/`. The existing +content staging and Quartz asset steps publish them at `/assets/brand/`. +See the [brand guide notes](../docs/brand/README.md) for the supplied colors, +logo variants, usage examples, and original style-guide PDF. The import does +not change the site's theme, header, or favicon. + ## Building locally From the repository root: @@ -73,6 +82,68 @@ Note this Quartz fork moved frontmatter parsing out of core and into the (with `hidePropertiesView: true`) purely so frontmatter gets parsed at all — its own visible properties panel is suppressed so it doesn't duplicate okf-meta-plugin's badges. +## okf-lightbox-plugin + +A Quartz component plugin (hand-written ESM in `dist/`, no build step, no external +dependency) that turns every diagram image in an article into a click-to-zoom overlay, +so wide SVGs squeezed into the text column can be inspected without leaving the page. + +- Clicking an `article img` (or its wrapping link) opens the image in a full-viewport + overlay: mouse wheel or pinch to zoom around the cursor/touch point, drag to pan, + double-click to reset, Esc/click-outside/close-button to dismiss. +- The plain link is still the fallback — middle-click or Ctrl/Cmd-click bypasses the + overlay and opens the image in a new tab as normal, and the overlay's own "Open full + size" button does the same (that one's the true 1:1 resolution, in a new tab). +- The overlay itself opens at `scale = 0.92 * viewportWidth / imageWidth` — width-driven + only, no height term, floored at whatever scale the image was already rendering at + inline so opening it can never look like a regression. It opens scrolled to the top of + the diagram rather than vertically centered, since the point is reading top-to-bottom; + height overflow is normal and the stage pans. This is deliberately *not* a min(width, + height) "fit the whole image" calculation: these diagrams are all portrait (taller + than wide) while browser viewports are landscape, so a height term is almost always + the binding constraint and produces an overlay image *narrower* than the already + size-squeezed inline column — exactly backwards from the point of clicking in. + Double-click and the Reset button return to this same fitted scale, not literal 1:1. +- The `naturalW`/`naturalH` this is computed from is the image's real intrinsic + resolution, not the CSS-squeezed inline size and not `.naturalWidth` either. + Every diagram SVG in this bundle has a `viewBox` but no `width`/`height` attribute, so + `.naturalWidth` reports the CSS default-object-size fallback (~300px) rather than + the SVG's actual dimensions — the plugin fetches the SVG and reads its `width`/`height` + or `viewBox` directly instead of trusting `naturalWidth`. +- The component itself renders no markup — it only registers a component so Quartz + collects its CSS and client script (see `componentResources.ts` in Quartz core) and + is declared with `layout.position: afterBody`, which is part of Quartz's *shared* + layout and so applies to every page type, not just `content` pages. +- The click handler is registered on `document` in the capture phase specifically so it + runs before Quartz's SPA router's click listener on `window` — otherwise a click on + the image's wrapping `` would be treated as page + navigation to the raw `.svg` file. The overlay element is re-appended to `document.body` + on Quartz's `nav` event, since Quartz's SPA router (`micromorph`) diffs and can strip + dynamically-added body elements not present in the freshly-fetched page. +- The script ships as `beforeDOMLoaded`, not `afterDOMLoaded`, on purpose. In a + production build Quartz code-splits every component's `afterDOMLoaded` script into + its own hashed file and loads them all in parallel via dynamic `import()`, awaited as + a group before the SPA router itself initializes. That leaves a real window — narrow, + but observed in practice on the deployed site — where a user can click a diagram + before that chunk has loaded and registered its click interceptor, so the click falls + through to the SPA router uncontested and silently navigates to the raw SVG. + `beforeDOMLoaded` scripts are always bundled into one single, blocking `prescript.js` + loaded synchronously in `` before the body is even parsed, so registering the + interceptor there guarantees it exists before anything on the page is clickable at + all. The overlay DOM itself is still built lazily, on the first real open, which is + safe since a real click implies the body has already rendered. +- The backdrop scrim is a fixed dark color rather than derived from `--light`/`--dark`: + those are foreground/background *role* tokens that swap literal colors between light + and dark mode (in dark mode `--dark` is a near-white text color), so using either for + a dimming backdrop would invert in dark mode. Toolbar buttons and hint text do use + the theme variables and correctly adapt. + ## Link resolution The bundle uses two link styles the OKF spec allows: bundle-absolute links (`/dir/file.md`) in concept documents and `./file.md` links in directory indexes. Quartz's `markdownLinkResolution` handles one style at a time, so `build.sh` first runs `tools/prepare_site_content.py`, which copies `knowledge/` to a temporary directory outside the repository (Quartz skips gitignored paths) and rewrites every internal link to the bundle-absolute form. Quartz then builds from that copy with `markdownLinkResolution: absolute`. The bundle in git is never modified. + +## Hosting: Cloudflare Workers static assets + +`site/wrangler.jsonc` defines an assets-only Worker named `oidm-knowledge` that serves `public/`. Its `html_handling: auto-trailing-slash` gives exactly the clean URLs Quartz links to (`/glossary/oifm` serves `glossary/oifm.html`, `/glossary/` serves the folder index), so no link rewriting is needed anywhere. `task deploy` builds and deploys; `task preview` serves the build locally through Wrangler. Continuous deployment on push to `main` is in `.github/workflows/deploy.yml` and needs the repository secrets `CLOUDFLARE_API_TOKEN` and `CLOUDFLARE_ACCOUNT_ID`. Worker logic (comments, endpoints) can be added to the same Worker later without changing the site build. + +The earlier object-storage publishing path (link flattening plus a bucket upload) was removed once Cloudflare became the host. diff --git a/site/build.sh b/site/build.sh index 1a0d190..c27bf70 100755 --- a/site/build.sh +++ b/site/build.sh @@ -33,8 +33,14 @@ fi git -C "$QUARTZ_SRC" fetch --quiet origin "$QUARTZ_SHA" || true git -C "$QUARTZ_SRC" checkout --quiet "$QUARTZ_SHA" -echo "==> Copying site/quartz.config.yaml into the checkout" -cp "$SITE_DIR/quartz.config.yaml" "$QUARTZ_SRC/quartz.config.yaml" +CONFIG_FILE="${QUARTZ_CONFIG:-$SITE_DIR/quartz.config.yaml}" # override with QUARTZ_CONFIG= (used by publish-tigris.sh) +echo "==> Copying ${CONFIG_FILE#"$REPO_ROOT"/} into the checkout" +cp "$CONFIG_FILE" "$QUARTZ_SRC/quartz.config.yaml" +if [ -n "${SITE_BASE_URL:-}" ]; then + # Per-target base URL (dev / staging / production) without editing the tracked config. + sed -i "s|^\(\s*\)baseUrl:.*$|\1baseUrl: ${SITE_BASE_URL}|" "$QUARTZ_SRC/quartz.config.yaml" + echo "==> baseUrl set to ${SITE_BASE_URL}" +fi echo "==> npm ci" ( cd "$QUARTZ_SRC" && npm ci ) diff --git a/site/okf-lightbox-plugin/package.json b/site/okf-lightbox-plugin/package.json new file mode 100644 index 0000000..1b5fc76 --- /dev/null +++ b/site/okf-lightbox-plugin/package.json @@ -0,0 +1,33 @@ +{ + "name": "okf-lightbox-plugin", + "version": "0.1.0", + "description": "Click-to-zoom image lightbox for Quartz - opens article diagrams in a pan/zoom overlay", + "type": "module", + "license": "MIT", + "main": "./dist/index.js", + "exports": { + ".": { + "import": "./dist/index.js" + }, + "./components": { + "import": "./dist/components/index.js" + } + }, + "quartz": { + "name": "okf-lightbox-plugin", + "displayName": "OKF Lightbox", + "category": "component", + "version": "0.1.0", + "quartzVersion": ">=5.0.0", + "defaultOrder": 50, + "defaultEnabled": true, + "defaultOptions": {}, + "components": { + "OkfLightbox": { + "displayName": "OKF Lightbox", + "defaultPosition": "afterBody", + "defaultPriority": 50 + } + } + } +} diff --git a/site/quartz.config.yaml b/site/quartz.config.yaml index 20e3866..aa476f9 100644 --- a/site/quartz.config.yaml +++ b/site/quartz.config.yaml @@ -272,6 +272,17 @@ plugins: layout: position: beforeBody priority: 15 + # Click-to-zoom pan/zoom overlay for article diagram images. Renders no + # markup itself - only injects CSS and a client script (afterBody is part + # of the shared layout, so it's present on every page type). Source path + # resolves to site/okf-lightbox-plugin — see site/build.sh. + - source: ../okf-lightbox-plugin + enabled: true + options: {} + order: 51 + layout: + position: afterBody + priority: 50 layout: groups: toolbar: diff --git a/site/wrangler.jsonc b/site/wrangler.jsonc new file mode 100644 index 0000000..4cf48aa --- /dev/null +++ b/site/wrangler.jsonc @@ -0,0 +1,29 @@ +// Cloudflare Worker serving the built Quartz site as static assets. +// +// Three targets, all assets-only Workers on the same account: +// task deploy -> oidm-knowledge-dev (default; day-to-day) +// task deploy:staging -> oidm-knowledge-staging +// task deploy:prod -> oidm-knowledge (the public site) +// +// html_handling "auto-trailing-slash" is what Quartz expects: /glossary/oifm serves +// glossary/oifm.html and /glossary/ serves glossary/index.html. Worker logic +// (comments, endpoints) can be added later without changing the site build. +{ + "name": "oidm-knowledge", + "compatibility_date": "2026-09-21", + "assets": { + "directory": "../public", + "html_handling": "auto-trailing-slash", + "not_found_handling": "404-page" + }, + "env": { + "dev": { + "name": "oidm-knowledge-dev", + "assets": { "directory": "../public", "html_handling": "auto-trailing-slash", "not_found_handling": "404-page" } + }, + "staging": { + "name": "oidm-knowledge-staging", + "assets": { "directory": "../public", "html_handling": "auto-trailing-slash", "not_found_handling": "404-page" } + } + } +} diff --git a/tools/diagrams/README.md b/tools/diagrams/README.md new file mode 100644 index 0000000..827c375 --- /dev/null +++ b/tools/diagrams/README.md @@ -0,0 +1,73 @@ +# Diagrams + +Diagrams in the bundle are Excalidraw files rendered to SVG and placed beside the document that embeds them (`knowledge//.excalidraw` and `.svg`). Mermaid is not used. + +## Source-of-truth rule + +Per diagram, one of two things is the source: + +- **Builder-generated.** `build_.py` in this directory writes the `.excalidraw` file. Edit the builder, not the file. Iterate by rendering and looking at the PNG. +- **Hand-edited.** Once anyone edits a `.excalidraw` file directly (in Excalidraw or as JSON), that file becomes the source. Retire its builder in the same change: delete `build_.py` and add the diagram to the list below. + +Hand-edited diagrams (builders retired): none yet. + +`build_pillars.py` takes a required `--seam a|b|c` choosing how the Data +Structures and Foundation Context bands meet (named attachments, dovetail, +shared membrane) and writes `knowledge/drafts/pillars-.excalidraw`. The +v3 seam it replaced -- an overlap crossed by twelve alternating threads -- was +rejected, so `knowledge/drafts/pillars.excalidraw` is stale until one of the +three is chosen and made the default. + +## Rendering + +From the excalidraw-diagram skill's references directory (it holds the Playwright environment): + +```bash +cd ~/.claude/skills/excalidraw-diagram/references +uv run python /home/talkasab/oidm-knowledge/tools/diagrams/render_excalidraw.py \ + /home/talkasab/oidm-knowledge/knowledge//.excalidraw \ + -o /home/talkasab/oidm-knowledge/sources/-vN.png \ + --svg /home/talkasab/oidm-knowledge/sources/-vN.svg +``` + +Then view the PNG, fix, re-render, until nothing crosses a box or a label and every label is readable. Copy the accepted SVG beside the document, drop the fixed `width`/`height` attributes on the root `` and add `style="max-width:100%;height:auto"`, and embed it with an image line plus an italic source line (see `knowledge/overview/architecture.md`). + +`render_template.html` loads the Excalidraw library from esm.sh pinned to 0.18.0; the unpinned build had a broken dependency. + +## Measuring text instead of estimating it + +`excalib.text()` estimates a string's width at `0.58 * fontSize` per character. That is fine for a label floating in open space, but it is wrong by 20-40% for real strings, so a layout packed to the pixel (a narrow canvas, a label that must not touch a lane) cannot be built on it. Measure instead: the render font is `Helvetica, Segoe UI Emoji` as resolved by headless Chromium, so a few lines of Playwright give exact widths. + +```python +# from the excalidraw-diagram skill's references directory, under `uv run` +from playwright.sync_api import sync_playwright +with sync_playwright() as p: + pg = p.chromium.launch(headless=True).new_page(); pg.goto("about:blank") + print(pg.evaluate("""(ss) => { const c = document.createElement('canvas').getContext('2d'); + c.font = '13px Helvetica, Segoe UI Emoji'; + return Object.fromEntries(ss.map(s => [s, c.measureText(s).width])); }""", + ["CT Chest WO contrast", "upper abdomen"])) +``` + +Size a box as `measured width + 20` (`box()` pads 10px each side) and pass the measured width to any helper that draws a backing box behind a label (`build_foundation_network.py` has `label_w` / `w` parameters for this). A label backing box that sits inside a tinted band should use the band's fill, not white. + +## Inspecting a render closely + +Viewing the whole PNG hides label-on-edge collisions. `render_template.html` can be driven directly to screenshot clipped regions at 2x: render as usual, then take the `#root svg` element's bounding box, divide its width by the `viewBox` width to get the scale, and screenshot `clip` rectangles expressed in diagram coordinates times that scale (the export adds 10px of padding on each side). Note that `exportToSvg` sizes the element by the browser's device pixel ratio while the `viewBox` stays in diagram units, so the scale must be read, not assumed. + +`excalib.py` holds the shared palette and element helpers (boxes, bound text, straight and elbowed arrows, lines, and image elements for embedded icons -- see below). + +## Icons + +Project logos and square marks are available in `knowledge/assets/brand/`. +Use the original SVGs with `excalib.image()` and omit its `color` argument. +The [brand notes](../../docs/brand/README.md) give paths, proportions, and +embedding examples. Use these marks to identify the projects in a diagram. + +`excalib.image(id_, x, y, w, h, svg_path, color=None)` embeds an SVG file as an Excalidraw `image` element: it reads the file, optionally replaces every `currentColor` in the SVG source with a hex string (so one licensed icon file can be recolored per diagram without editing the file on disk), base64-encodes it into the document's top-level `files` map, and adds an element referencing that `fileId`. `render_template.html` already passed `files` through to `exportToSvg` before this was added, so no renderer change was needed to make icons show up in the rendered PNG/SVG -- this was checked, not assumed. + +Icon source files live in `tools/diagrams/icons/`, kept as unmodified originals (recoloring happens at build time, not by editing the files). `icons/LICENSES.md` records where each one came from and its license. When a diagram needs an icon that isn't already there, prefer an existing open set already used in the bundle (Health Icons, Lucide) over adding a new one, to keep icon style consistent across diagrams; add the new file, credit it in `LICENSES.md`, and note in the relevant `build_.py` docstring which set was used for which slot. + +## Node shape and color conventions (2026-09-30) + +Node kinds share one palette across figures (see excalib): FindingClass and Diagnosis green (Diagnosis darker), Grouping pale green with dashed stroke, AssessmentScheme purple OVAL (never a diamond, which reads as a flowchart decision), AnatomicLocation blue, exam types yellow, Modality grey, DataElement light rose, Measurement light violet, Subspecialty and other metadata Concept nodes grey-violet. Arrowheads are small solid triangles (excalib.tri_head). Edge labels use the schema's committed relationship names in 13px on boxed labels. diff --git a/tools/diagrams/build_architecture.py b/tools/diagrams/build_architecture.py new file mode 100644 index 0000000..cff3936 --- /dev/null +++ b/tools/diagrams/build_architecture.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +"""Build the OIDM architecture diagram (three layers joined by identifiers). +Three adjacent stacked bands (applications, data structures, semantic +foundation); Imaging Persona and CDEs-at-RadElement are compact second rows +within their own band (persona under Imaging Problem List at column 3, CDEs +under Finding models at column 1) rather than a separate trailing section, +with captions beside them instead of incoming arrows -- since neither sits at +column 1/2, they never block the foundation->data join arrows, which stay in +columns 1-2. Exam types -> Exam Finding List is also a caption, not an arrow, +to remove the one join that had no clean column-aligned path. Title/subtitle +and the "Also:" applications note are left for the page text. +Output: knowledge/overview/architecture.excalidraw; render with render_excalidraw.py.""" +from excalib import PRIMARY, SECONDARY, TERTIARY, EXTERNAL, PLANNED, TITLE, SUBTITLE, BODY, LINE, els, base, text, box, find, arrow, hline, save + +# ---------------------------------------------------------------- layout +# Box labels are hand-wrapped (Excalidraw does not auto-wrap bound text) so +# no line exceeds ~21 chars; that lets boxes stay narrow at 900px width. +W, GAP = 190, 26 # box width, horizontal gap between boxes in a row +C1 = 80 # left gutter (80px) -- wide clearance for the Forge -> Finding models line and the band labels, which both start at C1 +C2 = C1 + W + GAP # 296 +C3 = C2 + W + GAP # 512 +FORGE_X = 0 # off the C1 grid so its arrow can drop straight down the gutter, clear of Observation +CONTENT_W = C3 + W # 702 + +H_APP, H, H_EXT = 100, 80, 100 # row heights: 4-line boxes (app row, CDE row) need more height than 3-line boxes +ROW_GAP = 90 # band-to-band vertical gap +ROW_GAP2 = 60 # row1->row2 gap within a band (no arrow crosses it, so it can be tighter) +LABEL_BUF = 85 # extra clearance above the data-structures row so "per exam"/"per patient" have room above the boxes, not on them + +Y_APP = 40 +Y_DATA_HDR = Y_APP + H_APP + ROW_GAP # where the divider + "DATA STRUCTURES" label sit +Y_DATA = Y_DATA_HDR + LABEL_BUF # boxes start lower than usual, leaving that extra strip clear +Y_DATA2 = Y_DATA + H + ROW_GAP2 # Imaging Persona row (column 3 only) +Y_FOUND_HDR = Y_DATA2 + H + ROW_GAP +Y_FOUND = Y_FOUND_HDR + 24 +Y_FOUND2 = Y_FOUND + H + ROW_GAP2 # CDEs row (column 1 only) + +# ---------------------------------------------------------------- applications +els.append(text("band_app", C1, Y_APP - 24, "APPLICATIONS", size=14, color=SUBTITLE)) +box("forge", FORGE_X, Y_APP, W, H_APP, "Finding Model Forge\nauthoring wizard\nfmf.oidm.org", SECONDARY) +box("extract", C2, Y_APP, W, H_APP, "Report extraction\nplatform\nLLM extraction\nand coding (dev)", SECONDARY) +box("viewer", C3, Y_APP, W, H_APP, "Imaging Problem\nList viewer\nimaging-problem-\nlist.pages.dev", SECONDARY) + +# ---------------------------------------------------------------- data structures (adjacent to applications) +hline("div1", 0, Y_DATA_HDR - 6, CONTENT_W) +els.append(text("band_data", C1, Y_DATA_HDR, "DATA STRUCTURES", size=14, color=SUBTITLE)) +box("obs", C1, Y_DATA, W, H, "Observation\nfinding + location\n+ attributes", PRIMARY) +box("efl", C2, Y_DATA, W, H, "Exam Finding List\nall observations\nof one exam", PRIMARY) +box("ipl", C3, Y_DATA, W, H, "Imaging Problem List\none patient, grouped\nby finding", PRIMARY) +# labels sit in the LABEL_BUF strip above the boxes, clear of both the band +# label above and the box tops below (checked: label bottom edge stays ~25px +# above the box top, well clear of the rounded corners) +arrow("a_obs_efl", "obs", "right", "efl", "left", "per exam", label_dy=-88) +arrow("a_efl_ipl", "efl", "right", "ipl", "left", "per patient", label_dy=-88) + +# applications -> data structures: both adjacent rows, short vertical arrows. +# These lines got taller once LABEL_BUF pushed the data-structures row down, +# so the labels need more upward offset to clear the div1 divider below them. +arrow("a_extract_efl", "extract", "bottom", "efl", "top", "extracts from\nreports", label_dy=-50) +arrow("a_ipl_viewer", "ipl", "top", "viewer", "bottom", "renders", label_dy=-32) + +# Imaging Persona: second data-structures row, under Imaging Problem List +# (column 3) so it never sits over columns 1-2, where the foundation->data +# joins run -- caption to its left instead of an incoming arrow. +box("persona", C3, Y_DATA2, W, H, "Imaging Persona\nplus clinical\ncontext (concept)", PLANNED, dashed=True) +# caption BELOW persona, not beside: column 3 is clear all the way down, but +# columns 1-2 at this row height are the foundation->data join corridor +els.append(text("persona_note", C3, Y_DATA2 + H + 14, "goal: extends the Imaging\nProblem List with context", size=13, color=PLANNED[2])) + +# ---------------------------------------------------------------- semantic foundation (adjacent to data structures) +hline("div2", 0, Y_FOUND_HDR - 6, CONTENT_W) +els.append(text("band_found", C1, Y_FOUND_HDR, "SEMANTIC FOUNDATION", size=14, color=SUBTITLE)) +box("fm", C1, Y_FOUND, W, H, "Finding models\nOIFM_ / OIFMA_\ncodes", TERTIARY) +box("al", C2, Y_FOUND, W, H, "Anatomic locations\nRadLex RID codes", TERTIARY) +box("et", C3, Y_FOUND, W, H, "Exam types\nLOINC / Playbook\n(planned)", PLANNED, dashed=True) +els.append(text("et_note", C3, Y_FOUND + H + 14, "supplies the LOINC\nexam code on the\nExam Finding List", size=13, color=PLANNED[2])) + +# foundation -> data: both adjacent rows, so every join is a short, direct +# line -- straight vertical where columns line up, a short one-column +# diagonal where two foundation boxes both feed Observation. Labels sit to +# the RIGHT of their line (away from the left-gutter "authors" arrow). +# fm->obs binds at 0.92 across the box (not centered): centered, this line +# would run at column 1's midpoint, straight through the "SEMANTIC +# FOUNDATION" label text above it (the label is ~162px wide, wider than half +# the 190px box) -- shifted right, it clears the label with room to spare. +arrow("a_fm_obs", "fm", "top", "obs", "bottom", "OIFM and\nOIFMA codes", s_frac=0.92, d_frac=0.92, label_dx=-70, label_dy=-40) +arrow("a_al_obs", "al", "top", "obs", "bottom", "RID", d_frac=0.8, label_dx=44, label_dy=-40) + +# Forge (applications) authors finding models (semantic foundation), two +# rows down -- routed through the left gutter (x lung, +pleural effusion -> pleural space) are plumb-straight drops: their sources and +targets share an x-coordinate on purpose. Because of that, "thorax" is offset +left of "lung" (it doesn't need to share lung's column, just sit near it) so +it doesn't block the straight drop coming down through its own row. + + +--------------------------------------------------------+ + | Band 1 -- Sector 1: Finding / diagnosis definitions | + +--------------------------------------------------------+ + (gap, short "scoped to" verticals cross here) + +--------------------------------------------------------+ + | Band 2 -- Sector 2: Anatomic locations | + +--------------------------------------------------------+ + (gap, short "covers"/"included"/"edge (usually)" verticals) + +--------------------------------------------------------+ + | Band 3 -- Sector 3: Exam types | + +--------------------------------------------------------+ + +--------------------------------------------------------+ + | Legend | + +--------------------------------------------------------+ + +The only long edges are pulmonary nodule -> CT Chest ("seen on") and +pulmonary nodule -> CT Thoracic spine ("possibly seen on", dashed), which +run down the left and right margins respectively, outside all three bands, +each in its own lane, jogging in only at the very end. + +v8 change: the assessment-scheme node (Lung-RADS) is an oval, not a diamond -- +a diamond reads as a flowchart decision. Same fill, stroke and size envelope; +the legend swatch follows. Its incoming "assessed by" edge now aims at the +oval's leftmost point (d_frac 0.5), which is the one place on that side where +the bounding box and the ellipse's boundary coincide. + +v7 change: every arrowhead is a solid filled triangle drawn by +excalib.tri_head() at a fixed size, matching the two-planes figure -- grey +within-sector, red cross-sector, dashed edges included. Excalidraw's built-in +heads scale with strokeWidth, which made the thick cross-sector edges carry +heads half again too big. + +v6 changes: canvas narrowed from 1200px to 955px. Every x-coordinate below +was recomputed from measured text widths rather than estimated -- the +rendering font is `Helvetica, Segoe UI Emoji` as resolved by headless +Chromium, and the widths used here came from canvas `measureText` in that +same browser (see the note on Sector 3 below). Box widths are therefore +`measured text width + 20` (box() pads 10px each side), and the layout is +packed to a few pixels of slack in places, so changing a label's TEXT means +re-measuring, not just nudging a coordinate. + +Sector 3 and the "two lines per Playbook member" request: the five Playbook +members cannot all carry their name on one line inside a <=960px canvas. +Their names measure 131 / 137 / 188 / 243 / 187 px at 13px, so five one-line +names plus box padding and gaps need ~1030px of row; the row has ~830px +between the grey "further nodes" dots and the right margin lane. The three +"CT Chest ..." members do fit on one line and are set that way (name, then +code); "CTA Chest vessels WO and W contrast IV" and "CT Thoracic spine W +contrast IV" wrap their name over two lines and keep the code on the last +line. Shrinking text below 13px or abbreviating the Playbook names were the +only other ways to make all five one-line, and both were rejected. + +Output: knowledge/drafts/foundation-network.excalidraw; render with +render_excalidraw.py (see tools/diagrams/README.md). +""" +from __future__ import annotations + +from excalib import (TITLE, SUBTITLE, BODY, LINE, els, base, text, box, find, edge_point, + arrow, tri_head, save) + +# ---------------------------------------------------------------- palette +FINDING = ("#d1fae5", "#059669", "#064e3b") # light green: finding +DIAGNOSIS = ("#6ee7b7", "#059669", "#064e3b") # darker green: diagnosis (subtly different fill) +ASSESS = ("#e9d5ff", "#7e22ce", "#4c1d95") # purple oval: assessment scheme +ANATOMY = ("#bfdbfe", "#1d4ed8", "#1e3a8a") # light blue: anatomic location +EXAM = ("#fde68a", "#b45309", "#78350f") # light amber: exam type +GREY = ("#e5e7eb", "#9ca3af", "#4b5563") # unlabeled / de-emphasized nodes +CROSS = "#be123c" # thick colored line: cross-sector relationship +BAND_BG = "#f8fafc" # sector band fill; label backings inside a band use it + +# Arrowheads are solid filled triangles drawn by excalib.tri_head(), matching +# the two-planes figure, not Excalidraw's built-in open heads: those are sized +# from the line's strokeWidth, so the thick cross-sector edges were forced to +# carry outsized heads. These are about 60% of that size and set independently +# of line weight. HEAD_X: cross-sector (red); HEAD_W: within-sector (grey). +HEAD_X, HEAD_W = 13.0, 10.0 + +# ---------------------------------------------------------------- helpers (local to this builder) +def region(id_: str, x: float, y: float, w: float, h: float, title: str) -> None: + """Faint background rectangle with a title, drawn first so nodes sit on top.""" + r = base("rectangle", id_, x, y, w, h, "#e2e8f0", BAND_BG, sw=1) + r["roundness"] = {"type": 3} + els.append(r) + els.append(text(id_ + "_title", x + 14, y + 10, title, size=15, color=TITLE)) + + +def edge(id_: str, *args, head: float = HEAD_W, **kwargs) -> None: + """excalib.arrow() with its open head replaced by a solid tri_head().""" + arrow(id_, *args, **kwargs) + a = find(id_) + a["endArrowhead"] = None + tip = (a["x"] + a["points"][-1][0], a["y"] + a["points"][-1][1]) + frm = (a["x"] + a["points"][-2][0], a["y"] + a["points"][-2][1]) + tri_head(id_ + "_h", tip, frm, a["strokeColor"], size=head) + + +def dot(id_: str, cx: float, cy: float, r: float, fill=GREY[0], stroke=GREY[1]) -> dict: + e = base("ellipse", id_, cx - r, cy - r, 2 * r, 2 * r, stroke, fill, sw=1) + els.append(e) + return e + + +def oval(id_: str, x: float, y: float, w: float, h: float, label: str, colors, size=13) -> dict: + """An ellipse node, inscribed in the given box. The bound text keeps clear + of the curve by sitting in the middle 60% of the width and 36% of the + height, where the ellipse is at or near its full extent.""" + fill, stroke, tcolor = colors + d = base("ellipse", id_, x, y, w, h, stroke, fill) + t = text(id_ + "_t", x + w * 0.2, y + h * 0.32, label, size=size, color=tcolor, align="center", w=w * 0.6, container=id_) + t["height"] = h * 0.36 + d["boundElements"] = [{"id": t["id"], "type": "text"}] + els.extend([d, t]) + return d + + +def faint(id_: str, x1: float, y1: float, x2: float, y2: float) -> None: + ln = base("arrow", id_, x1, y1, x2 - x1, y2 - y1, "#9ca3af", "transparent", sw=1) + ln.update({"points": [[0, 0], [x2 - x1, y2 - y1]], "startBinding": None, "endBinding": None, + "startArrowhead": None, "endArrowhead": None, "boundElements": None, "opacity": 40}) + els.append(ln) + + +def mpath(id_: str, pts: list[tuple[float, float]], color: str, dashed=False, sw=3, + label: str | None = None, label_pos: tuple[float, float] | None = None, label_color=BODY, + label_w: float | None = None, label_bg_color: str = "#ffffff", head: float = HEAD_X) -> None: + """Multi-point routed arrow (elbow arrow() only supports 3 points). + + label_w: MEASURED text width in px. The backing box is sized from it, so + passing a measured value (rather than a char-count estimate) is what keeps + a margin-lane label from pushing the canvas wider than the bands. + label_bg_color: BAND_BG for a label that lands inside a sector band, white + for one in a band gap -- a white patch on the tinted band is visible. + """ + x0, y0 = pts[0] + rel = [[px - x0, py - y0] for px, py in pts] + ar = base("arrow", id_, x0, y0, pts[-1][0] - x0, pts[-1][1] - y0, color, "transparent", dashed=dashed, sw=sw) + ar.update({"points": rel, "startBinding": None, "endBinding": None, + "startArrowhead": None, "endArrowhead": None, "boundElements": None}) + els.append(ar) + tri_head(id_ + "_h", pts[-1], pts[-2], color, size=head) + if label: + lw = label_w if label_w is not None else max(len(ln_) for ln_ in label.split("\n")) * 13 * 0.62 + lx, ly = label_pos + lh = len(label.split("\n")) * 13 * 1.25 + bg = base("rectangle", id_ + "_bg", lx - lw / 2 - 5, ly - 3, lw + 10, lh + 6, "transparent", label_bg_color, sw=0) + els.append(bg) + els.append(text(id_ + "_l", lx - lw / 2, ly, label, size=13, color=label_color, align="center", w=lw)) + + +def label_bg(id_: str, cx: float, cy: float, label: str, w: float, size=13, color=BODY, + bg_color: str = "#f8fafc") -> None: + """A standalone edge label with an opaque backing box so it never sits on + top of node text or an edge. w: MEASURED text width in px (see mpath). + bg_color defaults to the band fill, since every one of these sits inside a + band; pass white for a label placed in a band gap.""" + lines = label.split("\n") + bw = w + 10 + bh = len(lines) * size * 1.25 + 6 + bg = base("rectangle", id_ + "_bg", cx - bw / 2, cy - bh / 2, bw, bh, "transparent", bg_color, sw=0) + els.append(bg) + els.append(text(id_ + "_t", cx - bw / 2 + 5, cy - bh / 2 + 3, label, size=size, color=color, align="center", w=w)) + + +# ---------------------------------------------------------------- canvas / bands +CONTENT_W = 935 # + 2 x 10px export padding = 955px canvas +LANE_L = 8 # "seen on" lane, left margin +LANE_R = 912 # "possibly seen on" lane, just inside the right edge + +BAND1 = dict(x=0, y=70, w=CONTENT_W, h=300) # bottom 370 +GAP1 = 70 +BAND2 = dict(x=0, y=BAND1["y"] + BAND1["h"] + GAP1, w=CONTENT_W, h=370) # 440, bottom 810 +GAP2 = 70 +BAND3 = dict(x=0, y=BAND2["y"] + BAND2["h"] + GAP2, w=CONTENT_W, h=300) # 880, bottom 1180 +LEGEND = dict(x=0, y=BAND3["y"] + BAND3["h"] + 30, w=CONTENT_W, h=190) # 1210 + +els.append(text("maintitle", 0, 8, "Foundation Context: a mini-network", size=20, color=TITLE)) +els.append(text("subtitle", 0, 34, "three sectors of shared, curated knowledge — illustrative, not exhaustive", size=13, color=SUBTITLE)) + +region("rA", **BAND1, title="Sector 1 — Finding / diagnosis definitions") +region("rB", **BAND2, title="Sector 2 — Anatomic locations") +find("rB_title")["x"] += 40 # keep clear of the "seen on" lane running down x=8 +region("rC", **BAND3, title="Sector 3 — Exam types") +els.append(text("rC_tag", BAND3["x"] + 14, BAND3["y"] + 30, "(content to come)", size=13, color=BODY)) +region("rL", **LEGEND, title="Legend") + +# ================================================================== BAND 1: Finding / diagnosis definitions +# Row 1, left to right: lung cancer, pulmonary nodule, Lung-RADS, pleural +# effusion. Row 2, under pulmonary nodule: the three subtypes, spread wide for +# label room; solid component hangs below-right of part-solid, offset so it +# doesn't block pulmonary nodule's straight column down to lung. Grey "more" +# nodes sit at the far left of row 2. +COL_PN = 345 # pulmonary nodule / lung share this column (straight drop) +COL_PE = 708 # pleural effusion / pleural space share this one + +lung_cancer = box("lung_cancer", 20, 110, 140, 42, "lung cancer", DIAGNOSIS, size=14) +pulm_nodule = box("pulm_nodule", 272, 100, 146, 54, "pulmonary\nnodule", FINDING, size=14) # center 345 +lungrads = oval("lungrads", 492, 95, 125, 75, "Lung-RADS", ASSESS, size=13) +pleural_effusion = box("pleural_effusion", 637, 110, 142, 42, "pleural effusion", FINDING, size=13) # center 708 + +solid_nodule = box("solid_nodule", 120, 210, 105, 70, "solid\npulmonary\nnodule", FINDING, size=13) +partsolid_nodule = box("partsolid_nodule", 235, 210, 100, 70, "part-solid\npulmonary\nnodule", FINDING, size=13) +nonsolid_nodule = box("nonsolid_nodule", 530, 210, 100, 70, "non-solid\npulmonary\nnodule", FINDING, size=13) +solid_component = box("solid_component", 365, 295, 118, 38, "solid component", FINDING, size=13) + +dot("gA1", 50, 235, 15) +dot("gA2", 75, 270, 13) +dot("gA3", 55, 295, 12) +faint("fA_12", 50, 235, 75, 270) +faint("fA_13", 50, 235, 55, 295) +faint("fA_into", 75, 270, 120, 245) # gA2 -> solid pulmonary nodule (nearest labeled node) + +# The two left-hand "subtype of" labels sit BELOW the "seen on" lane's top +# horizontal (y=166) and to the LEFT of the red column at x=345; the right-hand +# one sits ABOVE the "possibly seen on" lane's top horizontal (y=190). That is +# what keeps the red pulmonary-nodule -> lung vertical off all three of them. +edge("e_solid_sub", "solid_nodule", "top", "pulm_nodule", "bottom", None, s_frac=0.5, d_frac=0.15) +edge("e_partsolid_sub", "partsolid_nodule", "top", "pulm_nodule", "bottom", None, s_frac=0.4, d_frac=0.5) +edge("e_nonsolid_sub", "nonsolid_nodule", "top", "pulm_nodule", "bottom", None, s_frac=0.2, d_frac=0.9) +# All three "subtype of" labels are white-backed and placed by hand: their own +# edges are diagonals that would otherwise run through the text, and the left +# two have to stay clear of the "seen on" lane above (y=166) and the red +# pulmonary-nodule column at x=345. +label_bg("l_solid_sub", 205, 189, "subtype of", 60.0) +label_bg("l_partsolid_sub", 290, 189, "subtype of", 60.0) +label_bg("l_nonsolid_sub", 464, 169, "subtype of", 60.0) # clear of the oval's lower-left curve +edge("e_partsolid_comp", "partsolid_nodule", "bottom", "solid_component", "top", "has component", s_frac=0.6, d_frac=0.3, + label_size=13, label_dx=60) +edge("e_manifest", "lung_cancer", "right", "pulm_nodule", "left", "may manifest as", s_frac=0.4, d_frac=0.35, + label_size=13, label_dy=-26) +edge("e_progress", "nonsolid_nodule", "left", "partsolid_nodule", "right", "may progress to", s_frac=0.5, d_frac=0.5, + dashed=True, label_size=13, label_dy=-24) +edge("e_assessed", "pulm_nodule", "right", "lungrads", "left", "assessed by", s_frac=0.25, d_frac=0.5, + label_size=13, label_dx=6, label_dy=-30) # -30: rides above the oval's upper-left curve +# pleural_effusion intentionally has no edge to pulm_nodule -- just a neighbor +# solid_component intentionally has no cross-sector "scoped to" edge -- only +# pulmonary nodule, lung cancer, and pleural effusion are scoped to anatomy + +# ================================================================== BAND 2: Anatomic locations +# thorax sits center-left, offset from lung's own column, on purpose: it leaves +# x=345 clear so pulmonary nodule's edge can drop straight into lung without +# detouring around thorax, AND leaves x=300 clear for lung cancer's arrival at +# lung's top-left. pleural space is pulled right, under pleural effusion, so +# ITS edge can also be a straight drop. +BY = BAND2["y"] +thorax = box("thorax", 160, BY + 40, 110, 42, "thorax", ANATOMY, size=14) # 160-270 +pleural_space = box("pleural_space", 654, BY + 40, 108, 44, "pleural\nspace", ANATOMY, size=13) # center 708 +upper_abdomen = box("upper_abdomen", 777, BY + 40, 115, 42, "upper abdomen", GREY, dashed=True, size=13) # ends 892, lane at 912 + +right_lung = box("right_lung", 150, BY + 110, 105, 40, "right lung", ANATOMY, size=13) +lung = box("lung", 280, BY + 110, 130, 42, "lung", ANATOMY, size=14) # center 345 +left_lung = box("left_lung", 435, BY + 110, 105, 40, "left lung", ANATOMY, size=13) + +# Row 3 is pushed down to BY+220 to open a clear horizontal corridor at BY+200 +# for the labels, and the gap between the two row-3 boxes (278..310) is the +# corridor the red "included" edge climbs to reach lung's bottom-left. +upper_lobe = box("upper_lobe", 140, BY + 220, 138, 42, "upper lobe of\nright lung", ANATOMY, size=13) +lung_parenchyma = box("lung_parenchyma", 310, BY + 220, 120, 44, "lung\nparenchyma", ANATOMY, size=13) + +dot("gB1", 50, BY + 250, 15) +dot("gB2", 75, BY + 285, 13) +dot("gB3", 55, BY + 310, 12) +faint("fB_12", 50, BY + 250, 75, BY + 285) +faint("fB_13", 50, BY + 250, 55, BY + 310) +faint("fB_into", 75, BY + 285, 140, BY + 245) # gB2 -> upper lobe of right lung (nearest labeled node) + +edge("e_rlung_lung", "right_lung", "right", "lung", "left", None, s_frac=0.5, d_frac=0.3) +edge("e_llung_lung", "left_lung", "left", "lung", "right", None, s_frac=0.5, d_frac=0.7) +edge("e_ulobe_rlung", "upper_lobe", "top", "right_lung", "bottom", None, s_frac=0.4, d_frac=0.4) +# lung parenchyma's edge runs into lung's BOTTOM-RIGHT (x=394), leaving the +# space under lung's center free for "laterality", which now sits between the +# red "included" arrowhead (x=294) and that edge -- on neither of them. +edge("e_parenchyma_lung", "lung_parenchyma", "top", "lung", "bottom", None, s_frac=0.7, d_frac=0.88) +edge("e_pspace_thorax", "pleural_space", "left", "thorax", "right", None, s_frac=0.5, d_frac=0.5) + +label_bg("l_ulobe_rlung", 197, BY + 172, "contained by", 73.7) +label_bg("l_laterality", 345, BY + 172, "laterality", 48.4) +label_bg("l_parenchyma_lung", 487, BY + 172, "part of", 36.9) +label_bg("l_pspace_thorax", 480, BY + 55, "contained by", 73.7) + +# ================================================================== BAND 3: Exam types +# Row 1: CT Chest (preferred, to come). Row 2, left to right: the four real +# Playbook entries with codes, then CT Thoracic spine (dashed) at the far +# right; grey "more" nodes at the far left. "Region imaged" hangs below +# "CT Chest W contrast IV". Box widths are measured-text + 20 and gaps are 8px +# -- see the module docstring on why only three of the five get a one-line name. +CY = BAND3["y"] +ct_chest = box("ct_chest", 285, CY + 40, 230, 60, "CT Chest\npreferred (to come)", EXAM, size=14) + +ct_wo = box("ct_wo", 90, CY + 130, 152, 70, "CT Chest WO contrast\n29252-4", EXAM, size=13) +ct_w = box("ct_w", 250, CY + 130, 158, 70, "CT Chest W contrast IV\n24628-0", EXAM, size=13) +ct_wo_w = box("ct_wo_w", 416, CY + 130, 209, 70, "CT Chest WO and W contrast IV\n30598-7", EXAM, size=13) +ct_cta = box("ct_cta", 633, CY + 130, 151, 70, "CTA Chest vessels\nWO and W contrast IV\n30804-9", EXAM, size=13) +ct_thoracic_spine = box("ct_thoracic_spine", 792, CY + 130, 126, 70, "CT Thoracic spine\nW contrast IV\n24979-7", GREY, dashed=True, size=13) + +region_imaged = box("region_imaged", 266, CY + 220, 126, 40, "Region imaged:\nThorax (RID1243)", GREY, size=13) + +dot("gC1", 42, CY + 165, 14) +dot("gC2", 64, CY + 198, 12) +faint("fC_12", 42, CY + 165, 64, CY + 198) +faint("fC_into", 42, CY + 165, 90, CY + 165) # gC1 -> CT Chest WO contrast (nearest labeled node) + +edge("e_wo_family", "ct_wo", "top", "ct_chest", "bottom", "member of family", s_frac=0.5, d_frac=0.1, + label_size=13, label_dx=-15, label_dy=-20) +edge("e_w_family", "ct_w", "top", "ct_chest", "bottom", None, s_frac=0.5, d_frac=0.35) +edge("e_wo_w_family", "ct_wo_w", "top", "ct_chest", "bottom", None, s_frac=0.5, d_frac=0.65) +edge("e_cta_family", "ct_cta", "top", "ct_chest", "bottom", None, s_frac=0.3, d_frac=0.9) +edge("e_w_regionimaged", "ct_w", "bottom", "region_imaged", "top", "Playbook part", s_frac=0.5, d_frac=0.5, + label_size=13, label_dx=107, label_dy=0) + +# ================================================================== cross-sector edges (thick, colored) +# Band 1 -> Band 2. +# "pulmonary nodule" and "lung" share x=345 -- a genuinely straight drop, clear +# of row 2's subtypes/solid component (both kept off that column), of all three +# "subtype of" labels, and of thorax (offset left of lung for exactly this +# reason). +mpath("cx_pn_lung", + [edge_point(find("pulm_nodule"), "bottom", 0.5), edge_point(find("lung"), "top", 0.5)], + color=CROSS, sw=3, label="scoped to", label_pos=(392, 396), label_w=56.4) + +# "lung cancer" drops from its own bottom, one right-angle jog at the midpoint +# of the band gap, then straight down into lung's top-left corner -- 45px left +# of pulmonary nodule's top-center arrival, so the two arrowheads land at +# separate points on "lung", not on top of each other. +mpath("cx_lc_lung", + [edge_point(find("lung_cancer"), "bottom", 0.5), (90, 405), (300, 405), + edge_point(find("lung"), "top", 0.15)], + color=CROSS, sw=3, label="scoped to", label_pos=(195, 393), label_w=56.4) + +# "pleural effusion" and "pleural space" also share an x (708) -- straight drop, +# since pleural space was pulled right specifically to sit under it. +mpath("cx_pe_pspace", + [edge_point(find("pleural_effusion"), "bottom", 0.5), edge_point(find("pleural_space"), "top", 0.5)], + color=CROSS, sw=3, label="scoped to", label_pos=(748, 286), label_w=56.4, label_bg_color=BAND_BG) + +# Band 3 -> Band 2 (pointing up): each uses its own left/right-margin column +# through band 2 so it clears the nodes directly in its way. "included" climbs +# the 32px corridor between the two row-3 boxes rather than cutting across the +# label row, so it crosses neither "contained by" nor the upper-lobe edge. +mpath("cx_ctchest_thorax", + [edge_point(find("ct_chest"), "top", 0.15), (319.5, 846), (100, 846), (100, BY + 61), + edge_point(find("thorax"), "left", 0.5)], + color=CROSS, sw=3, label="covers", label_pos=(66, 814), label_w=38.3) + +mpath("cx_ctchest_lung", + [edge_point(find("ct_chest"), "top", 0.3), (354, 868), (118, 868), (118, BY + 290), (294, BY + 290), + edge_point(find("lung"), "bottom", 0.11)], + color=CROSS, sw=3, label="included", label_pos=(160, 814), label_w=48.4) + +mpath("cx_ctchest_abdomen", + [edge_point(find("ct_chest"), "top", 0.85), (480.5, 846), (834.5, 846), + edge_point(find("upper_abdomen"), "bottom", 0.5)], + color=CROSS, dashed=True, sw=2, label="edge (usually)", label_pos=(834.5, 683), label_w=81.7, label_bg_color=BAND_BG) + +# The two long edges run down dedicated margin lanes outside all three bands, +# jogging in only once, right at the end. The right lane turns in above band 3's +# exam row, so CT Thoracic spine can use the full width up to the margin. +mpath("cx_pn_ctchest", + [edge_point(find("pulm_nodule"), "left", 1.0), (272, 166), (LANE_L, 166), (LANE_L, CY + 70), + edge_point(find("ct_chest"), "left", 0.5)], + color=CROSS, sw=3, label="seen on", label_pos=(48, 592), label_w=46.3, label_bg_color=BAND_BG) + +mpath("cx_pn_ctspine", + [edge_point(find("pulm_nodule"), "right", 1.0), (418, 190), (LANE_R, 190), (LANE_R, CY + 70), (855, CY + 70), + edge_point(find("ct_thoracic_spine"), "top", 0.5)], + color=CROSS, dashed=True, sw=2, label="possibly seen on", label_pos=(872, 392), label_w=96.8) + +# ================================================================== legend (full-width strip, 2 columns) +node_rows = [ + ("rect", FINDING, "finding"), + ("rect", DIAGNOSIS, "diagnosis"), + ("oval", ASSESS, "assessment scheme"), + ("rect", ANATOMY, "anatomic location"), + ("rect", EXAM, "exam type"), +] +edge_rows = [ + ("dot", GREY, "unlabeled grey = further nodes not shown"), + ("line", LINE, "solid edge = within-sector relationship"), + ("thick", CROSS, "colored thick edge = cross-sector relationship"), + ("dash", LINE, "dashed = possible or planned"), +] + +LX1, LX2 = LEGEND["x"] + 24, LEGEND["x"] + CONTENT_W // 2 + 10 +LY = LEGEND["y"] + 34 + +y = LY +for i, (kind, colors, label) in enumerate(node_rows): + fill, stroke, _tc = colors + if kind == "rect": + sw_el = base("rectangle", f"legA{i}", LX1, y, 22, 16, stroke, fill, sw=1) + sw_el["roundness"] = {"type": 3} + els.append(sw_el) + elif kind == "oval": + els.append(base("ellipse", f"legA{i}", LX1, y - 1, 24, 18, stroke, fill)) + els.append(text(f"legA{i}_l", LX1 + 32, y - 1, label, size=13, color=BODY, w=340)) + y += 28 + +y = LY +for i, (kind, color, label) in enumerate(edge_rows): + if kind == "dot": + dot(f"legB{i}", LX2 + 11, y + 8, 9, fill=color[0], stroke=color[1]) + elif kind == "line": + els.append(base("line", f"legB{i}", LX2, y + 8, 30, 0, color, "transparent", sw=2)) + find(f"legB{i}")["points"] = [[0, 0], [30, 0]] + find(f"legB{i}")["boundElements"] = None + elif kind == "thick": + els.append(base("line", f"legB{i}", LX2, y + 8, 30, 0, color, "transparent", sw=3)) + find(f"legB{i}")["points"] = [[0, 0], [30, 0]] + find(f"legB{i}")["boundElements"] = None + elif kind == "dash": + els.append(base("line", f"legB{i}", LX2, y + 8, 30, 0, color, "transparent", sw=2, dashed=True)) + find(f"legB{i}")["points"] = [[0, 0], [30, 0]] + find(f"legB{i}")["boundElements"] = None + els.append(text(f"legB{i}_l", LX2 + 40, y - 1, label, size=13, color=BODY, w=340)) + y += 28 + +save("knowledge/drafts/foundation-network.excalidraw") diff --git a/tools/diagrams/build_hierarchy.py b/tools/diagrams/build_hierarchy.py new file mode 100644 index 0000000..006a317 --- /dev/null +++ b/tools/diagrams/build_hierarchy.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +"""Build the data-structure ladder: Observation, Exam Finding List, Imaging +Problem List, Imaging Persona, with the fields each carries and its status. +Recomposed as a vertical ladder (Observation on top, Imaging Persona at the +bottom) with each box's field list set to its right, to fit a ~900px column. +Title/subtitle are left for the page text. +Output: knowledge/data-structures/hierarchy.excalidraw""" +from excalib import PRIMARY, SECONDARY, TERTIARY, EXTERNAL, PLANNED, TITLE, SUBTITLE, BODY, LINE, els, base, text, box, find, arrow, hline, save + +BOX_X = 0 +BOX_W, BOX_H = 250, 70 +TICK_W = 30 # short connector from box's right edge to its field list +FIELD_X = BOX_X + BOX_W + TICK_W +ARROW_GAP = 74 # vertical space between one box's bottom and the next box's top +FIELD_SIZE, STATUS_SIZE = 14, 13 +CONTENT_W = FIELD_X + 460 # keeps field-list lines within this width + +rows = [ + ("obs", "Observation\none finding, one exam", PRIMARY, False, + ["findingCode (OIFM)", "findingDescription", "anatomicLocation (RID)", "attributes[] with value codes", "reportText"], + "JSON in use; no published schema", SUBTITLE), + ("efl", "Exam Finding List\nevery observation of one exam", PRIMARY, False, + ["diagnosticReportId", "patientInfo", "examInfo with LOINC exam code", "findings[]: the observations"], + "JSON in use; no published schema", SUBTITLE), + ("ipl", "Imaging Problem List\none patient, keyed by finding", PRIMARY, False, + ["patient", "findings[] keyed by", "(findingCode, locationId)", "each with dated observations[]", "status derived, not stored"], + "JSON in use; grouping changed on dev", SUBTITLE), + ("persona", "Imaging Persona\nplus clinical context", PLANNED, True, + ["clinical context (orders, indications)", "medical baseline (problems, labs)", "specialized history (oncology)", "surgical history (operative, implants)"], + "concept only, no artifact", PLANNED[2]), +] +arrow_labels = ["per exam", "all exams", "with context"] + +y = 40 +prev_id = None +for i, (bid, label, colors, dashed, fields, status, status_color) in enumerate(rows): + box(bid, BOX_X, y, BOX_W, BOX_H, label, colors, dashed=dashed) + + field_h = len(fields) * FIELD_SIZE * 1.25 + fld_text = "\n".join(fields) + els.append(text(f"{bid}_fields", FIELD_X, y, fld_text, size=FIELD_SIZE, color="#374151")) + els.append(text(f"{bid}_status", FIELD_X, y + field_h + 8, status, size=STATUS_SIZE, color=status_color)) + tick = base("line", f"{bid}_tick", BOX_X + BOX_W, y + BOX_H / 2, TICK_W, 0, LINE, "transparent", sw=1) + tick.update({"points": [[0, 0], [TICK_W, 0]], "boundElements": None}) + els.append(tick) + + content_h = max(BOX_H, field_h + 8 + STATUS_SIZE * 1.25) + if prev_id is not None: + arrow(f"a_{prev_id}_{bid}", prev_id, "bottom", bid, "top", arrow_labels[i - 1], + label_dx=BOX_W / 2 + 14, label_dy=-12, dashed=dashed) + prev_id, y = bid, y + content_h + ARROW_GAP + +Y_NOTE = y - ARROW_GAP + 40 +els.append(text("note", 0, Y_NOTE, "Codes come from the semantic foundation: OIFM and OIFMA identifiers from finding\nmodels, RID from anatomic locations, LOINC for the exam.", size=13, color=BODY)) + +save("knowledge/data-structures/hierarchy.excalidraw") diff --git a/tools/diagrams/build_nodule_neighborhood.py b/tools/diagrams/build_nodule_neighborhood.py new file mode 100644 index 0000000..f3bfc64 --- /dev/null +++ b/tools/diagrams/build_nodule_neighborhood.py @@ -0,0 +1,411 @@ +#!/usr/bin/env python3 +"""Build the "pulmonary nodule neighborhood" diagram (v3). + +One FindingClass and everything that hangs off it, drawn as nodes and labeled +edges. The point of the figure is the SHAPE of the neighborhood -- which kinds +of thing attach to a finding definition, and by which named relationship -- +not the content of any one node, so every node carries only its name plus its +node kind on a small second line. + +v2 IS ILLUSTRATIVE, NOT A DUMP OF THE GRAPH +------------------------------------------- +v1 drew only edges committed to the CDE graph. v2 reflects updates the +project's clinical expert intends for that graph, so some nodes, names and +edges below do not exist at the pin. The figure says so on a caption line +under the legend, and the two lists in the next section say exactly which is +which. Nothing here was invented by the builder: every "intended" item came +from the project lead by way of the brief for this version. + +SOURCE OF THE COMMITTED DATA +---------------------------- +~/ACR-RSNA-CDEs, branch next-gen-2026, pinned commit +b541b74c22a33b64834309244569a60d06de79e4, file (read with `git show`, i.e. +the committed copy, not the working tree): + + docs/next-gen-schema/alpha/graph/definition-graph.json + +Centre node: FC-000005 "pulmonary nodule" (node: FindingClass). + +COMMITTED AT b541b74 -- 15 of the 22 edges drawn +------------------------------------------------ + SUBTYPE_OF 2 FC-000006 solid pulmonary nodule -> FC-000005 + FC-000007 part-solid pulmonary nodule -> FC-000005 + HAS_COMPONENT 1 FC-000007 -> FC-000009 solid component of part-solid + pulmonary nodule (the graph also carries the inverse + COMPONENT_OF, not drawn) + HAS_DATA_ELEMENT 3 FC-000005 -> DE-000001 presence, DE-000004 + calcification, DE-000015 interval change + HAS_MEASUREMENT 2 FC-000005 -> MS-000003 mean diameter, + MS-000001 long-axis diameter + ASSESSED_BY 1 FC-000005 -> AS-000001 Lung-RADS + SCOPED_TO 1 FC-000005 -> RID1301 lung + props: kind=region, strength=required + SEEN_ON 3 FC-000005 -> CT, XR, MR (the graph also has US and + PET on this finding; those two are not drawn) + IN_SUBSPECIALTY 1 FC-000005 -> CH + MAY_MANIFEST_AS 0 see below -- both drawn manifestation edges are + intended, neither is committed in the form drawn. + plus SUBTYPE_OF 2 drawn but NOT committed (see below), for 22 total. + +INTENDED, NOT AT THE PIN -- 7 edges and the nodes they need +------------------------------------------------------------ + Renamed data elements. "composition" replaces DE-000002 attenuation on this + finding, and "margin" replaces DE-000039 pulmonary margin. Both + HAS_DATA_ELEMENT edges are committed under the old names. A separate node + already named "composition" (DE-000006) exists in the graph for other + findings, so the rename points at a name the vocabulary already uses. + Dropped measurement. MS-000006 lesion count is a committed HAS_MEASUREMENT + target of FC-000005; removing it is the intended change. + Renamed subtype. "ground glass nodule" renames FC-000008 non-solid + pulmonary nodule. FC-000025 "ground-glass opacity" is a DIFFERENT node + that stays where it is. + Grouping node. "pulmonary parenchymal abnormality" and BOTH SUBTYPE_OF + edges into it (from pulmonary nodule and from pulmonary granuloma) are + intended. The alpha contains no Grouping nodes at all at this commit. + Diagnosis "pulmonary neoplasm" and its MAY_MANIFEST_AS -> pulmonary nodule. + No such node exists at the pin. The committed diagnoses that reach this + family are DX-000004 lung cancer, which manifests as all three SUBTYPES, + and DX-000009 metastatic disease, the only one with a direct edge into + FC-000005 (that was the diagnosis v1 drew). + Retargeted manifestation. DX-000002 pulmonary granuloma is committed, but + its MAY_MANIFEST_AS points at FC-000006 solid pulmonary nodule, not at + the parent. Pointing it at FC-000005 is the intended change. + AssessmentScheme "Fleischner criteria" and its ASSESSED_BY edge. Not at the + pin; the five committed schemes are Lung-RADS, ACR TI-RADS, LI-RADS, + Bosniak classification and BI-RADS assessment. + +Two labels are committed content shown in a reader-friendly form rather than +changed content. The Subspecialty node's `name` is the code "CH" and its +`definition` is "Chest Radiology"; the box shows the definition, since "CH" +alone says nothing. The Modality nodes carry RadLex definitions (Computed +Tomography, Projection Radiography, Magnetic Resonance Imaging) that do not +fit half-size boxes, so those three show the committed ids only. + +Not drawn at all, by instruction: values, time course, etiology. Also left +out: HAS_ANATOMIC_REFINEMENT_RULE -> ARR-000001, whose target is a node kind +outside the nine the legend names. + +RELATIONSHIP NAMES +------------------ +Every edge label is the committed `edge` string from definition-graph.json, +and all nine agree with the relationship table on +knowledge/drafts/next-generation-schema.md. The older names that circulate +elsewhere in the same repository are NOT used: HAS_ELEMENT (for +HAS_DATA_ELEMENT) and MAY_HAVE_COMPONENT (for HAS_COMPONENT), both of which +survive in graph/core.jsonl and in the retired 2026-09-03 fc-neighborhood +diagram. The schema page flags that older pair itself. + +LAYOUT +------ +About 1050 x 820. v1 packed eight arrows out of the centre node's right edge +into a 180px corridor; v2 has fewer targets there (five data elements, two +measurements) AND a corridor half again as wide, so the fan opens at roughly +39px of label pitch instead of 26px. The centre node sits mid-canvas with the +Grouping directly above it, the two assessment schemes up and to the right, +the two diagnoses up and to the left, the subtype row below, and the +context nodes -- lung, three modalities, the subspecialty -- down the left +margin. + +Two routing facts hold the left margin together. The diagnosis that also +points UP at the Grouping (granuloma) sits ABOVE the one that only points at +the nodule (neoplasm); reversing them makes the two arrows cross. And the +SCOPED_TO arrow leaves the centre node BELOW the point where the neoplasm's +manifestation arrow arrives, which is what keeps those two apart. + +Every arrow is emitted before every label plate: the plates are opaque and +mask the lines they lie across, so an arrow drawn after a plate would cut +through the label's text. + +Text widths are measured, not estimated (see tools/diagrams/README.md): the +render font is `Helvetica, Segoe UI Emoji` as resolved by headless Chromium, +and every box width and plate width below comes from canvas measureText() at +the same size in that browser. + +Colours follow build_foundation_network.py so the figures name the same kinds +the same way: FINDING green, DIAGNOSIS darker green, ASSESS purple, +ANATOMY blue, GREY modality. Four kinds are local to this figure: DataElement +takes the lightest step of excalib's ROSE ramp, Measurement the lightest step +of VIOLET, Grouping a paler green than FINDING with a dashed stroke (it is a +container, not a finding you would report), and Subspecialty a desaturated +grey-violet that reads as metadata next to both. + +v3 change: the two AssessmentScheme nodes are OVALS, not diamonds. A diamond +reads as a flowchart decision, which is not what an assessment scheme is. +Same purple fill and stroke, same 190x92 envelope, labels still centred, and +the legend swatch is an oval to match. Both ASSESSED_BY arrows are drawn by +ray() so their heads land on the ellipse outline rather than on a +bounding-box extreme; see that helper for why excalib.arrow() cannot. + +Excalidraw has no italic font variant -- fontFamily is an integer code with +no style axis -- so the caption under the legend is set small and grey rather +than italic. + +Output: knowledge/drafts/nodule-neighborhood.excalidraw; render with +render_excalidraw.py (see tools/diagrams/README.md). +""" +from __future__ import annotations + +from excalib import (BODY, LINE, CAPTION, els, base, text, find, edge_point, arrow, + tri_head, save) + +# ---------------------------------------------------------------- palette +# (fill, stroke, text, mid) -- "mid" is the tone for the small kind line. +FINDING = ("#d1fae5", "#059669", "#064e3b", "#047857") # FindingClass +GROUPING = ("#ecfdf5", "#10b981", "#065f46", "#059669") # Grouping (dashed) +DIAGNOSIS = ("#6ee7b7", "#059669", "#064e3b", "#047857") # Diagnosis +ASSESS = ("#e9d5ff", "#7e22ce", "#4c1d95", "#7e22ce") # AssessmentScheme (oval) +ANATOMY = ("#bfdbfe", "#1d4ed8", "#1e3a8a", "#1d4ed8") # AnatomicLocation +GREY = ("#e5e7eb", "#6b7280", "#374151", "#4b5563") # Modality +DATAEL = ("#ffe4e6", "#be123c", "#881337", "#be123c") # DataElement (ROSE, lightest) +MEAS = ("#ede9fe", "#6d28d9", "#4c1d95", "#6d28d9") # Measurement (VIOLET, lightest) +SUBSPEC = ("#e5e3ee", "#78748f", "#3c3a52", "#5d5a78") # Subspecialty (grey-violet) + +HEAD = 10.0 # solid tri_head length, independent of line weight +KIND_SIZE = 11 # the small second line inside every node + + +# ---------------------------------------------------------------- helpers +def kind_box(id_, x, y, w, h, name, kind, pal, size=14, lines=None, dashed=False, + kind_size=KIND_SIZE): + """A node: rounded rect, name centred, node kind on a small line under it. + `lines` overrides the name's line breaks (list of strings).""" + fill, stroke, tcol, mid = pal + r = base("rectangle", id_, x, y, w, h, stroke, fill, dashed=dashed) + r["roundness"] = {"type": 3} + els.append(r) + nl = lines or [name] + block = len(nl) * size * 1.25 + 3 + kind_size * 1.25 + ty = y + (h - block) / 2 + els.append(text(id_ + "_n", x + 8, ty, "\n".join(nl), size=size, color=tcol, + align="center", w=w - 16)) + els.append(text(id_ + "_k", x + 8, ty + len(nl) * size * 1.25 + 3, kind, + size=kind_size, color=mid, align="center", w=w - 16)) + return r + + +def oval_node(id_, x, y, w, h, name, kind, pal, size=14): + """Same two-line content as kind_box, in an ellipse. v3 change: these were + diamonds through v2, which read as flowchart decisions. Same fill, stroke + and size envelope; only the outline changed. + + The text column is the middle 72% of the width. An ellipse is widest at + its vertical centre and the two-line block reaches only +-17px from it, + where the half-width is still 93% of the semi-axis, so 72% clears the + curve with room to spare (a diamond only allowed 60%).""" + fill, stroke, tcol, mid = pal + d = base("ellipse", id_, x, y, w, h, stroke, fill) + els.append(d) + block = size * 1.25 + 3 + KIND_SIZE * 1.25 + ty = y + (h - block) / 2 + els.append(text(id_ + "_n", x + w * 0.14, ty, name, size=size, color=tcol, + align="center", w=w * 0.72)) + els.append(text(id_ + "_k", x + w * 0.14, ty + size * 1.25 + 3, kind, + size=KIND_SIZE, color=mid, align="center", w=w * 0.72)) + return d + + +def ray(id_, src, s_side, s_frac, dst, label, t): + """A straight arrow from a box edge to a point ON an ellipse's outline. + + excalib.arrow() lands on the destination's BOUNDING BOX, which for an + ellipse means the head stops at whichever of the four extreme points the + named side picks -- fine for a vertical or horizontal approach, wrong for + a diagonal one, which is what both ASSESSED_BY arrows are. This instead + solves for the boundary point along the line from the ellipse's centre to + the source, so each head meets the curve square on. `t` places the label + along the same line, so moving an endpoint moves its label with it.""" + a, b = find(src), find(dst) + x1, y1 = edge_point(a, s_side, s_frac) + cx, cy = b["x"] + b["width"] / 2, b["y"] + b["height"] / 2 + rx, ry = b["width"] / 2, b["height"] / 2 + dx, dy = x1 - cx, y1 - cy + k = 1.0 / ((dx / rx) ** 2 + (dy / ry) ** 2) ** 0.5 + x2, y2 = cx + dx * k, cy + dy * k + ln = ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5 or 1.0 + ex = x2 - (x2 - x1) / ln * HEAD * 0.55 # stop short so the head's base sits on the line + ey = y2 - (y2 - y1) / ln * HEAD * 0.55 + ar = base("arrow", id_, x1, y1, ex - x1, ey - y1, LINE, "transparent", sw=2) + ar.update({"points": [[0, 0], [ex - x1, ey - y1]], "startBinding": None, + "endBinding": None, "startArrowhead": None, "endArrowhead": None, + "boundElements": None}) + els.append(ar) + tri_head(id_ + "_h", (x2, y2), (x1, y1), LINE, size=HEAD) + lab("l_" + id_, x1 + t * (x2 - x1), y1 + t * (y2 - y1), label) + + +def edge(id_, src, s_side, dst, d_side, s_frac=0.5, d_frac=0.5, elbow=None): + """excalib.arrow() with its open head replaced by a fixed-size solid one.""" + arrow(id_, src, s_side, dst, d_side, s_frac=s_frac, d_frac=d_frac, + color=LINE, sw=2, elbow=elbow) + a = find(id_) + a["endArrowhead"] = None + tip = (a["x"] + a["points"][-1][0], a["y"] + a["points"][-1][1]) + frm = (a["x"] + a["points"][-2][0], a["y"] + a["points"][-2][1]) + tri_head(id_ + "_h", tip, frm, LINE, size=HEAD) + + +def plate(id_, cx, cy, s, w, size=13, pad_x=6, pad_y=4): + """An edge label on an opaque white plate centred on (cx, cy), so it masks + the line it sits on. `w` is the MEASURED text width.""" + bw, bh = w + 2 * pad_x, size * 1.25 + 2 * pad_y + r = base("rectangle", id_, cx - bw / 2, cy - bh / 2, bw, bh, "transparent", "#ffffff", sw=0) + r["roundness"] = {"type": 3} + els.append(r) + els.append(text(id_ + "_t", cx - bw / 2 + pad_x, cy - bh / 2 + pad_y, s, + size=size, color=BODY, align="center", w=w)) + + +# Measured label widths at 13px Helvetica (headless Chromium). +LW = {"MAY_MANIFEST_AS": 124.7, "ASSESSED_BY": 94.7, "SUBTYPE_OF": 86.0, + "HAS_DATA_ELEMENT": 135.3, "HAS_MEASUREMENT": 135.1, "SCOPED_TO": 79.9, + "SEEN_ON": 62.1, "HAS_COMPONENT": 118.5, "IN_SUBSPECIALTY": 117.5} + +LABELS: list[tuple[str, float, float, str]] = [] + + +def lab(id_, cx, cy, name): + """Queue an edge label; all of them are flushed after every arrow is drawn.""" + LABELS.append((id_, cx, cy, name)) + + +# ================================================================== nodes +# centre node and the Grouping directly above it +kind_box("fc", 400, 270, 240, 80, "pulmonary nodule", "FindingClass", FINDING, size=17) +kind_box("gr", 320, 25, 250, 70, "pulmonary parenchymal abnormality", "Grouping", + GROUPING, dashed=True) + +# diagnoses, upper-left. granuloma is ABOVE neoplasm because granuloma also +# points UP at the Grouping; the other order makes those two arrows cross. +kind_box("dx_gran", 20, 30, 165, 62, "pulmonary granuloma", "Diagnosis", DIAGNOSIS) +kind_box("dx_neo", 20, 140, 165, 62, "pulmonary neoplasm", "Diagnosis", DIAGNOSIS) + +# assessment schemes, upper-right +oval_node("as_lr", 600, 14, 190, 92, "Lung-RADS", "AssessmentScheme", ASSESS) +oval_node("as_fl", 845, 14, 190, 92, "Fleischner criteria", "AssessmentScheme", ASSESS) + +# subtypes (row below the centre node; smaller boxes, 13px names) +kind_box("s1", 300, 500, 140, 80, "solid pulmonary nodule", "FindingClass", FINDING, + size=13, lines=["solid", "pulmonary nodule"]) +kind_box("s2", 450, 500, 140, 80, "part-solid pulmonary nodule", "FindingClass", FINDING, + size=13, lines=["part-solid", "pulmonary nodule"]) +kind_box("s3", 600, 500, 140, 80, "ground glass nodule", "FindingClass", FINDING, + size=13, lines=["ground glass", "nodule"]) + +# the component hanging off part-solid +kind_box("sc", 400, 630, 240, 70, "solid component", "FindingClass", FINDING, size=13, + lines=["solid component of", "part-solid pulmonary nodule"]) + +# context nodes down the left margin +kind_box("an", 60, 290, 140, 60, "lung", "AnatomicLocation", ANATOMY) +kind_box("sp", 40, 370, 170, 60, "chest radiology", "Subspecialty", SUBSPEC) +for i, (mid_, nm) in enumerate([("md_ct", "CT"), ("md_xr", "XR"), ("md_mr", "MR")]): + kind_box(mid_, 55, 480 + i * 48, 90, 38, nm, "Modality", GREY, size=13, kind_size=9) + +# data elements and measurements, right column +COL_X, COL_W, ROW_H = 845, 190, 48 +DE_NAMES = ["presence", "composition", "margin", "calcification", "interval change"] +for i, nm in enumerate(DE_NAMES): + kind_box(f"de{i}", COL_X, 150 + i * 66, COL_W, ROW_H, nm, "DataElement", DATAEL) +for i, nm in enumerate(["mean diameter", "long-axis diameter"]): + kind_box(f"ms{i}", COL_X, 510 + i * 66, COL_W, ROW_H, nm, "Measurement", MEAS) + +# ================================================================== edges +# SUBTYPE_OF into the Grouping: from the centre node (plumb vertical) and from +# the granuloma (near-horizontal, in the 135px gap that fits its plate). +edge("e_gr_fc", "fc", "top", "gr", "bottom", s_frac=0.50, d_frac=0.80) +edge("e_gr_gn", "dx_gran", "right", "gr", "left", s_frac=0.50, d_frac=0.50) +lab("l_gr_fc", 520, 180, "SUBTYPE_OF") +lab("l_gr_gn", 252, 60, "SUBTYPE_OF") + +# MAY_MANIFEST_AS x2, both into the centre node's left edge +edge("e_mma_gn", "dx_gran", "right", "fc", "left", s_frac=0.87, d_frac=0.15) +edge("e_mma_neo", "dx_neo", "right", "fc", "left", s_frac=0.50, d_frac=0.55) +lab("l_mma_gn", 292, 183, "MAY_MANIFEST_AS") +lab("l_mma_neo", 292, 242, "MAY_MANIFEST_AS") + +# ASSESSED_BY x2, drawn by ray() so each head meets the oval's curve square +# on rather than stopping at a bounding-box extreme. Both run up and to the +# right; the Fleischner one passes well below the Lung-RADS oval and above +# the first data element. +ray("e_asb_lr", "fc", "top", 0.62, "as_lr", "ASSESSED_BY", 0.34) +ray("e_asb_fl", "fc", "top", 0.80, "as_fl", "ASSESSED_BY", 0.66) + +# SUBTYPE_OF x3: each subtype -> the centre node (arrows point UP into it). +# The three plates are staggered along their arrows; level with each other +# they would collide, and the right one also has to stay clear of the +# measurement labels, so it rides high. +edge("e_st1", "s1", "top", "fc", "bottom", d_frac=0.35) +edge("e_st2", "s2", "top", "fc", "bottom", d_frac=0.50) +edge("e_st3", "s3", "top", "fc", "bottom", d_frac=0.72) +lab("l_st1", 410, 448, "SUBTYPE_OF") +lab("l_st2", 520, 425, "SUBTYPE_OF") +lab("l_st3", 592, 380, "SUBTYPE_OF") + +# HAS_COMPONENT: part-solid -> solid component. The drop is only 50px, so the +# plate sits BESIDE the arrow; centred on it, it would cover the whole shaft. +edge("e_hc", "s2", "bottom", "sc", "top") +lab("l_hc", 625, 605, "HAS_COMPONENT") + +# HAS_DATA_ELEMENT x5 and HAS_MEASUREMENT x2: one fan out of the centre node's +# right edge into the right column, across a 205px corridor. +for i in range(5): + edge(f"e_de{i}", "fc", "right", f"de{i}", "left", s_frac=0.10 + i * 0.15) + lab(f"l_de{i}", 742, 226 + i * 39, "HAS_DATA_ELEMENT") +edge("e_ms0", "fc", "right", "ms0", "left", s_frac=0.85) +edge("e_ms1", "fc", "right", "ms1", "left", s_frac=0.95) +lab("l_ms0", 727, 421, "HAS_MEASUREMENT") +lab("l_ms1", 732, 460, "HAS_MEASUREMENT") + +# SCOPED_TO -> lung. It leaves the centre node BELOW where the neoplasm's +# manifestation arrow arrives, so the two do not cross. +edge("e_sc", "fc", "left", "an", "right", s_frac=0.875, d_frac=0.50) +lab("l_sc", 300, 330, "SCOPED_TO") + +# IN_SUBSPECIALTY -> chest radiology +edge("e_sp", "fc", "bottom", "sp", "right", s_frac=0.05, d_frac=0.50) +lab("l_sp", 311, 375, "IN_SUBSPECIALTY") + +# SEEN_ON x3 -> the three modality boxes, a fan off the centre node's bottom +# edge that passes to the right of lung and of the subspecialty box. +for i, (mid_, t) in enumerate([("md_ct", 0.42), ("md_xr", 0.50), ("md_mr", 0.68)]): + edge(f"e_sn{i}", "fc", "bottom", mid_, "right", s_frac=0.10 + i * 0.08, d_frac=0.50) + a = find(f"e_sn{i}") + x1, y1 = a["x"], a["y"] + x2, y2 = x1 + a["points"][-1][0], y1 + a["points"][-1][1] + lab(f"l_sn{i}", x1 + t * (x2 - x1), y1 + t * (y2 - y1), "SEEN_ON") + +for _id, _cx, _cy, _nm in LABELS: + plate(_id, _cx, _cy, _nm, LW[_nm]) + +# ================================================================== legend +LEG_Y, LEG_X0, LEG_X1 = 735, 15, 1035 +lg = base("rectangle", "leg", LEG_X0, LEG_Y, LEG_X1 - LEG_X0, 52, "#e2e8f0", "#f8fafc", sw=1) +lg["roundness"] = {"type": 3} +els.append(lg) + +# widths measured at 11px; the nine entries need the smaller size to sit in one row +LEGEND = [("FindingClass", FINDING, 63.6, False), ("Grouping", GROUPING, 45.3, True), + ("Diagnosis", DIAGNOSIS, 48.3, False), ("AssessmentScheme", ASSESS, 100.3, False), + ("AnatomicLocation", ANATOMY, 87.4, False), ("Modality", GREY, 41.0, False), + ("DataElement", DATAEL, 63.6, False), ("Measurement", MEAS, 67.3, False), + ("Subspecialty", SUBSPEC, 62.4, False)] +lx = 32 +for i, (name, pal, wpx, dashed) in enumerate(LEGEND): + fill, stroke, _t, _m = pal + if name == "AssessmentScheme": + els.append(base("ellipse", f"lg{i}", lx - 1, LEG_Y + 17, 26, 18, stroke, fill, sw=1)) + sw_w = 26 + else: + s = base("rectangle", f"lg{i}", lx, LEG_Y + 18, 22, 16, stroke, fill, sw=1, dashed=dashed) + s["roundness"] = {"type": 3} + els.append(s) + sw_w = 22 + els.append(text(f"lg{i}_t", lx + sw_w + 8, LEG_Y + 19, name, size=11, color=BODY, w=wpx)) + lx += sw_w + 8 + wpx + 16 + +# caption under the legend (Excalidraw has no italic variant; small and grey instead) +els.append(text("cap", (LEG_X0 + LEG_X1) / 2 - 300, LEG_Y + 64, + "illustrative: reflects pending updates to the CDE graph", + size=11, color=CAPTION, align="center", w=600)) + +save("knowledge/drafts/nodule-neighborhood.excalidraw") diff --git a/tools/diagrams/build_pillars.py b/tools/diagrams/build_pillars.py new file mode 100644 index 0000000..c42ccaa --- /dev/null +++ b/tools/diagrams/build_pillars.py @@ -0,0 +1,464 @@ +#!/usr/bin/env python3 +"""Build the OIDM "five pillars" technology-stack diagram. + +A layered stack, read bottom to top, each layer its own hue (no blue reused +from other diagrams in the bundle) so the picture reads without words: + + 1. Foundation Context (bottom) -- shared, curated knowledge: finding and + diagnosis definitions, anatomic locations, exam types. Short + double-headed arrows between the three blocks, with one "relationships" + label over the row, say the three are tied to each other. + 2. Data Structures -- this patient's data, sitting on the foundation. + 3. SDKs -- a thin band between the data layer and the top. + 4/5. Use Cases and Sample Applications -- two panels sharing the top band, + joined by a short horizontal connector labelled "illustrates". + +The seam -- how the Data Structures band and the Foundation Context band show +that the patient graph is woven into the foundation graph -- is pluggable, and +selected with the required `--seam` flag. v3's seam (an overlap crossed by +twelve alternating vertical threads) was rejected; the three candidates are: + + a Named attachments. The bands separate, and thin connectors run from the + data cards to named tags sitting on the Foundation band's top edge, each + tag over the foundation block it attaches to ("is a", "located at", ...). + b Dovetail. The bands are flush and the Data Structures band's lower edge + is cut into four teal tabs that drop into matching slots in the + Foundation band's top edge, one per attachment kind. No lines. + c Shared membrane. A narrow hatched band between the two holds four + attachment-point nodes, each ticking up into the data band and down into + the foundation band. + +A seam is a dict of four things: how much room the Data band leaves below its +cards, the gap between the two bands, how far below the Foundation band's top +edge its header starts, and a draw() that paints the seam itself once both +band rectangles are placed. + +Geometry rules: every band is CONTENT_W wide and starts at x=0; vertical gaps +between bands are all BAND_GAP, except the Data/Foundation seam, which each +seam sets for itself; band heights are computed from their contents, so no +band is taller than its own text needs. + +Icons: Health Icons (CC0/MIT, outline style) for anatomy/exam/person glyphs, +Lucide (ISC, with one Feather-derived MIT icon) for everything else -- see +icons/LICENSES.md for the full source list and the two slots where Health +Icons had no matching glyph and Lucide was used instead. Health Icons' +outline set is filled-path art on a 48x48 viewBox with built-in padding, so +it renders optically smaller than Lucide's 24x24 stroke art at the same box +size; ICON_FILLED compensates. + +Output: knowledge/drafts/pillars-.excalidraw (override with --out); +render with render_excalidraw.py. +""" +from __future__ import annotations + +import argparse +import math + +from excalib import els, base, text, image, save, AMBER, TEAL, VIOLET, ROSE, GREEN, CAPTION + +# ---------------------------------------------------------------- layout constants +CONTENT_W = 880 +BAND_GAP = 24 # the vertical gap between bands above the seam +PAD_BAND = 20 # a band's own inner padding on all sides +GAP = 20 # gap between sibling blocks inside a band +GAP_REL = 64 # wider gap, so a double-headed arrow reads as an arrow and not a diamond +ICON = 28 # harmonized icon render size +ICON_FILLED = 32 # filled-path icon sets need a bigger box to match optically +CORNER_R = 32 # Excalidraw's adaptive corner radius for a band-sized rectangle + +_uid = [0] + + +def uid(prefix: str) -> str: + _uid[0] += 1 + return f"{prefix}{_uid[0]}" + + +# ---------------------------------------------------------------- primitives +def band_rect(id_: str, x: float, y: float, w: float, h: float, pal: dict, at_front=False) -> dict: + """Draw a band's background rectangle. Pass at_front=True when the band's + true height is only known after laying out its header/blocks (they were + already appended to els) -- this inserts the rect at index 0 so it still + paints behind its own contents instead of covering them. Note the order + that matters at the seam: whichever band rect is inserted at index 0 last + ends up furthest back, so Foundation Context must be built last.""" + r = base("rectangle", id_, x, y, w, h, pal["stroke"], pal["band"]) + r["roundness"] = {"type": 3} + if at_front: + els.insert(0, r) + else: + els.append(r) + return r + + +def band_header(x: float, y: float, icon_path: str, pal: dict, title: str, subtitle: str, + size=20, filled_icon=False) -> float: + """Bold band title with its icon to the left, subtitle below. Returns bottom y.""" + s = ICON_FILLED if filled_icon else ICON + image(uid("bicon"), x, y - (s - ICON) / 2 - 2, s, s, icon_path, color=pal["stroke"]) + els.append(text(uid("btitle"), x + ICON + 12, y, title, size=size, color=pal["text"])) + y2 = y + size * 1.3 + els.append(text(uid("bsub"), x + ICON + 12, y2, subtitle, size=13, color=pal["mid"])) + return y2 + 13 * 1.25 + + +def icon_block_h(lines: list[str], desc: str | None = None) -> float: + """Height an icon_block needs for this many label lines/descriptor.""" + n_title = len(lines) + return 12 + ICON + 8 + n_title * 15 * 1.25 + (13 * 1.25 + 2 if desc else 0) + 10 + + +def icon_block(x: float, y: float, w: float, h: float, icon_path: str, pal: dict, + lines: list[str], desc: str | None = None, filled_icon=False) -> dict: + """Icon centered on top, label line(s) centered below, optional lighter + descriptor line last. Background is the band's own deeper pastel so the + block reads as 'inside' the band, not a separate object.""" + r = base("rectangle", uid("blk"), x, y, w, h, pal["stroke"], pal["block"], sw=1) + r["roundness"] = {"type": 3} + els.append(r) + cx = x + w / 2 + content_h = icon_block_h(lines, desc) - 22 # minus this fn's fixed 12+10 top/bottom pad + top = y + (h - content_h) / 2 + s = ICON_FILLED if filled_icon else ICON + image(uid("blki"), cx - s / 2, top - (s - ICON) / 2, s, s, icon_path, color=pal["stroke"]) + ty = top + ICON + 6 + for ln in lines: + els.append(text(uid("blkt"), x + 6, ty, ln, size=15, color=pal["text"], align="center", w=w - 12)) + ty += 15 * 1.25 + if desc: + els.append(text(uid("blkd"), x + 6, ty + 2, desc, size=13, color=pal["mid"], align="center", w=w - 12)) + return r + + +def chip(cx: float, y_top: float, s: str, fill: str, stroke: str, color: str, + size=13, pad_x=9, pad_y=3) -> float: + """A short caption on its own opaque rounded plate, centered on cx, so it + reads as a label for what it sits over and never mixes with a line or a + band fill behind it. Returns bottom y.""" + w = len(s) * size * 0.58 + 2 * pad_x + h = size * 1.25 + 2 * pad_y + r = base("rectangle", uid("chip"), cx - w / 2, y_top, w, h, stroke, fill, sw=1) + r["roundness"] = {"type": 3} + els.append(r) + els.append(text(uid("chipt"), cx - w / 2 + pad_x, y_top + pad_y, s, size=size, color=color, + align="center", w=w - 2 * pad_x)) + return y_top + h + + +def hconn(x1: float, x2: float, y: float, color: str, sw=1, both=False) -> None: + """A plain horizontal connector; both=True gives it two arrowheads.""" + a = base("arrow" if both else "line", uid("conn"), x1, y, x2 - x1, 0, color, "transparent", sw=sw) + a.update({"points": [[0, 0], [x2 - x1, 0]], "boundElements": None}) + if both: + a.update({"startArrowhead": "arrow", "endArrowhead": "arrow"}) + els.append(a) + + +def fill_rect(x: float, y: float, w: float, h: float, fill: str, rounded=False) -> dict: + """An unstroked patch of colour -- used to close the notch two rounded + bands leave where they meet, and to let a tab sit across a band edge + without that edge's stroke running through it.""" + r = base("rectangle", uid("fill"), x, y, w, h, "transparent", fill, sw=1) + r["roundness"] = {"type": 3} if rounded else None + els.append(r) + return r + + +def stroke_line(pts: list[tuple[float, float]], color: str, sw=2, opacity=100) -> dict: + """A polyline through pts (absolute coordinates), sharp corners.""" + x0, y0 = pts[0] + xs = [p[0] for p in pts] + ys = [p[1] for p in pts] + ln = base("line", uid("ln"), x0, y0, max(xs) - min(xs), max(ys) - min(ys), color, "transparent", sw=sw) + ln.update({"points": [[p[0] - x0, p[1] - y0] for p in pts], "boundElements": None, "roundness": None}) + ln["opacity"] = opacity + els.append(ln) + return ln + + +def arc_pts(cx: float, cy: float, r: float, a0: float, a1: float, n=4) -> list[tuple[float, float]]: + """Points along a circular arc, for rounding a corner of a polyline.""" + return [(cx + r * math.cos(a0 + (a1 - a0) * i / n), cy + r * math.sin(a0 + (a1 - a0) * i / n)) + for i in range(n + 1)] + + +def plate(cx: float, y_top: float, s: str, size=13, color=CAPTION, fill="#ffffff", + stroke="transparent", pad_x=7, pad_y=3, sw=1) -> tuple[float, float]: + """An opaque label plate centered on cx with its top at y_top. Returns + (width, height).""" + w = len(s) * size * 0.58 + 2 * pad_x + h = size * 1.25 + 2 * pad_y + r = base("rectangle", uid("plate"), cx - w / 2, y_top, w, h, stroke, fill, sw=sw) + r["roundness"] = {"type": 3} + els.append(r) + els.append(text(uid("platet"), cx - w / 2 + pad_x, y_top + pad_y, s, size=size, color=color, + align="center", w=w - 2 * pad_x)) + return w, h + + +def corner_patch(y_top: float, y_bot: float, pal: dict, anchor: dict) -> None: + """Two rounded bands that meet edge to edge leave a white notch at each + end, where both corner radii curve away from the seam. Fill those notches + with the band's own colour and redraw its outer border straight, so the + stack keeps one silhouette through the seam. + + A notch is CORNER_R deep, which reaches back into the band far enough to + cover a card corner or a header icon, so the patch is restacked to sit + directly above `anchor` (its own band rectangle) instead of on top of + everything the seam is drawn after.""" + made = [ + fill_rect(-1, y_top, CORNER_R + 1, y_bot - y_top, pal["band"]), + fill_rect(CONTENT_W - CORNER_R, y_top, CORNER_R + 1, y_bot - y_top, pal["band"]), + stroke_line([(0, y_top), (0, y_bot)], pal["stroke"], sw=2), + stroke_line([(CONTENT_W, y_top), (CONTENT_W, y_bot)], pal["stroke"], sw=2), + ] + for e in reversed(made): + els.remove(e) + els.insert(els.index(anchor) + 1, e) + + +# ============================================================ seam a: named attachments +# Each link: (data card index, exit fraction along its bottom edge, +# foundation block index, which of that block's two tags, label). +# Exit fractions and tag order run left to right by target, so the six +# connectors cross each other only at clean X points and never a label. +A_LINKS = [ + (0, 0.22, 0, 0, "is a"), + (0, 0.50, 1, 0, "located at"), + (0, 0.78, 2, 0, "seen on"), + (1, 0.50, 2, 1, "of an exam type"), + (2, 0.35, 0, 1, "per definition"), + (2, 0.65, 1, 1, "per location"), +] + + +def draw_seam_a(g: dict) -> None: + size, pad_x, pad_y = 13, 7, 3 + tag_h = size * 1.25 + 2 * pad_y + y_tag_top = g["found_top"] - tag_h + y_card = g["blocks_bottom"] + + labels = {(dj, slot): lab for (_si, _sf, dj, slot, lab) in A_LINKS} + tag_cx: dict[tuple[int, int], float] = {} + for j in range(3): + w0 = len(labels[(j, 0)]) * size * 0.58 + 2 * pad_x + w1 = len(labels[(j, 1)]) * size * 0.58 + 2 * pad_x + total = w0 + w1 + 12 + cx = g["f_positions"][j] + g["W3"] / 2 + tag_cx[(j, 0)] = cx - total / 2 + w0 / 2 + tag_cx[(j, 1)] = cx + total / 2 - w1 / 2 + + # connectors first, so each tag paints over the end of its own line + for (si, sf, dj, slot, _lab) in A_LINKS: + x1 = g["d_positions"][si] + g["W4"] * sf + stroke_line([(x1, y_card), (tag_cx[(dj, slot)], y_tag_top)], TEAL["stroke"], sw=1, opacity=75) + for key, lab in labels.items(): + plate(tag_cx[key], y_tag_top, lab, size=size, color=AMBER["text"], + stroke=AMBER["stroke"], pad_x=pad_x, pad_y=pad_y) + + els.append(text(uid("seaml"), 0, g["found_top"] + 13, + "interconnected at every finding, diagnosis, location, and exam type", + size=13, color=CAPTION, align="center", w=CONTENT_W)) + + +# ============================================================ seam b: dovetail +B_WORDS = ["finding", "diagnosis", "location", "exam type"] +B_TAB_W = 120.0 +B_TAB_D = 34.0 +B_TAB_R = 11.0 +B_LEAD = "woven together at every:" +B_RIGHT_MARGIN = 60.0 # amber left clear to the right of the last tab + + +def draw_seam_b(g: dict) -> None: + seam = g["found_top"] # the two bands are flush here + corner_patch(seam - CORNER_R, seam, TEAL, g["teal_band"]) + corner_patch(seam, seam + CORNER_R, AMBER, g["amber_band"]) + stroke_line([(0, seam), (CONTENT_W, seam)], TEAL["stroke"], sw=2) + + lead_w = len(B_LEAD) * 13 * 0.58 + x0 = PAD_BAND + lead_w + 22 + span = CONTENT_W - B_RIGHT_MARGIN - x0 + step = (span - B_TAB_W) / (len(B_WORDS) - 1) + els.append(text(uid("bl"), PAD_BAND, seam + (B_TAB_D - 13 * 1.25) / 2, B_LEAD, + size=13, color=AMBER["mid"])) + + for i, word in enumerate(B_WORDS): + x = x0 + i * step + # the tab's fill runs up past the seam, so the band edge's stroke stops + # at the tab: what is left reads as a slot cut into the Foundation band. + fill_rect(x, seam - 12, B_TAB_W, B_TAB_D + 12, TEAL["band"], rounded=True) + pts = [(x, seam - 7)] + pts += arc_pts(x + B_TAB_R, seam + B_TAB_D - B_TAB_R, B_TAB_R, math.pi, math.pi / 2) + pts += arc_pts(x + B_TAB_W - B_TAB_R, seam + B_TAB_D - B_TAB_R, B_TAB_R, math.pi / 2, 0.0) + pts += [(x + B_TAB_W, seam - 7)] + stroke_line(pts, TEAL["stroke"], sw=2) + els.append(text(uid("bw"), x, seam + (B_TAB_D - 13 * 1.25) / 2, word, + size=13, color=TEAL["text"], align="center", w=B_TAB_W)) + + +# ============================================================ seam c: shared membrane +C_WORDS = ["finding", "diagnosis", "location", "exam type"] +C_H = 64.0 +C_TITLE = "attachment points" +C_PILL_H = 28.0 +C_TICK = 9.0 + + +def draw_seam_c(g: dict) -> None: + top = g["data_band_bottom"] + bot = g["found_top"] + corner_patch(top - CORNER_R, top, TEAL, g["teal_band"]) + corner_patch(bot, bot + CORNER_R, AMBER, g["amber_band"]) + + # membrane ground, then a fine two-colour hatch clipped to it + fill_rect(0, top, CONTENT_W, bot - top, "#ffffff") + step, i, c = 16.0, 0, top - CONTENT_W + while c < bot: + x1, x2 = max(0.0, top - c), min(CONTENT_W, bot - c) + if x2 - x1 > 1: + stroke_line([(x1, x1 + c), (x2, x2 + c)], + TEAL["stroke"] if i % 2 == 0 else AMBER["stroke"], sw=1, opacity=25) + c += step + i += 1 + stroke_line([(0, top), (CONTENT_W, top)], TEAL["stroke"], sw=2) + stroke_line([(0, bot), (CONTENT_W, bot)], AMBER["stroke"], sw=2) + stroke_line([(0, top), (0, bot)], CAPTION, sw=1, opacity=55) + stroke_line([(CONTENT_W, top), (CONTENT_W, bot)], CAPTION, sw=1, opacity=55) + + pill_top = top + (C_H - C_PILL_H) / 2 + tw, _ = plate(PAD_BAND + len(C_TITLE) * 13 * 0.58 / 2 + 7, pill_top + (C_PILL_H - (13 * 1.25 + 6)) / 2, + C_TITLE, size=13, color=CAPTION) + x0 = PAD_BAND + tw + 20 + widths = [len(w) * 13 * 0.58 + 28 for w in C_WORDS] + span = CONTENT_W - PAD_BAND - x0 + gap = (span - sum(widths)) / (len(C_WORDS) - 1) + x = x0 + for word, w in zip(C_WORDS, widths): + cx = x + w / 2 + stroke_line([(cx, top - C_TICK), (cx, pill_top)], TEAL["stroke"], sw=2) + stroke_line([(cx, pill_top + C_PILL_H), (cx, bot + C_TICK)], AMBER["stroke"], sw=2) + r = base("rectangle", uid("pill"), x, pill_top, w, C_PILL_H, CAPTION, "#ffffff", sw=1) + r["roundness"] = {"type": 3} + els.append(r) + els.append(text(uid("pillt"), x, pill_top + (C_PILL_H - 13 * 1.25) / 2, word, + size=13, color="#334155", align="center", w=w)) + x += w + gap + + +SEAMS = { + "a": {"pad_below_blocks": PAD_BAND, "band_gap": 60.0, "found_top_pad": 46.0, "draw": draw_seam_a}, + "b": {"pad_below_blocks": PAD_BAND, "band_gap": 0.0, "found_top_pad": B_TAB_D + 18, "draw": draw_seam_b}, + "c": {"pad_below_blocks": PAD_BAND, "band_gap": C_H, "found_top_pad": 20.0, "draw": draw_seam_c}, +} + + +# ============================================================ the stack +def build(seam_key: str, out_path: str) -> str: + seam = SEAMS[seam_key] + + # ---------------------------------------- 5/4. Use Cases | Sample Applications + Y_TOP = 0 + GAP_MID = 104 # wide enough for "illustrates" to sit clear of both panels + PANEL_PAD = 14 + PANEL_INSET = PAD_BAND - 2 # same left inset as the full-width band headers + PANEL_TITLE = 18 + PANEL_H = PANEL_PAD + PANEL_TITLE * 1.3 + 13 * 1.25 + PANEL_PAD + panel_w = (CONTENT_W - GAP_MID) / 2 + + band_rect(uid("panel"), 0, Y_TOP, panel_w, PANEL_H, ROSE) + band_rect(uid("panel"), panel_w + GAP_MID, Y_TOP, panel_w, PANEL_H, GREEN) + band_header(PANEL_INSET, Y_TOP + PANEL_PAD, "icons/lucide-lightbulb.svg", ROSE, + "Use Cases", "what the project wants built", size=PANEL_TITLE) + band_header(panel_w + GAP_MID + PANEL_INSET, Y_TOP + PANEL_PAD, "icons/lucide-app-window.svg", GREEN, + "Sample Applications", "what has been built", size=PANEL_TITLE) + conn_y = Y_TOP + PANEL_H / 2 + hconn(panel_w + 2, panel_w + GAP_MID - 2, conn_y, CAPTION) + chip(panel_w + GAP_MID / 2, conn_y - 7 - (13 * 1.25 + 6), "illustrates", + "#ffffff", "transparent", CAPTION) + + # ---------------------------------------- 3. SDKs (thin full-width band) + Y_SDK = Y_TOP + PANEL_H + BAND_GAP + sdk_hdr_bottom = band_header(PAD_BAND - 2, Y_SDK + 16, "icons/lucide-package.svg", VIOLET, + "SDKs", "wrap the structures · attach the shared knowledge · support authoring", + size=18) + SDK_BOTTOM = sdk_hdr_bottom + 16 + band_rect(uid("band"), 0, Y_SDK, CONTENT_W, SDK_BOTTOM - Y_SDK, VIOLET, at_front=True) + + # ---------------------------------------- 2. Data Structures + Y_DATA = SDK_BOTTOM + BAND_GAP + hdr_bottom = band_header(PAD_BAND - 2, Y_DATA + 18, "icons/lucide-layers.svg", TEAL, + "Data Structures", "this patient · Patient Context", size=20) + BLOCK_ROW_Y = hdr_bottom + 14 + W4 = (CONTENT_W - 2 * PAD_BAND - 3 * GAP) / 4 + d_positions = [PAD_BAND + i * (W4 + GAP) for i in range(4)] + d_specs = [ + ("icons/lucide-clipboard.svg", ["Observation"], False), + ("icons/lucide-clipboard-list.svg", ["Exam Finding", "List"], False), + ("icons/lucide-list.svg", ["Imaging Problem", "List"], False), + ("icons/healthicons-person.svg", ["Imaging Persona"], True), + ] + ROW_H_DATA = max(icon_block_h(lines) for _, lines, _ in d_specs) + for xpos, (ipath, lines, filled) in zip(d_positions, d_specs): + icon_block(xpos, BLOCK_ROW_Y, W4, ROW_H_DATA, ipath, TEAL, lines, filled_icon=filled) + DATA_BLOCKS_BOTTOM = BLOCK_ROW_Y + ROW_H_DATA + + DATA_BAND_BOTTOM = DATA_BLOCKS_BOTTOM + seam["pad_below_blocks"] + teal_band = band_rect(uid("band"), 0, Y_DATA, CONTENT_W, DATA_BAND_BOTTOM - Y_DATA, TEAL, at_front=True) + + # ---------------------------------------- 1. Foundation Context (bottom) + # Built last so its rect lands behind the Data Structures band at the seam. + FOUND_TOP = DATA_BAND_BOTTOM + seam["band_gap"] + hdr_bottom_f = band_header(PAD_BAND - 2, FOUND_TOP + seam["found_top_pad"], + "icons/lucide-book-open.svg", AMBER, + "Foundation Context", "shared, curated knowledge", size=20) + REL_Y = hdr_bottom_f + 12 + rel_bottom = chip(CONTENT_W / 2, REL_Y, "relationships", AMBER["band"], AMBER["stroke"], AMBER["text"]) + F_ROW_Y = rel_bottom + 10 + W3 = (CONTENT_W - 2 * PAD_BAND - 2 * GAP_REL) / 3 + f_positions = [PAD_BAND + i * (W3 + GAP_REL) for i in range(3)] + f_specs = [ + ("icons/lucide-tag.svg", ["Finding/diagnosis definitions"], "finding models · CDEs", False), + ("icons/healthicons-lungs.svg", ["Anatomic locations"], "anchored in RadLex", True), + ("icons/healthicons-xray.svg", ["Exam types"], "LOINC/RSNA Playbook", True), + ] + ROW_H_FOUND = max(icon_block_h(lines, desc) for _, lines, desc, _ in f_specs) + for xpos, (ipath, lines, desc, filled) in zip(f_positions, f_specs): + icon_block(xpos, F_ROW_Y, W3, ROW_H_FOUND, ipath, AMBER, lines, desc=desc, filled_icon=filled) + FOUND_BLOCKS_BOTTOM = F_ROW_Y + ROW_H_FOUND + + arrow_y = F_ROW_Y + ROW_H_FOUND / 2 + for i in range(2): + x1 = f_positions[i] + W3 + 6 + hconn(x1, x1 + GAP_REL - 12, arrow_y, AMBER["stroke"], sw=2, both=True) + + FOUND_BAND_BOTTOM = FOUND_BLOCKS_BOTTOM + PAD_BAND + amber_band = band_rect(uid("band"), 0, FOUND_TOP, CONTENT_W, FOUND_BAND_BOTTOM - FOUND_TOP, AMBER, at_front=True) + + # ---------------------------------------- the seam, drawn over both bands + seam["draw"]({ + "blocks_bottom": DATA_BLOCKS_BOTTOM, + "data_band_bottom": DATA_BAND_BOTTOM, + "found_top": FOUND_TOP, + "d_positions": d_positions, "W4": W4, + "f_positions": f_positions, "W3": W3, + "teal_band": teal_band, "amber_band": amber_band, + }) + + return save(out_path) + + +def main() -> None: + ap = argparse.ArgumentParser(description=__doc__.split("\n")[0]) + ap.add_argument("--seam", choices=sorted(SEAMS), required=True, + help="which Data/Foundation seam to draw: a=named attachments, " + "b=dovetail, c=shared membrane") + ap.add_argument("--out", default=None, + help="output path relative to the repo root " + "(default knowledge/drafts/pillars-.excalidraw)") + args = ap.parse_args() + build(args.seam, args.out or f"knowledge/drafts/pillars-{args.seam}.excalidraw") + + +if __name__ == "__main__": + main() diff --git a/tools/diagrams/build_repository_map.py b/tools/diagrams/build_repository_map.py new file mode 100644 index 0000000..2b0647c --- /dev/null +++ b/tools/diagrams/build_repository_map.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +"""Build the repository data-flow map: one row per theme, each a short +left-to-right chain of at most three boxes, stacked top to bottom so every +cross-row flow is a short arrow to an ADJACENT row only -- rows are ordered +(CDE staging, finding models, applications, anatomy, terminology lookup) so +that CDE staging and applications both sit directly next to finding models, +and applications sits directly next to anatomy. Two edges that would have to +skip a row (CDEStaging -> RadElement, med-ontology-lookup -> findingmodel) +are dropped as captions instead -- both are already stated in the page prose. +Output: knowledge/repositories/repository-map.excalidraw""" +from excalib import PRIMARY, SECONDARY, TERTIARY, EXTERNAL, PLANNED, TITLE, SUBTITLE, BODY, LINE, els, base, text, box, find, arrow, save + +W, H = 190, 80 +GAP = 115 # wide enough that the longest horizontal-arrow label ("CDE-derived") fits centered above its arrow with room on each side +C1, C2, C3 = 0, W + GAP, 2 * (W + GAP) # 0, 305, 610 +ROW_GAP = 90 +CONTENT_W = C3 + W # 800 + +row_names = ["cde_stage", "fm_pipeline", "apps", "anatomy", "terms"] +row_labels = ["CDE STAGING", "FINDING MODELS", "APPLICATIONS", "ANATOMY", "TERMINOLOGY LOOKUP"] +Y = {} +y = 40 +for name, lbl in zip(row_names, row_labels): + Y[name] = y + els.append(text(f"hdr_{name}", C1, y - 24, lbl, size=14, color=SUBTITLE)) + y += H + ROW_GAP + +# row 1: CDE staging (2 boxes; columns line up with row 2's RadElement/findingmodels) +box("cdesnap", C1, Y["cde_stage"], W, H, "common_data_elements\nRadElement snapshot", TERTIARY) +box("cdes", C2, Y["cde_stage"], W, H, "CDEStaging\n259 draft CDE\ndefinitions", TERTIARY) + +# row 2: finding model pipeline +box("radelement", C1, Y["fm_pipeline"], W, H, "RadElement (ACR/RSNA)\nRDES and RDE codes", EXTERNAL) +box("fms", C2, Y["fm_pipeline"], W, H, "findingmodels\n2,382 finding models", TERTIARY) +box("fm", C3, Y["fm_pipeline"], W, H, "findingmodel\nOIFM format, index,\nCLIs, MCP", SECONDARY) +arrow("f1", "radelement", "right", "fms", "left", "CDE-derived") +arrow("f2", "fms", "right", "fm", "left", "definitions") + +# row1 <-> row2: both adjacent, straight verticals (same columns). +# cdesnap/cdes sit ABOVE radelement/fms on the page, so the "ascending" arrow +# (radelement -> cdesnap) binds radelement's top to cdesnap's bottom, and the +# "descending" one (cdes -> fms) binds cdes's bottom to fms's top. +arrow("f3", "radelement", "top", "cdesnap", "bottom", "snapshot") +arrow("f4", "cdes", "bottom", "fms", "top", "content batches") + +# row 3: applications (fed from row 2 above and row 4 below -- both adjacent) +box("ipl", C1, Y["apps"], W, H, "imaging-problem-list\nuses models +\nlocations", PRIMARY) +box("site", C2, Y["apps"], W, H, "finding-models-site\ncorpus catalog", PRIMARY) +box("forge", C3, Y["apps"], W, H, "Finding Model Forge\nfmf.oidm.org", PRIMARY) +arrow("f5", "fms", "bottom", "site", "top", "git submodule") # row2->row3, same column, straight vertical +arrow("f6", "fm", "bottom", "forge", "top", "engine") # row2->row3, same column, straight vertical +# C1 has no arrow through this gap (imaging-problem-list is fed from row 4 +# below, not row 2 above), so it is clear for this caption +els.append(text("cdes_note", C1, Y["fm_pipeline"] + H + 12, "(CDEStaging also has an\ninformal path to RadElement)", size=13, color=BODY, w=W)) + +# row 4: anatomy +box("radlex", C1, Y["anatomy"], W, H, "RadLex (RSNA)\nRID codes", EXTERNAL) +box("alorg", C2, Y["anatomy"], W, H, "anatomiclocations.org\n+ BodyPartIndex", TERTIARY) +box("alpkg", C3, Y["anatomy"], W, H, "anatomic-locations pkg\ninside findingmodel", SECONDARY) +arrow("f7", "radlex", "right", "alorg", "left", "subset") +arrow("f8", "alorg", "right", "alpkg", "left", "lineage", dashed=True) + +# row3 <-> row4: adjacent rows -- one clean line, no bends, even though it +# spans the row's full width (alpkg is the rightmost box in row 4, ipl the +# leftmost in row 3, to keep each row's own left-to-right reading intact) +arrow("f9", "alpkg", "top", "ipl", "bottom", "used by", s_frac=0.5, d_frac=0.5) + +# row 5: terminology lookup +box("others", C1, Y["terms"], W, H, "SNOMED CT, FMA,\nLOINC, UMLS", EXTERNAL) +box("molu", C2, Y["terms"], W, H, "med-ontology-lookup\nmolu", SECONDARY) +box("mvp", C3, Y["terms"], W, H, "IPL-MVP-\nExtractionAndLabeling\n(superseded)", PLANNED, dashed=True) +arrow("f10", "others", "right", "molu", "left", "lookups") +els.append(text("molu_note", C2, Y["terms"] + H + 14, "molu also enriches findingmodel\nmetadata by ontology search (see text)", size=13, color=BODY)) + +# ---------------------------------------------------------------- legend / footnote +Y_END = Y["terms"] + H + 60 +els.append(text("legend", 0, Y_END, "Orange: external terminology. Light blue: content repository.\nMid blue: library. Dark blue: application. Dashed: lineage or superseded.", size=13, color=BODY)) + +save("knowledge/repositories/repository-map.excalidraw") diff --git a/tools/diagrams/build_three_axes.py b/tools/diagrams/build_three_axes.py new file mode 100644 index 0000000..1553072 --- /dev/null +++ b/tools/diagrams/build_three_axes.py @@ -0,0 +1,396 @@ +#!/usr/bin/env python3 +"""Build the OIDM "three axes of Foundation Context" detail diagram. + +A smaller companion to build_pillars.py, zoomed into the Foundation +Context (AMBER) pillar of that stack: the three axes shared knowledge is +organized along -- findings/diagnoses, anatomic locations, exam types -- +each a curated layer over an existing external standard, and each with a +hierarchy of its own. Same AMBER palette and same icon files as the main +stack diagram (from excalib.py / icons/), so the two figures read as one +family. Icons: Lucide (tag), Health Icons (lungs, x-ray). + +Landscape, three independent columns -- nothing joins them in this +figure, by design. Each column carries: + - icon, title, a short "WHAT/WHERE/HOW" tagline + - stacked labelled sections: a full-width band naming the section, + then that section's example tree indented TREE_INDENT from the + column's inner edge + - a small darker block at the bottom: "layered over: " +The figure ends at the bottom of the columns; there is no caption. + +All three columns share the band grammar, so they read as one figure: +the findings column bands the next-generation CDE schema's node kinds +(Findings, Diagnoses, Assessments, Data Elements, Measurements), the +anatomy column bands body regions, and the exam column bands modalities. +Each band restarts the connector bookkeeping, so a section's tree never +links back into the section above it. + +Tree rows come in three kinds. A "band" is the section header. A "node" +is a concept in the hierarchy, drawn with real line connectors rather +than box-drawing characters so the indentation is exact in a +proportional font. An "ann" is a muted annotation hanging off the node +above it -- a value set, or the unit family a measurement kind implies. +It is half-indented and takes no connector, because it is not a child +concept. A measurement names the KIND of quantity; the units follow from +the kind, so "length" is annotated "mm, cm, ..." rather than one unit. + +The columns are the same height and their "layered over" blocks line up. +A column with fewer rows spreads them toward ROW_H_MAX so the leading +stays close across columns; whatever space is still left over falls +above that column's bottom block, because every column's first band must +start on the same line. + +Text widths below were measured in headless Chromium at the render font +(`Helvetica, Segoe UI Emoji`), per tools/diagrams/README.md. They place +the muted suffix after a root label and let the build assert that no row +overflows its column, neither of which can be estimated. CONTENT_W is +set by the widest single row (the `presence` value set) plus the margins. + +Exam type names are real LOINC/RSNA Playbook LongCommonName values, +checked against ~/exam-types/sources/LoincRsnaRadiologyPlaybook.xlsx -- +note the capital V in "XR Knee 2 Views", that the thyroid entry is "US +Thyroid gland" rather than "US Thyroid", and that the Playbook has no +"XR Chest Portable" (its portable names all begin "Portable XR ..."), so +the second XR Chest child here is "XR Chest PA and Lateral". A family +root such as "XR Chest" is a preferred-name family, not itself an entry. + +Output: knowledge/drafts/three-axes.excalidraw; render with +render_excalidraw.py at `--width 1010 --scale 1`. +""" +from excalib import els, base, text, image, save, AMBER + +ICON = 36 +ROOT_SIZE = 14 +CHILD_SIZE = 13 +BAND_SIZE = 13 +BAND_FILL = "#fcd34d" # one step darker than the column's block fill + +W14 = { + "pulmonary nodule": 111.3, "pulmonary neoplasm": 130.0, "Lung-RADS": 74.7, + "Salter-Harris category": 136.2, "presence": 57.6, "severity": 48.2, + "length": 38.1, "CT density": 66.9, + "lung": 26.5, "pleural space": 83.3, "mediastinum": 79.4, "kidney": 40.5, + "liver": 25.7, "spleen": 41.3, "brain": 31.1, "orbit": 27.2, + "urinary bladder": 93.4, "prostate": 50.6, + "CT Chest": 59.1, "MR Knee": 58.4, "MR Brain": 58.3, "XR Knee": 56.0, + "XR Chest": 59.9, "US Abdomen": 83.3, "US Thyroid gland": 108.2, +} +W13 = { + "solid": 26.7, "part-solid": 53.5, "non-solid": 52.8, + "non-small cell lung cancer": 150.3, "adenocarcinoma of the lung": 160.4, + "present · absent · indeterminate · unknown": 247.9, + "minimal · mild · moderate · severe": 197.2, "mm, cm, ...": 64.3, "HU": 18.8, + "right lung": 53.5, "left lung": 45.5, "heart": 29.6, + "upper lobe of right lung": 133.0, "middle lobe of right lung": 138.0, + "lower lobe of right lung": 130.8, "left kidney": 58.5, "right kidney": 66.5, + "renal pelvis": 65.8, "cerebellum": 63.6, "frontal lobe": 64.3, + "CT Chest WO contrast": 130.7, "CT Chest W contrast IV": 136.5, + "CT Chest WO and W contrast IV": 187.8, "CT Lung parenchyma WO contrast": 200.9, + "CTA Chest vessels": 109.6, "MR Knee WO contrast": 130.0, + "MR Knee W contrast IV": 135.8, "MR Brain WO contrast": 130.0, + "MR Brain WO and W contrast IV": 187.1, "XR Knee 2 Views": 100.9, + "XR Knee 3 Views": 100.9, "XR Chest 2 Views": 104.5, + "XR Chest PA and Lateral": 144.3, "US Abdomen limited": 118.5, + "US Abdomen RUQ": 109.8, "(preferred family)": 99.0, + "each a LOINC/RSNA Playbook entry": 211.7, +} + +_uid = [0] + + +def uid(prefix: str) -> str: + _uid[0] += 1 + return f"{prefix}{_uid[0]}" + + +def rule(x: float, y: float, w: float) -> None: + ln = base("line", uid("rule"), x, y, w, 0, AMBER["stroke"], "transparent", sw=1) + ln.update({"points": [[0, 0], [w, 0]], "boundElements": None, "opacity": 35}) + els.append(ln) + + +def connector(x1: float, y1: float, x2: float, y2: float) -> None: + ln = base("line", uid("tc"), x1, y1, x2 - x1, y2 - y1, AMBER["stroke"], "transparent", sw=1) + ln.update({"points": [[0, 0], [x2 - x1, y2 - y1]], "boundElements": None, "opacity": 45}) + els.append(ln) + + +# ------------------------------------------------------------------ tree +INDENT = 18 +ANN_INDENT = 8 # half a step: an annotation is not a child concept +ROW_H = 19 +ROW_H_MAX = 23 # a shorter column spreads its rows to fill the region, + # but only this far: leading that differs much more than + # this between columns stops reading as one figure +BAND_H = 20 +BAND_PAD_X = 10 +BAND_GAP_ABOVE = 12 +BAND_GAP_BELOW = 6 + +Row = tuple[str, int, str, "str | None", float] + + +def row_width(kind: str, depth: int, label: str, suffix: str | None, _gap: float = 0) -> float: + """Rendered width of a row. A band spans the column, so it constrains nothing.""" + if kind == "band": + return 0.0 + if kind == "ann": + return depth * INDENT + ANN_INDENT + W13[label] + w = depth * INDENT + (W14[label] if depth == 0 else W13[label]) + return w + (7 + W13[suffix] if suffix else 0) + + +def tree_fixed_h(rows: list[Row]) -> float: + """Height of everything in a tree that does not stretch: bands and gaps.""" + return sum((BAND_GAP_ABOVE if i else 0) + BAND_H + BAND_GAP_BELOW if k == "band" else g + for i, (k, _d, _l, _s, g) in enumerate(rows)) + + +def n_rows(rows: list[Row]) -> int: + return sum(1 for r in rows if r[0] != "band") + + +def tree(x: float, y: float, rows: list[Row], row_h: float, band_x: float, band_w: float) -> float: + """Draw the banded sections of one column; returns the y it ends at. + + x is the tree's own left edge (indented from band_x); bands are drawn + full width from band_x. Connectors are lines, not characters: a + vertical dropping from just under the parent's label to the child + row's center at the parent's connector column, and a short horizontal + stub into the child label. + """ + centers: dict[int, float] = {} + cy = y + for i, (kind, depth, label, suffix, gap) in enumerate(rows): + if kind == "band": + if i: + cy += BAND_GAP_ABOVE + b = base("rectangle", uid("tb"), band_x, cy, band_w, BAND_H, + "transparent", BAND_FILL, sw=1) + b["roundness"] = {"type": 3} + els.append(b) + els.append(text(uid("tbt"), band_x + BAND_PAD_X, + cy + (BAND_H - BAND_SIZE * 1.25) / 2, label, + size=BAND_SIZE, color=AMBER["text"])) + cy += BAND_H + BAND_GAP_BELOW + centers.clear() # a new section starts its own hierarchy + continue + + cy += gap + row_h / 2 + if kind == "ann": + els.append(text(uid("ta"), x + depth * INDENT + ANN_INDENT, + cy - CHILD_SIZE * 1.25 / 2, label, + size=CHILD_SIZE, color=AMBER["mid"])) + cy += row_h / 2 + continue + + size = ROOT_SIZE if depth == 0 else CHILD_SIZE + color = AMBER["text"] if depth == 0 else AMBER["stroke"] + tx = x + depth * INDENT + if depth > 0: + col_x = x + (depth - 1) * INDENT + 7 + # start below the parent's text, not at its center, or the + # vertical strikes through the parent label's first glyph + connector(col_x, centers[depth - 1] + 10, col_x, cy) + connector(col_x, cy, tx - 4, cy) + els.append(text(uid("tn"), tx, cy - size * 1.25 / 2, label, size=size, color=color)) + if suffix: + els.append(text(uid("tns"), tx + W14[label] + 7, cy - CHILD_SIZE * 1.25 / 2, + suffix, size=CHILD_SIZE, color=AMBER["mid"])) + centers[depth] = cy + cy += row_h / 2 + return cy + + +# ---------------------------------------------------------------- column +MARGIN = 18 # column inner margin: nothing sits against the border +TREE_INDENT = 16 # trees hang this far inside the band's left edge +PAD_TOP = 16 +PAD_BOTTOM = 16 +TITLE_SIZE = 17 +TAG_SIZE = 14 +NOTE_SIZE = 13 +BLOCK_H = 8 + 2 * NOTE_SIZE * 1.25 + 8 +NOTE_GAP = 20 +TREE_BLOCK_GAP = 18 + +ICON_Y = PAD_TOP +TITLE_Y = ICON_Y + ICON + 9 +TAG_Y = TITLE_Y + TITLE_SIZE * 1.25 + 5 +RULE_Y = TAG_Y + TAG_SIZE * 1.25 + 11 +TREE_TOP = RULE_Y + 12 + + +def notes_h(notes: list[str]) -> float: + return NOTE_GAP + len(notes) * NOTE_SIZE * 1.25 if notes else 0.0 + + +def column_group_h(rows: list[Row], notes: list[str], row_h: float = ROW_H) -> float: + return tree_fixed_h(rows) + n_rows(rows) * row_h + notes_h(notes) + + +def fitted_row_h(rows: list[Row], notes: list[str], region_h: float) -> float: + """Spread a short column's rows to fill the shared region, up to a cap, + so a column with fewer rows does not sit in a hole.""" + spare = region_h - notes_h(notes) - tree_fixed_h(rows) + return max(ROW_H, min(ROW_H_MAX, spare / n_rows(rows))) + + +def axis_column(x: float, y: float, w: float, region_h: float, icon_path: str, title: str, + tagline: str, rows: list[Row], notes: list[str], desc_lines: list[str]) -> None: + r = base("rectangle", uid("col"), x, y, w, COL_H, AMBER["stroke"], AMBER["block"], sw=2) + r["roundness"] = {"type": 3} + els.append(r) + + cx = x + w / 2 + image(uid("coli"), cx - ICON / 2, y + ICON_Y, ICON, ICON, icon_path, color=AMBER["stroke"]) + els.append(text(uid("colt"), x + 8, y + TITLE_Y, title, size=TITLE_SIZE, + color=AMBER["text"], align="center", w=w - 16)) + els.append(text(uid("coltag"), x + 8, y + TAG_Y, tagline, size=TAG_SIZE, + color=AMBER["mid"], align="center", w=w - 16)) + rule(x + MARGIN, y + RULE_Y, w - 2 * MARGIN) # same span as the bands + + band_x, band_w = x + MARGIN, w - 2 * MARGIN + row_h = fitted_row_h(rows, notes, region_h) + # top-aligned, not centered: the first band of every column then sits + # on the same line just under the rule, which is what makes the three + # read as one figure. Leftover space falls above the bottom block. + top = y + TREE_TOP + tree_bottom = tree(band_x + TREE_INDENT, top, rows, row_h, band_x, band_w) + + ny = tree_bottom + NOTE_GAP + for ln in notes: + els.append(text(uid("coln"), band_x, ny, ln, size=NOTE_SIZE, color=AMBER["mid"])) + ny += NOTE_SIZE * 1.25 + + rb = base("rectangle", uid("colblk"), band_x, y + BLOCK_Y, band_w, BLOCK_H, + AMBER["text"], AMBER["stroke"], sw=1) + rb["roundness"] = {"type": 3} + els.append(rb) + by = y + BLOCK_Y + (BLOCK_H - len(desc_lines) * NOTE_SIZE * 1.25) / 2 + 2 + for ln in desc_lines: + els.append(text(uid("colblkt"), band_x + 6, by, ln, size=NOTE_SIZE, + color="#fef3c7", align="center", w=band_w - 12)) + by += NOTE_SIZE * 1.25 + + +# ---------------------------------------------------------------- content +FINDINGS: list[Row] = [ + ("band", 0, "Findings", None, 0), + ("node", 0, "pulmonary nodule", None, 0), + ("node", 1, "solid", None, 0), + ("node", 1, "part-solid", None, 0), + ("node", 1, "non-solid", None, 0), + ("band", 0, "Diagnoses", None, 0), + ("node", 0, "pulmonary neoplasm", None, 0), + ("node", 1, "non-small cell lung cancer", None, 0), + ("node", 2, "adenocarcinoma of the lung", None, 0), + ("band", 0, "Assessments", None, 0), + ("node", 0, "Lung-RADS", None, 0), + ("node", 0, "Salter-Harris category", None, 0), + ("band", 0, "Data Elements", None, 0), + ("node", 0, "presence", None, 0), + ("ann", 0, "present · absent · indeterminate · unknown", None, 0), + ("node", 0, "severity", None, 0), + ("ann", 0, "minimal · mild · moderate · severe", None, 0), + # a measurement names the KIND of quantity; the unit family follows + ("band", 0, "Measurements", None, 0), + ("node", 0, "length", None, 0), + ("ann", 0, "mm, cm, ...", None, 0), + ("node", 0, "CT density", None, 0), + ("ann", 0, "HU", None, 0), +] + +ANATOMY: list[Row] = [ + ("band", 0, "thorax", None, 0), + ("node", 0, "lung", None, 0), + ("node", 1, "right lung", None, 0), + ("node", 2, "upper lobe of right lung", None, 0), + ("node", 2, "middle lobe of right lung", None, 0), + ("node", 2, "lower lobe of right lung", None, 0), + ("node", 1, "left lung", None, 0), + ("node", 0, "pleural space", None, 0), + ("node", 0, "mediastinum", None, 0), + ("node", 1, "heart", None, 0), + ("band", 0, "abdomen", None, 0), + ("node", 0, "kidney", None, 0), + ("node", 1, "left kidney", None, 0), + ("node", 1, "right kidney", None, 0), + ("node", 2, "renal pelvis", None, 0), + ("node", 0, "liver", None, 0), + ("node", 0, "spleen", None, 0), + ("band", 0, "head", None, 0), + ("node", 0, "brain", None, 0), + ("node", 1, "cerebellum", None, 0), + ("node", 1, "frontal lobe", None, 0), + ("node", 0, "orbit", None, 0), + ("band", 0, "pelvis", None, 0), + ("node", 0, "urinary bladder", None, 0), + ("node", 0, "prostate", None, 0), +] + +EXAMS: list[Row] = [ + ("band", 0, "CT", None, 0), + ("node", 0, "CT Chest", "(preferred family)", 0), + ("node", 1, "CT Chest WO contrast", None, 0), + ("node", 1, "CT Chest W contrast IV", None, 0), + ("node", 1, "CT Chest WO and W contrast IV", None, 0), + ("node", 1, "CT Lung parenchyma WO contrast", None, 0), + ("node", 1, "CTA Chest vessels", None, 0), + ("band", 0, "MR", None, 0), + ("node", 0, "MR Knee", "(preferred family)", 0), + ("node", 1, "MR Knee WO contrast", None, 0), + ("node", 1, "MR Knee W contrast IV", None, 0), + ("node", 0, "MR Brain", "(preferred family)", 6), + ("node", 1, "MR Brain WO contrast", None, 0), + ("node", 1, "MR Brain WO and W contrast IV", None, 0), + ("band", 0, "XR", None, 0), + ("node", 0, "XR Knee", "(preferred family)", 0), + ("node", 1, "XR Knee 2 Views", None, 0), + ("node", 1, "XR Knee 3 Views", None, 0), + ("node", 0, "XR Chest", "(preferred family)", 6), + ("node", 1, "XR Chest 2 Views", None, 0), + ("node", 1, "XR Chest PA and Lateral", None, 0), + ("band", 0, "US", None, 0), + ("node", 0, "US Abdomen", "(preferred family)", 0), + ("node", 1, "US Abdomen limited", None, 0), + ("node", 1, "US Abdomen RUQ", None, 0), + ("node", 0, "US Thyroid gland", None, 6), +] + +specs = [ + ("icons/lucide-tag.svg", "Findings/Diagnoses", "WHAT was found", FINDINGS, [], + ["layered over: finding models", "· ACR/RSNA CDEs"]), + ("icons/healthicons-lungs.svg", "Anatomic Locations", "WHERE it is", ANATOMY, [], + ["layered over: RadLex"]), + ("icons/healthicons-xray.svg", "Exam Types", "HOW it was seen", EXAMS, + ["each a LOINC/RSNA Playbook entry"], ["layered over: LOINC/RSNA", "Playbook"]), +] + +# ---------------------------------------------------------------- layout +GAP_COL = 20 +CUSHION = 8 # clear space between the longest row and the band's right edge +COL_W = 316 # 2*MARGIN + TREE_INDENT + widest row (255.9) + CUSHION +CONTENT_W = 3 * COL_W + 2 * GAP_COL +Y0 = 0 + +# The widest row sets the column width. A row must end inside the band +# above it, not merely inside the column, or it reads as an overflow -- +# so assert that here rather than discovering it in the render. +_fits = COL_W - 2 * MARGIN - TREE_INDENT - CUSHION +_widest = max((row_width(*r), r[2]) for _i, _t, _g, rows, _n, _d in specs for r in rows) +assert _widest[0] <= _fits, f"row {_widest[1]!r} ({_widest[0]}) exceeds {_fits}" + +REGION_H = max(column_group_h(rows, notes) for _i, _t, _g, rows, notes, _d in specs) +COL_H = TREE_TOP + REGION_H + TREE_BLOCK_GAP + BLOCK_H + PAD_BOTTOM +BLOCK_Y = COL_H - PAD_BOTTOM - BLOCK_H + +for i, (ipath, title, tagline, rows, notes, desc_lines) in enumerate(specs): + axis_column(i * (COL_W + GAP_COL), Y0, COL_W, REGION_H, ipath, title, tagline, + rows, notes, desc_lines) + +save("knowledge/drafts/three-axes.excalidraw") +print(f"figure {CONTENT_W}x{COL_H} region {REGION_H} widest row {_widest[1]!r} {_widest[0]}") +for _i, t, _g, rows, notes, _d in specs: + print(f" {t}: {n_rows(rows)} rows, row_h {fitted_row_h(rows, notes, REGION_H):.1f}") diff --git a/tools/diagrams/build_two_collections.py b/tools/diagrams/build_two_collections.py new file mode 100644 index 0000000..1168ab4 --- /dev/null +++ b/tools/diagrams/build_two_collections.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python3 +"""Build the "one kind of content, two collections" figure for the Finding +Models and Common Data Elements hub page. + +Finding/diagnosis definitions are one kind of content held in two collections +that differ only in how they are released. The figure says that three times +over: the two panels carry the same green as the finding/diagnosis definition +nodes in build_two_planes.py (excalib's FINDING palette, via FIND below), the +band between them reads as a beta-to-release gradient, and the amber band +underneath is the one schema both are moving onto. + + +--------------------------+ ~~~~~~~ +--------------------------+ GREEN + | (tag) Open Imaging | graduate | (tag) ACR/RSNA Common | + | Finding Models | ------> | Data Elements | + | inclusive . beta ... | [gradient]| well-reviewed . release | + | [hydronephrosis][renal] | <------ | [abdominal aortic an.] | + | [pulm nodule]---+-- index --+->[pulm nodule] | + +--------------------------+ codes +--------------------------+ + | moving onto | moving onto + +---------------------------------------------------------------+ AMBER + | the next-generation schema | + | one graph of interconnected concepts for both collections | + +---------------------------------------------------------------+ + +Constraints that drove the layout and are easy to break by nudging a number: + +1. The gap between the panels is 172px and it has to hold both band labels at + 13px, so every line of them is wrapped to <= 143px ("definition keeps its + OIFM" is the widest). Widening the panels to fit their own text on fewer + lines narrows this gap and breaks the labels instead. +2. The gap is a five-item vertical stack -- label, arrow, gradient bar, arrow, + label -- and the dotted index-codes link has to clear all of it. That is why + the two "pulmonary nodule" nodes are the BOTTOM row of each panel and the + other examples are the top row: the link then runs at y=220, below the band + stack, and crosses nothing. +3. Those two nodes face each other across the gap -- the left one is flush to + its panel's right padding, the right one flush to its panel's left padding -- + so the link is a short straight run rather than a line across two panels. +4. Arrowheads are drawn by excalib.tri_head(), not Excalidraw's built-ins, + which take their size from the line's strokeWidth; HEAD sets it directly so + the thin band arrows keep small solid heads. +5. The amber band's title is centred rather than carrying an icon in the left + corner like the panels do: the two "moving onto" arrows come down at the + panel centres (x=182 and x=718) and would crowd a left-aligned header. + +Text widths are measured, not estimated (see tools/diagrams/README.md): every +width below is `measureText` at `px Helvetica, Segoe UI Emoji` in +headless Chromium. + +Icons: Lucide (ISC) tag, the same glyph build_two_planes.py and +build_three_axes.py use for a finding/diagnosis definition. See icons/LICENSES.md. + +Output: knowledge/drafts/two-collections.excalidraw; render with render_excalidraw.py. +""" +from __future__ import annotations + +from excalib import els, base, text, image, save, tri_head, AMBER, CAPTION + +# ---------------------------------------------------------------- palette +# The finding/diagnosis definition green, straight from build_two_planes.py's +# KIND_DEF / build_foundation_network.py's FINDING: the panels ARE that node +# kind, drawn large. +FIND = {"band": "#d1fae5", "block": "#a7f3d0", "stroke": "#059669", + "text": "#064e3b", "mid": "#047857"} +# Beta -> release, seven steps of one hue so the band reads as a single ramp. +RAMP = ["#ecfdf5", "#d1fae5", "#a7f3d0", "#6ee7b7", "#34d399", "#10b981", "#059669"] + +W = 900 # canvas width +ICON = 26 # Lucide stroke art +PAD = 18 # panel inner padding +HEAD = 9.0 # filled arrowhead length (band + "moving onto" arrows) + +PANEL_Y, PANEL_H = 0, 272 +LW = RW = 364 # panel width +RX = W - RW # right panel x (536) +GAP_L, GAP_R = LW, RX # 364 .. 536 +GAP_C = (GAP_L + GAP_R) / 2 # 450 + +ROW_A_Y, ROW_B_Y, ROW_H = 144, 200, 40 +AMBER_Y, AMBER_H = 320, 92 + +_uid = [0] + + +def uid(prefix: str) -> str: + _uid[0] += 1 + return f"{prefix}{_uid[0]}" + + +# ---------------------------------------------------------------- helpers +def panel(id_: str, x: float, w: float, pal: dict) -> dict: + r = base("rectangle", id_, x, PANEL_Y, w, PANEL_H, pal["stroke"], pal["band"], sw=2) + r["roundness"] = {"type": 3} + els.append(r) + return r + + +def header(x: float, title: str, title_w: float, blocks: list[list[tuple[str, float]]], + pal: dict) -> None: + """Tag icon at the panel's left padding, title beside it, description lines + aligned to the title (not to the icon). `blocks` groups those lines: the + channel descriptors and the maintainer are separate blocks, set 7px apart, + so a descriptor that wraps to two lines still reads as one statement rather + than running into the maintainer line below it.""" + image(uid("hicon"), x + PAD, PANEL_Y + 16, ICON, ICON, "icons/lucide-tag.svg", + color=pal["stroke"]) + tx = x + PAD + ICON + 10 + els.append(text(uid("ht"), tx, PANEL_Y + 18, title, size=17, color=pal["text"], w=title_w)) + y = PANEL_Y + 50 + for block in blocks: + for s, lw in block: + els.append(text(uid("hs"), tx, y, s, size=13, color=pal["mid"], w=lw)) + y += 13 * 1.25 + y += 7 + + +def node(id_: str, x: float, y: float, label: str, label_w: float, pal: dict) -> dict: + """A tiny example definition: one 13px line in a small rounded box.""" + w = label_w + 20 + r = base("rectangle", id_, x, y, w, ROW_H, pal["stroke"], pal["block"], sw=2) + r["roundness"] = {"type": 3} + els.append(r) + els.append(text(id_ + "_t", x + 8, y + (ROW_H - 13 * 1.25) / 2, label, size=13, + color=pal["text"], align="center", w=w - 16)) + return r + + +def line(id_: str, pts: list[tuple[float, float]], color: str, sw=2, dashed=False, + head: float | None = HEAD) -> None: + """A straight or routed run, finished with a solid triangle whose size is set + here rather than derived from strokeWidth. head=None draws no head.""" + x0, y0 = pts[0] + end_pts = list(pts) + if head: + tip, frm = pts[-1], pts[-2] + dx, dy = tip[0] - frm[0], tip[1] - frm[1] + length = (dx ** 2 + dy ** 2) ** 0.5 or 1.0 + end_pts = list(pts[:-1]) + [(tip[0] - dx / length * head * 0.55, + tip[1] - dy / length * head * 0.55)] + ex, ey = end_pts[-1] + ar = base("arrow", id_, x0, y0, ex - x0, ey - y0, color, "transparent", + dashed=dashed, sw=sw) + ar.update({"points": [[px - x0, py - y0] for px, py in end_pts], + "startBinding": None, "endBinding": None, "startArrowhead": None, + "endArrowhead": None, "boundElements": None}) + els.append(ar) + if head: + tri_head(id_ + "_h", pts[-1], pts[-2], color, size=head) + + +def caption(id_: str, cx: float, y_top: float, lines: list[tuple[str, float]], + size=13, color=CAPTION) -> None: + """A centred multi-line label, each line given its MEASURED width so the + block centres exactly on cx.""" + w = max(lw for _, lw in lines) + y = y_top + for s, lw in lines: + els.append(text(uid(id_), cx - w / 2, y, s, size=size, color=color, + align="center", w=w)) + y += size * 1.25 + + +def plate(id_: str, cx: float, cy: float, s: str, w: float, size=13, color=CAPTION, + fill="#ffffff", pad_x=6, pad_y=3) -> None: + """An edge label on an opaque plate, centred on (cx, cy), so it masks the + line it sits on. w is the MEASURED text width.""" + bw, bh = w + 2 * pad_x, size * 1.25 + 2 * pad_y + r = base("rectangle", id_, cx - bw / 2, cy - bh / 2, bw, bh, "transparent", fill, sw=0) + r["roundness"] = {"type": 3} + els.append(r) + els.append(text(id_ + "_t", cx - bw / 2 + pad_x, cy - bh / 2 + pad_y, s, size=size, + color=color, align="center", w=w)) + + +# ================================================================ the two panels +panel("panel_oifm", 0, LW, FIND) +panel("panel_cde", RX, RW, FIND) + +header(0, "Open Imaging Finding Models", 226.8, + [[("inclusive · beta channel ·", 143.8), + ("rapid additions and updates", 159.7)], + [("maintained by the OIDM project", 182.8)]], FIND) +header(RX, "ACR/RSNA Common Data Elements", 277.8, + [[("well-reviewed · release channel · stable", 228.3)], + [("American College of Radiology ·", 186.4), + ("Radiological Society of North America ·", 228.2), + ("radelement.org", 87.4)]], FIND) + +# Top row: the examples that live in only one collection. Bottom row: the one +# definition that lives in both, flush to the facing edges so the dotted link +# between them is a short straight run clear of the band stack above. +node("n_hydro", PAD, ROW_A_Y, "hydronephrosis", 88.9, FIND) +node("n_calc", PAD + 88.9 + 20 + 14, ROW_A_Y, "renal calculus", 79.5, FIND) +nod_l = node("n_nodule_l", LW - PAD - (103.3 + 20), ROW_B_Y, "pulmonary nodule", 103.3, FIND) +node("n_aaa", RX + PAD, ROW_A_Y, "abdominal aortic aneurysm", 156.1, FIND) +nod_r = node("n_nodule_r", RX + PAD, ROW_B_Y, "pulmonary nodule", 103.3, FIND) + +# ================================================================ the band between +# Five items stacked in the 172px gap: label, arrow, gradient bar, arrow, label. +caption("bl_grad", GAP_C, 28, + [("definitions proved out", 123.6), ("here graduate to review", 136.6)]) +line("b_grad", [(GAP_L + 4, 72), (GAP_R - 4, 72)], FIND["stroke"], sw=2) + +BAR_Y, BAR_H = 86, 16 +BAR_X, BAR_W = GAP_L + 4, (GAP_R - 4) - (GAP_L + 4) # the same span as the two arrows +step = BAR_W / len(RAMP) +for i, col in enumerate(RAMP): + els.append(base("rectangle", uid("ramp"), BAR_X + i * step, BAR_Y, step + 0.5, BAR_H, + "transparent", col, sw=0)) + +line("b_cross", [(GAP_R - 4, 114), (GAP_L + 4, 114)], FIND["stroke"], sw=2) +caption("bl_cross", GAP_C, 124, + [("cross-links: a migrated", 130.0), ("definition keeps its OIFM", 143.1), + ("entry and carries its", 113.4), ("CDE identity", 72.2)]) + +# ================================================================ the shared definition +LINK_Y = ROW_B_Y + ROW_H / 2 +line("l_index", [(nod_l["x"] + nod_l["width"], LINK_Y), (nod_r["x"], LINK_Y)], + FIND["stroke"], sw=2, dashed=True, head=None) +plate("l_index_l", GAP_C, LINK_Y, "index codes", 69.4, color=FIND["mid"]) + +# ================================================================ the next-generation schema +amber = base("rectangle", "amber", 0, AMBER_Y, W, AMBER_H, AMBER["stroke"], AMBER["band"], sw=2) +amber["roundness"] = {"type": 3} +els.append(amber) + +A_TOP = AMBER_Y + (AMBER_H - (17 * 1.25 + 6 + 13 * 1.25)) / 2 +els.append(text("a_title", (W - 210.7) / 2, A_TOP, "the next-generation schema", + size=17, color=AMBER["text"], align="center", w=210.7)) +els.append(text("a_sub", (W - 329.5) / 2, A_TOP + 17 * 1.25 + 6, + "one graph of interconnected concepts for both collections", + size=13, color=AMBER["mid"], align="center", w=329.5)) + +for i, cx in enumerate((LW / 2, RX + RW / 2)): + line(f"m_onto{i}", [(cx, PANEL_Y + PANEL_H + 2), (cx, AMBER_Y - 2)], + AMBER["stroke"], sw=2) + els.append(text(uid("m_l"), cx + 12, (PANEL_Y + PANEL_H + AMBER_Y) / 2 - 8, + "moving onto", size=13, color=AMBER["mid"], w=70.8)) + +save("knowledge/drafts/two-collections.excalidraw") diff --git a/tools/diagrams/build_two_planes.py b/tools/diagrams/build_two_planes.py new file mode 100644 index 0000000..aad9a2b --- /dev/null +++ b/tools/diagrams/build_two_planes.py @@ -0,0 +1,386 @@ +#!/usr/bin/env python3 +"""Build the "two planes" overview figure for the knowledgebase root page. + +The one-picture version of the whole model: Patient Context and Foundation +Context as two tilted planes, one above the other, with every fact recorded +about this patient attached downward to the shared knowledge of what such a +thing is. + + +---------------------------------------------------------------+ TEAL + | Patient Context ,-------- found on --------------. | + | [CT chest WO] <-found on- [pulmonary nodule] [pleural eff] | + +---------------------------------------------------------------+ + | is a | is a | located at | is a | located at <- rose + +---------------------------------------------------------------+ AMBER + | Foundation Context | + | [CT Chest WO contrast] [pulm nodule def] [pleural eff def] | tier 1 + | |member of family |seen on |occurs at |occurs at | + | [CT Chest] -modality-> [CT] | | | tier 2 + | |covers | | | + | [thorax] -contains-> [lung] -> [upper lobe] [pleural space] | tier 3 + | `------------------ contains ------------------^ | + +---------------------------------------------------------------+ + +Geometry: both planes are the same parallelogram -- top edge offset SKEW px +to the right of the bottom edge -- so the pair reads as two isometric sheets +seen from slightly above. Because the top edge is inset, anything placed near +a plane's top must clear `left_edge(y)`, which is what `lx()` computes; every +x-coordinate below was checked against it rather than eyeballed. + +Constraints that drove the layout and are easy to break by nudging a number: + +1. The lower plane's header ("Foundation Context" + subtitle) occupies + x = 68..283 at y = 264..308, so the leftmost cross-plane edge has to come + down at x >= ~300 to miss it. Tier 1 therefore starts at x=120 and the + plane's left flank carries the grey "knowledge continues" nodes instead. +2. Five cross-plane edges, and none may cross another, so their x-order is the + same where they leave the upper plane (300 / 490 / 602 / 720 / 866) and + where they land (300 / 490 / 602 / 720 / 856). Four are plumb; the fifth + leans 10px to clear the effusion definition's right edge. Two of them run + past tier 1 into tier 3 and thread the gaps between tier 1's boxes -- x=602 + uses the 32px gap between the two definitions -- so those boxes cannot be + moved together, and neither definition can be widened. +3. With two findings in the upper plane, the second is too far right for a + straight "found on" edge back to the exam. Its edge runs ABOVE the row, in + the lane at y=72: every cross-plane edge leaves a node's BOTTOM, so the + band between the header and the row is the one place nothing crosses. +4. The foundation plane is three tiers and the vertical axis is generality: + what the patient's data attaches to sits in tier 1, and each tier below is + the more general thing. The exam axis (Playbook entry -> family -> modality) + and the anatomy axis (upper lobe <- lung <- thorax) both read that way, + which is why the family, not the specific entry, covers the thorax. +5. The pleural space is the thorax's second anatomic branch, but it sits at the + far right, under the effusion's definition. Its "contains" edge is drawn as + a lane BELOW tier 3 rather than a long horizontal through it, which would + have to cross both lung and the upper lobe. +6. Arrowheads are drawn by excalib.tri_head(), not by Excalidraw's built-in + ones: the built-ins take their size from the line's strokeWidth, which + forces a thick rose edge to carry an outsized head. HEAD_R and HEAD_G set + the two sizes directly. + +Text widths are measured, not estimated (see tools/diagrams/README.md): every +box width below is `measured width + padding` from canvas `measureText` at +`px Helvetica, Segoe UI Emoji` in headless Chromium. + +Icons: Health Icons (CC0/MIT, outline, filled-path art -- rendered at 32px) +for the x-ray and lungs glyphs; Lucide (ISC/MIT, stroke art -- 28px) for +layers, book-open, clipboard-list, clipboard and tag. See icons/LICENSES.md. + +Output: knowledge/drafts/two-planes.excalidraw; render with render_excalidraw.py. +""" +from __future__ import annotations + +from excalib import (els, base, text, image, save, tri_head, + AMBER, TEAL, ROSE, CAPTION) + +# ---------------------------------------------------------------- constants +SKEW = 55 # how far each plane's top edge sits right of its bottom edge +PW = 880 # plane width, measured along an edge +ICON = 28 # Lucide (stroke art) +ICON_FILLED = 32 # Health Icons (filled-path art, optically smaller at equal size) + +CROSS = ROSE["stroke"] # deep rose: the cross-plane attachments +FAINT = "#a8a29e" # warm grey: "the knowledge continues" edges +GREY_FILL, GREY_STROKE = "#e7e5e4", "#a8a29e" +REL = "#78716c" # grey relationship edges inside the lower plane + +# Node kinds inside the Foundation Context plane. Fills and strokes are taken +# straight from build_foundation_network.py's FINDING / ANATOMY / EXAM / GREY +# so the two figures name the same kinds with the same colours. Each dict keeps +# excalib's band/block/stroke/text/mid shape; only "band" (the plane tint) is +# shared, since every one of these sits on the amber plane. The modality grey +# uses a darker stroke than the mini-network's #9ca3af, which is too faint to +# hold an edge against the amber ground. +KIND_DEF = {"band": AMBER["band"], "block": "#d1fae5", "stroke": "#059669", + "text": "#064e3b", "mid": "#047857"} # finding/diagnosis definition +KIND_ANAT = {"band": AMBER["band"], "block": "#bfdbfe", "stroke": "#1d4ed8", + "text": "#1e3a8a", "mid": "#1d4ed8"} # anatomic location +KIND_EXAM = AMBER # exam type (already the amber block) +KIND_MOD = {"band": AMBER["band"], "block": "#e5e7eb", "stroke": "#6b7280", + "text": "#374151", "mid": "#4b5563"} # modality + +P1_Y, P1_H = 0, 190 # upper plane (Patient Context) +P2_Y, P2_H = 250, 440 # lower plane (Foundation Context); 60px gap between +HEAD_R, HEAD_G = 13.0, 10.0 # filled arrowhead length: rose edges, grey/teal edges + +_uid = [0] + + +def uid(prefix: str) -> str: + _uid[0] += 1 + return f"{prefix}{_uid[0]}" + + +def lx(y: float, py: float, ph: float) -> float: + """Left edge of a plane at height y -- the top edge is SKEW px further right.""" + return SKEW * (1 - (y - py) / ph) + + +# ---------------------------------------------------------------- helpers +def plane(id_: str, py: float, ph: float, pal: dict) -> None: + """A tilted parallelogram: a closed Excalidraw line, filled with the band tint.""" + ln = base("line", id_, SKEW, py, PW + SKEW, ph, pal["stroke"], pal["band"], sw=2) + ln.update({"points": [[0, 0], [PW, 0], [PW - SKEW, ph], [-SKEW, ph], [0, 0]], + "roundness": None, "boundElements": None}) + els.append(ln) + + +def header(x: float, y: float, icon_path: str, pal: dict, title: str, subtitle: str, + filled_icon=False) -> None: + """Plane title with its icon to the left and a subtitle under it.""" + s = ICON_FILLED if filled_icon else ICON + image(uid("hicon"), x, y + 2 - (s - ICON) / 2, s, s, icon_path, color=pal["stroke"]) + els.append(text(uid("htitle"), x + ICON + 12, y, title, size=20, color=pal["text"])) + els.append(text(uid("hsub"), x + ICON + 12, y + 26, subtitle, size=13, color=pal["mid"])) + + +def node_rect(id_: str, x: float, y: float, w: float, h: float, pal: dict) -> dict: + r = base("rectangle", id_, x, y, w, h, pal["stroke"], pal["block"], sw=2) + r["roundness"] = {"type": 3} + els.append(r) + return r + + +def hnode(id_: str, x: float, y: float, w: float, h: float, icon_path: str, pal: dict, + title: str, sub: str, filled_icon=False) -> dict: + """Icon on the left at a fixed inset, title line, lighter second line -- + the style used for the two Patient Context nodes.""" + r = node_rect(id_, x, y, w, h, pal) + s = ICON_FILLED if filled_icon else ICON + image(uid("ni"), x + 12 - (s - ICON) / 2, y + (h - s) / 2, s, s, icon_path, color=pal["stroke"]) + tx = x + 12 + ICON + 10 + top = y + (h - (16 * 1.25 + 2 + 13 * 1.25)) / 2 + els.append(text(uid("nt"), tx, top, title, size=16, color=pal["text"], w=w - (tx - x) - 10)) + els.append(text(uid("ns"), tx, top + 16 * 1.25 + 2, sub, size=13, color=pal["mid"], + w=w - (tx - x) - 10)) + return r + + +def chip(id_: str, x: float, y: float, w: float, h: float, pal: dict, title: str, + desc: str | None = None, icon_path: str | None = None, filled_icon=False, + text_w: float | None = None) -> dict: + """The Foundation Context node: content vertically centred, and horizontally + either centred text (no icon) or an icon + text-column group centred as a + unit. text_w is the MEASURED width of the widest of title/desc, needed to + centre that group; with no icon it is not used. Every foundation node is + the same height, so the three tiers read as three rows of one grid.""" + r = node_rect(id_, x, y, w, h, pal) + lines_h = 15 * 1.25 + (2 + 13 * 1.25 if desc else 0) + ty = y + (h - lines_h) / 2 + if icon_path: + s_ = ICON_FILLED if filled_icon else ICON + gx = x + (w - (s_ + 10 + text_w)) / 2 + image(uid("ni"), gx, y + (h - s_) / 2, s_, s_, icon_path, color=pal["stroke"]) + els.append(text(uid("nt"), gx + s_ + 10, ty, title, size=15, color=pal["text"], w=text_w)) + if desc: + els.append(text(uid("nd"), gx + s_ + 10, ty + 15 * 1.25 + 2, desc, size=13, + color=pal["mid"], w=text_w)) + else: + els.append(text(uid("nt"), x + 8, ty, title, size=15, color=pal["text"], + align="center", w=w - 16)) + if desc: + els.append(text(uid("nd"), x + 8, ty + 15 * 1.25 + 2, desc, size=13, + color=pal["mid"], align="center", w=w - 16)) + return r + + +def dot(id_: str, cx: float, cy: float, r: float) -> None: + e = base("ellipse", id_, cx - r, cy - r, 2 * r, 2 * r, GREY_STROKE, GREY_FILL, sw=1) + e["opacity"] = 70 + els.append(e) + + +def faint(x1: float, y1: float, x2: float, y2: float) -> None: + ln = base("line", uid("f"), x1, y1, x2 - x1, y2 - y1, FAINT, "transparent", sw=1) + ln.update({"points": [[0, 0], [x2 - x1, y2 - y1]], "boundElements": None, "opacity": 60}) + els.append(ln) + + +def path(id_: str, pts: list[tuple[float, float]], color: str, sw=3, head=HEAD_G) -> None: + """Multi-point routed arrow (excalib.arrow()'s elbow modes only do 3 points), + finished with excalib.tri_head(): a solid filled triangle whose size is set + here rather than derived from the line's strokeWidth, so a thick rose edge + and a thin grey one can carry heads of deliberately chosen sizes.""" + x0, y0 = pts[0] + tip, frm = pts[-1], pts[-2] + dx, dy = tip[0] - frm[0], tip[1] - frm[1] + length = (dx ** 2 + dy ** 2) ** 0.5 or 1.0 + # stop the line a little short so the head's base sits on it, not past it + end = (tip[0] - dx / length * head * 0.55, tip[1] - dy / length * head * 0.55) + line_pts = list(pts[:-1]) + [end] + ar = base("arrow", id_, x0, y0, end[0] - x0, end[1] - y0, color, "transparent", sw=sw) + ar.update({"points": [[px - x0, py - y0] for px, py in line_pts], "startBinding": None, + "endBinding": None, "startArrowhead": None, "endArrowhead": None, + "boundElements": None}) + els.append(ar) + tri_head(id_ + "_h", tip, frm, color, size=head) + + +def plate(id_: str, cx: float, cy: float, s: str, w: float, size=13, color=CAPTION, + fill="#ffffff", pad_x=6, pad_y=3) -> None: + """An edge label on an opaque plate, centred on (cx, cy), so it masks the + line it sits on. w is the MEASURED text width. fill is the tint the label + lands on -- a white patch inside a tinted plane is visible, so pass the + plane's band colour for labels drawn inside a plane.""" + bw, bh = w + 2 * pad_x, size * 1.25 + 2 * pad_y + r = base("rectangle", id_, cx - bw / 2, cy - bh / 2, bw, bh, "transparent", fill, sw=0) + r["roundness"] = {"type": 3} + els.append(r) + els.append(text(id_ + "_t", cx - bw / 2 + pad_x, cy - bh / 2 + pad_y, s, size=size, + color=color, align="center", w=w)) + + +# ================================================================ planes +plane("plane_patient", P1_Y, P1_H, TEAL) +plane("plane_foundation", P2_Y, P2_H, AMBER) + +header(67, P1_Y + 12, "icons/lucide-layers.svg", TEAL, + "Patient Context", "this patient · this exam") +header(68, P2_Y + 14, "icons/lucide-book-open.svg", AMBER, + "Foundation Context", "shared, curated knowledge") + +# ================================================================ upper plane: one exam, two findings +# All three sit on one row, so each finding's "found on" edge is short and +# neither crosses the cross-plane drops that leave the row's underside. The +# second finding is too far right for a straight edge back to the exam, so its +# edge runs ABOVE the row, in the lane at y=72 between the header and the nodes +# -- every cross-plane drop leaves a node's BOTTOM, so nothing is up there to +# cross. +ROW1_Y, ROW1_H = 92, 66 +exam = hnode("exam", 140, ROW1_Y, 246, ROW1_H, "icons/lucide-clipboard-list.svg", TEAL, + "CT chest without contrast", "this patient \u00b7 2026-03-04") +nodule = hnode("nodule", 470, ROW1_Y, 196, ROW1_H, "icons/lucide-clipboard.svg", TEAL, + "pulmonary nodule", "present \u00b7 8 mm \u00b7 new") +effusion = hnode("effusion", 706, ROW1_Y, 176, ROW1_H, "icons/lucide-clipboard.svg", TEAL, + "pleural effusion", "absent") +ROW1_B = ROW1_Y + ROW1_H + +path("e_found1", [(470, 125), (392, 125)], TEAL["stroke"], sw=2) +plate("l_found1", 431, 125, "found on", 50.6, color=TEAL["mid"], fill=TEAL["band"]) +path("e_found2", [(790, ROW1_Y), (790, 72), (250, 72), (250, ROW1_Y - 3)], TEAL["stroke"], sw=2) +plate("l_found2", 560, 72, "found on", 50.6, color=TEAL["mid"], fill=TEAL["band"]) + +# ================================================================ lower plane, tier 1 +# What the patient's own data attaches to: the specific Playbook exam type and +# one definition per finding. Widest lines measure 150.9 / 152.5 / 152.5px; +# with the 32/28px icon, its 10px gutter and 24px of padding that gives 218/216. +T1_Y, T1_H = 322, 62 +exam_type = chip("exam_type", 120, T1_Y, 218, T1_H, KIND_EXAM, "CT Chest WO contrast", + desc="exam type \u00b7 29252-4", icon_path="icons/healthicons-xray.svg", + filled_icon=True, text_w=150.9) +nodule_def = chip("nodule_def", 370, T1_Y, 216, T1_H, KIND_DEF, "pulmonary nodule", + desc="finding/diagnosis definition", icon_path="icons/lucide-tag.svg", + text_w=152.5) +effusion_def = chip("effusion_def", 618, T1_Y, 216, T1_H, KIND_DEF, "pleural effusion", + desc="finding/diagnosis definition", icon_path="icons/lucide-tag.svg", + text_w=152.5) +T1_B = T1_Y + T1_H + +# ================================================================ lower plane, tier 2 +T2_Y, T2_H = 448, 56 +family = chip("family", 130, T2_Y, 168, T2_H, KIND_EXAM, "CT Chest", desc="exam family \u00b7 preferred") +modality = chip("modality", 382, T2_Y, 80, T2_H, KIND_MOD, "CT", desc="modality") +T2_B = T2_Y + T2_H +T2_MID = T2_Y + T2_H / 2 + +path("r_member", [(200, T1_B), (200, T2_Y - 3)], REL, sw=2) +plate("l_member", 200, T1_B + 32, "member of family", 99.7, color=REL, fill=AMBER["band"]) +path("r_modality", [(298, T2_MID), (379, T2_MID)], REL, sw=2) +plate("l_modality", 340, T2_MID, "modality", 48.4, color=REL, fill=AMBER["band"]) +# "CT" is a hub: the family reaches it along tier 2, the nodule definition +# straight down from tier 1. +path("r_seen", [(422, T1_B), (422, T2_Y - 3)], REL, sw=2) +plate("l_seen", 422, T1_B + 32, "seen on", 46.3, color=REL, fill=AMBER["band"]) + +# ================================================================ lower plane, tier 3: anatomy +# thorax contains lung contains upper lobe; thorax also contains the pleural +# space, which sits at the far right under the effusion's definition. That +# second branch is drawn as a lane BELOW the tier rather than a long horizontal +# through it, which would have to cross lung and upper lobe. +T3_Y, T3_H = 568, 62 +thorax = chip("thorax", 130, T3_Y, 130, T3_H, KIND_ANAT, "thorax", desc="anatomic location") +lung = chip("lung", 342, T3_Y, 110, T3_H, KIND_ANAT, "lung", + icon_path="icons/healthicons-lungs.svg", filled_icon=True, text_w=28.4) +upper_lobe = chip("upper_lobe", 554, T3_Y, 185, T3_H, KIND_ANAT, "upper lobe of right lung") +pleural_space = chip("pleural_space", 760, T3_Y, 120, T3_H, KIND_ANAT, "pleural space") +T3_B = T3_Y + T3_H +T3_MID = T3_Y + T3_H / 2 + +path("r_contains1", [(260, T3_MID), (339, T3_MID)], REL, sw=2) +plate("l_contains1", 301, T3_MID, "contains", 48.4, color=REL, fill=AMBER["band"]) +path("r_contains2", [(452, T3_MID), (551, T3_MID)], REL, sw=2) +plate("l_contains2", 503, T3_MID, "contains", 48.4, color=REL, fill=AMBER["band"]) +LANE_Y = T3_B + 26 +path("r_contains3", [(215, T3_B), (215, LANE_Y), (820, LANE_Y), (820, T3_B + 3)], REL, sw=2) +plate("l_contains3", 500, LANE_Y, "contains", 48.4, color=REL, fill=AMBER["band"]) + +# The family covers the whole region; each definition occurs at its own +# structure. "occurs at" for the nodule elbows around the modality node rather +# than cutting the corner off it. +path("r_covers", [(200, T2_B), (200, T3_Y - 3)], REL, sw=2) +plate("l_covers", 200, T2_B + 32, "covers", 38.3, color=REL, fill=AMBER["band"]) +path("r_occurs1", [(560, T1_B), (560, 550), (440, 550), (440, T3_Y - 3)], REL, sw=2) +plate("l_occurs1", 552, T1_B + 32, "occurs at", 52.7, color=REL, fill=AMBER["band"]) +path("r_occurs2", [(790, T1_B), (790, T3_Y - 3)], REL, sw=2) +plate("l_occurs2", 790, T1_B + 32, "occurs at", 52.7, color=REL, fill=AMBER["band"]) + +# ================================================================ the knowledge continues +# The left cluster sits BELOW tier 1, where the plane's slanted left edge has +# moved far enough left to give a dot clearance; higher up it would straddle +# the border. +for gid, gx, gy, gr in [("g1", 96, 412, 11), ("g2", 62, 448, 9), ("g3", 92, 486, 10), + ("g4", 60, 528, 8), ("g5", 676, 452, 12), ("g6", 712, 492, 9)]: + dot(gid, gx, gy, gr) +faint(96, 412, 62, 448) +faint(96, 412, 92, 486) +faint(92, 486, 60, 528) +faint(104, 404, 124, 388) +faint(66, 535, 130, 590) +faint(676, 452, 712, 492) +faint(676, 440, 676, T1_B) + +# ================================================================ cross-plane attachments +# Five thick rose edges. Their x-order is the same where they leave the upper +# plane (300 / 490 / 602 / 720 / 866) and where they land (300 / 490 / 602 / +# 720 / 856), so none crosses another. Four are plumb; the fifth leans 10px to +# clear the effusion definition's right edge. The two that reach tier 3 thread +# the gaps between tier 1's boxes: x=602 runs down the 32px gap between the two +# definitions, which is why those two boxes cannot be moved together. +CX_LABEL_Y = 212 +path("x_exam", [(300, ROW1_B), (300, T1_Y - 3)], CROSS, sw=3, head=HEAD_R) +plate("x_exam_l", 300, CX_LABEL_Y, "is a", 20.2, color=ROSE["text"]) +path("x_nodule_isa", [(490, ROW1_B), (490, T1_Y - 3)], CROSS, sw=3, head=HEAD_R) +plate("x_nodule_isa_l", 490, CX_LABEL_Y, "is a", 20.2, color=ROSE["text"]) +path("x_nodule_loc", [(602, ROW1_B), (602, T3_Y - 3)], CROSS, sw=3, head=HEAD_R) +plate("x_nodule_loc_l", 602, CX_LABEL_Y, "located at", 56.4, color=ROSE["text"]) +path("x_effusion_isa", [(720, ROW1_B), (720, T1_Y - 3)], CROSS, sw=3, head=HEAD_R) +plate("x_effusion_isa_l", 720, CX_LABEL_Y, "is a", 20.2, color=ROSE["text"]) +path("x_effusion_loc", [(866, ROW1_B), (856, T3_Y - 3)], CROSS, sw=3, head=HEAD_R) +plate("x_effusion_loc_l", 864, CX_LABEL_Y, "located at", 56.4, color=ROSE["text"]) + +# ================================================================ legend +# One line of swatches under the plane, naming the four node kinds the fills +# stand for. Measured label widths, so the row centres exactly on the canvas. +LEG_ITEMS = [(KIND_DEF, "finding/diagnosis definition", 152.5), + (KIND_ANAT, "anatomic location", 101.2), + (KIND_EXAM, "exam type", 60.0), + (KIND_MOD, "modality", 48.4)] +SW_W, SW_H, SW_GAP, ITEM_GAP = 18, 13, 8, 28 +leg_w = sum(SW_W + SW_GAP + w for _, _, w in LEG_ITEMS) + ITEM_GAP * (len(LEG_ITEMS) - 1) +leg_x = (PW + SKEW - leg_w) / 2 +LEG_Y = P2_Y + P2_H + 22 +for _pal, _label, _w in LEG_ITEMS: + _r = base("rectangle", uid("leg"), leg_x, LEG_Y + 1.6, SW_W, SW_H, + _pal["stroke"], _pal["block"], sw=1) + _r["roundness"] = {"type": 3} + els.append(_r) + els.append(text(uid("legt"), leg_x + SW_W + SW_GAP, LEG_Y, _label, size=13, color=CAPTION, w=_w)) + leg_x += SW_W + SW_GAP + _w + ITEM_GAP + +# ================================================================ caption +els.append(text("caption", 0, P2_Y + P2_H + 54, + "every fact about this patient is attached to the shared knowledge " + "of what such a thing is", + size=14, color=CAPTION, align="center", w=PW + SKEW)) + +save("knowledge/drafts/two-planes.excalidraw") diff --git a/tools/diagrams/excalib.py b/tools/diagrams/excalib.py new file mode 100644 index 0000000..7baabe8 --- /dev/null +++ b/tools/diagrams/excalib.py @@ -0,0 +1,209 @@ +"""Shared helpers for building Excalidraw diagrams as JSON (used by build_*.py).""" +from __future__ import annotations + +import base64 +import json +import os + +# Palette (tools/diagrams follows the excalidraw-diagram skill palette) +PRIMARY = ("#3b82f6", "#1e3a5f", "#ffffff") # data structures: fill, stroke, text +SECONDARY = ("#60a5fa", "#1e3a5f", "#1e3a5f") # applications +TERTIARY = ("#93c5fd", "#1e3a5f", "#1e3a5f") # semantic foundation +EXTERNAL = ("#fed7aa", "#c2410c", "#7c2d12") # allied external project +PLANNED = ("#ffffff", "#64748b", "#475569") # dashed, documented or planned only +TITLE, SUBTITLE, BODY, LINE = "#1e40af", "#3b82f6", "#64748b", "#64748b" + +# "Five pillars" palette -- one hue per pillar of the OIDM stack, shared by +# build_pillars.py and any diagram that needs to visually match it (e.g. +# build_three_axes.py, a detail view of the Foundation Context / AMBER +# pillar). Each dict: band fill (lightest), block fill (a pastel step +# deeper, for content sitting on the band), stroke (dark border/icon +# color), text (darkest, for bold titles), mid (a mid-tone for subtitles +# and descriptors, same as stroke here since these are already fairly dark). +# Matched lightness steps across hues; no hue repeats, no blue reused. +AMBER = {"band": "#fef3c7", "block": "#fde68a", "stroke": "#b45309", "text": "#78350f", "mid": "#b45309"} +TEAL = {"band": "#ccfbf1", "block": "#99f6e4", "stroke": "#0f766e", "text": "#134e4a", "mid": "#0f766e"} +VIOLET = {"band": "#ede9fe", "block": "#ddd6fe", "stroke": "#6d28d9", "text": "#4c1d95", "mid": "#6d28d9"} +ROSE = {"band": "#ffe4e6", "block": "#fecdd3", "stroke": "#be123c", "text": "#881337", "mid": "#be123c"} +GREEN = {"band": "#dcfce7", "block": "#bbf7d0", "stroke": "#15803d", "text": "#14532d", "mid": "#15803d"} +CAPTION = "#64748b" # neutral gray for connective captions that sit between/across pillars + +els: list[dict] = [] +files: dict = {} +_seed = 1000 + + +def reset() -> None: + global _seed + els.clear() + files.clear() + _seed = 1000 + + +def seed() -> int: + global _seed + _seed += 1 + return _seed + + +def base(kind: str, id_: str, x: float, y: float, w: float, h: float, stroke: str, fill: str, dashed=False, sw=2) -> dict: + return { + "type": kind, "id": id_, "x": x, "y": y, "width": w, "height": h, + "strokeColor": stroke, "backgroundColor": fill, "fillStyle": "solid", + "strokeWidth": sw, "strokeStyle": "dashed" if dashed else "solid", "roughness": 0, + "opacity": 100, "angle": 0, "seed": seed(), "version": 1, "versionNonce": seed(), + "isDeleted": False, "groupIds": [], "boundElements": [], "link": None, "locked": False, + } + + +def text(id_: str, x: float, y: float, s: str, size=16, color=BODY, align="left", w: float | None = None, container: str | None = None, font=2) -> dict: + lines = s.split("\n") + est_w = w if w is not None else max(len(l) for l in lines) * size * 0.58 + h = len(lines) * size * 1.25 + t = base("text", id_, x, y, est_w, h, color, "transparent", sw=1) + t.update({"text": s, "originalText": s, "fontSize": size, "fontFamily": font, "textAlign": align, + "verticalAlign": "middle" if container else "top", "containerId": container, "lineHeight": 1.25, + "boundElements": None}) + return t + + +def box(id_: str, x: float, y: float, w: float, h: float, label: str, colors, dashed=False, size=16) -> dict: + fill, stroke, tcolor = colors + r = base("rectangle", id_, x, y, w, h, stroke, fill, dashed=dashed) + r["roundness"] = {"type": 3} + t = text(id_ + "_t", x + 10, y + 10, label, size=size, color=tcolor, align="center", w=w - 20, container=id_) + t["height"] = h - 20 + r["boundElements"] = [{"id": t["id"], "type": "text"}] + els.extend([r, t]) + return r + + +def image(id_: str, x: float, y: float, w: float, h: float, svg_path: str, color: str | None = None) -> dict: + """Embed an SVG icon as an Excalidraw image element. + + svg_path: path to an SVG file, absolute or relative to this module's directory + (icons/ holds the ones this repo uses). + color: if given, replace every `currentColor` in the SVG source with this hex + string before embedding -- used to recolor a stroke- or fill-based icon set to a + band's dark palette color without touching the licensed original file on disk. + """ + path = svg_path if os.path.isabs(svg_path) else os.path.join(os.path.dirname(__file__), svg_path) + with open(path, "r") as fh: + svg = fh.read() + if color: + svg = svg.replace("currentColor", color) + b64 = base64.b64encode(svg.encode("utf-8")).decode("ascii") + file_id = f"img_{id_}" + files[file_id] = { + "mimeType": "image/svg+xml", + "id": file_id, + "dataURL": f"data:image/svg+xml;base64,{b64}", + "created": 1700000000000, + } + el = base("image", id_, x, y, w, h, "transparent", "transparent", sw=1) + el.update({"fileId": file_id, "status": "saved", "scale": [1, 1], "roundness": None, "crop": None}) + els.append(el) + return el + + +def find(id_: str) -> dict: + return next(e for e in els if e["id"] == id_) + + +def edge_point(b: dict, side: str, frac: float = 0.5) -> tuple[float, float]: + x, y, w, h = b["x"], b["y"], b["width"], b["height"] + return {"top": (x + w * frac, y), "bottom": (x + w * frac, y + h), + "left": (x, y + h * frac), "right": (x + w, y + h * frac)}[side] + + +def arrow(id_: str, src: str, s_side: str, dst: str, d_side: str, label: str | None = None, s_frac=0.5, d_frac=0.5, + color=LINE, dashed=False, label_dx=0.0, label_dy=-22.0, sw=2, both=False, elbow: str | None = None, + label_size=14, inset=0.0, head="arrow") -> None: + a, b = find(src), find(dst) + (x1, y1), (x2, y2) = edge_point(a, s_side, s_frac), edge_point(b, d_side, d_frac) + if inset: + dx, dy = x2 - x1, y2 - y1 + length = (dx ** 2 + dy ** 2) ** 0.5 + if length > 2 * inset: + ux, uy = dx / length, dy / length + x1, y1 = x1 + ux * inset, y1 + uy * inset + x2, y2 = x2 - ux * inset, y2 - uy * inset + ar = base("arrow", id_, x1, y1, x2 - x1, y2 - y1, color, "transparent", dashed=dashed, sw=sw) + pts = [[0, 0], [x2 - x1, y2 - y1]] + if elbow == "vertical-first": + pts = [[0, 0], [0, y2 - y1], [x2 - x1, y2 - y1]] + elif elbow == "horizontal-first": + pts = [[0, 0], [x2 - x1, 0], [x2 - x1, y2 - y1]] + ar.update({"points": pts, + "startBinding": {"elementId": src, "focus": 0, "gap": 2}, + "endBinding": {"elementId": dst, "focus": 0, "gap": 2}, + "startArrowhead": head if both else None, "endArrowhead": head, "boundElements": None}) + a["boundElements"].append({"id": id_, "type": "arrow"}) + b["boundElements"].append({"id": id_, "type": "arrow"}) + els.append(ar) + if label: + mx, my = (x1 + x2) / 2 + label_dx, (y1 + y2) / 2 + label_dy + lw = max(len(ln) for ln in label.split("\n")) * label_size * 0.58 + els.append(text(id_ + "_l", mx - lw / 2, my, label, size=label_size, color=BODY, align="center", w=lw)) + + +def tri_head(id_: str, tip: tuple[float, float], frm: tuple[float, float], color: str, + size: float = 11.0, width_ratio: float = 0.62) -> dict: + """A solid filled arrowhead, drawn as its own closed triangle. + + Excalidraw's built-in arrowheads ("arrow", "triangle", ...) are sized from + the arrow's `strokeWidth`, so a thick line is forced to carry a big head. + This draws the head separately instead: give the arrow `endArrowhead: None` + and call this at its last point, passing the previous point as `frm` so the + triangle aims along the final segment. `size` is the head's length in px, + independent of the line weight. + """ + dx, dy = tip[0] - frm[0], tip[1] - frm[1] + length = (dx ** 2 + dy ** 2) ** 0.5 or 1.0 + ux, uy = dx / length, dy / length + px, py = -uy, ux # unit perpendicular + hw = size * width_ratio # half-width of the head's base + bx, by = tip[0] - ux * size, tip[1] - uy * size + pts = [tip, (bx + px * hw, by + py * hw), (bx - px * hw, by - py * hw)] + x0, y0 = pts[0] + el = base("line", id_, x0, y0, 0, 0, color, color, sw=1) + el.update({"points": [[x - x0, y - y0] for x, y in pts] + [[0, 0]], + "roundness": None, "boundElements": None, "fillStyle": "solid"}) + els.append(el) + return el + + +def boxed_label(id_: str, cx: float, y_bottom: float, s: str, size=13, color=BODY, pad_x=5, pad_y=2) -> dict: + """A small text label on an opaque white box -- for a caption that would + otherwise sit on top of a line or arrow it crosses. cx: horizontal + center. y_bottom: the y the label's bottom edge should align to, so a + caller can anchor it a fixed clearance above (or below, with a negative + clearance folded into y_bottom) some other element.""" + lines = s.split("\n") + w = max(len(ln) for ln in lines) * size * 0.58 + 2 * pad_x + h = len(lines) * size * 1.25 + 2 * pad_y + y = y_bottom - h + x = cx - w / 2 + r = base("rectangle", id_, x, y, w, h, "transparent", "#ffffff", sw=0) + r["roundness"] = {"type": 3} + els.append(r) + els.append(text(id_ + "_t", x + pad_x, y + pad_y, s, size=size, color=color, align="center", w=w - 2 * pad_x)) + return r + + +def hline(id_: str, x: float, y: float, w: float, dashed=True) -> None: + ln = base("line", id_, x, y, w, 0, LINE, "transparent", dashed=dashed, sw=1) + ln.update({"points": [[0, 0], [w, 0]], "boundElements": None}) + els.append(ln) + + + + +def save(rel_path: str) -> str: + out = os.path.normpath(os.path.join(os.path.dirname(__file__), "..", "..", rel_path)) + doc = {"type": "excalidraw", "version": 2, "source": "oidm-knowledge/tools/diagrams", + "elements": els, "appState": {"viewBackgroundColor": "#ffffff", "gridSize": None}, "files": files} + with open(out, "w") as fh: + json.dump(doc, fh, indent=1) + print("wrote", out, len(els), "elements") + return out diff --git a/tools/diagrams/icons/LICENSES.md b/tools/diagrams/icons/LICENSES.md new file mode 100644 index 0000000..fa0dde4 --- /dev/null +++ b/tools/diagrams/icons/LICENSES.md @@ -0,0 +1,64 @@ +# Icon sources + +Icons used in `build_pillars.py` (the five-pillar stack diagram). Each SVG here is the +**unmodified original** as fetched from its source repository. Recoloring (stroke/fill set +to a band's dark color) and resizing happen at build time in `build_pillars.py`, not by +editing these files, so the licensed originals stay intact and auditable. + +## Health Icons + + — outline style. Source repository: +[`resolvetosavelives/healthicons`](https://github.com/resolvetosavelives/healthicons) +(branch `main`). The project site states the icon designs are released under **CC0** +(public domain); the repository's own `LICENSE` file (covering the repo/tooling) is MIT, +copyright Resolve to Save Lives. Either way, reuse with attribution here is unrestricted. + +| File | Source path | Used for | +|---|---|---| +| `healthicons-lungs.svg` | `public/icons/svg/outline/body/lungs.svg` | Anatomic locations (Foundation Context) | +| `healthicons-xray.svg` | `public/icons/svg/outline/devices/xray.svg` | Exam types (Foundation Context) | +| `healthicons-person.svg` | `public/icons/svg/outline/people/person.svg` | Imaging Persona (Data Structures) | + +Note: Health Icons' outline set has no clipboard/report-style icon (searched the full tree +for "clipboard", "report", "record", "chart", "form", "doc" — nothing fits). Per the brief, +Lucide's `clipboard` and `clipboard-list` are used instead for Observation and Exam Finding +List. No CT-scanner icon exists either; `xray.svg` (x-ray machine) stands in for the exam +types glyph. + +## Lucide + +, MIT-family license. Source repository: +[`lucide-icons/lucide`](https://github.com/lucide-icons/lucide) (branch `main`), path +`icons/.svg`. Lucide icons are ISC-licensed by Lucide Icons and Contributors, **except** +a subset carried over from the Feather icon project, which stays under Feather's original MIT +license (Copyright Cole Bemis). Of the icons used here, only `clipboard` is in that +Feather-derived subset. + +| File | Source path | Used for | License | +|---|---|---|---| +| `lucide-book-open.svg` | `icons/book-open.svg` | Foundation Context band | ISC | +| `lucide-tag.svg` | `icons/tag.svg` | Finding/diagnosis definitions | ISC | +| `lucide-layers.svg` | `icons/layers.svg` | Data Structures band | ISC | +| `lucide-list.svg` | `icons/list.svg` | Imaging Problem List | ISC | +| `lucide-package.svg` | `icons/package.svg` | SDKs band (code-2 has no matching filename in the current icon set; package is the listed alternative) | ISC | +| `lucide-lightbulb.svg` | `icons/lightbulb.svg` | Use Cases | ISC | +| `lucide-app-window.svg` | `icons/app-window.svg` | Sample Applications | ISC | +| `lucide-clipboard.svg` | `icons/clipboard.svg` | Observation (Health Icons has no equivalent) | MIT (Feather) | +| `lucide-clipboard-list.svg` | `icons/clipboard-list.svg` | Exam Finding List (Health Icons has no equivalent) | ISC | + +## Harmonizing style + +- All icons are rendered at the same on-page size (~28px at 900px diagram width). +- Lucide icons are stroke-based (`stroke="currentColor"`, `stroke-width="2"`, 24x24 viewBox) + — the build script replaces `currentColor` with the target band's dark hex. +- Health Icons' outline set is filled-path-based (`fill="currentColor"`, 48x48 viewBox), not + stroke-based; there is no stroke-width to match, but at matched render size the two sets' + line weights read the same. The build script replaces `currentColor` with the target hex + the same way. + +The "relationships" glyph (three dots joined by lines, repeated between the Foundation +Context blocks) is hand-drawn with primitive ellipses/lines in `excalib.py`, not sourced +from an icon set — neither Health Icons nor Lucide's `network` icon (which is box-based, +not three dots) matched the brief's description closely enough. + +Reused without additions by build_three_axes.py (tag, lungs, xray) and build_two_planes.py (layers, book-open, clipboard-list, clipboard, xray, lungs, tag), 2026-09-28. diff --git a/tools/diagrams/icons/healthicons-lungs.svg b/tools/diagrams/icons/healthicons-lungs.svg new file mode 100644 index 0000000..6651458 --- /dev/null +++ b/tools/diagrams/icons/healthicons-lungs.svg @@ -0,0 +1,3 @@ + + + diff --git a/tools/diagrams/icons/healthicons-person.svg b/tools/diagrams/icons/healthicons-person.svg new file mode 100644 index 0000000..41e9d62 --- /dev/null +++ b/tools/diagrams/icons/healthicons-person.svg @@ -0,0 +1,4 @@ + + + + diff --git a/tools/diagrams/icons/healthicons-xray.svg b/tools/diagrams/icons/healthicons-xray.svg new file mode 100644 index 0000000..2f35233 --- /dev/null +++ b/tools/diagrams/icons/healthicons-xray.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/tools/diagrams/icons/lucide-app-window.svg b/tools/diagrams/icons/lucide-app-window.svg new file mode 100644 index 0000000..815548b --- /dev/null +++ b/tools/diagrams/icons/lucide-app-window.svg @@ -0,0 +1,16 @@ + + + + + + diff --git a/tools/diagrams/icons/lucide-book-open.svg b/tools/diagrams/icons/lucide-book-open.svg new file mode 100644 index 0000000..9e0ace5 --- /dev/null +++ b/tools/diagrams/icons/lucide-book-open.svg @@ -0,0 +1,14 @@ + + + + diff --git a/tools/diagrams/icons/lucide-clipboard-list.svg b/tools/diagrams/icons/lucide-clipboard-list.svg new file mode 100644 index 0000000..bbdd45f --- /dev/null +++ b/tools/diagrams/icons/lucide-clipboard-list.svg @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/tools/diagrams/icons/lucide-clipboard.svg b/tools/diagrams/icons/lucide-clipboard.svg new file mode 100644 index 0000000..de4cc01 --- /dev/null +++ b/tools/diagrams/icons/lucide-clipboard.svg @@ -0,0 +1,14 @@ + + + + diff --git a/tools/diagrams/icons/lucide-layers.svg b/tools/diagrams/icons/lucide-layers.svg new file mode 100644 index 0000000..a3b69ae --- /dev/null +++ b/tools/diagrams/icons/lucide-layers.svg @@ -0,0 +1,15 @@ + + + + + diff --git a/tools/diagrams/icons/lucide-lightbulb.svg b/tools/diagrams/icons/lucide-lightbulb.svg new file mode 100644 index 0000000..3f4e409 --- /dev/null +++ b/tools/diagrams/icons/lucide-lightbulb.svg @@ -0,0 +1,15 @@ + + + + + diff --git a/tools/diagrams/icons/lucide-list.svg b/tools/diagrams/icons/lucide-list.svg new file mode 100644 index 0000000..0d88fb1 --- /dev/null +++ b/tools/diagrams/icons/lucide-list.svg @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/tools/diagrams/icons/lucide-package.svg b/tools/diagrams/icons/lucide-package.svg new file mode 100644 index 0000000..308b1f4 --- /dev/null +++ b/tools/diagrams/icons/lucide-package.svg @@ -0,0 +1,16 @@ + + + + + + diff --git a/tools/diagrams/icons/lucide-tag.svg b/tools/diagrams/icons/lucide-tag.svg new file mode 100644 index 0000000..7a073e9 --- /dev/null +++ b/tools/diagrams/icons/lucide-tag.svg @@ -0,0 +1,14 @@ + + + + diff --git a/tools/diagrams/render_excalidraw.py b/tools/diagrams/render_excalidraw.py new file mode 100644 index 0000000..ad40bc8 --- /dev/null +++ b/tools/diagrams/render_excalidraw.py @@ -0,0 +1,194 @@ +"""Render Excalidraw JSON to PNG using Playwright + headless Chromium. + +Usage: + cd .claude/skills/excalidraw-diagram/references + uv run python render_excalidraw.py [--output path.png] [--scale 2] [--width 1920] + +First-time setup: + cd .claude/skills/excalidraw-diagram/references + uv sync + uv run playwright install chromium +""" + +from __future__ import annotations + +import argparse +import json +import sys +from pathlib import Path + + +def validate_excalidraw(data: dict) -> list[str]: + """Validate Excalidraw JSON structure. Returns list of errors (empty = valid).""" + errors: list[str] = [] + + if data.get("type") != "excalidraw": + errors.append(f"Expected type 'excalidraw', got '{data.get('type')}'") + + if "elements" not in data: + errors.append("Missing 'elements' array") + elif not isinstance(data["elements"], list): + errors.append("'elements' must be an array") + elif len(data["elements"]) == 0: + errors.append("'elements' array is empty — nothing to render") + + return errors + + +def compute_bounding_box(elements: list[dict]) -> tuple[float, float, float, float]: + """Compute bounding box (min_x, min_y, max_x, max_y) across all elements.""" + min_x = float("inf") + min_y = float("inf") + max_x = float("-inf") + max_y = float("-inf") + + for el in elements: + if el.get("isDeleted"): + continue + x = el.get("x", 0) + y = el.get("y", 0) + w = el.get("width", 0) + h = el.get("height", 0) + + # For arrows/lines, points array defines the shape relative to x,y + if el.get("type") in ("arrow", "line") and "points" in el: + for px, py in el["points"]: + min_x = min(min_x, x + px) + min_y = min(min_y, y + py) + max_x = max(max_x, x + px) + max_y = max(max_y, y + py) + else: + min_x = min(min_x, x) + min_y = min(min_y, y) + max_x = max(max_x, x + abs(w)) + max_y = max(max_y, y + abs(h)) + + if min_x == float("inf"): + return (0, 0, 800, 600) + + return (min_x, min_y, max_x, max_y) + + +def render( + excalidraw_path: Path, + output_path: Path | None = None, + scale: int = 2, + max_width: int = 1920, + svg_out: Path | None = None, +) -> Path: + """Render an .excalidraw file to PNG. Returns the output PNG path.""" + # Import playwright here so validation errors show before import errors + try: + from playwright.sync_api import sync_playwright + except ImportError: + print("ERROR: playwright not installed.", file=sys.stderr) + print("Run: cd .claude/skills/excalidraw-diagram/references && uv sync && uv run playwright install chromium", file=sys.stderr) + sys.exit(1) + + # Read and validate + raw = excalidraw_path.read_text(encoding="utf-8") + try: + data = json.loads(raw) + except json.JSONDecodeError as e: + print(f"ERROR: Invalid JSON in {excalidraw_path}: {e}", file=sys.stderr) + sys.exit(1) + + errors = validate_excalidraw(data) + if errors: + print(f"ERROR: Invalid Excalidraw file:", file=sys.stderr) + for err in errors: + print(f" - {err}", file=sys.stderr) + sys.exit(1) + + # Compute viewport size from element bounding box + elements = [e for e in data["elements"] if not e.get("isDeleted")] + min_x, min_y, max_x, max_y = compute_bounding_box(elements) + padding = 80 + diagram_w = max_x - min_x + padding * 2 + diagram_h = max_y - min_y + padding * 2 + + # Cap viewport width, let height be natural + vp_width = min(int(diagram_w), max_width) + vp_height = max(int(diagram_h), 600) + + # Output path + if output_path is None: + output_path = excalidraw_path.with_suffix(".png") + + # Template path (same directory as this script) + template_path = Path(__file__).parent / "render_template.html" + if not template_path.exists(): + print(f"ERROR: Template not found at {template_path}", file=sys.stderr) + sys.exit(1) + + template_url = template_path.as_uri() + + with sync_playwright() as p: + try: + browser = p.chromium.launch(headless=True) + except Exception as e: + if "Executable doesn't exist" in str(e) or "browserType.launch" in str(e): + print("ERROR: Chromium not installed for Playwright.", file=sys.stderr) + print("Run: cd .claude/skills/excalidraw-diagram/references && uv run playwright install chromium", file=sys.stderr) + sys.exit(1) + raise + + page = browser.new_page( + viewport={"width": vp_width, "height": vp_height}, + device_scale_factor=scale, + ) + + # Load the template + page.goto(template_url) + + # Wait for the ES module to load (imports from esm.sh) + page.wait_for_function("window.__moduleReady === true", timeout=30000) + + # Inject the diagram data and render + json_str = json.dumps(data) + result = page.evaluate(f"window.renderDiagram({json_str})") + + if not result or not result.get("success"): + error_msg = result.get("error", "Unknown render error") if result else "renderDiagram returned null" + print(f"ERROR: Render failed: {error_msg}", file=sys.stderr) + browser.close() + sys.exit(1) + + # Wait for render completion signal + page.wait_for_function("window.__renderComplete === true", timeout=15000) + + # Screenshot the SVG element + svg_el = page.query_selector("#root svg") + if svg_el is None: + print("ERROR: No SVG element found after render.", file=sys.stderr) + browser.close() + sys.exit(1) + + svg_el.screenshot(path=str(output_path)) + if svg_out is not None: + svg_markup = svg_el.evaluate("el => el.outerHTML") + Path(svg_out).write_text(svg_markup, encoding="utf-8") + browser.close() + + return output_path + + +def main() -> None: + parser = argparse.ArgumentParser(description="Render Excalidraw JSON to PNG") + parser.add_argument("input", type=Path, help="Path to .excalidraw JSON file") + parser.add_argument("--output", "-o", type=Path, default=None, help="Output PNG path (default: same name with .png)") + parser.add_argument("--scale", "-s", type=int, default=2, help="Device scale factor (default: 2)") + parser.add_argument("--width", "-w", type=int, default=1920, help="Max viewport width (default: 1920)") + parser.add_argument("--svg", type=Path, default=None, help="Also write the rendered SVG markup to this path") + args = parser.parse_args() + + if not args.input.exists(): + print(f"ERROR: File not found: {args.input}", file=sys.stderr) + sys.exit(1) + + png_path = render(args.input, args.output, args.scale, args.width, svg_out=args.svg) + print(str(png_path)) + + +if __name__ == "__main__": + main() diff --git a/tools/diagrams/render_template.html b/tools/diagrams/render_template.html new file mode 100644 index 0000000..877e33d --- /dev/null +++ b/tools/diagrams/render_template.html @@ -0,0 +1,57 @@ + + + + + + + +
+ + + + diff --git a/tools/diagrams/variants/build_pillars_b1.py b/tools/diagrams/variants/build_pillars_b1.py new file mode 100644 index 0000000..3aaacad --- /dev/null +++ b/tools/diagrams/variants/build_pillars_b1.py @@ -0,0 +1,303 @@ +#!/usr/bin/env python3 +"""Build the OIDM "five pillars" stack diagram -- variant B1, a true finger joint. + +This is a variant of ../build_pillars.py (seam b, the dovetail) and exists so +three seam explorations can run without stepping on each other. It differs +from the parent in three ways: + + 1. The seam is a finger joint, not a dovetail. In seam b the Data + Structures band grew four tabs that dropped into the Foundation band -- + one band sitting on the other. Here both bands grow fingers into a + single joint zone JOINT_D deep: four labelled teal tabs descend from + Data Structures, and five unlabelled amber fingers rise from Foundation + Context between and outside them, so the boundary is one square wave and + neither band is simply on top. The fingers are square, not rounded: a + finger joint reads as a finger joint because the fingers are square. + 2. The "relationships" plate and the two double-headed arrows between the + Foundation blocks are gone. + 3. The Foundation band is tightened so everything below the joint -- header, + subtitle, block row, bottom padding -- fits in under 200px. + +Everything else (icons, palette, block content, the bands above) is v4b. + +Joint geometry. JOINT_TOP is where the joint zone starts and JOINT_BOT = +JOINT_TOP + JOINT_D where it ends. The teal band rectangle runs down to +JOINT_BOT and the amber band rectangle starts at JOINT_TOP, so the two +overlap by exactly the joint depth; the teal rectangle is in front, so teal +is what shows in the zone by default, and the amber fingers are painted back +over it. That overlap also hides both rectangles' rounded corners inside the +zone, which is why the outermost fingers are amber and at least CORNER_R +wide -- they cover the curves, and two short vertical strokes redraw the +stack's outer edge straight through the joint. + +Output: knowledge/drafts/pillars-b1.excalidraw (override with --out). +""" +from __future__ import annotations + +import argparse +import os +import sys + +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")) + +from excalib import els, base, text, image, save, AMBER, TEAL, VIOLET, ROSE, GREEN, CAPTION # noqa: E402 + +# ---------------------------------------------------------------- layout constants +CONTENT_W = 880 +BAND_GAP = 24 # the vertical gap between bands above the seam +PAD_BAND = 20 # a band's own inner padding on all sides +GAP = 20 # gap between sibling blocks inside a band +GAP_F = 24 # gap between the three Foundation blocks (no arrows between them now) +ICON = 28 # harmonized icon render size +ICON_FILLED = 32 # filled-path icon sets need a bigger box to match optically +CORNER_R = 32 # Excalidraw's adaptive corner radius for a band-sized rectangle + +# ---------------------------------------------------------------- the finger joint +JOINT_D = 40.0 # how deep the joint zone is: how far each set of fingers reaches +TAB_W = 118.0 # width of a labelled teal tab +JOINT_WORDS = ["finding", "diagnosis", "location", "exam type"] +FINGER_W = (CONTENT_W - len(JOINT_WORDS) * TAB_W) / (len(JOINT_WORDS) + 1) # amber, unlabelled +CAPTION_SPACE = 38.0 # teal room above the joint for the lead caption +LEAD = "woven together at every:" + +_uid = [0] + + +def uid(prefix: str) -> str: + _uid[0] += 1 + return f"{prefix}{_uid[0]}" + + +# ---------------------------------------------------------------- primitives +def band_rect(id_: str, x: float, y: float, w: float, h: float, pal: dict, at_front=False) -> dict: + """Draw a band's background rectangle. Pass at_front=True when the band's + true height is only known after laying out its header/blocks (they were + already appended to els) -- this inserts the rect at index 0 so it still + paints behind its own contents instead of covering them. Note the order + that matters at the joint: whichever band rect is inserted at index 0 last + ends up furthest back, so Foundation Context must be built last.""" + r = base("rectangle", id_, x, y, w, h, pal["stroke"], pal["band"]) + r["roundness"] = {"type": 3} + if at_front: + els.insert(0, r) + else: + els.append(r) + return r + + +def band_header(x: float, y: float, icon_path: str, pal: dict, title: str, subtitle: str, + size=20, filled_icon=False) -> float: + """Bold band title with its icon to the left, subtitle below. Returns bottom y.""" + s = ICON_FILLED if filled_icon else ICON + image(uid("bicon"), x, y - (s - ICON) / 2 - 2, s, s, icon_path, color=pal["stroke"]) + els.append(text(uid("btitle"), x + ICON + 12, y, title, size=size, color=pal["text"])) + y2 = y + size * 1.3 + els.append(text(uid("bsub"), x + ICON + 12, y2, subtitle, size=13, color=pal["mid"])) + return y2 + 13 * 1.25 + + +def icon_block_h(lines: list[str], desc: str | None = None) -> float: + """Height an icon_block needs for this many label lines/descriptor.""" + n_title = len(lines) + return 12 + ICON + 8 + n_title * 15 * 1.25 + (13 * 1.25 + 2 if desc else 0) + 10 + + +def icon_block(x: float, y: float, w: float, h: float, icon_path: str, pal: dict, + lines: list[str], desc: str | None = None, filled_icon=False) -> dict: + """Icon centered on top, label line(s) centered below, optional lighter + descriptor line last. Background is the band's own deeper pastel so the + block reads as 'inside' the band, not a separate object.""" + r = base("rectangle", uid("blk"), x, y, w, h, pal["stroke"], pal["block"], sw=1) + r["roundness"] = {"type": 3} + els.append(r) + cx = x + w / 2 + content_h = icon_block_h(lines, desc) - 22 # minus this fn's fixed 12+10 top/bottom pad + top = y + (h - content_h) / 2 + s = ICON_FILLED if filled_icon else ICON + image(uid("blki"), cx - s / 2, top - (s - ICON) / 2, s, s, icon_path, color=pal["stroke"]) + ty = top + ICON + 6 + for ln in lines: + els.append(text(uid("blkt"), x + 6, ty, ln, size=15, color=pal["text"], align="center", w=w - 12)) + ty += 15 * 1.25 + if desc: + els.append(text(uid("blkd"), x + 6, ty + 2, desc, size=13, color=pal["mid"], align="center", w=w - 12)) + return r + + +def chip(cx: float, y_top: float, s: str, fill: str, stroke: str, color: str, + size=13, pad_x=9, pad_y=3) -> float: + """A short caption on its own opaque rounded plate, centered on cx, so it + reads as a label for what it sits over and never mixes with a line or a + band fill behind it. Returns bottom y.""" + w = len(s) * size * 0.58 + 2 * pad_x + h = size * 1.25 + 2 * pad_y + r = base("rectangle", uid("chip"), cx - w / 2, y_top, w, h, stroke, fill, sw=1) + r["roundness"] = {"type": 3} + els.append(r) + els.append(text(uid("chipt"), cx - w / 2 + pad_x, y_top + pad_y, s, size=size, color=color, + align="center", w=w - 2 * pad_x)) + return y_top + h + + +def hconn(x1: float, x2: float, y: float, color: str, sw=1, both=False) -> None: + """A plain horizontal connector; both=True gives it two arrowheads.""" + a = base("arrow" if both else "line", uid("conn"), x1, y, x2 - x1, 0, color, "transparent", sw=sw) + a.update({"points": [[0, 0], [x2 - x1, 0]], "boundElements": None}) + if both: + a.update({"startArrowhead": "arrow", "endArrowhead": "arrow"}) + els.append(a) + + +def fill_rect(x: float, y: float, w: float, h: float, fill: str, rounded=False) -> dict: + """An unstroked patch of colour -- used here to paint an amber finger back + over the teal band rectangle inside the joint zone.""" + r = base("rectangle", uid("fill"), x, y, w, h, "transparent", fill, sw=1) + r["roundness"] = {"type": 3} if rounded else None + els.append(r) + return r + + +def stroke_line(pts: list[tuple[float, float]], color: str, sw=2, opacity=100) -> dict: + """A polyline through pts (absolute coordinates), sharp corners.""" + x0, y0 = pts[0] + xs = [p[0] for p in pts] + ys = [p[1] for p in pts] + ln = base("line", uid("ln"), x0, y0, max(xs) - min(xs), max(ys) - min(ys), color, "transparent", sw=sw) + ln.update({"points": [[p[0] - x0, p[1] - y0] for p in pts], "boundElements": None, "roundness": None}) + ln["opacity"] = opacity + els.append(ln) + return ln + + +def tab_x(i: int) -> float: + """Left edge of labelled teal tab i. The run starts and ends with an amber + finger, so the pattern is A T A T A T A T A across the full width.""" + return FINGER_W + i * (TAB_W + FINGER_W) + + +def draw_finger_joint(g: dict) -> None: + top = g["joint_top"] + bot = top + JOINT_D + + # 1. the amber fingers, painted back over the teal band rectangle. Each runs + # a few px past the joint's bottom so it also covers the teal rectangle's + # own bottom stroke; below the zone it is amber on amber, so nothing shows. + finger_xs = [0.0] + [tab_x(i) + TAB_W for i in range(len(JOINT_WORDS))] + for fx in finger_xs: + fill_rect(fx, top, FINGER_W, JOINT_D + 3, AMBER["band"]) + + # 2. the interlocking boundary as one square wave, left edge to right edge + pts: list[tuple[float, float]] = [(0.0, top)] + for i in range(len(JOINT_WORDS)): + x = tab_x(i) + pts += [(x, top), (x, bot), (x + TAB_W, bot), (x + TAB_W, top)] + pts.append((CONTENT_W, top)) + stroke_line(pts, TEAL["stroke"], sw=2) + + # 3. the stack's outer edge through the joint. Both band rectangles curve + # away inside the zone; the amber fingers at each end cover those curves, + # so the edge is redrawn straight in the amber that is actually there. + for x in (0.0, CONTENT_W): + stroke_line([(x, top), (x, bot + 3)], AMBER["stroke"], sw=2) + + # 4. the four words, one per teal tab + for i, word in enumerate(JOINT_WORDS): + els.append(text(uid("jw"), tab_x(i), top + (JOINT_D - 13 * 1.25) / 2, word, + size=13, color=TEAL["text"], align="center", w=TAB_W)) + + # 5. the lead caption, in the teal room kept above the joint + els.append(text(uid("lead"), 0, top - CAPTION_SPACE + (CAPTION_SPACE - 13 * 1.25) / 2, LEAD, + size=13, color=TEAL["mid"], align="center", w=CONTENT_W)) + + +# ============================================================ the stack +def build(out_path: str) -> str: + # ---------------------------------------- 5/4. Use Cases | Sample Applications + Y_TOP = 0 + GAP_MID = 104 # wide enough for "illustrates" to sit clear of both panels + PANEL_PAD = 14 + PANEL_INSET = PAD_BAND - 2 # same left inset as the full-width band headers + PANEL_TITLE = 18 + PANEL_H = PANEL_PAD + PANEL_TITLE * 1.3 + 13 * 1.25 + PANEL_PAD + panel_w = (CONTENT_W - GAP_MID) / 2 + + band_rect(uid("panel"), 0, Y_TOP, panel_w, PANEL_H, ROSE) + band_rect(uid("panel"), panel_w + GAP_MID, Y_TOP, panel_w, PANEL_H, GREEN) + band_header(PANEL_INSET, Y_TOP + PANEL_PAD, "icons/lucide-lightbulb.svg", ROSE, + "Use Cases", "what the project wants built", size=PANEL_TITLE) + band_header(panel_w + GAP_MID + PANEL_INSET, Y_TOP + PANEL_PAD, "icons/lucide-app-window.svg", GREEN, + "Sample Applications", "what has been built", size=PANEL_TITLE) + conn_y = Y_TOP + PANEL_H / 2 + hconn(panel_w + 2, panel_w + GAP_MID - 2, conn_y, CAPTION) + chip(panel_w + GAP_MID / 2, conn_y - 7 - (13 * 1.25 + 6), "illustrates", + "#ffffff", "transparent", CAPTION) + + # ---------------------------------------- 3. SDKs (thin full-width band) + Y_SDK = Y_TOP + PANEL_H + BAND_GAP + sdk_hdr_bottom = band_header(PAD_BAND - 2, Y_SDK + 16, "icons/lucide-package.svg", VIOLET, + "SDKs", "wrap the structures · attach the shared knowledge · support authoring", + size=18) + SDK_BOTTOM = sdk_hdr_bottom + 16 + band_rect(uid("band"), 0, Y_SDK, CONTENT_W, SDK_BOTTOM - Y_SDK, VIOLET, at_front=True) + + # ---------------------------------------- 2. Data Structures + Y_DATA = SDK_BOTTOM + BAND_GAP + hdr_bottom = band_header(PAD_BAND - 2, Y_DATA + 18, "icons/lucide-layers.svg", TEAL, + "Data Structures", "this patient · Patient Context", size=20) + BLOCK_ROW_Y = hdr_bottom + 14 + W4 = (CONTENT_W - 2 * PAD_BAND - 3 * GAP) / 4 + d_positions = [PAD_BAND + i * (W4 + GAP) for i in range(4)] + d_specs = [ + ("icons/lucide-clipboard.svg", ["Observation"], False), + ("icons/lucide-clipboard-list.svg", ["Exam Finding", "List"], False), + ("icons/lucide-list.svg", ["Imaging Problem", "List"], False), + ("icons/healthicons-person.svg", ["Imaging Persona"], True), + ] + ROW_H_DATA = max(icon_block_h(lines) for _, lines, _ in d_specs) + for xpos, (ipath, lines, filled) in zip(d_positions, d_specs): + icon_block(xpos, BLOCK_ROW_Y, W4, ROW_H_DATA, ipath, TEAL, lines, filled_icon=filled) + DATA_BLOCKS_BOTTOM = BLOCK_ROW_Y + ROW_H_DATA + + # the joint zone: the two band rectangles overlap across exactly its depth + JOINT_TOP = DATA_BLOCKS_BOTTOM + CAPTION_SPACE + JOINT_BOT = JOINT_TOP + JOINT_D + band_rect(uid("band"), 0, Y_DATA, CONTENT_W, JOINT_BOT - Y_DATA, TEAL, at_front=True) + + # ---------------------------------------- 1. Foundation Context (bottom) + # Built last so its rect lands behind the Data Structures band in the joint. + FOUND_TOP = JOINT_TOP + hdr_bottom_f = band_header(PAD_BAND - 2, JOINT_BOT + 14, + "icons/lucide-book-open.svg", AMBER, + "Foundation Context", "shared, curated knowledge", size=20) + F_ROW_Y = hdr_bottom_f + 10 + W3 = (CONTENT_W - 2 * PAD_BAND - 2 * GAP_F) / 3 + f_positions = [PAD_BAND + i * (W3 + GAP_F) for i in range(3)] + f_specs = [ + ("icons/lucide-tag.svg", ["Finding/diagnosis definitions"], "finding models · CDEs", False), + ("icons/healthicons-lungs.svg", ["Anatomic locations"], "anchored in RadLex", True), + ("icons/healthicons-xray.svg", ["Exam types"], "LOINC/RSNA Playbook", True), + ] + ROW_H_FOUND = max(icon_block_h(lines, desc) for _, lines, desc, _ in f_specs) + for xpos, (ipath, lines, desc, filled) in zip(f_positions, f_specs): + icon_block(xpos, F_ROW_Y, W3, ROW_H_FOUND, ipath, AMBER, lines, desc=desc, filled_icon=filled) + FOUND_BAND_BOTTOM = F_ROW_Y + ROW_H_FOUND + PAD_BAND + band_rect(uid("band"), 0, FOUND_TOP, CONTENT_W, FOUND_BAND_BOTTOM - FOUND_TOP, AMBER, at_front=True) + + print(f"foundation band below the joint: {FOUND_BAND_BOTTOM - JOINT_BOT:.1f}px") + + # ---------------------------------------- the joint, drawn over both bands + draw_finger_joint({"joint_top": JOINT_TOP}) + + return save(out_path) + + +def main() -> None: + ap = argparse.ArgumentParser(description=__doc__.split("\n")[0]) + ap.add_argument("--out", default="knowledge/drafts/pillars-b1.excalidraw", + help="output path relative to the repo root") + args = ap.parse_args() + build(args.out) + + +if __name__ == "__main__": + main() diff --git a/tools/diagrams/variants/build_pillars_b2.py b/tools/diagrams/variants/build_pillars_b2.py new file mode 100644 index 0000000..d0773c8 --- /dev/null +++ b/tools/diagrams/variants/build_pillars_b2.py @@ -0,0 +1,404 @@ +#!/usr/bin/env python3 +"""Build the OIDM "five pillars" stack diagram -- seam variant B2, "tabs plug +into blocks". + +Variant of tools/diagrams/build_pillars.py --seam b. In v4b the four teal tabs +dropped out of the Data Structures band into empty amber ground: the joint was +band-to-band, and the three Foundation blocks sat well below it with no visible +relation to any particular tab. B2 makes the joint block-to-block instead. + + * The three Foundation Context blocks rise until their top edges *are* the + seam, so there is no amber ground between the joint and the blocks. + * Each teal tab lands in a named block: "finding" and "diagnosis" both plug + into "Finding/diagnosis definitions", "location" into "Anatomic locations", + "exam type" into "Exam types". A tab is drawn over the block's top edge, so + the edge reads as a notch the tab fills. + * The Foundation band header moves to a left column beside the blocks (icon + + wrapped title + subtitle), with the "woven together at every:" lead above + it, on the tab row, where it was in v4b. + * The "relationships" plate and the two double-headed arrows between the + Foundation blocks are gone, and the band is 151px tall including its header. + +Everything above the seam (Use Cases / Sample Applications, SDKs, the four Data +Structures cards) is unchanged from v4b. + +Because the Foundation band is laid out for this seam, the a/b/c seam switch of +the parent builder is not carried over: this file draws B2 and nothing else. + +Block and tab widths here are sized from measured Helvetica advance widths (see +tools/diagrams/README.md, "Measuring text instead of estimating it"), not from +excalib's 0.58-per-character estimate. + +Icons: unchanged from build_pillars.py -- Health Icons (CC0/MIT, outline) for +anatomy/exam/person glyphs, Lucide (ISC) for the rest; see icons/LICENSES.md. + +Output: knowledge/drafts/pillars-b2.excalidraw (override with --out). +""" +from __future__ import annotations + +import argparse +import math +import os +import sys + +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")) + +from excalib import els, base, text, image, save, AMBER, TEAL, VIOLET, ROSE, GREEN, CAPTION + +# ---------------------------------------------------------------- layout constants +CONTENT_W = 880 +BAND_GAP = 24 # the vertical gap between bands above the seam +PAD_BAND = 20 # a band's own inner padding on all sides +GAP = 20 # gap between sibling blocks inside a band +ICON = 28 # harmonized icon render size +ICON_FILLED = 32 # filled-path icon sets need a bigger box to match optically +CORNER_R = 32 # Excalidraw's adaptive corner radius for a band-sized rectangle + +# ---- the seam +TAB_W = 92.0 # a tab is sized to hold "diagnosis"/"exam type" (60px measured) with air +TAB_D = 30.0 # how far a tab descends past the seam into its block +TAB_R = 10.0 # the tab's bottom corner radius +TAB_GAP = 24.0 # between the two tabs that share the first block +TAB_RISE = 14.0 # how far the tab's fill runs up past the seam, to break the seam stroke +LEAD = "woven together at every:" + +# ---- the Foundation band's left header column +LEFT_W = 196.0 # holds "shared, curated knowledge" (156 measured) beside the icon, on one line +LEFT_GAP = 20.0 +PAD_BOTTOM = 26 # a little more air under the blocks than PAD_BAND, so their + # bottom corner radius does not crowd the band's own + +_uid = [0] + + +def uid(prefix: str) -> str: + _uid[0] += 1 + return f"{prefix}{_uid[0]}" + + +# ---------------------------------------------------------------- primitives +def band_rect(id_: str, x: float, y: float, w: float, h: float, pal: dict, at_front=False) -> dict: + """Draw a band's background rectangle. Pass at_front=True when the band's + true height is only known after laying out its header/blocks (they were + already appended to els) -- this inserts the rect at index 0 so it still + paints behind its own contents instead of covering them. Note the order + that matters at the seam: whichever band rect is inserted at index 0 last + ends up furthest back, so Foundation Context must be built last.""" + r = base("rectangle", id_, x, y, w, h, pal["stroke"], pal["band"]) + r["roundness"] = {"type": 3} + if at_front: + els.insert(0, r) + else: + els.append(r) + return r + + +def band_header(x: float, y: float, icon_path: str, pal: dict, title: str, subtitle: str, + size=20, filled_icon=False) -> float: + """Bold band title with its icon to the left, subtitle below. Returns bottom y.""" + s = ICON_FILLED if filled_icon else ICON + image(uid("bicon"), x, y - (s - ICON) / 2 - 2, s, s, icon_path, color=pal["stroke"]) + els.append(text(uid("btitle"), x + ICON + 12, y, title, size=size, color=pal["text"])) + y2 = y + size * 1.3 + els.append(text(uid("bsub"), x + ICON + 12, y2, subtitle, size=13, color=pal["mid"])) + return y2 + 13 * 1.25 + + +def left_header(x: float, y: float, icon_path: str, pal: dict, title_lines: list[str], + sub_lines: list[str], size=20) -> float: + """The band header as a narrow left column: the icon hangs at the left + margin beside the first title line, and every line of the title and the + subtitle shares one text column indented past it -- the same icon/text + relationship as the full-width band headers, just wrapped. Returns bottom y.""" + image(uid("bicon"), x, y + (size * 1.3 - ICON) / 2 - 1, ICON, ICON, icon_path, color=pal["stroke"]) + tx, yy = x + ICON + 12, y + for ln in title_lines: + els.append(text(uid("btitle"), tx, yy, ln, size=size, color=pal["text"])) + yy += size * 1.3 + yy += 4 + for ln in sub_lines: + els.append(text(uid("bsub"), tx, yy, ln, size=13, color=pal["mid"])) + yy += 13 * 1.25 + return yy + + +def left_header_h(n_title: int, n_sub: int, size=20) -> float: + return n_title * size * 1.3 + 4 + n_sub * 13 * 1.25 + + +def icon_block_h(lines: list[str], desc: str | None = None) -> float: + """Height an icon_block needs for this many label lines/descriptor.""" + n_title = len(lines) + return 12 + ICON + 8 + n_title * 15 * 1.25 + (13 * 1.25 + 2 if desc else 0) + 10 + + +def icon_block(x: float, y: float, w: float, h: float, icon_path: str, pal: dict, + lines: list[str], desc: str | None = None, filled_icon=False, + top_inset: float = 0.0) -> dict: + """Icon centered on top, label line(s) centered below, optional lighter + descriptor line last. Background is the band's own deeper pastel so the + block reads as 'inside' the band, not a separate object. + + top_inset reserves that much of the block's top edge for something else -- + here, the notch a seam tab plugs into -- and centres the contents in what + is left, so a tab never lands on the icon.""" + r = base("rectangle", uid("blk"), x, y, w, h, pal["stroke"], pal["block"], sw=1) + r["roundness"] = {"type": 3} + els.append(r) + cx = x + w / 2 + content_h = icon_block_h(lines, desc) - 22 # minus this fn's fixed 12+10 top/bottom pad + top = y + top_inset + (h - top_inset - content_h) / 2 + s = ICON_FILLED if filled_icon else ICON + image(uid("blki"), cx - s / 2, top - (s - ICON) / 2, s, s, icon_path, color=pal["stroke"]) + ty = top + ICON + 6 + for ln in lines: + els.append(text(uid("blkt"), x + 6, ty, ln, size=15, color=pal["text"], align="center", w=w - 12)) + ty += 15 * 1.25 + if desc: + els.append(text(uid("blkd"), x + 6, ty + 2, desc, size=13, color=pal["mid"], align="center", w=w - 12)) + return r + + +def chip(cx: float, y_top: float, s: str, fill: str, stroke: str, color: str, + size=13, pad_x=9, pad_y=3) -> float: + """A short caption on its own opaque rounded plate, centered on cx, so it + reads as a label for what it sits over and never mixes with a line or a + band fill behind it. Returns bottom y.""" + w = len(s) * size * 0.58 + 2 * pad_x + h = size * 1.25 + 2 * pad_y + r = base("rectangle", uid("chip"), cx - w / 2, y_top, w, h, stroke, fill, sw=1) + r["roundness"] = {"type": 3} + els.append(r) + els.append(text(uid("chipt"), cx - w / 2 + pad_x, y_top + pad_y, s, size=size, color=color, + align="center", w=w - 2 * pad_x)) + return y_top + h + + +def hconn(x1: float, x2: float, y: float, color: str, sw=1, both=False) -> None: + """A plain horizontal connector; both=True gives it two arrowheads.""" + a = base("arrow" if both else "line", uid("conn"), x1, y, x2 - x1, 0, color, "transparent", sw=sw) + a.update({"points": [[0, 0], [x2 - x1, 0]], "boundElements": None}) + if both: + a.update({"startArrowhead": "arrow", "endArrowhead": "arrow"}) + els.append(a) + + +def fill_rect(x: float, y: float, w: float, h: float, fill: str, rounded=False) -> dict: + """An unstroked patch of colour -- used to close the notch two rounded + bands leave where they meet, to square off a block's rounded top corners + where that top edge has become the seam, and to let a tab sit across a + band edge without that edge's stroke running through it.""" + r = base("rectangle", uid("fill"), x, y, w, h, "transparent", fill, sw=1) + r["roundness"] = {"type": 3} if rounded else None + els.append(r) + return r + + +def stroke_line(pts: list[tuple[float, float]], color: str, sw=2, opacity=100) -> dict: + """A polyline through pts (absolute coordinates), sharp corners.""" + x0, y0 = pts[0] + xs = [p[0] for p in pts] + ys = [p[1] for p in pts] + ln = base("line", uid("ln"), x0, y0, max(xs) - min(xs), max(ys) - min(ys), color, "transparent", sw=sw) + ln.update({"points": [[p[0] - x0, p[1] - y0] for p in pts], "boundElements": None, "roundness": None}) + ln["opacity"] = opacity + els.append(ln) + return ln + + +def arc_pts(cx: float, cy: float, r: float, a0: float, a1: float, n=4) -> list[tuple[float, float]]: + """Points along a circular arc, for rounding a corner of a polyline.""" + return [(cx + r * math.cos(a0 + (a1 - a0) * i / n), cy + r * math.sin(a0 + (a1 - a0) * i / n)) + for i in range(n + 1)] + + +def corner_patch(y_top: float, y_bot: float, pal: dict, anchor: dict) -> None: + """Two rounded bands that meet edge to edge leave a white notch at each + end, where both corner radii curve away from the seam. Fill those notches + with the band's own colour and redraw its outer border straight, so the + stack keeps one silhouette through the seam. + + A notch is CORNER_R deep, which reaches back into the band far enough to + cover a card corner or a header icon, so the patch is restacked to sit + directly above `anchor` (its own band rectangle) instead of on top of + everything the seam is drawn after.""" + made = [ + fill_rect(-1, y_top, CORNER_R + 1, y_bot - y_top, pal["band"]), + fill_rect(CONTENT_W - CORNER_R, y_top, CORNER_R + 1, y_bot - y_top, pal["band"]), + stroke_line([(0, y_top), (0, y_bot)], pal["stroke"], sw=2), + stroke_line([(CONTENT_W, y_top), (CONTENT_W, y_bot)], pal["stroke"], sw=2), + ] + for e in reversed(made): + els.remove(e) + els.insert(els.index(anchor) + 1, e) + + +# ============================================================ the seam +def tab_xs(bx: float, bw: float, n: int) -> list[float]: + """Left edges of the n tabs that plug into a block of width bw at bx.""" + total = n * TAB_W + (n - 1) * TAB_GAP + x0 = bx + (bw - total) / 2 + return [x0 + i * (TAB_W + TAB_GAP) for i in range(n)] + + +def draw_seam(g: dict) -> None: + """The joint: the seam line, then one teal tab per attachment kind cut + into the top edge of the Foundation block it attaches to.""" + seam = g["found_top"] + corner_patch(seam - CORNER_R, seam, TEAL, g["teal_band"]) + corner_patch(seam, seam + CORNER_R, AMBER, g["amber_band"]) + + # The Foundation blocks' top edges are the seam now, so square off their + # rounded top corners -- otherwise each block reads as a lozenge tucked + # under the band rather than a block the band rests on. + for bx, bw in zip(g["f_positions"], g["f_widths"]): + fill_rect(bx, seam, bw, CORNER_R, AMBER["block"]) + stroke_line([(bx, seam), (bx, seam + CORNER_R)], AMBER["stroke"], sw=1) + stroke_line([(bx + bw, seam), (bx + bw, seam + CORNER_R)], AMBER["stroke"], sw=1) + + # Over a block, the seam is that block's own top edge, so it is drawn in + # the block's stroke at the block's own weight: the teal tab then visibly + # interrupts an amber edge, which is what makes the joint read as a notch + # cut into this block rather than a scallop in the band above it. Each tab + # paints over its own stretch of that edge next. Everywhere else the seam + # is the Data Structures band's own bottom edge, in teal at band weight. + edges: list[float] = [0.0] + for bx, bw in zip(g["f_positions"], g["f_widths"]): + stroke_line([(bx, seam), (bx + bw, seam)], AMBER["stroke"], sw=1) + edges += [bx, bx + bw] + edges.append(CONTENT_W) + for x1, x2 in zip(edges[0::2], edges[1::2]): + if x2 - x1 > 0.5: + stroke_line([(x1, seam), (x2, seam)], TEAL["stroke"], sw=2) + + els.append(text(uid("lead"), PAD_BAND, seam + (TAB_D - 13 * 1.25) / 2, LEAD, + size=13, color=AMBER["mid"])) + + for x, word in g["tabs"]: + # the tab's fill runs up past the seam and down over the block's top + # edge, so both strokes stop at the tab: what is left reads as a notch + # cut into the block, filled by the tab. + fill_rect(x, seam - TAB_RISE, TAB_W, TAB_D + TAB_RISE, TEAL["band"], rounded=True) + pts = [(x, seam)] + pts += arc_pts(x + TAB_R, seam + TAB_D - TAB_R, TAB_R, math.pi, math.pi / 2) + pts += arc_pts(x + TAB_W - TAB_R, seam + TAB_D - TAB_R, TAB_R, math.pi / 2, 0.0) + pts += [(x + TAB_W, seam)] + stroke_line(pts, TEAL["stroke"], sw=2) + els.append(text(uid("tabw"), x, seam + (TAB_D - 13 * 1.25) / 2, word, + size=13, color=TEAL["text"], align="center", w=TAB_W)) + + +# ============================================================ the stack +def build(out_path: str) -> str: + # ---------------------------------------- 5/4. Use Cases | Sample Applications + Y_TOP = 0 + GAP_MID = 104 # wide enough for "illustrates" to sit clear of both panels + PANEL_PAD = 14 + PANEL_INSET = PAD_BAND - 2 # same left inset as the full-width band headers + PANEL_TITLE = 18 + PANEL_H = PANEL_PAD + PANEL_TITLE * 1.3 + 13 * 1.25 + PANEL_PAD + panel_w = (CONTENT_W - GAP_MID) / 2 + + band_rect(uid("panel"), 0, Y_TOP, panel_w, PANEL_H, ROSE) + band_rect(uid("panel"), panel_w + GAP_MID, Y_TOP, panel_w, PANEL_H, GREEN) + band_header(PANEL_INSET, Y_TOP + PANEL_PAD, "icons/lucide-lightbulb.svg", ROSE, + "Use Cases", "what the project wants built", size=PANEL_TITLE) + band_header(panel_w + GAP_MID + PANEL_INSET, Y_TOP + PANEL_PAD, "icons/lucide-app-window.svg", GREEN, + "Sample Applications", "what has been built", size=PANEL_TITLE) + conn_y = Y_TOP + PANEL_H / 2 + hconn(panel_w + 2, panel_w + GAP_MID - 2, conn_y, CAPTION) + chip(panel_w + GAP_MID / 2, conn_y - 7 - (13 * 1.25 + 6), "illustrates", + "#ffffff", "transparent", CAPTION) + + # ---------------------------------------- 3. SDKs (thin full-width band) + Y_SDK = Y_TOP + PANEL_H + BAND_GAP + sdk_hdr_bottom = band_header(PAD_BAND - 2, Y_SDK + 16, "icons/lucide-package.svg", VIOLET, + "SDKs", "wrap the structures · attach the shared knowledge · support authoring", + size=18) + SDK_BOTTOM = sdk_hdr_bottom + 16 + band_rect(uid("band"), 0, Y_SDK, CONTENT_W, SDK_BOTTOM - Y_SDK, VIOLET, at_front=True) + + # ---------------------------------------- 2. Data Structures + Y_DATA = SDK_BOTTOM + BAND_GAP + hdr_bottom = band_header(PAD_BAND - 2, Y_DATA + 18, "icons/lucide-layers.svg", TEAL, + "Data Structures", "this patient · Patient Context", size=20) + BLOCK_ROW_Y = hdr_bottom + 14 + W4 = (CONTENT_W - 2 * PAD_BAND - 3 * GAP) / 4 + d_positions = [PAD_BAND + i * (W4 + GAP) for i in range(4)] + d_specs = [ + ("icons/lucide-clipboard.svg", ["Observation"], False), + ("icons/lucide-clipboard-list.svg", ["Exam Finding", "List"], False), + ("icons/lucide-list.svg", ["Imaging Problem", "List"], False), + ("icons/healthicons-person.svg", ["Imaging Persona"], True), + ] + ROW_H_DATA = max(icon_block_h(lines) for _, lines, _ in d_specs) + for xpos, (ipath, lines, filled) in zip(d_positions, d_specs): + icon_block(xpos, BLOCK_ROW_Y, W4, ROW_H_DATA, ipath, TEAL, lines, filled_icon=filled) + DATA_BLOCKS_BOTTOM = BLOCK_ROW_Y + ROW_H_DATA + + DATA_BAND_BOTTOM = DATA_BLOCKS_BOTTOM + PAD_BAND + teal_band = band_rect(uid("band"), 0, Y_DATA, CONTENT_W, DATA_BAND_BOTTOM - Y_DATA, TEAL, at_front=True) + + # ---------------------------------------- 1. Foundation Context (bottom) + # Built last so its rect lands behind the Data Structures band at the seam. + # The two bands are flush: the seam is this band's top edge, and it is also + # the top edge of all three blocks, which start at it with no amber ground + # in between. The header sits in a left column beside them. + FOUND_TOP = DATA_BAND_BOTTOM + + f_specs = [ + ("icons/lucide-tag.svg", ["Finding/diagnosis definitions"], "finding models · CDEs", False, + ["finding", "diagnosis"]), + ("icons/healthicons-lungs.svg", ["Anatomic locations"], "anchored in RadLex", True, + ["location"]), + ("icons/healthicons-xray.svg", ["Exam types"], "LOINC/RSNA Playbook", True, + ["exam type"]), + ] + # The first block holds two tabs, so it is the widest; it also holds the + # longest label ("Finding/diagnosis definitions", 188px measured). + F_WIDTHS = [236.0, 174.0, 174.0] + BX0 = PAD_BAND + LEFT_W + LEFT_GAP + f_positions = [] + x = BX0 + for w in F_WIDTHS: + f_positions.append(x) + x += w + GAP + + ROW_H_FOUND = TAB_D + max(icon_block_h(lines, desc) for _, lines, desc, _, _ in f_specs) + tabs: list[tuple[float, str]] = [] + for xpos, bw, (ipath, lines, desc, filled, words) in zip(f_positions, F_WIDTHS, f_specs): + icon_block(xpos, FOUND_TOP, bw, ROW_H_FOUND, ipath, AMBER, lines, desc=desc, + filled_icon=filled, top_inset=TAB_D) + tabs += list(zip(tab_xs(xpos, bw, len(words)), words)) + FOUND_BLOCKS_BOTTOM = FOUND_TOP + ROW_H_FOUND + + hdr_top = FOUND_TOP + TAB_D + (ROW_H_FOUND - TAB_D - left_header_h(2, 1)) / 2 + left_header(PAD_BAND, hdr_top, "icons/lucide-book-open.svg", AMBER, + ["Foundation", "Context"], ["shared, curated knowledge"], size=20) + + FOUND_BAND_BOTTOM = FOUND_BLOCKS_BOTTOM + PAD_BOTTOM + amber_band = band_rect(uid("band"), 0, FOUND_TOP, CONTENT_W, FOUND_BAND_BOTTOM - FOUND_TOP, + AMBER, at_front=True) + + # ---------------------------------------- the seam, drawn over both bands + draw_seam({ + "found_top": FOUND_TOP, + "f_positions": f_positions, "f_widths": F_WIDTHS, + "tabs": tabs, + "teal_band": teal_band, "amber_band": amber_band, + }) + print(f"foundation band height: {FOUND_BAND_BOTTOM - FOUND_TOP:.0f}px") + + return save(out_path) + + +def main() -> None: + ap = argparse.ArgumentParser(description=__doc__.split("\n")[0]) + ap.add_argument("--out", default="knowledge/drafts/pillars-b2.excalidraw", + help="output path relative to the repo root") + args = ap.parse_args() + build(args.out) + + +if __name__ == "__main__": + main() diff --git a/tools/diagrams/variants/build_pillars_b3.py b/tools/diagrams/variants/build_pillars_b3.py new file mode 100644 index 0000000..f938597 --- /dev/null +++ b/tools/diagrams/variants/build_pillars_b3.py @@ -0,0 +1,462 @@ +#!/usr/bin/env python3 +"""Build the OIDM "five pillars" stack diagram -- seam variant B3, v7. + +Descended from ../build_pillars.py seam b. Where that file offered three +alternative treatments of one seam, this one uses a single treatment -- a +castellated edge -- at every place two bands meet, so the stack's joints are +one visual language instead of three unrelated devices. + +A castellated joint is a square wave drawn once along the boundary of two +bands that overlap by the wave's swing. The upper band is painted over the +lower one throughout the overlap; castellate() then restores the lower band's +fill in the gaps between the teeth and strokes the wave in the upper band's +colour, so the two bands share one interlocking edge with no gap, no tab +shapes and no connectors. Teeth are always twice as wide as the gaps between +them, whatever their count or depth, which is what makes the three joints read +as a family. + +The three joints, top to bottom: + + Sample Applications -> SDKs four green teeth, JOINT_DEPTH deep, labelled + with what an application gets: create, read, + resolve, author. Only the right half of the + SDK band's top edge is joined; Use Cases + keeps a plain BAND_GAP above it, because it + is what the project wants built rather than + something running on the SDKs. + SDKs -> Data Structures two wide violet teeth (wraps, manipulates + instances) plus one narrow tooth at the + right margin that does not close: it carries + on down a reserved lane beside the cards. + Data Structures -> Foundation one castellated line across the whole of the + Foundation band's top edge, SEAM_DEPTH deep: + four teal teeth carrying the attachment + kinds, then, flush right, one violet tooth + where the lane lands, reading what the SDKs + do to the foundation. The lane stops at that + edge rather than running on into the band, + so the band keeps an even margin both sides, + and the SDKs' reach into the foundation is + shown without an arrow. + +Two depths, belonging to the edge rather than to the joint: JOINT_DEPTH for the +two joints above, SEAM_DEPTH for the Foundation band's top edge, which the seam +and the lane's foot share. + +Each joint whose upper band has room for it carries a lead line in that band's +gutter, left-aligned on the first tooth so its colon runs into the list; the +SDK/Data joint has no gutter and so no lead. + +Icons: Health Icons (CC0/MIT, outline style) for anatomy/exam/person glyphs, +Lucide (ISC, with one Feather-derived MIT icon) for everything else -- see +icons/LICENSES.md. ICON_FILLED compensates for Health Icons' filled-path art +rendering optically smaller than Lucide's stroke art at the same box size. + +Output: knowledge/drafts/pillars-b3.excalidraw (override with --out); render +with render_excalidraw.py. +""" +from __future__ import annotations + +import argparse +import os +import sys + +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +from excalib import els, base, text, image, save, AMBER, TEAL, VIOLET, ROSE, GREEN, CAPTION # noqa: E402 + +# ---------------------------------------------------------------- layout constants +CONTENT_W = 880 +BAND_GAP = 24 # the vertical gap wherever two bands do NOT join +PAD_BAND = 20 # a band's own inner padding on all sides +GAP = 20 # gap between sibling blocks inside a band, both rows +ICON = 28 # harmonized icon render size +ICON_FILLED = 32 # filled-path icon sets need a bigger box to match optically +CORNER_R = 32 # Excalidraw's adaptive corner radius for a band-sized rectangle + +# ---------------------------------------------------------------- joint constants +TOOTH_RATIO = 2 # every joint: a tooth is this many gaps wide +JOINT_OVERRUN = 3.0 # a gap's fill runs this far past the lower level, to bury + # the upper band's own border where it crosses the gap +LEAD_GAP = 10.0 # clearance between a lead line and the wave's upper level + +SEAM_DEPTH = 36.0 # Data Structures -> Foundation Context +SEAM_WORDS = ["finding", "diagnosis", "location", "exam type"] +SEAM_LEAD = "woven together at every:" + +JOINT_DEPTH = 24.0 # the two smaller joints +APP_WORDS = ["create", "read", "resolve", "author"] +APP_LEAD = "an application can:" +SDK_WORDS = ["wraps", "manipulates instances"] + +LANE_W = 34.0 # the narrow violet tooth that carries on down. 28 read as a + # wire rather than as structure, so this is a little wider. +LANE_CLEAR = 12.0 # clear space between the Data Structures cards and the lane +# The lane's foot: one wide violet tooth cut into the Foundation band's top edge, +# at the same depth as the seam's own teeth, so the whole of that edge is one +# castellated line -- four teal teeth and, where the lane lands, a violet one. +# Two separate teeth were the brief; they cannot be drawn, because a tooth wide +# enough for the longer phrase does not sit under a 34px lane, so the second +# would float unattached. The middot carries the two roles instead. +FOOT_LABEL = "attaches to · authors & maintains" +FOOT_PAD = 20.0 # horizontal padding inside the foot, as in the other wide teeth + +DATA_TOP_PAD = 34.0 # Data Structures' header, clear of the violet teeth +FOUND_TOP_PAD = 45.0 # Foundation Context's header, clear of the teal teeth +FOUND_HDR_GAP = 12.0 +FOUND_ROW_SHRINK = 11.0 +FOUND_BOTTOM_PAD = 15.0 + +# Measured, not estimated: excalib.text()'s 0.58 * fontSize per character is +# 25-40% wide for these strings, which blew the "illustrates" plate out to twice +# the width of its own text and swallowed the connector either side of it. Only +# strings positioned or sized by their width need an entry; a word centred in a +# tooth does not. Widths in px for Helvetica as headless Chromium resolves it -- +# see "Measuring text instead of estimating it" in tools/diagrams/README.md. +MEASURED = { + ("illustrates", 13): 54.9, + (SEAM_LEAD, 13): 142.4, + (APP_LEAD, 13): 108.4, + (FOOT_LABEL, 13): 190.0, +} +FOOT_W = MEASURED[(FOOT_LABEL, 13)] + 2 * FOOT_PAD + +_uid = [0] + + +def uid(prefix: str) -> str: + _uid[0] += 1 + return f"{prefix}{_uid[0]}" + + +def even_teeth(x0: float, x1: float, n: int) -> list[tuple[float, float]]: + """n teeth evenly spread between x0 and x1, each TOOTH_RATIO units wide with + a one-unit gap between them and at both ends, filling the span exactly.""" + unit = (x1 - x0) / (n * TOOTH_RATIO + n + 1) + return [(x0 + ((TOOTH_RATIO + 1) * i + 1) * unit, + x0 + ((TOOTH_RATIO + 1) * i + 1 + TOOTH_RATIO) * unit) for i in range(n)] + + +# ---------------------------------------------------------------- primitives +def band_rect(id_: str, x: float, y: float, w: float, h: float, pal: dict, at_front=False) -> dict: + """Draw a band's background rectangle. Pass at_front=True when the band's + true height is only known after laying out its header/blocks (they were + already appended to els) -- this inserts the rect at index 0 so it still + paints behind its own contents instead of covering them. + + The order this produces is what makes the joints work: each band rect is + inserted at 0 after the one above it, so the stack paints back to front, + bottom band first, and every band covers the one below it wherever they + overlap. castellate() then only has to put the lower band's colour back.""" + r = base("rectangle", id_, x, y, w, h, pal["stroke"], pal["band"]) + r["roundness"] = {"type": 3} + if at_front: + els.insert(0, r) + else: + els.append(r) + return r + + +def band_header(x: float, y: float, icon_path: str, pal: dict, title: str, + subtitle: str | None, size=20, filled_icon=False) -> float: + """Bold band title with its icon to the left, subtitle below. A band whose + edges already say what it does takes subtitle=None. Returns bottom y.""" + s = ICON_FILLED if filled_icon else ICON + image(uid("bicon"), x, y - (s - ICON) / 2 - 2, s, s, icon_path, color=pal["stroke"]) + els.append(text(uid("btitle"), x + ICON + 12, y, title, size=size, color=pal["text"])) + y2 = y + size * 1.3 + if subtitle is None: + return y2 + els.append(text(uid("bsub"), x + ICON + 12, y2, subtitle, size=13, color=pal["mid"])) + return y2 + 13 * 1.25 + + +def icon_block_h(lines: list[str], desc: str | None = None) -> float: + """Height an icon_block needs for this many label lines/descriptor.""" + n_title = len(lines) + return 12 + ICON + 8 + n_title * 15 * 1.25 + (13 * 1.25 + 2 if desc else 0) + 10 + + +def icon_block(x: float, y: float, w: float, h: float, icon_path: str, pal: dict, + lines: list[str], desc: str | None = None, filled_icon=False) -> dict: + """Icon centered on top, label line(s) centered below, optional lighter + descriptor line last. Background is the band's own deeper pastel so the + block reads as 'inside' the band, not a separate object. Content is + centered in h, so passing an h below icon_block_h() trims the block's own + padding without touching the icon or the type.""" + r = base("rectangle", uid("blk"), x, y, w, h, pal["stroke"], pal["block"], sw=1) + r["roundness"] = {"type": 3} + els.append(r) + cx = x + w / 2 + content_h = icon_block_h(lines, desc) - 22 # minus this fn's fixed 12+10 top/bottom pad + top = y + (h - content_h) / 2 + s = ICON_FILLED if filled_icon else ICON + image(uid("blki"), cx - s / 2, top - (s - ICON) / 2, s, s, icon_path, color=pal["stroke"]) + ty = top + ICON + 6 + for ln in lines: + els.append(text(uid("blkt"), x + 6, ty, ln, size=15, color=pal["text"], align="center", w=w - 12)) + ty += 15 * 1.25 + if desc: + els.append(text(uid("blkd"), x + 6, ty + 2, desc, size=13, color=pal["mid"], align="center", w=w - 12)) + return r + + +def chip(cx: float, y_top: float, s: str, fill: str, stroke: str, color: str, + size=13, pad_x=9, pad_y=3) -> float: + """A short caption on its own opaque rounded plate, centered on cx, so it + reads as a label for what it sits over and never mixes with a line or a + band fill behind it. Returns bottom y.""" + w = MEASURED.get((s, size), len(s) * size * 0.58) + 2 * pad_x + h = size * 1.25 + 2 * pad_y + r = base("rectangle", uid("chip"), cx - w / 2, y_top, w, h, stroke, fill, sw=1) + r["roundness"] = {"type": 3} + els.append(r) + els.append(text(uid("chipt"), cx - w / 2 + pad_x, y_top + pad_y, s, size=size, color=color, + align="center", w=w - 2 * pad_x)) + return y_top + h + + +def hconn(x1: float, x2: float, y: float, color: str, sw=1) -> None: + """A plain horizontal connector.""" + a = base("line", uid("conn"), x1, y, x2 - x1, 0, color, "transparent", sw=sw) + a.update({"points": [[0, 0], [x2 - x1, 0]], "boundElements": None}) + els.append(a) + + +def fill_rect(x: float, y: float, w: float, h: float, fill: str) -> dict: + """An unstroked patch of colour -- used to carry one band's fill back + across the other band's, without either border's stroke showing through.""" + r = base("rectangle", uid("fill"), x, y, w, h, "transparent", fill, sw=1) + r["roundness"] = None + els.append(r) + return r + + +def stroke_line(pts: list[tuple[float, float]], color: str, sw=2, opacity=100) -> dict: + """A polyline through pts (absolute coordinates), sharp corners.""" + x0, y0 = pts[0] + xs = [p[0] for p in pts] + ys = [p[1] for p in pts] + ln = base("line", uid("ln"), x0, y0, max(xs) - min(xs), max(ys) - min(ys), color, "transparent", sw=sw) + ln.update({"points": [[p[0] - x0, p[1] - y0] for p in pts], "boundElements": None, "roundness": None}) + ln["opacity"] = opacity + els.append(ln) + return ln + + +def corner_fix(y_top: float, y_bot: float, pal: dict, anchor: dict, + x_from: float, x_to: float) -> None: + """A rounded rectangle's corner curves away from its own edge, so where a + band is overlapped at a joint its corner leaves a notch of bare page. Fill + the notch with that band's own colour. + + The patch is restacked to sit directly above `anchor` -- the band rect it + belongs to -- rather than on top of everything the joint is drawn after, so + it can be as deep as the corner radius without covering a header or a + card.""" + made = [fill_rect(x_from - 1, y_top, CORNER_R + 1, y_bot - y_top, pal["band"]), + fill_rect(x_to - CORNER_R, y_top, CORNER_R + 1, y_bot - y_top, pal["band"])] + for e in reversed(made): + els.remove(e) + els.insert(els.index(anchor) + 1, e) + + +# ============================================================ the castellated joint +def castellate(hi: float, lo: float, teeth: list[tuple[float, float]], words: list[str | None], + upper: dict, lower: dict, upper_band: dict, lower_band: dict, + x_from: float = 0.0, x_to: float = CONTENT_W, + lower_borders: tuple[bool, bool] = (True, True), + open_teeth: tuple[int, ...] = (), lead: str | None = None) -> None: + """Draw one interlocking edge between two overlapping bands. + + hi/lo are the wave's upper and lower levels: the lower band's rect starts at + hi, the upper band's ends at lo, and the upper band owns the whole overlap + until this runs. x_from/x_to bound the joint, which need not be the full + width. lower_borders says whether the lower band actually has a side border + at each end (it does not where the joint stops short of the band's own + edge). A tooth listed in open_teeth is left unclosed, for something else to + carry on downwards from. + """ + corner_fix(lo - CORNER_R, lo, upper, upper_band, x_from, x_to) + corner_fix(hi, hi + CORNER_R, lower, lower_band, x_from, x_to) + + # The lower band's colour back over the gaps: flush with the upper level, + # since the wave is stroked along it last, and past the lower one to bury + # the upper band's border. The end gaps overshoot the side borders too. + for x1, x2 in zip([x_from] + [t[1] for t in teeth], [t[0] for t in teeth] + [x_to]): + a = x1 - 1 if x1 == x_from else x1 + b = x2 + 1 if x2 == x_to else x2 + if b - a > 2: # a tooth flush with the end leaves no gap to fill + fill_rect(a, hi, b - a, lo - hi + JOINT_OVERRUN, lower["band"]) + for x, has_lower in ((x_from, lower_borders[0]), (x_to, lower_borders[1])): + stroke_line([(x, hi - CORNER_R), (x, hi)], upper["stroke"], sw=2) + if has_lower: + stroke_line([(x, hi), (x, lo + CORNER_R)], lower["stroke"], sw=2) + + # The wave itself, stroked once. An open tooth breaks it into two runs. + runs: list[list[tuple[float, float]]] = [] + cur: list[tuple[float, float]] = [(x_from, hi)] + for j, (x1, x2) in enumerate(teeth): + if j in open_teeth: + cur.append((x1, hi)) + runs.append(cur) + cur = [(x2, hi)] + else: + cur += [(x1, hi), (x1, lo), (x2, lo), (x2, hi)] + cur.append((x_to, hi)) + runs.append(cur) + for run in runs: + if len(set(run)) > 1: # an open tooth flush with the end leaves no run + stroke_line(run, upper["stroke"], sw=2) + + for word, (x1, x2) in zip(words, teeth): + if word: + els.append(text(uid("jw"), x1, hi + (lo - hi - 13 * 1.25) / 2, word, + size=13, color=upper["text"], align="center", w=x2 - x1)) + + # The lead's colon runs into the list, so it starts where the first tooth + # does; anywhere left of that it reads as a label for the first gap instead. + if lead: + els.append(text(uid("jl"), teeth[0][0], hi - LEAD_GAP - 13 * 1.25, lead, + size=13, color=upper["mid"])) + + +def draw_lane(x1: float, x2: float, y_top: float, foot_top: float, depth: float, + foot_w: float, label: str) -> None: + """The narrow violet tooth carried on down its lane, ending where the + Foundation band's top edge begins by widening into one tooth cut into it. + Drawn last, so it passes in front of every band and joint it crosses.""" + foot_left = x2 - foot_w + fill_rect(x1, y_top, x2 - x1, foot_top - y_top, VIOLET["band"]) + fill_rect(foot_left, foot_top, foot_w, depth, VIOLET["band"]) + stroke_line([(x1, y_top), (x1, foot_top), (foot_left, foot_top), + (foot_left, foot_top + depth), (x2, foot_top + depth), (x2, y_top)], + VIOLET["stroke"], sw=2) + els.append(text(uid("lanet"), foot_left, foot_top + (depth - 13 * 1.25) / 2, label, + size=13, color=VIOLET["text"], align="center", w=foot_w)) + + +# ============================================================ the stack +def build(out_path: str) -> str: + # ---------------------------------------- 5/4. Use Cases | Sample Applications + Y_TOP = 0 + GAP_MID = 120 # wide enough for "illustrates" to sit on the connector + # with a readable stub of line showing each side + PANEL_PAD = 16 # same as the SDK band's, so the two headers' + # identically built bands come out the same height + PANEL_INSET = PAD_BAND - 2 # same left inset as the full-width band headers + PANEL_TITLE = 18 + PANEL_H = PANEL_PAD + PANEL_TITLE * 1.3 + 13 * 1.25 + PANEL_PAD + # Sample Applications takes the larger share, so its four teeth get closer to + # the proportions of the seam's; Use Cases only has to hold its own subtitle. + use_w = (CONTENT_W - GAP_MID) * 0.4 + app_w = (CONTENT_W - GAP_MID) - use_w + APP_X = use_w + GAP_MID + + # The SDK band's top edge is where Sample Applications comes down to meet it; + # Use Cases keeps a plain gap above that same edge. + SDK_TOP = Y_TOP + PANEL_H + BAND_GAP + APP_LO = SDK_TOP + JOINT_DEPTH + + band_rect(uid("panel"), 0, Y_TOP, use_w, PANEL_H, ROSE) + app_panel = band_rect(uid("panel"), APP_X, Y_TOP, app_w, APP_LO - Y_TOP, GREEN) + band_header(PANEL_INSET, Y_TOP + PANEL_PAD, "icons/lucide-lightbulb.svg", ROSE, + "Use Cases", "what the project wants built", size=PANEL_TITLE) + band_header(APP_X + PANEL_INSET, Y_TOP + PANEL_PAD, "icons/lucide-app-window.svg", GREEN, + "Sample Applications", "what has been built", size=PANEL_TITLE) + conn_y = Y_TOP + PANEL_PAD + (PANEL_TITLE * 1.3 + 13 * 1.25) / 2 + hconn(use_w + 2, APP_X - 2, conn_y, CAPTION) + chip(use_w + GAP_MID / 2, conn_y - (13 * 1.25 + 6) / 2, "illustrates", + "#ffffff", "transparent", CAPTION) + + # ---------------------------------------- 3. SDKs (thin full-width band) + # No subtitle: the three joints on this band's two edges now say everything + # the subtitle used to, word for word. + sdk_hdr_bottom = band_header(PAD_BAND - 2, SDK_TOP + 16, "icons/lucide-package.svg", VIOLET, + "SDKs", None, size=18) + SDK_BOTTOM = sdk_hdr_bottom + 16 + SDK_LO = SDK_BOTTOM + JOINT_DEPTH + sdk_band = band_rect(uid("band"), 0, SDK_TOP, CONTENT_W, SDK_LO - SDK_TOP, VIOLET, at_front=True) + + # ---------------------------------------- 2. Data Structures + # A lane down the right margin is left clear in the card row below, for the + # narrow violet tooth to travel in. It runs flush with the bands' own right + # border: inset from it, the strip of band colour left outside the lane reads + # as a sliver rather than as a lane. It stops at the Foundation band's top + # edge, so that band keeps an even PAD_BAND margin on both sides. + LANE_X2 = CONTENT_W + LANE_X1 = LANE_X2 - LANE_W + ROW_RIGHT = LANE_X1 - LANE_CLEAR + + Y_DATA = SDK_BOTTOM + hdr_bottom = band_header(PAD_BAND - 2, Y_DATA + DATA_TOP_PAD, "icons/lucide-layers.svg", TEAL, + "Data Structures", "this patient · Patient Context", size=20) + BLOCK_ROW_Y = hdr_bottom + 14 + W4 = (ROW_RIGHT - PAD_BAND - 3 * GAP) / 4 + d_positions = [PAD_BAND + i * (W4 + GAP) for i in range(4)] + d_specs = [ + ("icons/lucide-clipboard.svg", ["Observation"], False), + ("icons/lucide-clipboard-list.svg", ["Exam Finding", "List"], False), + ("icons/lucide-list.svg", ["Imaging Problem", "List"], False), + ("icons/healthicons-person.svg", ["Imaging Persona"], True), + ] + ROW_H_DATA = max(icon_block_h(lines) for _, lines, _ in d_specs) + for xpos, (ipath, lines, filled) in zip(d_positions, d_specs): + icon_block(xpos, BLOCK_ROW_Y, W4, ROW_H_DATA, ipath, TEAL, lines, filled_icon=filled) + DATA_BLOCKS_BOTTOM = BLOCK_ROW_Y + ROW_H_DATA + + # room below the cards for the seam's lead line and the seam's own swing + DATA_BAND_BOTTOM = DATA_BLOCKS_BOTTOM + SEAM_DEPTH + 2 * LEAD_GAP + 13 * 1.25 + teal_band = band_rect(uid("band"), 0, Y_DATA, CONTENT_W, DATA_BAND_BOTTOM - Y_DATA, TEAL, at_front=True) + + # ---------------------------------------- 1. Foundation Context (bottom) + FOUND_TOP = DATA_BAND_BOTTOM - SEAM_DEPTH + hdr_bottom_f = band_header(PAD_BAND - 2, FOUND_TOP + FOUND_TOP_PAD, + "icons/lucide-book-open.svg", AMBER, + "Foundation Context", "shared, curated knowledge", size=20) + F_ROW_Y = hdr_bottom_f + FOUND_HDR_GAP + W3 = (CONTENT_W - 2 * PAD_BAND - 2 * GAP) / 3 + f_positions = [PAD_BAND + i * (W3 + GAP) for i in range(3)] + f_specs = [ + ("icons/lucide-tag.svg", ["Finding/diagnosis definitions"], "finding models · CDEs", False), + ("icons/healthicons-lungs.svg", ["Anatomic locations"], "anchored in RadLex", True), + ("icons/healthicons-xray.svg", ["Exam types"], "LOINC/RSNA Playbook", True), + ] + ROW_H_FOUND = max(icon_block_h(lines, desc) for _, lines, desc, _ in f_specs) - FOUND_ROW_SHRINK + for xpos, (ipath, lines, desc, filled) in zip(f_positions, f_specs): + icon_block(xpos, F_ROW_Y, W3, ROW_H_FOUND, ipath, AMBER, lines, desc=desc, filled_icon=filled) + FOUND_BAND_BOTTOM = F_ROW_Y + ROW_H_FOUND + FOUND_BOTTOM_PAD + amber_band = band_rect(uid("band"), 0, FOUND_TOP, CONTENT_W, FOUND_BAND_BOTTOM - FOUND_TOP, + AMBER, at_front=True) + + # ---------------------------------------- the three joints, top to bottom + castellate(SDK_TOP, APP_LO, even_teeth(APP_X, CONTENT_W, len(APP_WORDS)), APP_WORDS, + GREEN, VIOLET, app_panel, sdk_band, x_from=APP_X, x_to=CONTENT_W, + lower_borders=(False, True), lead=APP_LEAD) + + sdk_teeth = even_teeth(0, LANE_X1, len(SDK_WORDS)) + [(LANE_X1, LANE_X2)] + castellate(SDK_BOTTOM, SDK_LO, sdk_teeth, SDK_WORDS + [None], VIOLET, TEAL, + sdk_band, teal_band, open_teeth=(len(SDK_WORDS),)) + + # The seam's own teeth share this edge with the lane's foot, so they are laid + # out in the width the foot leaves: one more gap, then the foot, flush right. + castellate(FOUND_TOP, DATA_BAND_BOTTOM, even_teeth(0, CONTENT_W - FOOT_W, len(SEAM_WORDS)), + SEAM_WORDS, TEAL, AMBER, teal_band, amber_band, lead=SEAM_LEAD) + + draw_lane(LANE_X1, LANE_X2, SDK_BOTTOM, FOUND_TOP, SEAM_DEPTH, FOOT_W, FOOT_LABEL) + + print(f"foundation band below its edge: {FOUND_BAND_BOTTOM - FOUND_TOP:.0f}px; " + f"figure {FOUND_BAND_BOTTOM:.0f}px tall") + return save(out_path) + + +def main() -> None: + ap = argparse.ArgumentParser(description=__doc__.split("\n")[0]) + ap.add_argument("--out", default="knowledge/drafts/pillars-b3.excalidraw", + help="output path relative to the repo root") + args = ap.parse_args() + build(args.out) + + +if __name__ == "__main__": + main() diff --git a/tools/verify.py b/tools/verify.py new file mode 100644 index 0000000..54406cf --- /dev/null +++ b/tools/verify.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python3 +# /// script +# requires-python = ">=3.11" +# dependencies = ["pyyaml"] +# /// +"""Mark bundle documents as verified by a human, or report review status. + + uv run tools/verify.py knowledge/glossary/oifm.md [more paths...] mark verified + uv run tools/verify.py --by human:someone knowledge/... different reviewer + uv run tools/verify.py --status counts per directory + uv run tools/verify.py --list knowledge/glossary draft documents under a directory + +Marking adds a `verified` entry with the current UTC time, sets `status: stable`, +and leaves everything else in the frontmatter untouched (text edit, not a YAML +round-trip, so key order and quoting survive). +""" +from __future__ import annotations + +import argparse +import datetime as dt +import glob +import os +import re +import sys + +import yaml + +REPO = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +FM = re.compile(r"^---\n(.*?)\n---\n", re.S) + + +def load(path: str) -> tuple[str, dict, str]: + text = open(path, encoding="utf-8").read() + m = FM.match(text) + if not m: + raise SystemExit(f"{path}: no frontmatter") + return text, yaml.safe_load(m.group(1)) or {}, m.group(1) + + +def mark(path: str, by: str) -> None: + text, data, fm = load(path) + now = dt.datetime.now(dt.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") + entry = f" - {{ by: {by}, at: {now} }}" + if "verified" in data: + # append to an existing list (normalize a single mapping to a list) + if isinstance(data["verified"], dict): + fm = re.sub(r"^verified:.*$", f"verified:\n - {{ by: {data['verified']['by']}, at: {data['verified']['at']} }}\n{entry}", fm, count=1, flags=re.M) + else: + fm = re.sub(r"^(verified:\n(?: - .*\n?)*)", lambda m: m.group(1).rstrip("\n") + "\n" + entry + "\n", fm, count=1, flags=re.M) + else: + # insert after generated, else at the end + if re.search(r"^generated:.*$", fm, flags=re.M): + fm = re.sub(r"^(generated:.*)$", r"\1\nverified:\n" + entry, fm, count=1, flags=re.M) + else: + fm = fm.rstrip("\n") + "\nverified:\n" + entry + if re.search(r"^status:.*$", fm, flags=re.M): + fm = re.sub(r"^status:.*$", "status: stable", fm, count=1, flags=re.M) + else: + fm += "\nstatus: stable" + head = FM.match(text) + assert head is not None + new = "---\n" + fm + "\n---\n" + text[head.end():] + open(path, "w", encoding="utf-8").write(new) + print(f"verified {os.path.relpath(path, REPO)} by {by} at {now}") + + +def concepts(root: str) -> list[str]: + out = [] + for p in sorted(glob.glob(os.path.join(root, "**", "*.md"), recursive=True)): + if os.path.basename(p) in ("index.md", "log.md"): + continue + out.append(p) + return out + + +def status_report(bundle: str) -> None: + rows: dict[str, list[int]] = {} + for p in concepts(bundle): + _, data, _ = load(p) + d = os.path.relpath(os.path.dirname(p), bundle) + d = d.split(os.sep)[0] if d != "." else "." + row = rows.setdefault(d, [0, 0]) + row[1] += 1 + if data.get("status", "stable") == "stable" and data.get("verified"): + row[0] += 1 + total_v = sum(r[0] for r in rows.values()); total = sum(r[1] for r in rows.values()) + print(f"{'directory':28} verified / total") + for d, (v, n) in sorted(rows.items()): + print(f"{d:28} {v:3} / {n}") + print(f"{'all':28} {total_v:3} / {total}") + + +def list_drafts(root: str) -> None: + for p in concepts(root): + _, data, _ = load(p) + if not data.get("verified"): + print(os.path.relpath(p, REPO)) + + +def main() -> int: + ap = argparse.ArgumentParser() + ap.add_argument("paths", nargs="*") + ap.add_argument("--by", default="human:talkasab") + ap.add_argument("--status", action="store_true") + ap.add_argument("--list", metavar="DIR") + a = ap.parse_args() + if a.status: + status_report(os.path.join(REPO, "knowledge")); return 0 + if a.list: + list_drafts(os.path.join(REPO, a.list)); return 0 + if not a.paths: + ap.print_help(); return 2 + for p in a.paths: + mark(os.path.join(REPO, p) if not os.path.isabs(p) else p, a.by) + return 0 + + +if __name__ == "__main__": + sys.exit(main())