@instruments/taxonomy 1.1.6 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/README.md +5 -5
  2. package/dist/assertions.d.ts +70 -0
  3. package/dist/authoring.d.ts +33 -0
  4. package/dist/axes/axis.d.ts +35 -0
  5. package/dist/axes/construction.d.ts +3 -0
  6. package/dist/axes/daylight.d.ts +7 -0
  7. package/dist/axes/element-fabric.d.ts +2 -0
  8. package/dist/axes/element-fitout.d.ts +2 -0
  9. package/dist/axes/element-shared.d.ts +13 -0
  10. package/dist/axes/element.d.ts +2 -0
  11. package/dist/axes/finish.d.ts +9 -0
  12. package/dist/axes/format.d.ts +3 -0
  13. package/dist/axes/index.d.ts +33 -0
  14. package/dist/axes/installation-layout.d.ts +3 -0
  15. package/dist/axes/material.d.ts +3 -0
  16. package/dist/axes/mood-anchors.d.ts +4 -0
  17. package/dist/axes/mood.d.ts +2 -0
  18. package/dist/axes/palette.d.ts +7 -0
  19. package/dist/axes/pattern.d.ts +13 -0
  20. package/dist/axes/period-anchors.d.ts +4 -0
  21. package/dist/axes/period.d.ts +29 -0
  22. package/dist/axes/place-anchors.d.ts +4 -0
  23. package/dist/axes/place.d.ts +5 -0
  24. package/dist/axes/product-category.d.ts +3 -0
  25. package/dist/axes/requirement.d.ts +3 -0
  26. package/dist/axes/season.d.ts +2 -0
  27. package/dist/axes/space/arrival.d.ts +2 -0
  28. package/dist/axes/space/circulation.d.ts +2 -0
  29. package/dist/axes/space/civic.d.ts +2 -0
  30. package/dist/axes/space/culture.d.ts +2 -0
  31. package/dist/axes/space/dining.d.ts +2 -0
  32. package/dist/axes/space/domestic.d.ts +2 -0
  33. package/dist/axes/space/fitness.d.ts +2 -0
  34. package/dist/axes/space/gathering.d.ts +2 -0
  35. package/dist/axes/space/healthcare.d.ts +2 -0
  36. package/dist/axes/space/learning.d.ts +2 -0
  37. package/dist/axes/space/market-neutral.d.ts +1 -0
  38. package/dist/axes/space/other.d.ts +2 -0
  39. package/dist/axes/space/outdoor.d.ts +2 -0
  40. package/dist/axes/space/retail.d.ts +2 -0
  41. package/dist/axes/space/sanitary.d.ts +2 -0
  42. package/dist/axes/space/service.d.ts +2 -0
  43. package/dist/axes/space/shared.d.ts +30 -0
  44. package/dist/axes/space/sleeping.d.ts +2 -0
  45. package/dist/axes/space/working.d.ts +2 -0
  46. package/dist/axes/space-anchors/arrival.d.ts +3 -0
  47. package/dist/axes/space-anchors/circulation.d.ts +3 -0
  48. package/dist/axes/space-anchors/civic.d.ts +3 -0
  49. package/dist/axes/space-anchors/culture.d.ts +3 -0
  50. package/dist/axes/space-anchors/dining.d.ts +3 -0
  51. package/dist/axes/space-anchors/domestic.d.ts +3 -0
  52. package/dist/axes/space-anchors/fitness.d.ts +3 -0
  53. package/dist/axes/space-anchors/gathering.d.ts +3 -0
  54. package/dist/axes/space-anchors/healthcare.d.ts +3 -0
  55. package/dist/axes/space-anchors/learning.d.ts +3 -0
  56. package/dist/axes/space-anchors/other.d.ts +3 -0
  57. package/dist/axes/space-anchors/outdoor.d.ts +3 -0
  58. package/dist/axes/space-anchors/retail.d.ts +3 -0
  59. package/dist/axes/space-anchors/sanitary.d.ts +3 -0
  60. package/dist/axes/space-anchors/service.d.ts +3 -0
  61. package/dist/axes/space-anchors/sleeping.d.ts +3 -0
  62. package/dist/axes/space-anchors/working.d.ts +3 -0
  63. package/dist/axes/space-anchors.d.ts +8 -0
  64. package/dist/axes/space.d.ts +61 -0
  65. package/dist/axes/style-anchors.d.ts +7 -0
  66. package/dist/axes/style.d.ts +2 -0
  67. package/dist/axes/tier.d.ts +42 -0
  68. package/dist/axes/typology.d.ts +2 -0
  69. package/dist/axes/unit-shape.d.ts +3 -0
  70. package/dist/canonicalisation.d.ts +44 -0
  71. package/dist/crossover-sources.d.ts +52 -0
  72. package/dist/crosswalks/mapping.d.ts +29 -0
  73. package/dist/crosswalks/strength.d.ts +19 -0
  74. package/dist/dictionaries.d.ts +4 -0
  75. package/dist/estate/concepts.d.ts +117 -0
  76. package/dist/estate/decomposition.d.ts +40 -0
  77. package/dist/estate/index.d.ts +4 -0
  78. package/dist/estate/residue-report.d.ts +45 -0
  79. package/dist/estate/rows/architecture-projects.d.ts +2 -0
  80. package/dist/estate/rows/editorial-imagery.d.ts +2 -0
  81. package/dist/estate/rows/furnishings-retailer.d.ts +2 -0
  82. package/dist/estate/rows/index.d.ts +2 -0
  83. package/dist/estate/rows/materials-retrieval.d.ts +2 -0
  84. package/dist/estate/rows/paint-samples.d.ts +2 -0
  85. package/dist/estate/rows/rendering-pipeline.d.ts +2 -0
  86. package/dist/estate/sources.d.ts +106 -0
  87. package/dist/index.d.ts +5 -339
  88. package/dist/index.js +902 -670
  89. package/dist/match.d.ts +107 -0
  90. package/dist/search-corpus-source.d.ts +6 -0
  91. package/dist/taste-assertion.d.ts +112 -0
  92. package/dist/taste.d.ts +2 -0
  93. package/dist/term.d.ts +352 -0
  94. package/dist/v1.d.ts +141 -0
  95. package/package.json +13 -13
@@ -0,0 +1,61 @@
1
+ import type { Sector } from "../authoring.js";
2
+ import type { Term } from "../term.js";
3
+ /**
4
+ * A sector of the SPACE axis: a group of rooms that answer the same programme question.
5
+ *
6
+ * NOT THE SECTOR AXIS, despite the shared word, and the collision is old rather than chosen:
7
+ * these are PROGRAMME groups (where you sleep, wash, eat), while `sector.*` is the market a
8
+ * project serves. The market claim lives on individual terms as `serves` edges - see
9
+ * `marketsServed` below and the register in `space/market-neutral.ts` - and this grouping makes
10
+ * no market claim at all: the "healthcare" file holds `clean_room`, which serves no single
11
+ * market, and the "domestic" file is a programme word, not `sector.residential`.
12
+ *
13
+ * NOT A FACET, and not part of a term's identifier. `space.scullery` is the id whatever sector the
14
+ * scullery is filed under, and re-filing a room must never move its URI. This is a browse
15
+ * structure, and it exists because 197 rooms sorted alphabetically put Operating Room next to
16
+ * Orangery - which is a list you can search and not a list you can read.
17
+ *
18
+ * NOR IS IT `broaderSlug`. A scullery is not a kind of "Dining", so an ISA edge would be false;
19
+ * ADR 0001's relation rule is explicit that subsumption means every instance of the narrower term
20
+ * is an instance of the broader one. Sector is a filing decision about the vocabulary, which is a
21
+ * different kind of claim from a fact about the world, and conflating the two is how hierarchies
22
+ * fill up with things that are not parents.
23
+ */
24
+ export interface SpaceSector {
25
+ slug: string;
26
+ /** The reader's word for the sector. */
27
+ label: string;
28
+ terms: readonly Term[];
29
+ }
30
+ /**
31
+ * The seventeen sectors, in the order a browse page should show them.
32
+ *
33
+ * Ordered by programme rather than alphabetically or by size: where you arrive, where you move,
34
+ * where you sleep, wash, eat, gather, and so on out to the specialised sectors and the unclassified
35
+ * tail. A reader looking for their own corner of the built environment finds it by walking through
36
+ * a building, which is the order this list is in.
37
+ *
38
+ * `SPACE_TERMS` is DERIVED from this, so the flat list and the grouped one cannot disagree. It was
39
+ * previously the other way round - seventeen spreads into one array, with the grouping expressed
40
+ * only by which file a term happened to sit in, where nothing outside the package could read it.
41
+ */
42
+ export declare const SPACE_SECTORS: readonly SpaceSector[];
43
+ export declare const SPACE_TERMS: readonly Term[];
44
+ /**
45
+ * The markets a space exists to serve, resolved through its ISA chain, or null where no market is
46
+ * part of the room's identity.
47
+ *
48
+ * THE ACCESSOR EXISTS SO THE INHERITANCE IS NOT REINVENTED. A `serves` edge restricts every
49
+ * descendant - each suite is a hotel room, so each suite serves hospitality - and a consumer
50
+ * reading raw edges would see `suite` carrying none and read it as unrestricted. The walk stops at
51
+ * the NEAREST edge-bearing ancestor, because a child's own edges are a narrower claim that
52
+ * replaces the inherited one rather than adding to it (`training_room` serves workplace inside a
53
+ * neutral `classroom`).
54
+ *
55
+ * Null is a reviewed claim, not a gap: the term serves whatever market its project serves. The
56
+ * register in `space/market-neutral.ts` is what makes that true, and the disposition test in
57
+ * `axes.test.ts` is what keeps it true. Answering "what belongs in a residential scheme" is
58
+ * therefore: every term whose result is null or includes "residential" - the neutral majority
59
+ * spans all sectors, and excluding it would fail closed.
60
+ */
61
+ export declare const marketsServed: (termSlug: string) => readonly Sector[] | null;
@@ -0,0 +1,7 @@
1
+ import { STYLE_TERMS } from "./style.js";
2
+ export type StyleSlug = (typeof STYLE_TERMS)[number]["slug"];
3
+ /** At least one anchor, so a key cannot be added and left empty. */
4
+ export type Anchors = readonly [string, ...string[]];
5
+ export declare const STYLE_ANCHORS: Readonly<Record<string, Anchors>>;
6
+ /** The anchors for a style term, or undefined when the id names no style. */
7
+ export declare const anchorsFor: (styleId: string) => Anchors | undefined;
@@ -0,0 +1,2 @@
1
+ import type { Term } from "../term.js";
2
+ export declare const STYLE_TERMS: readonly Term[];
@@ -0,0 +1,42 @@
1
+ import type { Term } from "../term.js";
2
+ /**
3
+ * The positioning ladder. Where a maker, a product line or a project sits in the market, as a
4
+ * judgement anyone in the trade would recognise.
5
+ *
6
+ * The five values a materials-retrieval system's brand extractor is instructed to choose between, minus
7
+ * `trade-only`, which is a channel and already has its own dictionary there. `evidenced` rather
8
+ * than `vendored`, because the list is not a dictionary anywhere upstream - it exists in a prompt
9
+ * string and a column comment, and writing it down as a vocabulary is the point of this facet.
10
+ *
11
+ * A project-materials database's budget bands are the same ladder under other names, so its `budget` and
12
+ * `mid_market` sit in `seenAs` on the rungs they mean rather than becoming extra terms.
13
+ *
14
+ * `seenAs` HERE CARRIES ONLY FORMS ACTUALLY FOUND UPSTREAM. The trade uses a dozen words for each
15
+ * of these rungs and it would be easy to list them, but `seenAs` is an evidence claim - it says a
16
+ * corpus was seen to use this word for this term - and filling it from plausibility would make the
17
+ * crosswalk unusable for the one job it has. Editorial synonyms go in `altLabels`, where they are
18
+ * a judgement rather than an observation.
19
+ */
20
+ export declare const TIER_MARKET_TERMS: readonly Term[];
21
+ /**
22
+ * Hospitality chain scale. The industry's own six-rung classification of a hotel's market segment.
23
+ *
24
+ * AUTHORED HERE, and the only facet on this axis with nothing upstream to reconcile against: a
25
+ * search of eight repositories for chain scale, star rating or hotel class returned zero hits.
26
+ * The rungs are the segmentation the sector actually uses in development briefs and performance
27
+ * reporting, so they are named as the trade names them rather than mapped onto the market ladder,
28
+ * which has four rungs and different boundaries.
29
+ */
30
+ export declare const TIER_CHAIN_SCALE_TERMS: readonly Term[];
31
+ export declare const TIER_PRICE_BAND_TERMS: readonly Term[];
32
+ export declare const TIER_FACETS: readonly ["market", "chain-scale", "price-band"];
33
+ export type TierFacet = (typeof TIER_FACETS)[number];
34
+ /**
35
+ * The next rung down on a term's own ladder, or undefined at the bottom.
36
+ *
37
+ * Exists because the question is asked: a materials-retrieval system ships a `cheaperTier()` that walks its price
38
+ * ladder to answer "show me this, but less expensive". Answering it here means one implementation
39
+ * of the step rather than one per consumer, and it refuses at the bottom rather than clamping,
40
+ * because a bottom rung with nothing below it is a real answer.
41
+ */
42
+ export declare const oneRungDown: (terms: readonly Term[], slug: string) => Term | undefined;
@@ -0,0 +1,2 @@
1
+ import type { Term } from "../term.js";
2
+ export declare const TYPOLOGY_TERMS: readonly Term[];
@@ -0,0 +1,3 @@
1
+ import type { Term } from "../term.js";
2
+ /** The visible outline of one discrete physical unit, independent of supply and arrangement. */
3
+ export declare const UNIT_SHAPE_TERMS: readonly Term[];
@@ -0,0 +1,44 @@
1
+ import type { CanonicalAlternatives, CanonicalBundle } from "./match.js";
2
+ import type { AssertionMeaning, AssertionProvenance } from "./taste-assertion.js";
3
+ import type { MatchStrength } from "./term.js";
4
+ export interface CanonicalisationInput {
5
+ sourceSystem: string;
6
+ sourceField: string;
7
+ sourceValue: string;
8
+ provenance: AssertionProvenance;
9
+ }
10
+ interface CanonicalisationBase extends CanonicalisationInput {
11
+ crosswalkVersion: string;
12
+ taxonomySnapshotVersion: string;
13
+ }
14
+ export interface ResolvedCanonicalisation extends CanonicalisationBase {
15
+ status: "resolved";
16
+ canonical: CanonicalBundle;
17
+ /**
18
+ * How strongly the canonical bundle stands for the source value, in SKOS's own vocabulary. A
19
+ * consumer may treat `exact` as an identity and must treat everything else as an approximation
20
+ * it has been told about. See `crosswalks/strength.ts` for the direction convention.
21
+ */
22
+ match: MatchStrength;
23
+ /** Why the row is not exact. Present whenever `match` is not `exact`. */
24
+ note?: string;
25
+ }
26
+ export interface AmbiguousCanonicalisation extends CanonicalisationBase {
27
+ status: "ambiguous";
28
+ alternatives: CanonicalAlternatives;
29
+ /** How strongly each alternative would stand for the source value, were it the right reading. */
30
+ match: MatchStrength;
31
+ note?: string;
32
+ }
33
+ export interface UnresolvedCanonicalisation extends CanonicalisationBase {
34
+ status: "unresolved";
35
+ }
36
+ export interface DeclinedCanonicalisation extends CanonicalisationBase {
37
+ status: "declined";
38
+ reason: string;
39
+ }
40
+ /** Four honest outcomes: absence of a mapping is never silently treated as a decline or a match. */
41
+ export type CanonicalisationVerdict = ResolvedCanonicalisation | AmbiguousCanonicalisation | UnresolvedCanonicalisation | DeclinedCanonicalisation;
42
+ /** Convert a usable verdict to assertion meaning; a declined value does not assert anything. */
43
+ export declare const assertionMeaningFrom: (verdict: CanonicalisationVerdict) => AssertionMeaning | null;
44
+ export {};
@@ -0,0 +1,52 @@
1
+ export declare const RETRIEVAL_LEXICON_SOURCE = "colour-material lexicon in a materials-retrieval system (src-05)";
2
+ export declare const COLORSCOPE_CROSSOVER_SOURCE = "materialinstruments/colorscope@c0662caabe7cd8604241a8a7b2608fa5bc71de51:packages/core/data/reference/v1/taxonomy.json";
3
+ export declare const BRASS_MATERIAL_SOURCE = "https://archive.copper.org/applications/industrial/DesignGuide/terms.php";
4
+ export declare const BRASS_FINISH_SOURCE = "https://nickelinstitute.org/media/lxxh1zwr/2023-nickelplatinghandbooka5_printablepdf.pdf section 5";
5
+ export declare const NICKEL_MATERIAL_SOURCE = "https://nickelinstitute.org/en/nickel-applications/";
6
+ export declare const NICKEL_FINISH_SOURCE = "https://nickelinstitute.org/en/nickel-applications/plating";
7
+ export declare const CROSSOVER_DEFINITION_SOURCES: {
8
+ readonly alabaster: "https://webapps.bgs.ac.uk/memoirs/docs/B06070.html";
9
+ readonly brass: "https://archive.copper.org/applications/industrial/DesignGuide/terms.php; https://nickelinstitute.org/media/lxxh1zwr/2023-nickelplatinghandbooka5_printablepdf.pdf section 5";
10
+ readonly bronze: "https://archive.copper.org/applications/industrial/DesignGuide/terms.php; https://archive.copper.org/applications/architecture/arch_dhb/technical-discussion/copper_alloys/";
11
+ readonly cherry: "https://research.fs.usda.gov/download/treesearch/37440.pdf";
12
+ readonly chestnut: "https://research.fs.usda.gov/download/treesearch/37440.pdf";
13
+ readonly chrome: "ISO 1456:2009, https://www.iso.org/standard/50237.html; ISO 6158:2018, https://www.iso.org/standard/72269.html";
14
+ readonly clay: "https://pubs.usgs.gov/info/clays/";
15
+ readonly concrete: "https://www.concrete.org/frequentlyaskedquestions.aspx?faqid=640";
16
+ readonly copper: "https://archive.copper.org/applications/industrial/DesignGuide/selection/elect02.php";
17
+ readonly cork: "https://apcor.pt/en/what-it-is";
18
+ readonly cotton: "https://www.fao.org/docrep/pdf/012/i0987e/i0987e00.pdf";
19
+ readonly denim: "https://cottonworks.com/encyclopedia-item/denim/";
20
+ readonly ebony: "https://research.fs.usda.gov/download/treesearch/37440.pdf";
21
+ readonly gold: "https://www.usgs.gov/centers/national-minerals-information-center/gold-statistics-and-information";
22
+ readonly gunmetal: "https://live.copper.org/applications/marine/cuni/alloys/pub-206-copper-alloys-for-marine-environments.pdf";
23
+ readonly iron: "https://www.usgs.gov/centers/national-minerals-information-center/iron-and-steel-statistics-and-information";
24
+ readonly jade: "https://www.gia.edu/jade-description";
25
+ readonly jute: "https://www.fao.org/markets-and-trade/commodities-overview/fibres/jute-and-hard-fibres/";
26
+ readonly leather: "ISO 15115, https://www.iso.org/obp/ui?_escaped_fragment_=iso%3Astd%3Aiso%3A15115%3Aed-1%3Av1%3Aen";
27
+ readonly limestone: "https://pubs.usgs.gov/fs/2008/3089/";
28
+ readonly linen: "https://allianceflaxlinenhemp.eu/en/document_resources/35/download";
29
+ readonly mahogany: "https://research.fs.usda.gov/download/treesearch/37440.pdf";
30
+ readonly marble: "https://www.naturalstoneinstitute.org/designprofessionals/varieties/definition/; ASTM C503 via https://www.naturalstoneinstitute.org/stoneprofessionals/astm/";
31
+ readonly nickel: "https://nickelinstitute.org/en/nickel-applications/; https://nickelinstitute.org/en/nickel-applications/plating";
32
+ readonly oak: "https://research.fs.usda.gov/download/treesearch/37440.pdf";
33
+ readonly obsidian: "https://www.usgs.gov/glossary/volcano-hazards-program-glossary";
34
+ readonly onyx: "https://www.naturalstoneinstitute.org/consumers/varieties/marble/";
35
+ readonly pewter: "Getty AAT 300010979, https://www.getty.edu/vow/AATFullDisplay?find=&logic=AND&note=&page=1&subjectid=300010979";
36
+ readonly platinum: "https://www.usgs.gov/centers/national-minerals-information-center/platinum-group-metals-statistics-and-information";
37
+ readonly rosewood: "https://research.fs.usda.gov/download/treesearch/37440.pdf";
38
+ readonly silver: "https://silverinstitute.org/silver-element-essentials/";
39
+ readonly sisal: "https://www.fao.org/docrep/pdf/012/i0987e/i0987e00.pdf";
40
+ readonly slate: "ASTM C629 via https://www.naturalstoneinstitute.org/stoneprofessionals/astm/";
41
+ readonly steel: "https://worldsteel.org/about-steel/what-is-steel/";
42
+ readonly stone: "https://www.naturalstoneinstitute.org/about/sponsorship-and-advertising/sponsored-content-guidelines/";
43
+ readonly suede: "ISO 15115, https://www.iso.org/obp/ui?_escaped_fragment_=iso%3Astd%3Aiso%3A15115%3Aed-1%3Av1%3Aen";
44
+ readonly teak: "https://research.fs.usda.gov/download/treesearch/37440.pdf";
45
+ readonly terracotta: "Getty AAT 300047296, https://www.getty.edu/vow/AATFullDisplay?find=building&logic=AND&note=&subjectid=300047296";
46
+ readonly travertine: "https://www.naturalstoneinstitute.org/about/sponsorship-and-advertising/sponsored-content-guidelines/";
47
+ readonly walnut: "https://research.fs.usda.gov/treesearch/32210";
48
+ readonly wood: "https://research.fs.usda.gov/download/treesearch/37440.pdf";
49
+ readonly wool: "https://www.fao.org/docrep/pdf/012/i0987e/i0987e00.pdf";
50
+ };
51
+ export type CrossoverPhrase = keyof typeof CROSSOVER_DEFINITION_SOURCES;
52
+ export declare const crossoverSource: (phrase: CrossoverPhrase) => string;
@@ -0,0 +1,29 @@
1
+ import type { BundleMemberInput } from "../match.js";
2
+ import type { MatchStrength } from "../term.js";
3
+ export type CrosswalkMapping = {
4
+ status: "resolved";
5
+ assertions: readonly BundleMemberInput[];
6
+ match: MatchStrength;
7
+ note?: string;
8
+ } | {
9
+ status: "ambiguous";
10
+ alternatives: readonly (readonly BundleMemberInput[])[];
11
+ match: MatchStrength;
12
+ note?: string;
13
+ } | {
14
+ status: "declined";
15
+ reason: string;
16
+ };
17
+ /** A compound row: the source value is fully carried by the assertions together. */
18
+ export declare const resolved: (...assertions: readonly string[]) => CrosswalkMapping;
19
+ /** One canonical term, interchangeable with the source value in retrieval. */
20
+ export declare const constitutive: (assertion: string) => CrosswalkMapping;
21
+ /**
22
+ * A row that is not an identity. The strength says how it falls short and the note says why, both
23
+ * required: an approximation nobody had to justify is how a close match ships as an exact one.
24
+ */
25
+ export declare const approximates: (match: Exclude<MatchStrength, "exact">, note: string, ...assertions: readonly string[]) => CrosswalkMapping;
26
+ /** The source is known to mean one of these and never recorded which. `match` grades each reading. */
27
+ export declare const ambiguous: (match: MatchStrength, ...assertions: readonly string[]) => CrosswalkMapping;
28
+ /** A curated refusal. Distinct from an absent row, which means nobody has looked. */
29
+ export declare const declined: (reason: string) => CrosswalkMapping;
@@ -0,0 +1,19 @@
1
+ import type { MatchStrength } from "../term.js";
2
+ export type { MatchStrength } from "../term.js";
3
+ /**
4
+ * The SKOS property each strength renders to.
5
+ *
6
+ * `skos:relatedMatch`, not `skos:related`: the target sits in another scheme, and SKOS reserves the
7
+ * unqualified property for associations inside one scheme.
8
+ */
9
+ export declare const SKOS_MATCH_PREDICATE: Readonly<Record<MatchStrength, string>>;
10
+ /** The strengths, at runtime. TypeScript cannot enumerate a union, so this is by hand. */
11
+ export declare const MATCH_STRENGTHS: readonly ["broad", "close", "exact", "narrow", "related"];
12
+ type AssertNever<T extends never> = T;
13
+ /** Totality guard: a strength added to `term.ts` and not listed above becomes a compile error. */
14
+ export type UnlistedMatchStrength = AssertNever<Exclude<MatchStrength, (typeof MATCH_STRENGTHS)[number]>>;
15
+ /**
16
+ * True when the row asserts the two concepts are interchangeable. The only strength a consumer may
17
+ * treat as an identity; everything else is an approximation it has been told about.
18
+ */
19
+ export declare const isInterchangeable: (strength: MatchStrength) => boolean;
@@ -0,0 +1,4 @@
1
+ import type { Term } from "./term.js";
2
+ export declare const MATERIAL_FAMILY_TERMS: readonly Term[];
3
+ export declare const SECTOR_TERMS: readonly Term[];
4
+ export declare const APPLICATION_TERMS: readonly Term[];
@@ -0,0 +1,117 @@
1
+ import type { Row } from "./decomposition.js";
2
+ export declare const ESTATE_REPOS: readonly ["rendering-pipeline", "architecture-projects", "editorial-imagery", "furnishings-retailer", "materials-retrieval", "paint-samples"];
3
+ export type EstateRepo = (typeof ESTATE_REPOS)[number];
4
+ export interface ConceptCell {
5
+ source: string;
6
+ repo: EstateRepo;
7
+ /** The source's own spelling, verbatim. This is the thing the page exists to show. */
8
+ term: string;
9
+ row: Row;
10
+ }
11
+ /**
12
+ * Fold a source term to its word-form: case, separators and joining punctuation removed.
13
+ *
14
+ * `rustic`, `Rustic` and `RUSTIC` are one wording. `Rustic & Artisan` is a different one. This is
15
+ * the line between a spelling difference and a disagreement, and it needs drawing because a matrix
16
+ * of verbatim strings flatters the disagreement: three casings of one word LOOK like three
17
+ * vocabularies falling out, and they are one vocabulary written three ways.
18
+ */
19
+ export declare const wordForm: (term: string) => string;
20
+ export interface Concept {
21
+ /** The canonical head term, fully qualified. `evokes(...)` wrappers are stripped. */
22
+ canonical: string;
23
+ /** True when the canon reaches this concept by a relation rather than by assertion. */
24
+ viaEvokes: boolean;
25
+ /** Distinct repositories carrying a term that heads here. The row's sort key. */
26
+ reach: number;
27
+ /**
28
+ * How many repositories could plausibly have reached this concept: those carrying any vocabulary
29
+ * on the same axis.
30
+ *
31
+ * NOT the repository count, and the difference started mattering the moment the paint-sample
32
+ * retailer joined the census. Its vocabulary is colour and nothing else, so it can never reach
33
+ * `style.rustic` and counting it against that row would report a disagreement where there is only
34
+ * a different subject. Six repositories, but only five of them have anything to say about style, and only
35
+ * three about colour.
36
+ */
37
+ couldReach: number;
38
+ cells: readonly ConceptCell[];
39
+ /** Rows whose crosswalk declines, and rows carried as anchors. The page marks both. */
40
+ declines: number;
41
+ anchors: number;
42
+ /**
43
+ * How many distinct WORDINGS the sources use, after folding case and separators.
44
+ *
45
+ * The number that says whether a row is a real disagreement. `reach` of 5 with one wording means
46
+ * five repositories writing the same word five ways, which a crosswalk fixes trivially. `reach`
47
+ * of 5 with five wordings means five different ideas about what to call the thing, which it does
48
+ * not. Measured across the whole corpus, only one of the twenty shared concepts is spelling-only,
49
+ * so casing turns out to be a rounding error rather than the story - but a reader looking at
50
+ * `rustic / Rustic / Rustic & Artisan` cannot tell that without being told.
51
+ */
52
+ wordings: number;
53
+ }
54
+ export declare const concepts: () => readonly Concept[];
55
+ /** One axis's worth of the matrix: its concepts, and only the repositories that speak about it. */
56
+ export interface AxisDisagreement {
57
+ axis: string;
58
+ concepts: readonly Concept[];
59
+ repos: readonly EstateRepo[];
60
+ /** Concepts on this axis that more than one repository reaches. */
61
+ shared: number;
62
+ }
63
+ /**
64
+ * The disagreement matrix, split one table per axis.
65
+ *
66
+ * ONE TABLE MIXING AXES IS SPARSE BY CONSTRUCTION, and the sparseness is not a finding. Each
67
+ * repository speaks about some axes and not others: the paint-sample retailer's vocabulary is colour
68
+ * and nothing else, so against every style concept it is a column of dashes. Rendered as one table that reads
69
+ * as six repositories disagreeing when it is really six repositories talking about different
70
+ * subjects, and it costs enough width to break the canonical identifiers across three lines.
71
+ *
72
+ * Split by axis, every table is dense and each makes its own point. Style is the argument, at five
73
+ * repositories and twenty-three concepts. Place is the sharpest, because every repository reaches
74
+ * it and every concept on it is shared - which is the axis the design review said was the gap.
75
+ *
76
+ * An axis is only worth a table if more than one repository speaks about it and there is more than
77
+ * a handful to show; the rest are reported as a count rather than drawn.
78
+ */
79
+ export declare const disagreementsByAxis: ({ minConcepts, }?: {
80
+ minConcepts?: number;
81
+ }) => readonly AxisDisagreement[];
82
+ /** The dictionaries as columns, in the order the matrix renders them. */
83
+ export declare const MATRIX_COLUMNS: readonly {
84
+ id: string;
85
+ repo: EstateRepo;
86
+ label: string;
87
+ }[];
88
+ /** The headline the disagreement page opens with, computed rather than asserted. */
89
+ export declare const agreementSummary: () => {
90
+ concepts: number;
91
+ reachedByAll: number;
92
+ reachedByFourOrMore: number;
93
+ distinctSpellings: number;
94
+ exactStringMatchesAcrossRepos: number;
95
+ /** Concepts more than one repository reaches. */
96
+ shared: number;
97
+ /** Repositories in the census. Not every one speaks about every axis. */
98
+ repos: number;
99
+ /** Of those, the ones where every source uses the same word and differs only in spelling. */
100
+ spellingOnly: number;
101
+ };
102
+ /**
103
+ * The share of a furnishings retailer's room schemes the two ambiguous style values account for, as a
104
+ * percentage.
105
+ *
106
+ * A SHARE AND NOT A COUNT, and the distinction is the whole reason this function exists rather than
107
+ * a consumer reading `ROOM_SCHEME_STYLE_COUNTS` directly. The underlying figures are a third
108
+ * party's catalogue volumes and are not ours to publish. The claim anything downstream actually
109
+ * needs is that `Modern` and `Contemporary` sit at comparable volume and together account for a
110
+ * large slice of the corpus - which a percentage carries exactly as well and a count carries no
111
+ * better.
112
+ *
113
+ * Exported so no page has to hand-type the number. A figure typed by hand is a figure that drifts
114
+ * from its data, and one derived from counts nobody may publish is the same disclosure a layer
115
+ * down.
116
+ */
117
+ export declare const ambiguousStyleShare: () => number;
@@ -0,0 +1,40 @@
1
+ import type { CanonicalAlternatives } from "../match.js";
2
+ export type Verdict =
3
+ /** Maps faithfully onto one or more canonical terms. Nothing is lost. */
4
+ "decomposed"
5
+ /** Decomposes, but the compound carries meaning the parts do not. Needs an anchor as well. */
6
+ | "lossy"
7
+ /** The canon can express both readings; the source cannot be safely mapped to one. Declines. */
8
+ | "ambiguous"
9
+ /** A real term, but answering a question outside the interiors aesthetic axes. */
10
+ | "out-of-axis"
11
+ /** Resists decomposition. Must be carried as an anchor, not a concept. */
12
+ | "residue";
13
+ /** Why an `out-of-axis` term is out of axis. */
14
+ export type OutOfAxisReason =
15
+ /** Describes a material, not a room. Belongs on the material half of the canon. */
16
+ "material-property"
17
+ /** A query-router marker with no descriptive content at all. */
18
+ | "query-marker"
19
+ /** Answers an axis that already exists here (sector, space, typology). */
20
+ | "other-canonical-axis"
21
+ /** A real question no axis here answers yet, and the gap is declared rather than absorbed. */
22
+ | "axis-not-authored";
23
+ export interface Row {
24
+ /** The vocabulary id from `./sources.ts`. */
25
+ source: string;
26
+ /** The source term, verbatim. */
27
+ term: string;
28
+ verdict: Verdict;
29
+ /** Canonical targets asserted together. `evokes(...)` marks a relation rather than a term. */
30
+ onto: readonly string[];
31
+ /** Typed disjunction when the source is known to mean one of several bundles but cannot say which. */
32
+ alternatives?: CanonicalAlternatives;
33
+ /** Canonical terms that had to be minted on an EXISTING axis to hold this source term. */
34
+ mintedTerm?: readonly string[];
35
+ /** Canonical terms that only exist because a WHOLE AXIS had to be created. */
36
+ mintedAxis?: readonly string[];
37
+ reason?: OutOfAxisReason;
38
+ note?: string;
39
+ }
40
+ export { DECOMPOSITION } from "./rows/index.js";
@@ -0,0 +1,4 @@
1
+ export { agreementSummary, ambiguousStyleShare, concepts, type AxisDisagreement, disagreementsByAxis, type Concept, type ConceptCell, ESTATE_REPOS, type EstateRepo, MATRIX_COLUMNS, } from "./concepts.js";
2
+ export { DECOMPOSITION, type OutOfAxisReason, type Row, type Verdict, } from "./decomposition.js";
3
+ export { declaredGaps, mintingDemand, rateBySource, type ResidueReport, residueReport, unresolved, } from "./residue-report.js";
4
+ export { ARCHITECTURE_PROJECTS_STYLES, EDITORIAL_STYLE_ANCHORS, RETAIL_PRODUCT_STYLES, ROOM_SCHEME_STYLE_COUNTS, ROOM_SCHEME_STYLES, ESTATE_VOCABULARIES, type EstateVocabulary, RENDERING_INTENT_KEYWORDS, RENDERING_SCENE_MOOD, RETRIEVAL_MS_CHARACTER, RETRIEVAL_MS_MOOD, RETRIEVAL_MS_STYLE, type VocabularyKind, } from "./sources.js";
@@ -0,0 +1,45 @@
1
+ import type { Row } from "./decomposition.js";
2
+ export interface ResidueReport {
3
+ /** Every term across all seven estate vocabularies. */
4
+ total: number;
5
+ /** Terms that were never aesthetic vocabulary: query markers and material properties. */
6
+ excluded: number;
7
+ /** The denominator the headline is quoted against. */
8
+ aesthetic: number;
9
+ decomposed: number;
10
+ lossy: number;
11
+ ambiguous: number;
12
+ /** Terms that resist decomposition entirely and can only be carried as anchors. */
13
+ residue: number;
14
+ outOfAxis: number;
15
+ /** `decomposed` as a share of `aesthetic`. TAX-14's threshold was 80 per cent. */
16
+ cleanRate: number;
17
+ /**
18
+ * The circularity guard. The axes here were authored after reading these terms, so the headline
19
+ * rate is partly fitted to its own inputs. This is the share that decomposes onto canon that
20
+ * existed BEFORE the test - vendored from the materials-retrieval system, colorscope and the
21
+ * architecture-projects platform, or already published in this package. It is the floor the
22
+ * design would have reached with no new authoring at all, and it is the number to argue with.
23
+ */
24
+ preExistingRate: number;
25
+ preExisting: number;
26
+ /** Source terms that needed a term minted on an axis that already existed. */
27
+ neededMintedTerm: number;
28
+ /** Source terms that needed a whole axis that did not exist. */
29
+ neededMintedAxis: number;
30
+ }
31
+ export declare const residueReport: () => ResidueReport;
32
+ export declare const mintingDemand: () => {
33
+ onExistingAxes: readonly (readonly [string, number])[];
34
+ onNewAxes: readonly (readonly [string, number])[];
35
+ };
36
+ /** Per-source decomposition rate, over the aesthetic subset. */
37
+ export declare const rateBySource: () => readonly {
38
+ source: string;
39
+ decomposed: number;
40
+ terms: number;
41
+ }[];
42
+ /** Every row the canon could not take cleanly. The site publishes this list in full. */
43
+ export declare const unresolved: () => readonly Row[];
44
+ /** Real questions the estate asks that no axis here answers yet. Declared, never absorbed. */
45
+ export declare const declaredGaps: () => readonly Row[];
@@ -0,0 +1,2 @@
1
+ import type { Row } from "../decomposition.js";
2
+ export declare const ARCHITECTURE_PROJECTS_ROWS: readonly Row[];
@@ -0,0 +1,2 @@
1
+ import type { Row } from "../decomposition.js";
2
+ export declare const EDITORIAL_ROWS: readonly Row[];
@@ -0,0 +1,2 @@
1
+ import type { Row } from "../decomposition.js";
2
+ export declare const RETAILER_ROWS: readonly Row[];
@@ -0,0 +1,2 @@
1
+ import type { Row } from "../decomposition.js";
2
+ export declare const DECOMPOSITION: readonly Row[];
@@ -0,0 +1,2 @@
1
+ import type { Row } from "../decomposition.js";
2
+ export declare const RETRIEVAL_ROWS: readonly Row[];
@@ -0,0 +1,2 @@
1
+ import type { Row } from "../decomposition.js";
2
+ export declare const PAINT_SAMPLE_ROWS: readonly Row[];
@@ -0,0 +1,2 @@
1
+ import type { Row } from "../decomposition.js";
2
+ export declare const RENDERING_ROWS: readonly Row[];
@@ -0,0 +1,106 @@
1
+ export interface CitedSource {
2
+ /** Stable and opaque. Never reassigned, never a name, and never decoded here. */
3
+ id: string;
4
+ /** How the source is written in prose, article included. */
5
+ name: string;
6
+ /** The same source as one token: a column key, a repository key, a vocabulary id prefix. */
7
+ slug: string;
8
+ /** The same source as a column heading, without the article. */
9
+ label: string;
10
+ }
11
+ export declare const CITED_SOURCES: {
12
+ readonly ARCHITECTURE_PROJECTS: {
13
+ readonly id: "src-01";
14
+ readonly label: "architecture-projects platform";
15
+ readonly name: "an architecture-projects platform";
16
+ readonly slug: "architecture-projects";
17
+ };
18
+ readonly EDITORIAL_IMAGERY: {
19
+ readonly id: "src-02";
20
+ readonly label: "editorial image library";
21
+ readonly name: "an editorial image library";
22
+ readonly slug: "editorial-imagery";
23
+ };
24
+ readonly FURNISHINGS_RETAILER: {
25
+ readonly id: "src-03";
26
+ readonly label: "furnishings retailer";
27
+ readonly name: "a furnishings retailer";
28
+ readonly slug: "furnishings-retailer";
29
+ };
30
+ readonly MARKETPLACE_CATALOGUE: {
31
+ readonly id: "src-04";
32
+ readonly label: "materials-marketplace catalogue";
33
+ readonly name: "a materials-marketplace catalogue";
34
+ readonly slug: "materials-marketplace";
35
+ };
36
+ readonly MATERIALS_RETRIEVAL: {
37
+ readonly id: "src-05";
38
+ readonly label: "materials-retrieval system";
39
+ readonly name: "a materials-retrieval system";
40
+ readonly slug: "materials-retrieval";
41
+ };
42
+ readonly PAINT_SAMPLES: {
43
+ readonly id: "src-06";
44
+ readonly label: "paint-sample retailer";
45
+ readonly name: "a paint-sample retailer";
46
+ readonly slug: "paint-samples";
47
+ };
48
+ readonly PROJECT_MATERIALS: {
49
+ readonly id: "src-07";
50
+ readonly label: "project-materials database";
51
+ readonly name: "a project-materials database";
52
+ readonly slug: "project-materials";
53
+ };
54
+ readonly RENDERING_PIPELINE: {
55
+ readonly id: "src-08";
56
+ readonly label: "rendering pipeline";
57
+ readonly name: "a rendering pipeline";
58
+ readonly slug: "rendering-pipeline";
59
+ };
60
+ };
61
+ export type VocabularyKind =
62
+ /** A closed enum a writer must choose from. */
63
+ "enum"
64
+ /** A keyword set matched against free text. */
65
+ | "keyword-set"
66
+ /** Free-text prose used as an embedding anchor; the label is a handle, not a value. */
67
+ | "embedding-anchor"
68
+ /** Uncontrolled free text captured from a third party's index. */
69
+ | "captured-free-text";
70
+ export interface EstateVocabulary {
71
+ id: string;
72
+ name: string;
73
+ repo: string;
74
+ snapshot: string;
75
+ kind: VocabularyKind;
76
+ /** What question the vocabulary was built to answer, in the authors' own framing. */
77
+ purpose: string;
78
+ terms: readonly string[];
79
+ }
80
+ export declare const RENDERING_SCENE_MOOD: EstateVocabulary;
81
+ export declare const RENDERING_INTENT_KEYWORDS: EstateVocabulary;
82
+ export declare const ARCHITECTURE_PROJECTS_STYLES: EstateVocabulary;
83
+ export declare const EDITORIAL_STYLE_ANCHORS: EstateVocabulary;
84
+ export declare const ROOM_SCHEME_STYLES: EstateVocabulary;
85
+ /**
86
+ * Scheme counts over the 1,922 schemes carrying at least one product. Bands, not counts, are what
87
+ * gets published (see `Term.usage`); the raw figures live here because the decomposition test has
88
+ * to weight by usage and cannot do that from a band.
89
+ */
90
+ export declare const ROOM_SCHEME_STYLE_COUNTS: Readonly<Record<string, number>>;
91
+ export declare const RETAIL_PRODUCT_STYLES: EstateVocabulary;
92
+ export declare const RETRIEVAL_MS_STYLE: EstateVocabulary;
93
+ export declare const RETRIEVAL_MS_MOOD: EstateVocabulary;
94
+ export declare const RETRIEVAL_MS_CHARACTER: EstateVocabulary;
95
+ export declare const PAINT_SAMPLE_COLOUR_COLLECTIONS: EstateVocabulary;
96
+ /**
97
+ * A standing fact, visible in this capture rather than asserted.
98
+ *
99
+ * THE PAINT-SAMPLE RETAILER IS A SAMPLING CHANNEL, NOT A PAINT BRAND. It prints peel-and-stick
100
+ * sheets of other manufacturers' colours and manufactures nothing. Its own product index groups by
101
+ * maker, and every maker is somebody else: the largest share of the catalogue sits in a
102
+ * `benjamin-moore` collection, then `sherwin-williams`, then `behr`. If a query ever returns the
103
+ * retailer as the maker of a colour, the query is wrong and this is the evidence.
104
+ */
105
+ export declare const PAINT_SAMPLE_MAKER_COLLECTIONS: readonly ["benjamin-moore", "sherwin-williams", "behr"];
106
+ export declare const ESTATE_VOCABULARIES: readonly EstateVocabulary[];