# Alignment and concept bridges Different editions, languages, and upstream sources describe the same ideas in different words. Alignment records those correspondences explicitly — without ever merging meanings by assumption. One revision in two languages is two editions with a declared correspondence, never one shared meaning. Confirmation marks in parentheses, such as (S) or (I), follow the [legend on the topic index](/corpus/#how-this-topic-marks-confidence). ## A worked mapping: the renamed holding link The lab tour renames the shared holding relation between two fixture states: `owns` in `labparcels.iface` at `0.1.0` becomes `holds` at `0.2.0`, with parameters, kind, key, and label unchanged. The compiler treats those as two different nodes — a relation pin is not executed, so no annotation carries the old identity across. Saying "holds continues owns" is therefore a human-authored mapping, and a useful one only spells out its direction, its preserved conditions, and its status: - **Direction.** Old revision to new revision: rows recorded under `owns` read as rows under `holds`. The reverse is not claimed — nothing promises the old consumers accept the new name. - **Preserved conditions.** Same parameter shapes (`Owner`, `Parcel`), same kind (`institutional`), same key (`parcel`), same label text. Any later change to one side reopens the mapping. - **Status.** `review` while a second author checks the claim, `accepted` once recorded, `revoked` if the meanings drift apart. Revocation deletes no rows; it withdraws the permission to read across. The report schema for the narrow profiles draws the decisive boundary for exactly this shape: a decision carries `interpretation_basis` `declared_mapping_assumption`, keeps `all_source_conditions_retained` true, and keeps `semantic_equivalence_proved` false — see the [report format](/protocols/schemas/concept-rule-alignment-report/). The mapping below follows that shape as a team-kept illustration **(T)**; no checkout command produces this report for the parcels fixtures, whose profiles cover other pairs of systems: ```json { "source": "labparcels.iface@0.1.0 owns", "target": "labparcels.iface@0.2.0 holds", "direction": "source_to_target_under_interpretation", "status": "accepted", "conditions": { "interpretation_basis": "declared_mapping_assumption", "all_source_conditions_retained": true, "semantic_equivalence_proved": false } } ``` Read the last line as the whole point: the record proves that a reviewed human said "these correspond under these conditions", never that the two nodes mean the same thing. ## The align declaration The grammar offers an edition-level correspondence block between two references, with a relation name, a free-text status, and a reviewer: ```text alignment_decl = "align", reference, "with", reference, "{", { alignment_item }, "}" ; alignment_item = "relation", qualified_name, ";" | "status", identifier, ";" | "reviewer", expression, ";" | metadata_item ; ``` The declaration is metadata only: it is stored on the document, never lowered into formulas or evidence. Status values are a per-package team convention, not a closed vocabulary. Four maturity facts, kept in sync with the vocabulary bridge notes: the declaration is supported grammar and compiles in real packages **(S)**; no structural query reads align rows back — the links question covers five other link kinds **(S)**; adoption is broad, with over two thousand blocks across dozens of source files observed in the corpus **(S)**; and the semantic effect is nil **(S)**. ## Manual alignment packages For dictionary-scale correspondence, the established pattern is an ordinary package that maps shared vocabularies to outside records, handwritten and reviewed like any other corpus content. The reference example, `arxo.jurisdiction_alignment`, maps the currency, geography, country, and courts dictionaries to their outside records. A generic composition mechanism was considered for this job and rejected in favor of explicit packages. This is a **team convention** (T). Shared dictionaries themselves (`vocab.geo` and its siblings) stay types-plus-constants packages with no rules and no sources, which is what makes them safe mapping endpoints. **(S)** ## The concept catalog The concept catalog is a derived full-text index over compiled packages and import snapshots. It answers "which packages talk about this idea" and never merges semantics: a catalog hit is a pointer for a human or a policy to follow up, not an identity claim. Observed tool surface: ```text $ python3 corpus/tools/concepts/catalog.py --help usage: catalog.py [-h] --db DB {build,search,show,candidates} ... Derived concept catalogue: pinned package/Import IR views, never a semantic merger. ``` Build the index from pinned inputs, then search, show, or list candidates from the database file. The catalog tool **requires a source checkout** (I): it lives in the repository, not in the public release. A worked route over the lab fixtures: an author needs a parcel concept for a new package and checks the catalog before minting one. The inputs are pinned in a manifest — two compiled dependency snapshots, nothing else: ```json fixture="catalog-mini/manifest.json" { "format": "arxo.concept-catalog.inputs/0.1", "packages": ["../parcels-fees/deps/*.lawir.json"], "imports": [] } ``` Build the index, then search for the idea: ```text $ python3 corpus/tools/concepts/catalog.py --db /tmp/lab-work/catalog-route.db build docs/corpus/lab/fixtures/catalog-mini/manifest.json {"concepts":13,"indexed":2,"removed":0,"reused":0,"sources":2} $ python3 corpus/tools/concepts/catalog.py --db /tmp/lab-work/catalog-route.db search parcel | python3 -c "import json,sys; [print(r['concept']['native_id'],'|',r['concept']['project']) for r in json.load(sys.stdin)]" urn:law:lab:parcels:iface#Parcel | labparcels.iface urn:law:lab:parcels:registry#Parcel | labparcels.registry urn:law:lab:parcels:registry#ParcelKind | labparcels.registry urn:law:lab:parcels:iface#Owner | labparcels.iface urn:law:lab:parcels:registry#registered | labparcels.registry urn:law:lab:parcels:iface#owns | labparcels.iface urn:law:lab:parcels:iface#ParcelKind | labparcels.iface urn:law:lab:parcels:registry#kind_of | labparcels.registry urn:law:lab:parcels:registry#transfer_request | labparcels.registry ``` Nine hits across two packages. Inspect the canonical-looking one: ```text $ python3 corpus/tools/concepts/catalog.py --db /tmp/lab-work/catalog-route.db show 'urn:law:lab:parcels:iface#Parcel' | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['name'],'|',d['family'],'|',d['native_id']); print('visibility:',d['raw']['visibility'],'| project:',d['project']); print('labels:',[l['text'] for l in d['labels']])" Parcel | type | urn:law:lab:parcels:iface#Parcel visibility: public | project: labparcels.iface labels: ['registered parcel'] ``` A public entity type with a matching label — a reuse candidate. Ask the catalog for correspondence candidates before deciding: ```text $ python3 corpus/tools/concepts/catalog.py --db /tmp/lab-work/catalog-route.db candidates 'urn:law:lab:parcels:iface#Parcel' | python3 -c "import json,sys; d=json.load(sys.stdin); print('automatic_acceptance:',d['automatic_acceptance'],'| scope:',d['scope']); [print(c['target']['native_id'],'|',c['status'],'| score',c['score'],'|',','.join(c['reasons']),'| failures:',','.join(c['checks']['failures']) or 'none') for c in d['candidates']]" | head -3; echo ... automatic_acceptance: False | scope: bounded identifier/label/signature retrieval; no equivalence proof urn:law:lab:parcels:iface#Owner | candidate | score 5 | lexical_overlap | failures: none urn:law:lab:parcels:registry#Parcel | incompatible | score 45 | lexical_overlap,same_label | failures: different_type_kind ... ``` Eight further rows follow, all `incompatible` (the full JSON also carries `pending: semantic_correspondence_requires_review` on every row). No automatic acceptance — and read the top-scoring row carefully: `registry#Parcel` is refused as a correspondence endpoint with `different_type_kind`, but that is a matcher limitation, not a verdict of different concepts. The matcher only compares declaration kinds (entity versus alias) and never follows the alias target; the compiled node itself says where it points: ```text $ python3 -c "import json; d=json.load(open('fixtures/parcels-fees/deps/labparcels.registry.lawir.json')); n=next(n for n in d['nodes'] if n.get('name')=='Parcel'); print(n['typeKind'], '->', n['target']['name'])" alias -> labparcels.iface#Parcel ``` `registry#Parcel` is a direct alias for the shared `iface::Parcel` — same concept, re-exported spelling. The reuse decision is the author's, and here it is to reuse: import `labparcels.iface` at its pinned version and reference its public `Parcel`, instead of minting a third parcel type. The catalog row stays a pointer; the decision lives in the new package's import pins. ## Narrow alignment profiles A few bespoke bridges map specific outside systems into corpus form. Each is a hand-registered module for one pair of systems — physics units against a public unit ontology, order theory against two proof assistants — plus a positive-rules helper. Observed modules: ```text $ ls corpus/tools/concepts/alignment_profiles/ __pycache__ isabelle_orders.py lean_orders.py lean_stacks.py physics.py positive_rules.py ``` Each profile ships its own policy and report formats, and the full-profile checks verify source links, replay, revocation, and impact. These are narrow experimental bridges, not a general mapping framework: adding a new pair means authoring a new module with its own policy. **Experimental** (X). ## What to read next - [LawQL reference](/lawql/) for the structural relations that alignment tooling queries. - [Schema catalog](/protocols/schemas/) for the alignment policy and report formats. - [MCP tools](/guide/mcp-tools/) for catalog-style discovery from clients.