autotel-eventcatalog 1.0.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/CHANGELOG.md +196 -0
- package/CONTRIBUTING.md +212 -0
- package/README.md +307 -0
- package/action.yml +155 -0
- package/dist/cli.cjs +1071 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +2 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +1065 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +794 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +267 -0
- package/dist/index.d.ts +267 -0
- package/dist/index.js +764 -0
- package/dist/index.js.map +1 -0
- package/docs/CONTRACT.md +280 -0
- package/docs/EXTENDING.md +248 -0
- package/docs/TROUBLESHOOTING.md +220 -0
- package/docs/UPGRADING.md +202 -0
- package/package.json +78 -0
- package/schemas/README.md +44 -0
- package/schemas/drift-report-v0.1.0.json +107 -0
- package/schemas/drift-report-v0.2.0.json +137 -0
- package/schemas/drift-summary-v0.1.0.json +74 -0
- package/schemas/drift-summary-v0.2.0.json +74 -0
- package/schemas/stamp-summary-v0.1.0.json +54 -0
- package/src/__fixtures__/drift-report-all.golden.json +33 -0
- package/src/__fixtures__/drift-summary-clean.golden.json +17 -0
- package/src/__fixtures__/drift-summary-drifty.golden.json +17 -0
- package/src/__fixtures__/stamp-summary-noop.golden.json +10 -0
- package/src/catalog.test.ts +63 -0
- package/src/catalog.ts +169 -0
- package/src/cli.e2e.test.ts +310 -0
- package/src/cli.ts +402 -0
- package/src/contract.test.ts +395 -0
- package/src/diff-vs-base.test.ts +145 -0
- package/src/diff-vs-base.ts +242 -0
- package/src/diff.test.ts +384 -0
- package/src/diff.ts +296 -0
- package/src/index.ts +73 -0
- package/src/policy.test.ts +75 -0
- package/src/policy.ts +41 -0
- package/src/renderers/index.ts +35 -0
- package/src/renderers/json.ts +33 -0
- package/src/renderers/markdown.ts +223 -0
- package/src/renderers/renderers.test.ts +79 -0
- package/src/renderers/terminal.ts +30 -0
- package/src/renderers/types.ts +26 -0
- package/src/report.test.ts +205 -0
- package/src/report.ts +27 -0
- package/src/snapshot.ts +25 -0
- package/src/stamp.test.ts +283 -0
- package/src/stamp.ts +232 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/snapshot.ts","../src/catalog.ts","../src/diff.ts","../src/diff-vs-base.ts","../src/renderers/markdown.ts","../src/renderers/terminal.ts","../src/renderers/json.ts","../src/renderers/index.ts","../src/policy.ts","../src/stamp.ts"],"names":["shouldFail","normaliseEventId","readFile"],"mappings":"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","file":"index.js","sourcesContent":["// Re-export the snapshot types from autotel-subscribers and provide a\n// convenience loader. Keeping the types defined in one place makes the\n// contract between subscriber and generator unambiguous.\n\nimport { readFile } from 'node:fs/promises';\n\nexport type {\n ArchitectureSnapshot,\n EventObservation,\n} from 'autotel-subscribers/architecture-snapshot';\n\nimport type { ArchitectureSnapshot } from 'autotel-subscribers/architecture-snapshot';\n\nexport async function loadSnapshot(\n path: string,\n): Promise<ArchitectureSnapshot> {\n const raw = await readFile(path, 'utf8');\n const parsed = JSON.parse(raw) as ArchitectureSnapshot;\n if (!parsed?.spec?.startsWith('autotel-architecture/')) {\n throw new Error(\n `Not an autotel architecture snapshot (missing spec marker): ${path}`,\n );\n }\n return parsed;\n}\n","// Read the current state of an EventCatalog using @eventcatalog/sdk. We\n// re-use SDK types (`Event`, `Service`, `Channel`) verbatim and only add the\n// two fields the SDK doesn't expose: the resolved on-disk `filePath`, and the\n// dotted field-path + schema-constraint extractions our drift diff consumes.\n// Inventing our own catalog types would silently drift from the SDK as it\n// evolves.\n\nimport utils from '@eventcatalog/sdk';\nimport type { Channel, Event, Service } from '@eventcatalog/sdk';\n\nexport type SchemaConstraint = {\n types?: string[];\n enumValues?: unknown[];\n};\n\nexport type CatalogEvent = Event & {\n /** Absolute path to the event's `index.mdx`, resolved via SDK. */\n filePath: string;\n /** Field paths declared in the event's JSON Schema (if present). */\n declaredFieldPaths?: string[];\n declaredSchemaConstraints?: Record<string, SchemaConstraint>;\n};\n\nexport type CatalogService = Service & {\n filePath: string;\n};\n\nexport type CatalogChannel = Channel & {\n filePath: string;\n};\n\nexport type CatalogState = {\n events: Map<string, CatalogEvent>;\n services: Map<string, CatalogService>;\n channels: Map<string, CatalogChannel>;\n};\n\nexport async function readCatalogState(\n catalogPath: string,\n): Promise<CatalogState> {\n const sdk = utils(catalogPath);\n\n const [events, services, channels] = await Promise.all([\n sdk.getEvents({ latestOnly: true, attachSchema: true }),\n sdk.getServices({ latestOnly: true }),\n sdk.getChannels({ latestOnly: true }),\n ]);\n\n const state: CatalogState = {\n events: new Map(),\n services: new Map(),\n channels: new Map(),\n };\n\n // SDK quirk (as of 2.21.2): unlike the other helpers, `getResourcePath` is\n // not curried with `catalogDir`, so we pass the catalog path explicitly.\n const resolveFilePath = async (id: string, version?: string) => {\n const paths = await sdk.getResourcePath(catalogPath, id, version);\n return paths?.fullPath ?? '';\n };\n\n for (const e of events ?? []) {\n const filePath = await resolveFilePath(e.id, e.version);\n const schemaExtractions = e.schema\n ? {\n declaredFieldPaths: extractDeclaredFieldPaths(e.schema),\n declaredSchemaConstraints: extractDeclaredSchemaConstraints(e.schema),\n }\n : {};\n state.events.set(e.id, { ...e, filePath, ...schemaExtractions });\n }\n\n for (const s of services ?? []) {\n const filePath = await resolveFilePath(s.id, s.version);\n state.services.set(s.id, { ...s, filePath });\n }\n\n for (const c of channels ?? []) {\n const filePath = await resolveFilePath(c.id, c.version);\n state.channels.set(c.id, { ...c, filePath });\n }\n\n return state;\n}\n\n/**\n * Extract field paths from a JSON Schema. Mirrors the dotted-path convention\n * used by the snapshot subscriber: arrays collapse to `[]`, nested objects\n * use `.`. We walk `properties` (objects) and `items` (arrays).\n */\nexport function extractDeclaredFieldPaths(\n schema: unknown,\n prefix = '',\n): string[] {\n const out = new Set<string>();\n walkSchema(schema, prefix, out);\n return [...out].toSorted();\n}\n\nfunction walkSchema(schema: unknown, prefix: string, out: Set<string>): void {\n if (!schema || typeof schema !== 'object') return;\n const s = schema as Record<string, unknown>;\n\n if (s.properties && typeof s.properties === 'object') {\n for (const [key, sub] of Object.entries(\n s.properties as Record<string, unknown>,\n )) {\n const path = prefix === '' ? key : `${prefix}.${key}`;\n out.add(path);\n walkSchema(sub, path, out);\n }\n }\n\n if (s.items) {\n const arrayPrefix = prefix + '[]';\n walkSchema(s.items, arrayPrefix, out);\n }\n}\n\nexport function extractDeclaredSchemaConstraints(\n schema: unknown,\n prefix = '',\n): Record<string, SchemaConstraint> {\n const out = new Map<string, SchemaConstraint>();\n walkSchemaConstraints(schema, prefix, out);\n const obj: Record<string, SchemaConstraint> = {};\n for (const [path, c] of out) obj[path] = c;\n return obj;\n}\n\nfunction walkSchemaConstraints(\n schema: unknown,\n prefix: string,\n out: Map<string, SchemaConstraint>,\n): void {\n if (!schema || typeof schema !== 'object') return;\n const s = schema as Record<string, unknown>;\n const typeVal = s.type;\n const enumVal = s.enum;\n if (prefix !== '' && (typeVal !== undefined || enumVal !== undefined)) {\n const types = toTypeArray(typeVal);\n const enumValues = Array.isArray(enumVal) ? [...enumVal] : undefined;\n out.set(prefix, {\n ...(types.length > 0 ? { types } : {}),\n ...(enumValues ? { enumValues } : {}),\n });\n }\n\n if (s.properties && typeof s.properties === 'object') {\n for (const [key, sub] of Object.entries(\n s.properties as Record<string, unknown>,\n )) {\n const path = prefix === '' ? key : `${prefix}.${key}`;\n walkSchemaConstraints(sub, path, out);\n }\n }\n if (s.items) {\n const arrayPrefix = prefix + '[]';\n walkSchemaConstraints(s.items, arrayPrefix, out);\n }\n}\n\nfunction toTypeArray(typeVal: unknown): string[] {\n if (typeof typeVal === 'string') return [typeVal];\n if (Array.isArray(typeVal)) {\n return typeVal.filter((t): t is string => typeof t === 'string').toSorted();\n }\n return [];\n}\n","// Compute drift between an autotel architecture snapshot and an existing\n// EventCatalog. The diff is intentionally conservative: it reports only\n// existence and field-path drift. Type drift, value drift, and enum-value\n// checks are deferred — they need richer signal than v0 carries.\n\nimport type { ArchitectureSnapshot } from './snapshot';\nimport type { CatalogState } from './catalog';\n\nexport type EventDrift = {\n /** Event names observed in the snapshot but not present in the catalog. */\n observedButUndocumented: string[];\n /** Event names declared in the catalog but never observed in the snapshot. */\n documentedButUnseen: string[];\n /** Per-event field-path mismatches. */\n fieldDrift: FieldDrift[];\n /** Per-event field type mismatches against declared schema types. */\n typeDrift: TypeDrift[];\n /** Per-event enum/value mismatches against declared schema enums. */\n valueDrift: ValueDrift[];\n};\n\nexport type FieldDrift = {\n event: string;\n /** Field paths in the observed payload but not declared in the schema. */\n extra: string[];\n /** Field paths declared in the schema but never observed in a payload. */\n missing: string[];\n};\n\nexport type TypeDrift = {\n event: string;\n path: string;\n declared: string[];\n observed: string[];\n};\n\nexport type ValueDrift = {\n event: string;\n path: string;\n declared: unknown[];\n observed: unknown[];\n};\n\nexport type ServiceDrift = {\n /** Producers in the snapshot but not present in the catalog as services. */\n observedButUndocumented: string[];\n};\n\nexport type ChannelDrift = {\n /** Channels in the snapshot but not present in the catalog. */\n observedButUndocumented: string[];\n};\n\nexport type DriftReport = {\n snapshotGeneratedAt: string;\n snapshotService: string;\n events: EventDrift;\n services: ServiceDrift;\n channels: ChannelDrift;\n};\n\n/** True if the report contains any drift worth surfacing in a PR check. */\nexport function hasDrift(report: DriftReport): boolean {\n const c = countDriftReport(report);\n return c.total > 0;\n}\n\n/**\n * Per-category counts for a DriftReport. Keeps the dashboard's hero meter,\n * the CLI's summary-output, and the action's structured output all agreeing\n * on what \"N findings\" means.\n */\nexport type DriftCounts = {\n /** Total of all categories — what a dashboard \"drift findings\" badge shows. */\n total: number;\n observedButUndocumentedEvents: number;\n documentedButUnseenEvents: number;\n /** Number of distinct events with field-path drift entries. */\n fieldDriftEvents: number;\n /** Sum of every individual extra + missing path across all fieldDrift entries. */\n fieldDriftPaths: number;\n typeDriftPaths: number;\n valueDriftPaths: number;\n undocumentedServices: number;\n undocumentedChannels: number;\n};\n\nexport function countDriftReport(report: DriftReport): DriftCounts {\n const typeDrift = report.events.typeDrift ?? [];\n const valueDrift = report.events.valueDrift ?? [];\n const fieldDriftEvents = report.events.fieldDrift.length;\n const fieldDriftPaths = report.events.fieldDrift.reduce(\n (sum, fd) => sum + fd.extra.length + fd.missing.length,\n 0,\n );\n const typeDriftPaths = typeDrift.length;\n const valueDriftPaths = valueDrift.length;\n const observedButUndocumentedEvents =\n report.events.observedButUndocumented.length;\n const documentedButUnseenEvents = report.events.documentedButUnseen.length;\n const undocumentedServices = report.services.observedButUndocumented.length;\n const undocumentedChannels = report.channels.observedButUndocumented.length;\n\n return {\n observedButUndocumentedEvents,\n documentedButUnseenEvents,\n fieldDriftEvents,\n fieldDriftPaths,\n typeDriftPaths,\n valueDriftPaths,\n undocumentedServices,\n undocumentedChannels,\n total:\n observedButUndocumentedEvents +\n documentedButUnseenEvents +\n fieldDriftPaths +\n typeDriftPaths +\n valueDriftPaths +\n undocumentedServices +\n undocumentedChannels,\n };\n}\n\nexport function diffCatalogAgainstSnapshot(\n snapshot: ArchitectureSnapshot,\n catalog: CatalogState,\n): DriftReport {\n const snapshotEvents = new Set(Object.keys(snapshot.events));\n const catalogEventIds = new Set(catalog.events.keys());\n\n // Catalog event IDs are PascalCase (\"OrderPlaced\") while track() names are\n // dotted (\"order.placed\"). We compare on a normalised form so the same\n // event isn't reported as both missing and extra.\n const catalogEventByNormalised = new Map<string, string>();\n for (const id of catalogEventIds) {\n catalogEventByNormalised.set(normaliseEventId(id), id);\n }\n\n const observedButUndocumented: string[] = [];\n const matchedCatalogIds = new Set<string>();\n for (const name of snapshotEvents) {\n const matched = catalogEventByNormalised.get(normaliseEventId(name));\n if (matched) {\n matchedCatalogIds.add(matched);\n } else {\n observedButUndocumented.push(name);\n }\n }\n\n const documentedButUnseen: string[] = [];\n for (const id of catalogEventIds) {\n if (!matchedCatalogIds.has(id)) documentedButUnseen.push(id);\n }\n\n const fieldDrift: FieldDrift[] = [];\n const typeDrift: TypeDrift[] = [];\n const valueDrift: ValueDrift[] = [];\n for (const [snapName, obs] of Object.entries(snapshot.events)) {\n const catalogId = catalogEventByNormalised.get(normaliseEventId(snapName));\n if (!catalogId) continue;\n const eventDecl = catalog.events.get(catalogId);\n const declared = eventDecl?.declaredFieldPaths;\n if (!declared) continue;\n\n const declaredSet = new Set(declared);\n const observedSet = new Set(obs.fieldPaths);\n\n const extra = obs.fieldPaths.filter((p) => !declaredSet.has(p));\n const missing = declared.filter((p) => !observedSet.has(p));\n\n if (extra.length > 0 || missing.length > 0) {\n fieldDrift.push({ event: snapName, extra, missing });\n }\n\n const constraints = eventDecl?.declaredSchemaConstraints ?? {};\n const stats =\n (\n obs as {\n fieldStats?: Record<\n string,\n { types: string[]; sampleValues: unknown[] }\n >;\n }\n ).fieldStats ?? {};\n for (const [path, declaredConstraint] of Object.entries(constraints)) {\n const observed = stats[path];\n if (!observed) continue;\n if (declaredConstraint.types && declaredConstraint.types.length > 0) {\n // JSON Schema has `integer`; JavaScript has only `number`. Treat the\n // two as compatible at the runtime-type level, then use sample values\n // to flag the real signal (a non-integer value seen against an\n // integer-only declaration).\n const accepts = expandDeclaredTypes(declaredConstraint.types);\n const badTypes = observed.types.filter((t: string) => !accepts.has(t));\n const integerDeclared =\n declaredConstraint.types.includes('integer') &&\n !declaredConstraint.types.includes('number');\n const nonIntegerSamples = integerDeclared\n ? observed.sampleValues.filter(\n (v: unknown) => typeof v === 'number' && !Number.isInteger(v),\n )\n : [];\n if (badTypes.length > 0 || nonIntegerSamples.length > 0) {\n typeDrift.push({\n event: snapName,\n path,\n declared: declaredConstraint.types,\n observed: [...new Set(observed.types)].toSorted(),\n });\n }\n }\n if (\n declaredConstraint.enumValues &&\n declaredConstraint.enumValues.length > 0 &&\n observed.sampleValues.length > 0\n ) {\n const observedOutsideEnum = observed.sampleValues.filter(\n (v: unknown) =>\n !declaredConstraint.enumValues?.some((d) => Object.is(d, v)),\n );\n if (observedOutsideEnum.length > 0) {\n valueDrift.push({\n event: snapName,\n path,\n declared: declaredConstraint.enumValues,\n observed: [...new Set(observedOutsideEnum)] as unknown[],\n });\n }\n }\n }\n }\n\n const snapshotServices = collectProducers(snapshot);\n const catalogServiceIds = new Set(catalog.services.keys());\n const undocumentedServices = [...snapshotServices].filter(\n (id) => !catalogServiceIds.has(id),\n );\n\n const snapshotChannels = collectChannels(snapshot);\n const catalogChannelIds = new Set(catalog.channels.keys());\n const undocumentedChannels = [...snapshotChannels].filter(\n (id) => !catalogChannelIds.has(id),\n );\n\n return {\n snapshotGeneratedAt: snapshot.generatedAt,\n snapshotService: snapshot.service,\n events: {\n observedButUndocumented: observedButUndocumented.sort(),\n documentedButUnseen: documentedButUnseen.sort(),\n fieldDrift: fieldDrift.sort((a, b) => a.event.localeCompare(b.event)),\n typeDrift: typeDrift.sort((a, b) =>\n `${a.event}.${a.path}`.localeCompare(`${b.event}.${b.path}`),\n ),\n valueDrift: valueDrift.sort((a, b) =>\n `${a.event}.${a.path}`.localeCompare(`${b.event}.${b.path}`),\n ),\n },\n services: { observedButUndocumented: undocumentedServices.sort() },\n channels: { observedButUndocumented: undocumentedChannels.sort() },\n };\n}\n\n/**\n * Map declared JSON Schema types to the set of runtime types we accept at\n * `typeof` level. JSON Schema's `integer` is a refinement of `number` (JS\n * does not have a separate integer type), so we accept observed `number` for\n * either declaration. The integer-vs-fractional distinction is then enforced\n * separately against sample values.\n */\nfunction expandDeclaredTypes(declared: string[]): Set<string> {\n const accepts = new Set<string>(declared);\n if (declared.includes('integer')) accepts.add('number');\n return accepts;\n}\n\nfunction normaliseEventId(id: string): string {\n // \"order.placed\" -> \"orderplaced\", \"OrderPlaced\" -> \"orderplaced\".\n return id.toLowerCase().replaceAll(/[._\\-\\s]/g, '');\n}\n\nfunction collectProducers(snapshot: ArchitectureSnapshot): Set<string> {\n const out = new Set<string>();\n for (const obs of Object.values(snapshot.events)) {\n if (obs.producer) out.add(obs.producer);\n }\n return out;\n}\n\nfunction collectChannels(snapshot: ArchitectureSnapshot): Set<string> {\n const out = new Set<string>();\n for (const obs of Object.values(snapshot.events)) {\n if (obs.channel) out.add(obs.channel);\n }\n return out;\n}\n","// Compare two drift reports (base branch vs PR head) and produce a \"what\n// this PR introduces\" view. Without this, a PR check fails forever on\n// pre-existing drift; with it, the check only fails on drift the PR is\n// responsible for.\n\nimport type {\n DriftReport,\n FieldDrift,\n DriftCounts,\n TypeDrift,\n ValueDrift,\n} from './diff';\n\nexport type DriftDelta = {\n /** Drift entries present in head but not in base. */\n introduced: DriftEntries;\n /** Drift entries present in base but not in head — the PR fixed these. */\n resolved: DriftEntries;\n /** True if `introduced` has any non-empty section. */\n hasNewDrift: boolean;\n};\n\nexport type DriftEntries = {\n events: {\n observedButUndocumented: string[];\n documentedButUnseen: string[];\n fieldDrift: FieldDrift[];\n typeDrift: TypeDrift[];\n valueDrift: ValueDrift[];\n };\n services: { observedButUndocumented: string[] };\n channels: { observedButUndocumented: string[] };\n};\n\nexport function compareDriftReports(\n base: DriftReport,\n head: DriftReport,\n): DriftDelta {\n const introducedEvents = diffStringList(\n base.events.observedButUndocumented,\n head.events.observedButUndocumented,\n );\n const introducedMissing = diffStringList(\n base.events.documentedButUnseen,\n head.events.documentedButUnseen,\n );\n const introducedFieldDrift = diffFieldDrift(\n base.events.fieldDrift,\n head.events.fieldDrift,\n );\n const introducedServices = diffStringList(\n base.services.observedButUndocumented,\n head.services.observedButUndocumented,\n );\n const introducedChannels = diffStringList(\n base.channels.observedButUndocumented,\n head.channels.observedButUndocumented,\n );\n\n const introduced: DriftEntries = {\n events: {\n observedButUndocumented: introducedEvents.added,\n documentedButUnseen: introducedMissing.added,\n fieldDrift: introducedFieldDrift.added,\n typeDrift: diffTypeDrift(\n base.events.typeDrift ?? [],\n head.events.typeDrift ?? [],\n ).added,\n valueDrift: diffValueDrift(\n base.events.valueDrift ?? [],\n head.events.valueDrift ?? [],\n ).added,\n },\n services: { observedButUndocumented: introducedServices.added },\n channels: { observedButUndocumented: introducedChannels.added },\n };\n\n const resolved: DriftEntries = {\n events: {\n observedButUndocumented: introducedEvents.removed,\n documentedButUnseen: introducedMissing.removed,\n fieldDrift: introducedFieldDrift.removed,\n typeDrift: diffTypeDrift(\n base.events.typeDrift ?? [],\n head.events.typeDrift ?? [],\n ).removed,\n valueDrift: diffValueDrift(\n base.events.valueDrift ?? [],\n head.events.valueDrift ?? [],\n ).removed,\n },\n services: { observedButUndocumented: introducedServices.removed },\n channels: { observedButUndocumented: introducedChannels.removed },\n };\n\n const hasNewDrift =\n introduced.events.observedButUndocumented.length > 0 ||\n introduced.events.documentedButUnseen.length > 0 ||\n introduced.events.fieldDrift.length > 0 ||\n introduced.events.typeDrift.length > 0 ||\n introduced.events.valueDrift.length > 0 ||\n introduced.services.observedButUndocumented.length > 0 ||\n introduced.channels.observedButUndocumented.length > 0;\n\n return { introduced, resolved, hasNewDrift };\n}\n\n/**\n * Per-category counts for one side of a DriftDelta (introduced or resolved).\n * Same shape as DriftCounts so dashboards and CI can render the\n * introduced/resolved sections with identical accounting.\n */\nexport function countDriftEntries(entries: DriftEntries): DriftCounts {\n const fieldDriftEvents = entries.events.fieldDrift.length;\n const fieldDriftPaths = entries.events.fieldDrift.reduce(\n (sum, fd) => sum + fd.extra.length + fd.missing.length,\n 0,\n );\n const observedButUndocumentedEvents =\n entries.events.observedButUndocumented.length;\n const documentedButUnseenEvents = entries.events.documentedButUnseen.length;\n const undocumentedServices = entries.services.observedButUndocumented.length;\n const undocumentedChannels = entries.channels.observedButUndocumented.length;\n const typeDriftPaths = (entries.events.typeDrift ?? []).length;\n const valueDriftPaths = (entries.events.valueDrift ?? []).length;\n\n return {\n observedButUndocumentedEvents,\n documentedButUnseenEvents,\n fieldDriftEvents,\n fieldDriftPaths,\n typeDriftPaths,\n valueDriftPaths,\n undocumentedServices,\n undocumentedChannels,\n total:\n observedButUndocumentedEvents +\n documentedButUnseenEvents +\n fieldDriftPaths +\n typeDriftPaths +\n valueDriftPaths +\n undocumentedServices +\n undocumentedChannels,\n };\n}\n\nexport function countDriftDelta(delta: DriftDelta): {\n introduced: DriftCounts;\n resolved: DriftCounts;\n} {\n return {\n introduced: countDriftEntries(delta.introduced),\n resolved: countDriftEntries(delta.resolved),\n };\n}\n\nfunction diffStringList(\n base: string[],\n head: string[],\n): { added: string[]; removed: string[] } {\n const baseSet = new Set(base);\n const headSet = new Set(head);\n return {\n added: head.filter((s) => !baseSet.has(s)).sort(),\n removed: base.filter((s) => !headSet.has(s)).sort(),\n };\n}\n\nfunction diffFieldDrift(\n base: FieldDrift[],\n head: FieldDrift[],\n): { added: FieldDrift[]; removed: FieldDrift[] } {\n const baseByEvent = new Map(base.map((d) => [d.event, d]));\n const headByEvent = new Map(head.map((d) => [d.event, d]));\n\n const added: FieldDrift[] = [];\n const removed: FieldDrift[] = [];\n\n for (const [event, h] of headByEvent) {\n const b = baseByEvent.get(event);\n if (!b) {\n // Entire event's field drift is new to head.\n added.push(h);\n continue;\n }\n const addedExtra = h.extra.filter((p) => !b.extra.includes(p));\n const addedMissing = h.missing.filter((p) => !b.missing.includes(p));\n if (addedExtra.length > 0 || addedMissing.length > 0) {\n added.push({ event, extra: addedExtra, missing: addedMissing });\n }\n }\n\n for (const [event, b] of baseByEvent) {\n const h = headByEvent.get(event);\n if (!h) {\n removed.push(b);\n continue;\n }\n const removedExtra = b.extra.filter((p) => !h.extra.includes(p));\n const removedMissing = b.missing.filter((p) => !h.missing.includes(p));\n if (removedExtra.length > 0 || removedMissing.length > 0) {\n removed.push({ event, extra: removedExtra, missing: removedMissing });\n }\n }\n\n return { added, removed };\n}\n\nfunction diffTypeDrift(\n base: TypeDrift[],\n head: TypeDrift[],\n): { added: TypeDrift[]; removed: TypeDrift[] } {\n return diffStructuredByKey(base, head, (x) => `${x.event}::${x.path}`);\n}\n\nfunction diffValueDrift(\n base: ValueDrift[],\n head: ValueDrift[],\n): { added: ValueDrift[]; removed: ValueDrift[] } {\n return diffStructuredByKey(base, head, (x) => `${x.event}::${x.path}`);\n}\n\nfunction diffStructuredByKey<T>(\n base: T[],\n head: T[],\n keyOf: (v: T) => string,\n): { added: T[]; removed: T[] } {\n const baseMap = new Map(base.map((v) => [keyOf(v), v]));\n const headMap = new Map(head.map((v) => [keyOf(v), v]));\n const added: T[] = [];\n const removed: T[] = [];\n\n for (const [k, hv] of headMap) {\n const bv = baseMap.get(k);\n if (!bv || JSON.stringify(bv) !== JSON.stringify(hv)) added.push(hv);\n }\n for (const [k, bv] of baseMap) {\n const hv = headMap.get(k);\n if (!hv || JSON.stringify(hv) !== JSON.stringify(bv)) removed.push(bv);\n }\n return { added, removed };\n}\n","// GitHub-flavoured Markdown — the default. Used directly as the body of\n// the sticky PR comment posted by the bundled action.\n\nimport type { DriftReport, FieldDrift } from '../diff';\nimport { hasDrift } from '../diff';\nimport type { DriftDelta, DriftEntries } from '../diff-vs-base';\nimport type { Renderer } from './types';\n\nexport function renderMarkdown(report: DriftReport): string {\n const lines: string[] = [\n '# Architecture drift report',\n '',\n `_Snapshot from \\`${report.snapshotService}\\` at ${report.snapshotGeneratedAt}_`,\n '',\n ];\n\n if (!hasDrift(report)) {\n lines.push('No drift detected. Catalog and runtime agree.', '');\n return lines.join('\\n');\n }\n\n if (report.events.observedButUndocumented.length > 0) {\n lines.push(\n '## Events observed but undocumented',\n '',\n 'These event names appear in the snapshot but no matching entry',\n 'exists in the catalog. Add them or stop emitting them.',\n '',\n );\n for (const name of report.events.observedButUndocumented) {\n lines.push(`- \\`${name}\\``);\n }\n lines.push('');\n }\n\n if (report.events.documentedButUnseen.length > 0) {\n lines.push(\n '## Events documented but never observed',\n '',\n 'These events exist in the catalog but no payload was captured.',\n 'Either the tests do not exercise this event, or it has been removed.',\n '',\n );\n for (const name of report.events.documentedButUnseen) {\n lines.push(`- \\`${name}\\``);\n }\n lines.push('');\n }\n\n if (report.events.fieldDrift.length > 0) {\n lines.push('## Field-path drift', '');\n for (const drift of report.events.fieldDrift) {\n lines.push(`### \\`${drift.event}\\``, '');\n if (drift.extra.length > 0) {\n lines.push(\n '**Extra fields in payloads (not in declared schema):**',\n '',\n );\n for (const p of drift.extra) lines.push(`- \\`${p}\\``);\n lines.push('');\n }\n if (drift.missing.length > 0) {\n lines.push('**Fields declared but never observed:**', '');\n for (const p of drift.missing) lines.push(`- \\`${p}\\``);\n lines.push('');\n }\n }\n }\n\n if ((report.events.typeDrift ?? []).length > 0) {\n lines.push('## Type drift', '');\n for (const drift of report.events.typeDrift ?? []) {\n lines.push(\n `- \\`${drift.event}\\` \\`${drift.path}\\``,\n ` declared: \\`${drift.declared.join(' | ')}\\`, observed: \\`${drift.observed.join(' | ')}\\``,\n );\n }\n lines.push('');\n }\n\n if ((report.events.valueDrift ?? []).length > 0) {\n lines.push('## Value drift', '');\n for (const drift of report.events.valueDrift ?? []) {\n lines.push(\n `- \\`${drift.event}\\` \\`${drift.path}\\``,\n ` declared enum: \\`${drift.declared.map((v) => JSON.stringify(v)).join(', ')}\\`, observed: \\`${drift.observed.map((v) => JSON.stringify(v)).join(', ')}\\``,\n );\n }\n lines.push('');\n }\n\n if (report.services.observedButUndocumented.length > 0) {\n lines.push('## Services observed but undocumented', '');\n for (const id of report.services.observedButUndocumented) {\n lines.push(`- \\`${id}\\``);\n }\n lines.push('');\n }\n\n if (report.channels.observedButUndocumented.length > 0) {\n lines.push('## Channels observed but undocumented', '');\n for (const id of report.channels.observedButUndocumented) {\n lines.push(`- \\`${id}\\``);\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Render the diff-of-diffs as a PR-comment-friendly markdown block. Sections\n * appear only when they have content, so a clean PR produces a tight message.\n */\nexport function renderDeltaMarkdown(delta: DriftDelta): string {\n const lines: string[] = [\n '# Architecture drift — what this change introduces',\n '',\n ];\n\n if (!delta.hasNewDrift) {\n const fixedAny = entriesHasContent(delta.resolved);\n if (fixedAny) {\n lines.push('No new drift. The changes below resolve existing drift:', '');\n renderEntries(delta.resolved, lines, { sign: '−' });\n } else {\n lines.push('No new drift detected. Catalog and runtime agree.');\n }\n lines.push('');\n return lines.join('\\n');\n }\n\n lines.push('This change introduces drift:', '');\n renderEntries(delta.introduced, lines, { sign: '+' });\n\n if (entriesHasContent(delta.resolved)) {\n lines.push('', '### Resolved by this change', '');\n renderEntries(delta.resolved, lines, { sign: '−' });\n }\n\n return lines.join('\\n');\n}\n\nfunction entriesHasContent(e: DriftEntries): boolean {\n return (\n e.events.observedButUndocumented.length > 0 ||\n e.events.documentedButUnseen.length > 0 ||\n e.events.fieldDrift.length > 0 ||\n (e.events.typeDrift ?? []).length > 0 ||\n (e.events.valueDrift ?? []).length > 0 ||\n e.services.observedButUndocumented.length > 0 ||\n e.channels.observedButUndocumented.length > 0\n );\n}\n\nfunction renderEntries(\n entries: DriftEntries,\n out: string[],\n options: { sign: '+' | '−' },\n): void {\n if (entries.events.observedButUndocumented.length > 0) {\n out.push('**Events observed but undocumented**', '');\n for (const n of entries.events.observedButUndocumented) {\n out.push(`- \\`${n}\\``);\n }\n out.push('');\n }\n if (entries.events.documentedButUnseen.length > 0) {\n out.push('**Events documented but never observed**', '');\n for (const n of entries.events.documentedButUnseen) {\n out.push(`- \\`${n}\\``);\n }\n out.push('');\n }\n for (const fd of entries.events.fieldDrift) {\n out.push(`**Field drift on \\`${fd.event}\\`**`, '');\n for (const p of fd.extra) out.push(`- ${options.sign} \\`${p}\\` (extra)`);\n for (const p of fd.missing)\n out.push(`- ${options.sign} \\`${p}\\` (missing)`);\n out.push('');\n }\n for (const td of entries.events.typeDrift ?? []) {\n out.push(\n `**Type drift on \\`${td.event}\\` \\`${td.path}\\`**`,\n '',\n `- ${options.sign} declared \\`${td.declared.join(' | ')}\\`, observed \\`${td.observed.join(' | ')}\\``,\n '',\n );\n }\n for (const vd of entries.events.valueDrift ?? []) {\n out.push(\n `**Value drift on \\`${vd.event}\\` \\`${vd.path}\\`**`,\n '',\n `- ${options.sign} declared enum \\`${vd.declared.map((v) => JSON.stringify(v)).join(', ')}\\`, observed \\`${vd.observed.map((v) => JSON.stringify(v)).join(', ')}\\``,\n '',\n );\n }\n if (entries.services.observedButUndocumented.length > 0) {\n out.push('**Services observed but undocumented**', '');\n for (const id of entries.services.observedButUndocumented) {\n out.push(`- \\`${id}\\``);\n }\n out.push('');\n }\n if (entries.channels.observedButUndocumented.length > 0) {\n out.push('**Channels observed but undocumented**', '');\n for (const id of entries.channels.observedButUndocumented) {\n out.push(`- \\`${id}\\``);\n }\n out.push('');\n }\n // FieldDrift import kept for typing of the for..of above; reference here so\n // the import isn't flagged as unused by some linter configurations.\n void (null as unknown as FieldDrift);\n}\n\nexport const markdownRenderer: Renderer = {\n name: 'markdown',\n description:\n 'GitHub-flavoured Markdown (default). Suitable for sticky PR comments.',\n renderReport: renderMarkdown,\n renderDelta: renderDeltaMarkdown,\n};\n","// Plain-text rendering — for terminals, log files, Slack messages, anywhere\n// markdown decorations would render as noise. Reuses the markdown renderer\n// and strips heading marks, inline code backticks, and bold emphasis.\n\nimport type { DriftReport } from '../diff';\nimport type { DriftDelta } from '../diff-vs-base';\nimport { renderMarkdown, renderDeltaMarkdown } from './markdown';\nimport type { Renderer } from './types';\n\nexport function renderTerminal(report: DriftReport): string {\n return stripMarkdownDecorations(renderMarkdown(report));\n}\n\nexport function renderDeltaTerminal(delta: DriftDelta): string {\n return stripMarkdownDecorations(renderDeltaMarkdown(delta));\n}\n\nfunction stripMarkdownDecorations(md: string): string {\n return md\n .replaceAll(/^#+\\s+/gm, '')\n .replaceAll('`', '')\n .replaceAll(/\\*\\*([^*]+)\\*\\*/g, '$1');\n}\n\nexport const terminalRenderer: Renderer = {\n name: 'terminal',\n description: 'Plain text. Same content as markdown, decorations stripped.',\n renderReport: renderTerminal,\n renderDelta: renderDeltaTerminal,\n};\n","// Versioned JSON envelope. Downstream tooling (dashboards, custom CI steps,\n// Slack bots) should read this rather than scraping the Markdown body. The\n// shape is governed by the published schema at\n// `schemas/drift-report-v0.2.0.json` and locked by golden contract tests.\n\nimport type { DriftReport } from '../diff';\nimport type { DriftDelta } from '../diff-vs-base';\nimport type { Renderer } from './types';\n\n/**\n * Versioned identifier baked into the JSON envelope. Bumping it is a\n * breaking change for downstream consumers — add fields rather than rename.\n */\nexport const REPORT_SPEC = 'autotel-eventcatalog-report/v0.2.0' as const;\n\nexport type JsonReport =\n | { mode: 'all'; report: DriftReport }\n | { mode: 'new-only'; delta: DriftDelta };\n\nexport type JsonReportEnvelope = { spec: typeof REPORT_SPEC } & JsonReport;\n\nexport function renderJson(data: JsonReport): string {\n const envelope: JsonReportEnvelope = { spec: REPORT_SPEC, ...data };\n return JSON.stringify(envelope, null, 2);\n}\n\nexport const jsonRenderer: Renderer = {\n name: 'json',\n description:\n 'Versioned JSON envelope. Validate against schemas/drift-report-v0.2.0.json.',\n renderReport: (report) => renderJson({ mode: 'all', report }),\n renderDelta: (delta) => renderJson({ mode: 'new-only', delta }),\n};\n","// Registry of available renderers. The CLI dispatches `--format <name>`\n// through here; future renderers (sarif, slack, github-check-runs) drop in\n// by adding an entry to `RENDERERS`.\n\nimport type { Renderer } from './types';\nimport { markdownRenderer } from './markdown';\nimport { terminalRenderer } from './terminal';\nimport { jsonRenderer } from './json';\n\nexport const RENDERERS: readonly Renderer[] = [\n markdownRenderer,\n terminalRenderer,\n jsonRenderer,\n];\n\nexport const RENDERER_NAMES = RENDERERS.map((r) => r.name);\n\nexport function getRenderer(name: string): Renderer | undefined {\n return RENDERERS.find((r) => r.name === name);\n}\n\nexport type RendererName = (typeof RENDERER_NAMES)[number];\n\n// Re-export the individual functions for backwards compatibility — they have\n// been the public API since v0.1.0 and consumers may import them directly.\n\nexport { renderMarkdown, renderDeltaMarkdown } from './markdown';\nexport { renderTerminal, renderDeltaTerminal } from './terminal';\nexport {\n renderJson,\n REPORT_SPEC,\n type JsonReport,\n type JsonReportEnvelope,\n} from './json';\nexport { type Renderer } from './types';\n","// Decide whether a drift outcome should fail a CI job.\n//\n// `policy` answers the gating question; it deliberately doesn't render or\n// print anything. `reason` carries a short, log-friendly explanation that\n// CLI / Action layers can surface in their exit messages.\n\nimport type { DriftDelta } from './diff-vs-base';\nimport type { DriftReport } from './diff';\nimport { hasDrift } from './diff';\n\nexport type DriftPolicyMode = 'all' | 'new-only';\n\nexport type PolicyEvaluationInput =\n | { mode: 'all'; report: DriftReport }\n | { mode: 'new-only'; delta: DriftDelta };\n\nexport type PolicyEvaluationResult = {\n shouldFail: boolean;\n reason: string;\n};\n\nexport function evaluatePolicy(\n input: PolicyEvaluationInput,\n): PolicyEvaluationResult {\n if (input.mode === 'all') {\n const shouldFail = hasDrift(input.report);\n return {\n shouldFail,\n reason: shouldFail\n ? 'Drift detected in current snapshot.'\n : 'No drift detected.',\n };\n }\n const shouldFail = input.delta.hasNewDrift;\n return {\n shouldFail,\n reason: shouldFail\n ? 'New drift introduced compared to baseline snapshot.'\n : 'No new drift introduced compared to baseline snapshot.',\n };\n}\n","// Stamp an architecture snapshot into a catalog's event mdx files.\n//\n// For each event in the snapshot that matches an event in the catalog (by\n// normalised name), the stamp command writes an evidence block between\n// `<!-- autotel:stamp-start -->` and `<!-- autotel:stamp-end -->` markers.\n// Subsequent runs replace the content between the markers idempotently, so\n// re-stamping is safe to run on every commit / in CI.\n//\n// If the markers do not yet exist in a file, they are inserted at the most\n// natural place: just before the `<Footer />` component if present, else\n// just before the closing `</...>` tag of the last visible content, else\n// appended to the file.\n\nimport { readFile, writeFile } from 'node:fs/promises';\nimport type { ArchitectureSnapshot, EventObservation } from './snapshot';\nimport { readCatalogState } from './catalog';\n\nexport const STAMP_START = '<!-- autotel:stamp-start -->';\nexport const STAMP_END = '<!-- autotel:stamp-end -->';\n\nexport interface StampOptions {\n /** Loaded snapshot, OR pass `loadSnapshot(path)` from the caller. */\n snapshot: ArchitectureSnapshot;\n /** Catalog root (the directory containing eventcatalog.config.*). */\n catalogPath: string;\n /** If true, do not write files — just return the diff plan. */\n dryRun?: boolean;\n /** Override \"now\" for deterministic tests. */\n now?: () => Date;\n}\n\nexport type StampUpdate = {\n /** Catalog event id, e.g. `OrderPlaced`. */\n catalogId: string;\n /** Snapshot event name, e.g. `order.placed`. */\n snapshotName: string;\n /** Absolute path to the mdx file that was (or would be) updated. */\n filePath: string;\n /** Was this an insert (no prior markers) or a replace? */\n action: 'insert' | 'replace';\n /**\n * True if the proposed content differs from what's on disk. False when a\n * replace would write byte-identical content — meaning no real change.\n * Used by `--summary-output` so CI can answer \"did this PR need stamping?\"\n * without diffing files.\n */\n changed: boolean;\n};\n\nexport type StampSkip = {\n snapshotName: string;\n reason: 'no-catalog-match';\n};\n\nexport type StampResult = {\n updates: StampUpdate[];\n skips: StampSkip[];\n};\n\nexport async function stampCatalog(opts: StampOptions): Promise<StampResult> {\n const { snapshot, catalogPath, dryRun = false } = opts;\n const catalog = await readCatalogState(catalogPath);\n\n const catalogByNormalised = new Map<\n string,\n { id: string; filePath: string }\n >();\n for (const [id, ev] of catalog.events) {\n catalogByNormalised.set(normaliseEventId(id), {\n id,\n filePath: ev.filePath,\n });\n }\n\n const updates: StampUpdate[] = [];\n const skips: StampSkip[] = [];\n\n for (const [name, obs] of Object.entries(snapshot.events)) {\n const match = catalogByNormalised.get(normaliseEventId(name));\n if (!match) {\n skips.push({ snapshotName: name, reason: 'no-catalog-match' });\n continue;\n }\n\n const block = buildStampBlock(obs);\n const { action, changed } = await stampFile(match.filePath, block, dryRun);\n\n updates.push({\n catalogId: match.id,\n snapshotName: name,\n filePath: match.filePath,\n action,\n changed,\n });\n }\n\n return { updates, skips };\n}\n\n/**\n * Render the evidence block. Designed to be readable in raw mdx AND visually\n * distinct when rendered by EventCatalog (uses the existing\n * `.evidence-callout` class, plus a small header label).\n */\nexport function buildStampBlock(obs: EventObservation): string {\n const lines: string[] = [\n STAMP_START,\n '',\n '<div class=\"evidence-callout\">',\n '<strong>Observed in autotel snapshot</strong>',\n '',\n ];\n const facts: string[] = [];\n facts.push(`**Volume**: ${obs.observedCount.toLocaleString()} events`);\n facts.push(`**Last seen**: ${formatTimestamp(obs.lastSeen)}`);\n if (obs.producer) facts.push(`**Producer**: ${obs.producer}`);\n if (obs.channel) facts.push(`**Channel**: \\`${obs.channel}\\``);\n lines.push(facts.join(' · '));\n if (obs.fieldPaths.length > 0) {\n lines.push('');\n lines.push(\n `**Field paths observed**: ${obs.fieldPaths.map((p) => `\\`${p}\\``).join(', ')}`,\n );\n }\n if (obs.sampleTraceIds.length > 0) {\n lines.push('');\n lines.push(\n `**Sample traces**: ${obs.sampleTraceIds.map((t) => `\\`${t}\\``).join(', ')}`,\n );\n }\n lines.push('</div>', '', STAMP_END);\n\n return lines.join('\\n');\n}\n\nasync function stampFile(\n filePath: string,\n block: string,\n dryRun: boolean,\n): Promise<{ action: 'insert' | 'replace'; changed: boolean }> {\n const content = await readFile(filePath, 'utf8');\n\n const startIdx = content.indexOf(STAMP_START);\n const endIdx = content.indexOf(STAMP_END);\n\n let next: string;\n let action: 'insert' | 'replace';\n\n if (startIdx !== -1 && endIdx > startIdx) {\n // Replace existing block (including markers).\n const before = content.slice(0, startIdx);\n const after = content.slice(endIdx + STAMP_END.length);\n next = before + block + after;\n action = 'replace';\n } else {\n // Insert. Prefer just before <Footer /> if present, else append.\n const footerIdx = content.search(/<Footer\\s*\\/>/);\n const insertion = '\\n\\n' + block + '\\n';\n next =\n footerIdx >= 0\n ? content.slice(0, footerIdx) +\n insertion +\n '\\n' +\n content.slice(footerIdx)\n : content.replace(/\\s*$/, '') + insertion;\n action = 'insert';\n }\n\n const changed = next !== content;\n if (!dryRun && changed) {\n await writeFile(filePath, next, 'utf8');\n }\n return { action, changed };\n}\n\n/** Versioned identifier for the stamp summary JSON file. */\nexport const STAMP_SUMMARY_SPEC =\n 'autotel-eventcatalog-stamp-summary/v0.1.0' as const;\n\nexport type StampSummary = {\n spec: typeof STAMP_SUMMARY_SPEC;\n dryRun: boolean;\n /** Total snapshot events the stamp run considered (matched + skipped). */\n attempted: number;\n /** Skipped events (no catalog match). */\n skipped: number;\n /** Matched events that resulted in an insert action. */\n inserts: number;\n /** Matched events that resulted in a replace action. */\n replaces: number;\n /** Number of files whose content actually changed (or would change in dry-run). */\n changedFiles: number;\n /**\n * True when the run produced (or would produce) any real change. CI can\n * gate on this: \"if the committed catalog is stamped, this should be\n * false after running stamp; if not, the PR forgot to re-stamp.\"\n */\n hadChanges: boolean;\n};\n\nexport function buildStampSummary(\n result: StampResult,\n dryRun: boolean,\n): StampSummary {\n const inserts = result.updates.filter((u) => u.action === 'insert').length;\n const replaces = result.updates.filter((u) => u.action === 'replace').length;\n const changedFiles = result.updates.filter((u) => u.changed).length;\n return {\n spec: STAMP_SUMMARY_SPEC,\n dryRun,\n attempted: result.updates.length + result.skips.length,\n skipped: result.skips.length,\n inserts,\n replaces,\n changedFiles,\n hadChanges: changedFiles > 0,\n };\n}\n\nfunction normaliseEventId(id: string): string {\n return id.toLowerCase().replaceAll(/[._\\-\\s]/g, '');\n}\n\nfunction formatTimestamp(iso: string): string {\n // 2026-05-22T05:23:50.024Z → 2026-05-22 05:23 UTC\n const d = new Date(iso);\n const pad = (n: number) => String(n).padStart(2, '0');\n return (\n `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())} ` +\n `${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())} UTC`\n );\n}\n"]}
|
package/docs/CONTRACT.md
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# The public JSON contract
|
|
2
|
+
|
|
3
|
+
`autotel-eventcatalog` ships **three versioned JSON shapes** as published
|
|
4
|
+
JSON Schema files. Downstream tooling (your own GitHub Actions,
|
|
5
|
+
dashboards, Slack bots, custom CI checks) should read these.
|
|
6
|
+
|
|
7
|
+
| Schema file | Produced by | Spec field |
|
|
8
|
+
| --------------------------------------------------------------------------- | ------------------------------- | ------------------------------------------- |
|
|
9
|
+
| [`schemas/drift-report-v0.1.0.json`](../schemas/drift-report-v0.1.0.json) | `drift --format json` | `autotel-eventcatalog-report/v0.1.0` |
|
|
10
|
+
| [`schemas/drift-summary-v0.1.0.json`](../schemas/drift-summary-v0.1.0.json) | `drift --summary-output <path>` | `autotel-eventcatalog-drift-summary/v0.1.0` |
|
|
11
|
+
| [`schemas/stamp-summary-v0.1.0.json`](../schemas/stamp-summary-v0.1.0.json) | `stamp --summary-output <path>` | `autotel-eventcatalog-stamp-summary/v0.1.0` |
|
|
12
|
+
|
|
13
|
+
Each envelope carries a `spec:` field. Downstream code should refuse to
|
|
14
|
+
parse an unknown major version.
|
|
15
|
+
|
|
16
|
+
## Why this matters
|
|
17
|
+
|
|
18
|
+
Without a versioned contract, every JSON field becomes implicit API
|
|
19
|
+
surface. A refactor that renames `shouldFail` to `failing` silently breaks
|
|
20
|
+
every downstream consumer.
|
|
21
|
+
|
|
22
|
+
With a versioned contract:
|
|
23
|
+
|
|
24
|
+
- The schemas are the canonical shape; they live in this package and in
|
|
25
|
+
the published npm artifact.
|
|
26
|
+
- The byte-equal golden fixtures in `src/__fixtures__/` make accidental
|
|
27
|
+
shape changes fail CI inside this package.
|
|
28
|
+
- The `spec:` field gives downstream consumers a single string to gate
|
|
29
|
+
on.
|
|
30
|
+
|
|
31
|
+
## Version policy
|
|
32
|
+
|
|
33
|
+
We follow semver on the schema's URL path (`v0.1.0`):
|
|
34
|
+
|
|
35
|
+
- **Minor bump** (`v0.1.0` → `v0.2.0`): adds optional fields. Existing
|
|
36
|
+
consumers continue to parse new output. Producer adds the field with a
|
|
37
|
+
sensible default.
|
|
38
|
+
- **Major bump** (`v0.1.0` → `v1.0.0`): breaks shape by renaming,
|
|
39
|
+
removing, or changing types. Existing consumers should detect via
|
|
40
|
+
`spec` and refuse to parse.
|
|
41
|
+
- **Patch** is not used. If a typo lands in a description we fix it
|
|
42
|
+
in place; the shape is the contract, not the prose.
|
|
43
|
+
|
|
44
|
+
In v0, fields _will_ be added (we'll move from `v0.1.0` → `v0.2.0` when
|
|
45
|
+
we add SARIF-friendly fields, for example). The shape will not be broken
|
|
46
|
+
inside v0; breaking changes wait for v1.
|
|
47
|
+
|
|
48
|
+
## Schema details
|
|
49
|
+
|
|
50
|
+
### `drift-summary-v0.1.0`
|
|
51
|
+
|
|
52
|
+
Use this for **CI gating**. It's the smallest, most stable shape.
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"spec": "autotel-eventcatalog-drift-summary/v0.1.0",
|
|
57
|
+
"mode": "all",
|
|
58
|
+
"shouldFail": true,
|
|
59
|
+
"reason": "Drift detected in current snapshot.",
|
|
60
|
+
"counts": {
|
|
61
|
+
"observedButUndocumentedEvents": 0,
|
|
62
|
+
"documentedButUnseenEvents": 1,
|
|
63
|
+
"fieldDriftEvents": 1,
|
|
64
|
+
"fieldDriftPaths": 1,
|
|
65
|
+
"undocumentedServices": 0,
|
|
66
|
+
"undocumentedChannels": 0,
|
|
67
|
+
"total": 2
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Field-by-field:**
|
|
73
|
+
|
|
74
|
+
- `mode`: which policy was applied. `"all"` = fail on any drift in the
|
|
75
|
+
current snapshot. `"new-only"` = fail only on drift introduced
|
|
76
|
+
compared to a base snapshot. Knowing this is useful for downstream
|
|
77
|
+
consumers that want to render a different message per mode.
|
|
78
|
+
- `shouldFail`: the gating boolean. This is what your CI step ultimately
|
|
79
|
+
decides on. Always reflects the policy you asked for; the CLI's exit
|
|
80
|
+
code only differs if `--fail-on-drift` was set.
|
|
81
|
+
- `reason`: a short human-readable explanation. Suitable for Slack
|
|
82
|
+
posts, log lines, or PR status descriptions.
|
|
83
|
+
- `counts.total`: the headline number. Matches the dashboard "N
|
|
84
|
+
findings" badge: sums of all individual paths (not events).
|
|
85
|
+
- `counts.fieldDriftEvents` vs `counts.fieldDriftPaths`: the distinction
|
|
86
|
+
matters. If three events each have two extra fields, `fieldDriftEvents:
|
|
87
|
+
3` but `fieldDriftPaths: 6`.
|
|
88
|
+
|
|
89
|
+
### `stamp-summary-v0.1.0`
|
|
90
|
+
|
|
91
|
+
Use this to gate **"did this PR forget to re-stamp?"** checks.
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"spec": "autotel-eventcatalog-stamp-summary/v0.1.0",
|
|
96
|
+
"dryRun": false,
|
|
97
|
+
"attempted": 4,
|
|
98
|
+
"skipped": 0,
|
|
99
|
+
"inserts": 0,
|
|
100
|
+
"replaces": 4,
|
|
101
|
+
"changedFiles": 0,
|
|
102
|
+
"hadChanges": false
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Field-by-field:**
|
|
107
|
+
|
|
108
|
+
- `attempted`: every snapshot event the stamper considered.
|
|
109
|
+
- `skipped`: snapshot events with no matching catalog entry.
|
|
110
|
+
- `inserts` vs `replaces`: first-time stamps vs. updating an existing
|
|
111
|
+
marked block.
|
|
112
|
+
- `changedFiles` vs `replaces`: a replace might produce _identical_
|
|
113
|
+
content if the snapshot hasn't changed. `changedFiles` only counts
|
|
114
|
+
files whose bytes differ. This is the field to gate on.
|
|
115
|
+
- `hadChanges`: convenience boolean for `changedFiles > 0`. If your CI
|
|
116
|
+
has just run `stamp` and `hadChanges === true`, the PR forgot to
|
|
117
|
+
commit the freshly-stamped catalog. Fail it.
|
|
118
|
+
|
|
119
|
+
### `drift-report-v0.1.0` (the full envelope)
|
|
120
|
+
|
|
121
|
+
Use this when you need the full structured findings, not just counts.
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"spec": "autotel-eventcatalog-report/v0.1.0",
|
|
126
|
+
"mode": "all",
|
|
127
|
+
"report": {
|
|
128
|
+
"snapshotGeneratedAt": "2026-05-22T00:00:00.000Z",
|
|
129
|
+
"snapshotService": "fixture",
|
|
130
|
+
"events": {
|
|
131
|
+
"observedButUndocumented": ["order.cancelled"],
|
|
132
|
+
"documentedButUnseen": ["LegacyEvent"],
|
|
133
|
+
"fieldDrift": [
|
|
134
|
+
{
|
|
135
|
+
"event": "recommendation.generated",
|
|
136
|
+
"extra": ["personalization_seed"],
|
|
137
|
+
"missing": []
|
|
138
|
+
}
|
|
139
|
+
]
|
|
140
|
+
},
|
|
141
|
+
"services": { "observedButUndocumented": [] },
|
|
142
|
+
"channels": { "observedButUndocumented": [] }
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
When `--base-snapshot` is supplied (PR-style "what this change
|
|
148
|
+
introduces" mode), the envelope contains a `delta` instead of a `report`,
|
|
149
|
+
matching the schema's `oneOf` branch.
|
|
150
|
+
|
|
151
|
+
## Consuming the contract
|
|
152
|
+
|
|
153
|
+
### Option 1: read the spec, then trust the fields
|
|
154
|
+
|
|
155
|
+
The shortest workflow. Relies on the published schema for documentation,
|
|
156
|
+
not for runtime validation.
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
const summary = JSON.parse(readFileSync('drift-summary.json', 'utf8'));
|
|
160
|
+
if (!summary.spec?.startsWith('autotel-eventcatalog-drift-summary/v0.')) {
|
|
161
|
+
throw new Error(`Unsupported spec: ${summary.spec}`);
|
|
162
|
+
}
|
|
163
|
+
if (summary.shouldFail) {
|
|
164
|
+
await slack.post(`${summary.counts.total} drift findings on this PR.`);
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Option 2: validate with ajv (or any JSON Schema validator)
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
import Ajv from 'ajv';
|
|
172
|
+
import schema from 'autotel-eventcatalog/schemas/drift-summary-v0.1.0.json';
|
|
173
|
+
|
|
174
|
+
const ajv = new Ajv();
|
|
175
|
+
const validate = ajv.compile(schema);
|
|
176
|
+
|
|
177
|
+
const summary = JSON.parse(readFileSync('drift-summary.json', 'utf8'));
|
|
178
|
+
if (!validate(summary)) {
|
|
179
|
+
throw new Error(
|
|
180
|
+
`Drift summary failed validation: ${ajv.errorsText(validate.errors)}`,
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
The schemas use only standard JSON Schema 2020-12 features, so any
|
|
186
|
+
mainstream validator works.
|
|
187
|
+
|
|
188
|
+
### Option 3: TypeScript types from the package
|
|
189
|
+
|
|
190
|
+
If you're already in a TypeScript project, the package exports the types:
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
import type {
|
|
194
|
+
DriftReport,
|
|
195
|
+
DriftDelta,
|
|
196
|
+
DriftCounts,
|
|
197
|
+
JsonReportEnvelope,
|
|
198
|
+
} from 'autotel-eventcatalog';
|
|
199
|
+
|
|
200
|
+
function describe(report: JsonReportEnvelope): string {
|
|
201
|
+
if (report.mode === 'all') {
|
|
202
|
+
return `${report.report.events.observedButUndocumented.length} new events`;
|
|
203
|
+
}
|
|
204
|
+
return `${report.delta.introduced.events.observedButUndocumented.length} new events`;
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Consumer recipes
|
|
209
|
+
|
|
210
|
+
### A custom GitHub Action step that posts the count to Slack
|
|
211
|
+
|
|
212
|
+
```yaml
|
|
213
|
+
- uses: jagreehal/autotel-eventcatalog@v0
|
|
214
|
+
id: drift
|
|
215
|
+
with:
|
|
216
|
+
snapshot: ./services/test/snapshot.json
|
|
217
|
+
catalog: ./catalog
|
|
218
|
+
|
|
219
|
+
- name: Slack ping when drift exists
|
|
220
|
+
if: steps.drift.outputs.drift-detected == 'true'
|
|
221
|
+
run: |
|
|
222
|
+
SUMMARY=$(cat "${{ runner.temp }}/autotel-eventcatalog-summary.json")
|
|
223
|
+
COUNT=$(node -e "console.log(JSON.parse(process.argv[1]).counts.total)" "$SUMMARY")
|
|
224
|
+
curl -X POST -H 'Content-Type: application/json' \
|
|
225
|
+
-d "{\"text\":\"⚠️ ${COUNT} drift findings on PR #${{ github.event.number }}\"}" \
|
|
226
|
+
"${{ secrets.SLACK_WEBHOOK }}"
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### A nightly dashboard that polls the snapshot
|
|
230
|
+
|
|
231
|
+
Render the JSON envelope into your own UI. Validate the `spec:` field on
|
|
232
|
+
load; refuse to render anything you don't recognise.
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
const res = await fetch('https://my-runner/drift.json');
|
|
236
|
+
const envelope = await res.json();
|
|
237
|
+
if (envelope.spec !== 'autotel-eventcatalog-report/v0.1.0') {
|
|
238
|
+
return showVersionMismatchBanner(envelope.spec);
|
|
239
|
+
}
|
|
240
|
+
renderReport(envelope.report);
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### A pre-commit hook that fails when stamps are stale
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
#!/usr/bin/env bash
|
|
247
|
+
SUMMARY=$(mktemp)
|
|
248
|
+
npx autotel-eventcatalog stamp \
|
|
249
|
+
--snapshot ./services/test/snapshot.json \
|
|
250
|
+
--catalog ./catalog \
|
|
251
|
+
--summary-output "$SUMMARY"
|
|
252
|
+
HAD_CHANGES=$(jq -r .hadChanges "$SUMMARY")
|
|
253
|
+
if [ "$HAD_CHANGES" = "true" ]; then
|
|
254
|
+
echo "✗ Catalog stamp is stale. Run 'pnpm catalog:stamp' and commit."
|
|
255
|
+
exit 1
|
|
256
|
+
fi
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## What is NOT part of the contract
|
|
260
|
+
|
|
261
|
+
Things downstream consumers should _not_ depend on:
|
|
262
|
+
|
|
263
|
+
- **Stdout output** of `drift` and `stamp`. It's for humans reading
|
|
264
|
+
terminal output. Use `--output <path>` or `--summary-output <path>`
|
|
265
|
+
if you need a stable target.
|
|
266
|
+
- **Exit code beyond 0/1/2/other**. We document `0` = clean, `1` =
|
|
267
|
+
drift (with `--fail-on-drift`), `2` = bad arguments. Anything else
|
|
268
|
+
is a hard CLI error and the contract is "tell the user."
|
|
269
|
+
- **Markdown formatting details**: bullet style, exact section headings,
|
|
270
|
+
line breaks. Parse the JSON if you need structure; markdown is for
|
|
271
|
+
humans.
|
|
272
|
+
- **File paths in `StampUpdate.filePath`**. They're absolute on the
|
|
273
|
+
emitting machine. If you need stable identifiers, use `catalogId`.
|
|
274
|
+
- **Order of array elements** unless explicitly stated. Field paths in
|
|
275
|
+
`DriftCounts` are sorted; event lists are sorted by name; `fieldDrift`
|
|
276
|
+
entries are sorted by event. Anything else is implementation-defined.
|
|
277
|
+
|
|
278
|
+
If you're depending on something not listed in a schema and not
|
|
279
|
+
documented here, file an issue. We'll either bake it into the contract
|
|
280
|
+
or help you find another way.
|