@instruments/taxonomy 1.1.6 → 1.2.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.
- package/dist/assertions.d.ts +70 -0
- package/dist/authoring.d.ts +33 -0
- package/dist/axes/construction.d.ts +3 -0
- package/dist/axes/element-fabric.d.ts +2 -0
- package/dist/axes/element-fitout.d.ts +2 -0
- package/dist/axes/element-shared.d.ts +13 -0
- package/dist/axes/element.d.ts +2 -0
- package/dist/axes/finish.d.ts +9 -0
- package/dist/axes/format.d.ts +3 -0
- package/dist/axes/index.d.ts +62 -0
- package/dist/axes/installation-layout.d.ts +3 -0
- package/dist/axes/material.d.ts +3 -0
- package/dist/axes/mood-anchors.d.ts +4 -0
- package/dist/axes/mood.d.ts +2 -0
- package/dist/axes/palette.d.ts +7 -0
- package/dist/axes/pattern.d.ts +13 -0
- package/dist/axes/period-anchors.d.ts +4 -0
- package/dist/axes/period.d.ts +29 -0
- package/dist/axes/place-anchors.d.ts +4 -0
- package/dist/axes/place.d.ts +5 -0
- package/dist/axes/product-category.d.ts +3 -0
- package/dist/axes/requirement.d.ts +3 -0
- package/dist/axes/space/arrival.d.ts +2 -0
- package/dist/axes/space/circulation.d.ts +2 -0
- package/dist/axes/space/civic.d.ts +2 -0
- package/dist/axes/space/culture.d.ts +2 -0
- package/dist/axes/space/dining.d.ts +2 -0
- package/dist/axes/space/domestic.d.ts +2 -0
- package/dist/axes/space/fitness.d.ts +2 -0
- package/dist/axes/space/gathering.d.ts +2 -0
- package/dist/axes/space/healthcare.d.ts +2 -0
- package/dist/axes/space/learning.d.ts +2 -0
- package/dist/axes/space/market-neutral.d.ts +1 -0
- package/dist/axes/space/other.d.ts +2 -0
- package/dist/axes/space/outdoor.d.ts +2 -0
- package/dist/axes/space/retail.d.ts +2 -0
- package/dist/axes/space/sanitary.d.ts +2 -0
- package/dist/axes/space/service.d.ts +2 -0
- package/dist/axes/space/shared.d.ts +30 -0
- package/dist/axes/space/sleeping.d.ts +2 -0
- package/dist/axes/space/working.d.ts +2 -0
- package/dist/axes/space-anchors/arrival.d.ts +3 -0
- package/dist/axes/space-anchors/circulation.d.ts +3 -0
- package/dist/axes/space-anchors/civic.d.ts +3 -0
- package/dist/axes/space-anchors/culture.d.ts +3 -0
- package/dist/axes/space-anchors/dining.d.ts +3 -0
- package/dist/axes/space-anchors/domestic.d.ts +3 -0
- package/dist/axes/space-anchors/fitness.d.ts +3 -0
- package/dist/axes/space-anchors/gathering.d.ts +3 -0
- package/dist/axes/space-anchors/healthcare.d.ts +3 -0
- package/dist/axes/space-anchors/learning.d.ts +3 -0
- package/dist/axes/space-anchors/other.d.ts +3 -0
- package/dist/axes/space-anchors/outdoor.d.ts +3 -0
- package/dist/axes/space-anchors/retail.d.ts +3 -0
- package/dist/axes/space-anchors/sanitary.d.ts +3 -0
- package/dist/axes/space-anchors/service.d.ts +3 -0
- package/dist/axes/space-anchors/sleeping.d.ts +3 -0
- package/dist/axes/space-anchors/working.d.ts +3 -0
- package/dist/axes/space-anchors.d.ts +8 -0
- package/dist/axes/space.d.ts +61 -0
- package/dist/axes/style-anchors.d.ts +7 -0
- package/dist/axes/style.d.ts +2 -0
- package/dist/axes/tier.d.ts +42 -0
- package/dist/axes/typology.d.ts +2 -0
- package/dist/axes/unit-shape.d.ts +3 -0
- package/dist/canonicalisation.d.ts +44 -0
- package/dist/crosswalks/designshop.d.ts +30 -0
- package/dist/crosswalks/mapping.d.ts +29 -0
- package/dist/crosswalks/materialgraph.d.ts +38 -0
- package/dist/crosswalks/miu.d.ts +13 -0
- package/dist/crosswalks/strength.d.ts +19 -0
- package/dist/dictionaries.d.ts +4 -0
- package/dist/downstream-check-policy.d.ts +34 -0
- package/dist/env.d.ts +6 -0
- package/dist/estate/concepts.d.ts +116 -0
- package/dist/estate/decomposition.d.ts +40 -0
- package/dist/estate/index.d.ts +4 -0
- package/dist/estate/residue-report.d.ts +45 -0
- package/dist/estate/rows/architizer.d.ts +2 -0
- package/dist/estate/rows/designround.d.ts +2 -0
- package/dist/estate/rows/designshop.d.ts +2 -0
- package/dist/estate/rows/index.d.ts +2 -0
- package/dist/estate/rows/materia.d.ts +2 -0
- package/dist/estate/rows/materialgraph.d.ts +2 -0
- package/dist/estate/rows/samplize.d.ts +2 -0
- package/dist/estate/sources.d.ts +47 -0
- package/dist/index.d.ts +5 -339
- package/dist/index.js +52 -1
- package/dist/match.d.ts +107 -0
- package/dist/materialgraph-crossover-sources.d.ts +52 -0
- package/dist/search-corpus-source.d.ts +8 -0
- package/dist/taste-assertion.d.ts +112 -0
- package/dist/taste.d.ts +2 -0
- package/dist/term.d.ts +346 -0
- package/dist/v1.d.ts +141 -0
- package/package.json +13 -13
|
@@ -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 materialgraph'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
|
+
* materialsinuse'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: materialgraph 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,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,30 @@
|
|
|
1
|
+
import type { CanonicalisationInput, CanonicalisationVerdict } from "../canonicalisation.js";
|
|
2
|
+
import type { CrosswalkMapping } from "./mapping.js";
|
|
3
|
+
export declare const DESIGNSHOP_CROSSWALK_VERSION: "designshop-2026-08-31.1";
|
|
4
|
+
export declare const DESIGNSHOP_SOURCE_SYSTEM: "designshop";
|
|
5
|
+
export declare const DESIGNSHOP_SOURCE_FIELDS: readonly ["product_category", "material", "pattern", "finish", "format", "construction", "scheme_style", "product_style", "mood", "space", "requirement"];
|
|
6
|
+
export type DesignShopSourceField = (typeof DESIGNSHOP_SOURCE_FIELDS)[number];
|
|
7
|
+
type Mapping = CrosswalkMapping;
|
|
8
|
+
/**
|
|
9
|
+
* Source-specific rows. Source fields are deliberately retained: DesignShop's `material:Mosaic`
|
|
10
|
+
* resolves to a format, and pretending the source field was already canonical would preserve its
|
|
11
|
+
* category error instead of its evidence.
|
|
12
|
+
*/
|
|
13
|
+
export declare const DESIGNSHOP_CROSSWALK: Readonly<Record<DesignShopSourceField, Readonly<Record<string, Mapping>>>>;
|
|
14
|
+
export interface DesignShopCanonicalisationInput extends Omit<CanonicalisationInput, "sourceSystem" | "sourceField"> {
|
|
15
|
+
sourceField: DesignShopSourceField;
|
|
16
|
+
}
|
|
17
|
+
/** Unknown values are unresolved, never declined. Declines require an explicit curated row. */
|
|
18
|
+
export declare const canonicaliseDesignShop: (input: DesignShopCanonicalisationInput) => CanonicalisationVerdict;
|
|
19
|
+
export interface DesignShopAppearanceTestVector {
|
|
20
|
+
expectedAssertions: readonly string[];
|
|
21
|
+
facets: readonly {
|
|
22
|
+
sourceField: DesignShopSourceField;
|
|
23
|
+
sourceValue: string;
|
|
24
|
+
}[];
|
|
25
|
+
id: string;
|
|
26
|
+
market: "residential" | "commercial";
|
|
27
|
+
}
|
|
28
|
+
/** Shared fixtures prove axes compose instead of welding material identity to appearance. */
|
|
29
|
+
export declare const DESIGNSHOP_APPEARANCE_TEST_VECTORS: readonly DesignShopAppearanceTestVector[];
|
|
30
|
+
export {};
|
|
@@ -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,38 @@
|
|
|
1
|
+
import type { CanonicalisationInput, CanonicalisationVerdict } from "../canonicalisation.js";
|
|
2
|
+
import type { BundleRole } from "../match.js";
|
|
3
|
+
import type { CrosswalkMapping } from "./mapping.js";
|
|
4
|
+
export declare const MATERIALGRAPH_CROSSWALK_VERSION: "materialgraph-2026-08-27.1";
|
|
5
|
+
export declare const MATERIALGRAPH_SOURCE_SYSTEM: "materialgraph";
|
|
6
|
+
export declare const MATERIALGRAPH_SNAPSHOT: "2026-08-27";
|
|
7
|
+
/**
|
|
8
|
+
* The two dictionaries this crosswalk covers. Both were `ms_`-prefixed until MaterialGraph renamed
|
|
9
|
+
* them on 2026-08-27; the bare names are the current ones.
|
|
10
|
+
*/
|
|
11
|
+
export declare const MATERIALGRAPH_SOURCE_FIELDS: readonly ["role", "character"];
|
|
12
|
+
export type MaterialGraphSourceField = (typeof MATERIALGRAPH_SOURCE_FIELDS)[number];
|
|
13
|
+
/**
|
|
14
|
+
* Two `role` values that are not product properties at all, and where they actually go.
|
|
15
|
+
*
|
|
16
|
+
* A role IN A SCHEME is what `match.ts` already calls a `BundleRole`: `accent` means present and
|
|
17
|
+
* deliberate but the scheme survives without it, `constitutive` means remove it and the thing stops
|
|
18
|
+
* being what it is. A feature surface is the second by definition. Publishing these as a mapping to
|
|
19
|
+
* the bundle role rather than as terms is what stops the same slab being permanently labelled a
|
|
20
|
+
* feature surface because one scheme once used it as one.
|
|
21
|
+
*/
|
|
22
|
+
export declare const MATERIALGRAPH_COMPOSITIONAL_ROLES: Readonly<Record<string, BundleRole>>;
|
|
23
|
+
export declare const MATERIALGRAPH_CROSSWALK: Readonly<Record<MaterialGraphSourceField, Readonly<Record<string, CrosswalkMapping>>>>;
|
|
24
|
+
export interface MaterialGraphCanonicalisationInput extends Omit<CanonicalisationInput, "sourceSystem" | "sourceField"> {
|
|
25
|
+
sourceField: MaterialGraphSourceField;
|
|
26
|
+
}
|
|
27
|
+
/** Unknown values are unresolved, never declined. Declines require an explicit curated row. */
|
|
28
|
+
export declare const canonicaliseMaterialGraph: (input: MaterialGraphCanonicalisationInput) => CanonicalisationVerdict;
|
|
29
|
+
/**
|
|
30
|
+
* The upstream dictionaries, vendored as id tuples so this file can be checked against them.
|
|
31
|
+
*
|
|
32
|
+
* Verbatim from materialgraph packages/schema/src/registry/value-dictionaries — `role` in
|
|
33
|
+
* `material-semantics-core.ts`, `character` in `material-semantics-aesthetics.ts`, both at the
|
|
34
|
+
* 2026-08-27 snapshot, after the rename that dropped their `ms_` prefixes.
|
|
35
|
+
*/
|
|
36
|
+
export declare const MATERIALGRAPH_ROLE_VALUES: readonly ["wall_finish", "flooring", "ceiling", "joinery", "upholstery", "drapery", "accent", "worksurface", "casegoods", "feature_surface", "trim", "other"];
|
|
37
|
+
export declare const MATERIALGRAPH_CHARACTER_VALUES: readonly ["quiet", "expressive", "restrained", "bold", "rustic", "crafted", "refined", "formal", "casual", "natural_reading", "synthetic_reading", "soft_reading", "hard_reading"];
|
|
38
|
+
export declare const MATERIALGRAPH_SOURCE_VALUES: Readonly<Record<MaterialGraphSourceField, readonly string[]>>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Application, MaterialFamily, Sector } from "../authoring.js";
|
|
2
|
+
export declare const MIU_MATERIAL_FAMILIES: readonly ["wood", "wood_veneer", "engineered_wood", "bamboo", "cork", "natural_stone", "terrazzo", "ceramic_porcelain", "glass", "metal", "concrete", "plaster", "clay", "brick", "paint_coating", "wallcovering", "laminate", "solid_surface", "mineral_composite", "resin", "linoleum", "vinyl", "rubber", "carpet", "rug", "textile", "leather", "acoustic_felt", "acoustic_composite", "recycled_composite", "paper_cardboard", "biobased_composite", "greenery_planting", "lighting", "hardware", "digital_media", "water_feature", "mixed_material", "color_palette_only", "unknown"];
|
|
3
|
+
export type MiuMaterialFamily = (typeof MIU_MATERIAL_FAMILIES)[number];
|
|
4
|
+
export declare const MIU_FAMILY_TO_CANONICAL: Readonly<Record<MiuMaterialFamily, MaterialFamily | null>>;
|
|
5
|
+
export declare const MIU_PROJECT_SECTORS: readonly ["hospitality", "food_and_beverage", "workplace", "residential", "multifamily", "retail_and_showroom", "healthcare", "wellness", "education", "civic", "cultural", "community", "sports_recreation", "entertainment", "industrial", "logistics", "maker", "transportation", "landscape_public_realm", "mixed_use", "master_planning", "temporary_exhibition", "religious", "senior_living", "student_housing", "unknown"];
|
|
6
|
+
export type MiuProjectSector = (typeof MIU_PROJECT_SECTORS)[number];
|
|
7
|
+
export declare const MIU_SECTOR_TO_CANONICAL: Readonly<Record<MiuProjectSector, Sector | null>>;
|
|
8
|
+
export declare const MIU_SURFACE_APPLICATIONS: readonly ["flooring", "floor_inlay", "stair_tread", "stair_riser", "wall_finish", "wall_panel", "wainscot", "baseboard", "trim", "ceiling_finish", "ceiling_cloud", "column_wrap", "door_finish", "frame_finish", "shower_wall", "shower_floor", "backsplash", "vanity_top", "toilet_partition", "commercial_kitchen_floor", "kitchen_wall", "food_service_counter", "laundry_floor", "pool_deck_surface", "reception_desk", "bar_front", "bar_top", "back_bar", "banquette_base", "cabinet_front", "shelving", "display_fixture", "closet_system", "workstation_casework", "checkout_counter", "upholstery", "loose_furniture", "built_in_seating", "banquette_upholstery", "drapery", "window_treatment", "rug", "carpet_tile", "bedding", "privacy_curtain", "acoustic_fabric_panel", "lighting_fixture", "acoustic_treatment", "partition", "operable_wall", "signage", "wayfinding", "hardware", "plumbing_fixture", "decorative_screen", "art_installation", "green_wall", "facade_cladding", "soffit", "exterior_screen", "paving", "decking", "outdoor_furniture", "planter", "pool_coping", "shade_structure", "railing", "fence_screen", "unknown"];
|
|
9
|
+
export type MiuSurfaceApplication = (typeof MIU_SURFACE_APPLICATIONS)[number];
|
|
10
|
+
export declare const MIU_SURFACE_APPLICATION_TO_CANONICAL: Readonly<Record<MiuSurfaceApplication, Application | null>>;
|
|
11
|
+
export declare const miuFamilyToCanonical: (value: string) => MaterialFamily | null;
|
|
12
|
+
export declare const miuSectorToCanonical: (value: string) => Sector | null;
|
|
13
|
+
export declare const miuSurfaceApplicationToCanonical: (value: string) => Application | null;
|
|
@@ -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,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a cross-repository check may skip, or must fail for want of its subject.
|
|
3
|
+
*
|
|
4
|
+
* A check that no-ops when it cannot find what it inspects reads green forever, and this
|
|
5
|
+
* one has already rotted that way once: the materialgraph sync test asserted nothing for
|
|
6
|
+
* twelve days after a file split, unnoticed, because it only ran where a sibling checkout
|
|
7
|
+
* happened to exist and never in CI.
|
|
8
|
+
*
|
|
9
|
+
* Blanket-failing is not the fix either. CI legitimately has no sibling repo, so a hard
|
|
10
|
+
* requirement would break every run for a condition nobody can satisfy there.
|
|
11
|
+
*
|
|
12
|
+
* So the strictness is opt-in and explicit. By default an absent checkout skips, which is
|
|
13
|
+
* honest about what CI can see. A context that is *meant* to be able to run the check —
|
|
14
|
+
* a release gate, a verification pass, a developer who wants to know — sets the
|
|
15
|
+
* environment variable, and then a missing checkout is a failure rather than a shrug.
|
|
16
|
+
*/
|
|
17
|
+
export declare const REQUIRE_DOWNSTREAM_CHECK_ENV = "TAXONOMY_REQUIRE_DOWNSTREAM_CHECKS";
|
|
18
|
+
export type DownstreamCheckDecision = {
|
|
19
|
+
kind: "run";
|
|
20
|
+
} | {
|
|
21
|
+
kind: "skip";
|
|
22
|
+
reason: string;
|
|
23
|
+
} | {
|
|
24
|
+
kind: "fail";
|
|
25
|
+
reason: string;
|
|
26
|
+
};
|
|
27
|
+
export declare const decideDownstreamCheck: (input: {
|
|
28
|
+
/** Whether the thing being inspected is actually on disk. */
|
|
29
|
+
subjectPresent: boolean;
|
|
30
|
+
/** What is being looked for, named in the failure so it is actionable. */
|
|
31
|
+
subjectLabel: string;
|
|
32
|
+
/** The raw environment value; any non-empty value other than "0"/"false" means strict. */
|
|
33
|
+
requireFlag: string | undefined;
|
|
34
|
+
}) => DownstreamCheckDecision;
|
package/dist/env.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether cross-repository checks must fail rather than skip when their subject is
|
|
3
|
+
* missing. Undefined in almost every context, including CI — see
|
|
4
|
+
* `downstream-check-policy` for why that default is the honest one.
|
|
5
|
+
*/
|
|
6
|
+
export declare const readRequireDownstreamChecks: () => string | undefined;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { Row } from "./decomposition.js";
|
|
2
|
+
export declare const ESTATE_REPOS: readonly ["materia", "architizer", "designround", "designshop", "materialgraph", "samplize"];
|
|
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 samplize joined the
|
|
32
|
+
* census. Samplize's vocabulary is colour and nothing else, so it can never reach `style.rustic`
|
|
33
|
+
* and counting it against that row would report a disagreement where there is only a different
|
|
34
|
+
* 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: samplize's vocabulary is colour and nothing
|
|
68
|
+
* 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 the DesignShop corpus the two ambiguous style values account for, as a percentage.
|
|
104
|
+
*
|
|
105
|
+
* A SHARE AND NOT A COUNT, and the distinction is the whole reason this function exists rather than
|
|
106
|
+
* a consumer reading `DESIGNSHOP_SCHEME_STYLE_COUNTS` directly. The underlying figures are a third
|
|
107
|
+
* party's catalogue volumes and are not ours to publish. The claim anything downstream actually
|
|
108
|
+
* needs is that `Modern` and `Contemporary` sit at comparable volume and together account for a
|
|
109
|
+
* large slice of the corpus - which a percentage carries exactly as well and a count carries no
|
|
110
|
+
* better.
|
|
111
|
+
*
|
|
112
|
+
* Exported so no page has to hand-type the number. A figure typed by hand is a figure that drifts
|
|
113
|
+
* from its data, and one derived from counts nobody may publish is the same disclosure a layer
|
|
114
|
+
* down.
|
|
115
|
+
*/
|
|
116
|
+
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 { ARCHITIZER_STYLES, DESIGNROUND_STYLE_ANCHORS, DESIGNSHOP_PRODUCT_STYLES, DESIGNSHOP_SCHEME_STYLE_COUNTS, DESIGNSHOP_SCHEME_STYLES, ESTATE_VOCABULARIES, type EstateVocabulary, MATERIA_INTENT_KEYWORDS, MATERIA_SCENE_MOOD, MATERIALGRAPH_MS_CHARACTER, MATERIALGRAPH_MS_MOOD, MATERIALGRAPH_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 materialgraph, colorscope and architizer, or already
|
|
21
|
+
* published in this package. It is the floor the design would have reached with no new authoring
|
|
22
|
+
* 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,47 @@
|
|
|
1
|
+
export type VocabularyKind =
|
|
2
|
+
/** A closed enum a writer must choose from. */
|
|
3
|
+
"enum"
|
|
4
|
+
/** A keyword set matched against free text. */
|
|
5
|
+
| "keyword-set"
|
|
6
|
+
/** Free-text prose used as an embedding anchor; the label is a handle, not a value. */
|
|
7
|
+
| "embedding-anchor"
|
|
8
|
+
/** Uncontrolled free text captured from a third party's index. */
|
|
9
|
+
| "captured-free-text";
|
|
10
|
+
export interface EstateVocabulary {
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
repo: string;
|
|
14
|
+
file: string;
|
|
15
|
+
snapshot: string;
|
|
16
|
+
kind: VocabularyKind;
|
|
17
|
+
/** What question the vocabulary was built to answer, in the authors' own framing. */
|
|
18
|
+
purpose: string;
|
|
19
|
+
terms: readonly string[];
|
|
20
|
+
}
|
|
21
|
+
export declare const MATERIA_SCENE_MOOD: EstateVocabulary;
|
|
22
|
+
export declare const MATERIA_INTENT_KEYWORDS: EstateVocabulary;
|
|
23
|
+
export declare const ARCHITIZER_STYLES: EstateVocabulary;
|
|
24
|
+
export declare const DESIGNROUND_STYLE_ANCHORS: EstateVocabulary;
|
|
25
|
+
export declare const DESIGNSHOP_SCHEME_STYLES: EstateVocabulary;
|
|
26
|
+
/**
|
|
27
|
+
* Scheme counts over the 1,922 schemes carrying at least one product. Bands, not counts, are what
|
|
28
|
+
* gets published (see `Term.usage`); the raw figures live here because the decomposition test has
|
|
29
|
+
* to weight by usage and cannot do that from a band.
|
|
30
|
+
*/
|
|
31
|
+
export declare const DESIGNSHOP_SCHEME_STYLE_COUNTS: Readonly<Record<string, number>>;
|
|
32
|
+
export declare const DESIGNSHOP_PRODUCT_STYLES: EstateVocabulary;
|
|
33
|
+
export declare const MATERIALGRAPH_MS_STYLE: EstateVocabulary;
|
|
34
|
+
export declare const MATERIALGRAPH_MS_MOOD: EstateVocabulary;
|
|
35
|
+
export declare const MATERIALGRAPH_MS_CHARACTER: EstateVocabulary;
|
|
36
|
+
export declare const SAMPLIZE_COLOUR_COLLECTIONS: EstateVocabulary;
|
|
37
|
+
/**
|
|
38
|
+
* A standing fact, visible in this capture rather than asserted.
|
|
39
|
+
*
|
|
40
|
+
* SAMPLIZE IS A SAMPLING CHANNEL, NOT A PAINT BRAND. It prints peel-and-stick sheets of other
|
|
41
|
+
* manufacturers' colours and manufactures nothing. Its own product index groups by maker, and every
|
|
42
|
+
* maker is somebody else: the largest share of the catalogue sits in a `benjamin-moore` collection,
|
|
43
|
+
* then `sherwin-williams`, then `behr`. If a query ever returns Samplize as the maker of a colour,
|
|
44
|
+
* the query is wrong and this is the evidence.
|
|
45
|
+
*/
|
|
46
|
+
export declare const SAMPLIZE_MAKER_COLLECTIONS: readonly ["benjamin-moore", "sherwin-williams", "behr"];
|
|
47
|
+
export declare const ESTATE_VOCABULARIES: readonly EstateVocabulary[];
|