Skip to content

OpenConceptLab/ocl_issues#2817 | Write the Matching Algorithms page - #75

Merged
paynejd merged 5 commits into
mainfrom
OpenConceptLab/ocl_issues#2817-matching-algorithms
Oct 26, 2026
Merged

paynejd merged 5 commits into
mainfrom
OpenConceptLab/ocl_issues#2817-matching-algorithms

Conversation

@paynejd

@paynejd paynejd commented Oct 26, 2026 •

Copy link
Copy Markdown
Member

What changed and why

The Mapper's Matching Algorithm "Learn more" link points at docs/source/oclmap/matching-algorithms.md, which was a stub. This replaces the stub with the full page. The page leads with the open-source OCL Mapper and OCL API and ends with a section on what OCL Online adds:

  • Intro: the five steps the Mapper takes for each row, and a note that everything on the page is open source except the last section. It links the $match reference as the specification of the request and response.
  • The algorithms (open): OCL Search, OCL Semantic and Custom Match Algorithm, what each does, which input columns it uses, what it needs and when to pick it. The Custom section gives the contract a matching service has to meet. Model names are given as the OCL API's defaults. A short section explains Batch Size and Concurrent Requests.
  • One algorithm or several (open): the combination rules (OCL Search and OCL Semantic can't be selected together; OCL Semantic needs a target repository version with semantic search; up to five algorithms), how candidates from several algorithms are merged into one per concept, and how every candidate gets one unified 0 to 100 score from the reranker, inline in $match for a single OCL algorithm and through $rerank otherwise.
  • Score thresholds (open): the Recommended and Available thresholds (99 and 70 by default), the three groups they make, and how they apply in the candidate list, in AutoMatch's proposals and in the row list.
  • Available on OCL Online: Bridge terminology search, ScispaCy LOINC search and where the OCL AI Assistant fits. They run on services OCL hosts, so a self-installed Mapper doesn't offer them, and the OCL Online account decides which can be used.

It also corrects the $match reference (docs/source/oclapi/apireference/match.md):

  • id is a word-by-word text search, not an exact match (Codex pass 1, F1.1).
  • Access is described as permission to use the Mapper (403 otherwise) and per-user rate limits (429).
  • It's brought in line with oclapi2:
    • the bridge algorithm is reported as ocl-bridge, and runs whenever filter.target_repo isn't the repository being searched;
    • numCandidates defaults to 500;
    • reranker applies to any request whose row has a name.

Custom Match Algorithm is documented as part of the open Mapper. Today oclmap lists it only when the OCL Online algorithm catalog serves it; OpenConceptLab/ocl_issues#2966 makes every build offer it.

Every statement was checked against the public code: OpenConceptLab/oclapi2 master (4b331a0, rechecked at c1ba1eb2) and OpenConceptLab/oclmap main (933058b; e19ad3a adds no source changes). What was checked:

  • oclapi2:
    • POST /concepts/$match/ (MetadataToConceptsListView, ConceptFuzzySearch): semantic requires has_semantic_match_algorithm; id is an analyzed TextField matched with an OR match query; the bridge mode is semantic search filtered on mapped_codes.source; reranker scores inline; num_candidates_default = 500.
    • POST /concepts/$rerank/ (RerankConceptsListView, Reranker): name plus up to MAX_SYNONYMS_TO_SCORE = 5 synonyms, best match kept, × 100.
    • Source.SEMANTIC_MATCH_ALGORITHM = 'llm'; check_for_match_algorithms (staff only).
    • settings.ENCODER_MODEL_NAME = "BAAI/bge-reranker-v2-m3" and LM_MODEL_NAME = 'all-MiniLM-L6-v2'.
  • oclmap:
    • algorithms.jsx: the built-in algorithms (OCL Search and OCL Semantic), batch sizes 10 and 50.
    • MapProject.jsx: the other algorithms come from OCL_ONLINE_API_URL's catalog; CANDIDATES_LIMIT = 15, reranker: !isMultiAlgo, the $rerank/ pass; default score_configuration {recommended: 99, available: 70}; batched processWithConcurrency only for Search, Semantic and custom; row-by-row bridge and ScispaCy; the ScispaCy warm-up retries, and the AI Assistant payload and AutoMatch step.
    • LazyLoader.jsx: the bridge component is loaded only when configured.
    • MultiAlgoSelector.jsx: maxAlgos=5, the Search/Semantic exclusion, match_algorithms includes llm, the custom algorithm's GET check and token.
    • Candidates.jsx: score buckets. normalizers.js and viewBuilders.js: canonical concept identity and target-repository filtering. tokenScope.js: a custom algorithm gets only its own token.

How I tested it

  • Built in a Python 3.12 venv (.readthedocs.yaml builds on 3.12): pip install -r requirements.txt, then make -C docs clean html. At d52e443: build succeeded, 18 warnings. These are the same 18 warnings main gives, and none comes from the touched files.
  • Opened the built pages in headless Chromium at 1280 px and 390 px: oclmap/matching-algorithms.html and oclapi/apireference/match.html. No broken in-page anchors (including #available-on-ocl-online), no console errors from the pages, no horizontal page overflow.
  • The theme doesn't wrap table cells, so the page uses lists rather than tables.

There is no test suite or CI in this repo. The Sphinx build and the render check above are the gate.

Review

  • Codex pass 1 (bbe5a66): 2 P1, both fixed in 9e3a299.
    • F1.1: ID matching isn't exact. Also fixed in the $match reference.
    • F1.2: Batch Size and Concurrent Requests don't apply to Bridge and ScispaCy, which match one row at a time.
  • Codex pass 2 (9e3a299): clean.
  • Simplification review: 7 items. S2, S3, S4, S6 and S7 were applied in cada220; S1 and S5 were kept, with reasons on the PR.
  • Codex check of the cuts (cada220): clean.
  • Codex pass 3 (16099c1, the open/OCL Online restructure and the $match corrections): clean.
  • Codex check of d52e443 (one sentence trimmed in the OCL Online section): clean.
  • Nothing is left open.

Acceptance criteria

  • What each algorithm does and when to pick it: OCL Search, OCL Semantic, Custom under "The algorithms"; Bridge terminology search (CIEL) and ScispaCy LOINC search under "Available on OCL Online".
  • Which combinations are allowed (OCL Search and OCL Semantic are exclusive; OCL Semantic needs a target repo with semantic search enabled), and how results from several algorithms are merged and scored. See "One algorithm or several", "How candidates are merged" and "How candidates are scored".
  • How the score thresholds (Recommended / Available / Low Ranked) apply. See "Score thresholds".
  • Where the OCL AI Assistant fits. See "Where the OCL AI Assistant fits", under "Available on OCL Online".

Docs updated

  • docs/source/oclmap/matching-algorithms.md, rewritten. It was already in the OCL Mapper toctree, and nothing else linked to the stub's text.
  • docs/source/oclapi/apireference/match.md: id, access, numCandidates, reranker and the bridge algorithm.

What I chose not to do

  • Settings only staff see (reranker model, AI model and prompt template) are left out. The OCL Online section says only that the account decides which of its algorithms and services can be used.
  • The page describes Bridge terminology search and ScispaCy LOINC search only as far as the public oclmap and oclapi2 code shows.
  • A table of input columns per algorithm: the page lists the columns briefly and links to the $match reference.

Follow-ups

Noticed, not fixed

  • oclmap's Field Configuration describes the ID field as "Exact match on concept ID" (ID_HEADER in constants.jsx), which isn't what oclapi2 does (see F1.1).
  • Cross-page anchor links in Markdown, such as collectionReferenceEvaluation.md#cascade in resolveReference.md and collections.md, build as .md#… links that don't resolve on the built site. recommonmark only rewrites .md links without a fragment.
  • Two oclmap inconsistencies the page documents as they are:
    • When a custom algorithm is a project's only algorithm, AutoMatch takes the service's search_normalized_score as the unified score, but matching a row by hand reranks the same candidates (trustServerRerank differs between the two paths).
    • With one OCL algorithm, a row without a name is scored relative to its best hit, which scores 100 and is therefore proposed. With several algorithms, the same row's candidates stay unranked.

closes OpenConceptLab/ocl_issues#2817

🤖 Generated with Claude Code

Opened by an Octoad session worker (worker-v0.11, recipe lean-loop, flow public>public, run openconceptlab-ocl-issues-2817-20261026-103915). Restructured into open core and OCL Online sections in a Claude Code session with Jonathan Payne.

Replaces the Mapper's Matching Algorithms stub with the full page: what
OCL Search, OCL Semantic, Bridge terminology search, ScispaCy LOINC
search and a custom algorithm each do and when to pick them; which
combinations are allowed; how candidates from several algorithms are
merged and given one unified score by the reranker; how the
Recommended, Available and Low Ranked thresholds group candidates and
drive AutoMatch; and where the OCL AI Assistant fits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrxkQb6LXc868Qyp4BfEuZ
@paynejd paynejd added origin/ai-generated Issue or PR created by an AI agent origin/session-worker Opened by the Octoad session worker; a run record backs it labels Oct 26, 2026
@paynejd paynejd self-assigned this Oct 26, 2026

@paynejd paynejd left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Codex review, pass 1 (codex-cli 0.164.0, commit bbe5a66)

2 findings: 2 P1.

  • F1.1 · P1 · docs/source/oclmap/matching-algorithms.md:26 · ID matching is not exact: ConceptFuzzySearch uses get_or_match_criteria (an OR match) on ConceptDocument.id, an analyzed TextField. (An ID-only row containing ABC-123 can retrieve DEF-123 because they share a token; with OCL Search alone the top result can score 100 and become Proposed despite its different ID.)
  • F1.2 · P1 · docs/source/oclmap/matching-algorithms.md:68 · Batch Size and Concurrent Requests do not control every algorithm: fetchBulkBridgeCandidates and fetchBulkScispacyCandidates send sequential per-row requests. (A user sets Bridge or ScispaCy to Batch Size 10 and Concurrent Requests 2, but AutoMatch still sends one row per request, so lowering the batch size cannot address timeouts as the page advises.)
findings.json
{
  "reviewer": "codex-cli 0.164.0",
  "perspective": "defects",
  "mode": "full",
  "commit": "bbe5a6660d02e3581f53ea015d2922f9e8f14a16",
  "verdict": "findings",
  "prior": [],
  "findings": [
    {
      "id": "F1.1",
      "severity": "P1",
      "tag": null,
      "file": "docs/source/oclmap/matching-algorithms.md",
      "line": 26,
      "claim": "ID matching is not exact. ConceptFuzzySearch uses get_or_match_criteria on ConceptDocument.id, an analyzed TextField, with operator OR.",
      "scenario": "An ID-only row containing ABC-123 can retrieve DEF-123 because they share a token. With OCL Search alone, the top result can receive a normalized score of 100 and become Proposed despite its different ID. The documented exact-match guarantee would mislead users reviewing these matches.",
      "action": "Describe ID matching as analyzed token search that can return nonidentical codes; remove the exact-match guarantee.",
      "lines_delta": null,
      "confidence": "high"
    },
    {
      "id": "F1.2",
      "severity": "P1",
      "tag": null,
      "file": "docs/source/oclmap/matching-algorithms.md",
      "line": 68,
      "claim": "Batch Size and Concurrent Requests do not control every algorithm. MapProject's fetchBulkBridgeCandidates and fetchBulkScispacyCandidates use sequential per-row requests and ignore both settings.",
      "scenario": "A user configures Bridge or ScispaCy with Batch Size 10 and Concurrent Requests 2, but AutoMatch still sends one row per request, sequentially. Lowering their batch size cannot address timeouts as this paragraph advises.",
      "action": "Scope the batching and concurrency explanation to OCL Search, OCL Semantic and Custom, and state that Bridge and ScispaCy currently process rows sequentially.",
      "lines_delta": null,
      "confidence": "high"
    }
  ]
}

…x pass 1

The ID column is a word-by-word text search of concept IDs, not an exact
match, here and in the $match reference's two descriptions of `id`.
Batch Size and Concurrent Requests apply only to OCL Search, OCL
Semantic and custom algorithms; Bridge terminology search and ScispaCy
LOINC search match one row at a time. Says that a name-less row's best
candidate is always proposed with a single OCL algorithm, and states
the AI Assistant's inputs as the Mapper sends them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrxkQb6LXc868Qyp4BfEuZ
@paynejd

paynejd commented Oct 26, 2026

Copy link
Copy Markdown
Member Author

Response to Codex pass 1

  • F1.1 fixed in 9e3a299: the ID column is now described as a word-by-word text search that can return other IDs (ABC-123 also finds DEF-123). The same exact-match claim is fixed in the $match reference's two id descriptions. The page also now says that, with a single OCL algorithm, a name-less row's best candidate scores 100 and is always proposed.
  • F1.2 fixed in 9e3a299: Batch Size and Concurrent Requests are scoped to OCL Search, OCL Semantic and custom algorithms, and the page says Bridge terminology search and ScispaCy LOINC search match one row at a time.

Same commit, my own correction: the AI Assistant section now states its inputs as the Mapper sends them (the target-repository candidates to choose from, CIEL bridge concepts as context only) instead of describing how the assistant itself chooses.

@paynejd paynejd left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Codex review, pass 2 (codex-cli 0.164.0, commit 9e3a299)

Clean. F1.1 and F1.2 resolved.

findings.json
{
  "reviewer": "codex-cli 0.164.0",
  "perspective": "defects",
  "mode": "verify",
  "commit": "9e3a29991410ce9ac0600ce9e1e34cfbb14d9dd5",
  "verdict": "clean",
  "prior": [
    {
      "id": "F1.1",
      "status": "resolved"
    },
    {
      "id": "F1.2",
      "status": "resolved"
    }
  ],
  "findings": []
}

@paynejd

paynejd commented Oct 26, 2026

Copy link
Copy Markdown
Member Author

Response to Codex pass 2

No findings. With F1.1 and F1.2 resolved and no P0 or P1 open, the Codex loop stops here. The simplification review is next.

@paynejd paynejd left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Simplification review (commit 9e3a299)

7 items: 1 native, 2 shrink, 4 delete.

  • S1 · native · docs/source/oclmap/matching-algorithms.md:15 · the five-item list under "The algorithms", which repeats each subsection's opening and the theme's sidebar entries → nothing; the heading leads straight into the subsections (-5)
  • S2 · shrink · docs/source/oclmap/matching-algorithms.md:76 · "Two rules limit the combinations:" and its two bullets → one sentence: OCL Search and OCL Semantic can't be selected together, and OCL Semantic needs a target repository version with semantic search (-2)
  • S3 · delete · docs/source/oclmap/matching-algorithms.md:44 · ", and the OCL AI Assistant gets them as context", repeated in the AI Assistant section → nothing (0)
  • S4 · delete · docs/source/oclmap/matching-algorithms.md:74 · "Each one runs on every row, and their candidates are merged into one list per row.", the page's third statement of retrieve-and-merge → nothing (0)
  • S5 · delete · docs/source/oclmap/matching-algorithms.md:121 · "with its assessment, its primary candidate, the alternates and its reasoning" → nothing (0)
  • S6 · shrink · docs/source/oclmap/matching-algorithms.md:46 · "It finds candidates only through those mappings, so" → "Pick it when CIEL has mappings into your target repository; it isn't available for every target repository." (0)
  • S7 · delete · docs/source/oclmap/matching-algorithms.md:74 · the ScispaCy pairing in the "Several algorithms" example, repeated from the ScispaCy section → nothing (0)
findings.json
{"reviewer":"claude subagent","perspective":"simplify","mode":"full","commit":"9e3a29991410ce9ac0600ce9e1e34cfbb14d9dd5","verdict":"findings","prior":[],"findings":[{"id":"S1","severity":null,"tag":"native","file":"docs/source/oclmap/matching-algorithms.md","line":15,"claim":"The five-item list under '## The algorithms' (lines 15-19) repeats the opening sentence of each H3 that follows it. Line 19 ('calls a matching service you run') reappears verbatim at line 58, line 16 ('search by meaning') at line 34 and line 17 at line 42. sphinx_rtd_theme's sidebar already lists the five algorithms as links to those H3s: the built page has toctree-l3 entries for each. The page already opens with one summary, the five-step list at lines 5-11, so this is a second.","scenario":null,"action":"Nothing replaces it: '## The algorithms' leads straight into '### OCL Search Algorithm', and the rtd sidebar serves as the index. Optionally keep one lead-in such as 'The Mapper offers five algorithms.' (then -4).","lines_delta":-5,"confidence":"medium"},{"id":"S2","severity":null,"tag":"shrink","file":"docs/source/oclmap/matching-algorithms.md","line":76,"claim":"'Two rules limit the combinations:' and its two bullets (lines 76-79) spend three lines on one rule. The second bullet says 'as described above' and restates line 36. 'Once you select one, the other can't be selected.' restates 'exclude each other'.","scenario":null,"action":"Replace lines 76-79 with one paragraph that keeps both AC2 points in this section: '**OCL Search and OCL Semantic can't be selected together**, and OCL Semantic needs a target repository version with semantic search.' Line 36 keeps the detail.","lines_delta":-2,"confidence":"high"},{"id":"S3","severity":null,"tag":"delete","file":"docs/source/oclmap/matching-algorithms.md","line":44,"claim":"', and the OCL AI Assistant gets them as context' at the end of line 44 repeats the last sentence of line 114, the pass-1 correction saying the CIEL concepts go to the assistant 'as context only'. About 9 words; no line change.","scenario":null,"action":"Nothing replaces it: end line 44 at 'They appear when you group candidates by algorithm.' Line 114, in the AI Assistant section where AC4 readers look, keeps the fact.","lines_delta":0,"confidence":"high"},{"id":"S4","severity":null,"tag":"delete","file":"docs/source/oclmap/matching-algorithms.md","line":74,"claim":"'Each one runs on every row, and their candidates are merged into one list per row.' is the page's third statement of retrieve-and-merge, after steps 1 and 2 (lines 7-8) and the merge section (line 83), which is the AC2 explanation and stays. About 16 words; no line change.","scenario":null,"action":"Nothing replaces it: the paragraph reads '**Several algorithms** widen the net. You can select up to five. Add a second algorithm when one method alone misses matches, ...'.","lines_delta":0,"confidence":"medium"},{"id":"S5","severity":null,"tag":"delete","file":"docs/source/oclmap/matching-algorithms.md","line":121,"claim":"'with its assessment, its primary candidate, the alternates and its reasoning' restates line 114, which already says the assistant recommends one candidate as the match and others as alternates, or none, and explains why. About 11 words; no line change.","scenario":null,"action":"Nothing replaces it: 'Its analysis appears in the candidate list, and you can group the candidates by **AI Analysis**.'","lines_delta":0,"confidence":"low"},{"id":"S6","severity":null,"tag":"shrink","file":"docs/source/oclmap/matching-algorithms.md","line":46,"claim":"'It finds candidates only through those mappings' restates line 42, which already says the search is 'limited to CIEL concepts that have mappings into your target repository' and 'follows those mappings'. About 7 words; no line change.","scenario":null,"action":"'Pick it when CIEL has mappings into your target repository; it isn't available for every target repository.' This keeps AC1's 'when to pick it'.","lines_delta":0,"confidence":"low"},{"id":"S7","severity":null,"tag":"delete","file":"docs/source/oclmap/matching-algorithms.md","line":74,"claim":"', or OCL Semantic Algorithm plus ScispaCy LOINC search for laboratory tests mapped to LOINC' repeats line 52's advice ('Pick it alongside OCL Search or OCL Semantic when you map laboratory test names to LOINC'). About 14 words; no line change.","scenario":null,"action":"Nothing replaces it: the example ends at 'for example OCL Semantic Algorithm plus Bridge terminology search.' Line 52 keeps the ScispaCy pairing.","lines_delta":0,"confidence":"low"}]}

…cation review cuts

Folds the two combination rules into one sentence, and drops repeated
statements: where the CIEL concepts go (the AI Assistant section keeps
it), how several algorithms run and merge (the merge section keeps it),
the ScispaCy pairing example (the ScispaCy section keeps it), and the
bridge's reason for not being available everywhere.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrxkQb6LXc868Qyp4BfEuZ
@paynejd

paynejd commented Oct 26, 2026

Copy link
Copy Markdown
Member Author

Response to the simplification review

  • S1 kept: readers arriving from the Mapper's "Learn more" link get the five algorithms at a glance. The sidebar entries that would replace the list start collapsed, and phones hide the sidebar.
  • S2 applied in cada220
  • S3 applied in cada220
  • S4 applied in cada220
  • S5 kept: the sentence names what the assistant's box in the candidate list shows (assessment, primary, alternates, reasoning), which isn't what the earlier sentence covers (how the assistant reaches its recommendation).
  • S6 applied in cada220
  • S7 applied in cada220

@paynejd paynejd left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Codex check of the cuts (commit cada220)

Clean. The cuts in 9e3a299..cada220 broke nothing.

findings.json
{
  "reviewer": "codex-cli 0.164.0",
  "perspective": "defects",
  "mode": "cuts",
  "commit": "cada2203d85ae9da98a7d9ba252b66d325fddbee",
  "verdict": "clean",
  "prior": [],
  "findings": []
}

paynejd and others added 2 commits October 26, 2026 16:46
…st, OCL Online last

The page now leads with what the open-source OCL Mapper and OCL API do:
OCL Search, OCL Semantic and Custom Match Algorithm, merging, the
unified score and the score thresholds. Bridge terminology search,
ScispaCy LOINC search and the OCL AI Assistant move to a closing
section, Available on OCL Online, which says they run on services OCL
hosts and that the account decides which can be used. The intro links
the $match reference as the specification of the request and response.
Model names are given as the OCL API's defaults.

The $match reference describes access neutrally (permission to use the
Mapper; per-user rate limits answered with 429) and is brought in line
with oclapi2: the bridge algorithm is reported as ocl-bridge and runs
whenever filter.target_repo isn't the repository searched, numCandidates
defaults to 500, and the reranker applies to any request with a row
name.

Custom Match Algorithm is documented as part of the open Mapper;
OpenConceptLab/ocl_issues#2966 makes every build offer it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ion names only what an account decides

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@paynejd paynejd left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Codex review, pass 3 (codex-cli 0.164.0, commit 16099c1)

Clean. F1.1 and F1.2 stay resolved. This pass covered the restructure in 16099c1: the open-source Mapper and OCL API first, then a closing section, Available on OCL Online, and the corrections to the $match reference.

findings.json
{
  "reviewer": "codex-cli 0.164.0",
  "perspective": "defects",
  "mode": "verify",
  "commit": "16099c1",
  "verdict": "clean",
  "prior": [
    {
      "id": "F1.1",
      "status": "resolved"
    },
    {
      "id": "F1.2",
      "status": "resolved"
    }
  ],
  "findings": []
}

@paynejd paynejd left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Codex check of commits 16099c1..d52e443

Clean. The trim of the OCL Online section's intro broke nothing.

findings.json
{
  "reviewer": "codex-cli 0.164.0",
  "perspective": "defects",
  "mode": "cuts",
  "commit": "d52e443",
  "verdict": "clean",
  "prior": [],
  "findings": []
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

origin/ai-generated Issue or PR created by an AI agent origin/session-worker Opened by the Octoad session worker; a run record backs it

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Write the Matching Algorithms page in OCL Docs

1 participant