Archetype conformance
Classify object lifecycles against six optional versioned archetypes without coupling Platform to their vocabulary.
@fabricorg/archetypes provides six pre-1.0 semantic archetypes: Party, Offering, Agreement,
Resource, Activity, and Settlement. The package is optional. @fabricorg/platform stores its
namespaced annotation as opaque JSON and contains no archetype names.
import {
archetypeSemantics,
assertArchetypeConformance,
} from "@fabricorg/archetypes";
const serviceVisit = {
type: "ServiceVisit",
semantics: archetypeSemantics({
id: "fabric.Activity",
version: "0.1",
stateMap: {
scheduled: "planned",
working: "executing",
blocked: "waiting",
completed: "completed",
},
}),
};
assertArchetypeConformance(fieldServicesModule);
const registry = createModuleRegistry([fieldServicesModule]);Conformance mappings are explicit and versioned. The validator never guesses from state labels. It
checks complete mapping, state-class compatibility, permitted refinements, required base transitions,
and exception behavior. validateArchetypeConformance returns findings as data for report-only tools;
assertArchetypeConformance fails startup when an application explicitly requires enforcement.
Base createModuleRegistry() remains archetype-agnostic. Certification tooling consumes
archetypeConformanceAdapter; the compiler does not need to know any archetype name.
The vocabulary remains pre-1.0 until roofing, restaurant, and Activity/Resource-centric field-service fixtures remain conformant.
Defining your own
The six shipped archetypes are a reference vocabulary. A platform meant for verticals nobody has
named yet cannot ship their nouns, so the seam is the definition itself. A vertical declares an
archetype with defineArchetype and certifies its modules with a conformance built over that set:
import { createArchetypeConformance, defineArchetype } from "@fabricorg/archetypes";
const relationship = defineArchetype({
id: "outdoor.Relationship",
version: "0.1",
description: "One party acting for, serving, or belonging to another for a bounded period.",
states: {
proposed: { id: "proposed", stateClass: "initial" },
active: { id: "active", stateClass: "active" },
ended: { id: "ended", stateClass: "terminal" },
exception: { id: "exception", stateClass: "exception" },
},
transitions: [
{ from: "proposed", to: "active", required: true },
{ from: "active", to: "ended", required: true },
{ from: "proposed", to: "exception" },
{ from: "active", to: "exception" },
],
obligations: ["both parties are attributable", "the role is explicit", "validity is bounded"],
});
const conformance = createArchetypeConformance([relationship]);
conformance.assert(dealerModule);
compileManifestBundle(bundle, { conformanceAdapters: [conformance.adapter] });Ids are <namespace>.<PascalName>, and the fabric. namespace is reserved for the reference set, so a
vertical's vocabulary cannot be mistaken for it or redefine it. The reference archetypes are included
by default, so one assembly certifies both; pass includeReference: false to certify against the
vertical's set alone. A definition is validated structurally before it can certify anything: it
needs a state to start in and a way to end, every transition names a declared state, and self-loops
and duplicate transitions are refused. Conformance itself then checks that a module realizes every
required transition. The conformance's adapter carries an id distinct from the shipped adapter's, so
certification tooling can hold one or the other without keying two results under one name; register
the vertical's, since it already includes the reference set.