@objectstack/lint 12.6.0 → 13.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/dist/index.cjs +430 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +99 -23
- package/dist/index.d.ts +99 -23
- package/dist/index.js +418 -0
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/validate-widget-bindings.ts","../src/validate-expressions.ts","../src/validate-list-view-mode.ts","../src/validate-responsive-styles.ts","../src/validate-jsx-pages.ts","../src/validate-react-pages.ts","../src/validate-react-page-props.ts","../src/validate-page-source-styling.ts","../src/validate-record-title.ts","../src/validate-semantic-roles.ts","../src/validate-form-layout.ts"],"sourcesContent":["// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { isIncoherentAggregate } from '@objectstack/spec/data';\n\n/**\n * Build-time dashboard widget binding diagnostics (issues #1719, #1721).\n *\n * Runs at `objectstack validate`/`compile`/`build` AFTER the stack has been\n * schema-parsed, so every widget's `dataset` reference can be linked to its\n * `defineDataset` and each entry in `dimensions`/`values` resolved to a\n * declared dimension/measure. This is the semantic/cross-reference phase —\n * the rules here cannot run during plain Zod parsing of the raw widget\n * literal (the dataset may even live in another package of the stack).\n *\n * Reference-integrity rules (#1721) — severity `error`, the page is broken:\n *\n * - `widget-dataset-unknown` — `dataset` does not resolve to a declared\n * `Dataset`.\n * - `widget-dimension-unknown` — a `dimensions[]` entry is not a dimension\n * name on the bound dataset.\n * - `widget-measure-unknown` — a `values[]` entry is not a measure name on\n * the bound dataset.\n * - `chart-field-unknown` — a `chartConfig` binding names a field the query\n * result will not contain: `xAxis.field` must be one of the widget's\n * dimensions (or a dataset dimension), and each `yAxis[].field` /\n * `series[].name` must be one of the widget's selected measures\n * (`values`). Post-cutover (ADR-0021) the result rows are keyed by\n * measure NAME (e.g. `sum_amount`), not the base column (`amount`) — a\n * stale base-column reference renders the axis but an empty series.\n *\n * Advisory rules — severity `warning`, build stays green:\n *\n * - `chart-config-missing` — a chart-type widget (bar/line/pie/…) has no\n * `chartConfig`, so the renderer cannot tell which measure to plot.\n * - `table-count-only` (#1719) — a `table`/`pivot` widget whose selected\n * measures are ALL `aggregate: 'count'` and which declares no\n * `dimensions` asks the analytics service for a single summary row. That\n * is the shape a `metric` widget wants — for a table it almost always\n * means the author wanted a per-record listing, which is not an\n * analytics dataset at all (model it as an object-bound ListView,\n * ADR-0017). Evaluated on the WIDGET's binding, not the dataset.\n * - `measure-aggregate-incoherent` — a dataset measure aggregates its field\n * in a way that produces a meaningless number: today, SUM (or\n * `count_distinct`) of a `percent`/rate field, whose total routinely\n * exceeds 100%. Rates must AVG. Checked once per dataset (independent of\n * any widget) when the bound object's field types are known.\n *\n * Warnings can be deliberately suppressed per widget via\n * `suppressWarnings: ['<rule-id>']`; errors cannot — they describe a\n * binding the analytics service cannot satisfy.\n */\n\nexport const WIDGET_DATASET_UNKNOWN = 'widget-dataset-unknown';\nexport const WIDGET_DIMENSION_UNKNOWN = 'widget-dimension-unknown';\nexport const WIDGET_MEASURE_UNKNOWN = 'widget-measure-unknown';\nexport const CHART_FIELD_UNKNOWN = 'chart-field-unknown';\nexport const CHART_CONFIG_MISSING = 'chart-config-missing';\nexport const TABLE_COUNT_ONLY = 'table-count-only';\nexport const MEASURE_AGGREGATE_INCOHERENT = 'measure-aggregate-incoherent';\n\nexport type WidgetBindingSeverity = 'error' | 'warning';\n\nexport interface WidgetBindingFinding {\n /** `error` = unresolvable binding (broken page); `warning` = advisory. */\n severity: WidgetBindingSeverity;\n /** Diagnostic rule id (registry entry), e.g. `widget-measure-unknown`. */\n rule: string;\n /** Human-readable location, e.g. `dashboard \"x\" › widget \"y\"`. */\n where: string;\n /** Config path, e.g. `dashboards[0].widgets[3]`. */\n path: string;\n /** What is wrong. */\n message: string;\n /** How to fix (or deliberately suppress) it. */\n hint: string;\n}\n\ntype AnyRec = Record<string, unknown>;\n\n/** Coerce a collection (array or name-keyed map) to an array. */\nfunction asArray(v: unknown): AnyRec[] {\n if (Array.isArray(v)) return v as AnyRec[];\n if (v && typeof v === 'object') {\n return Object.entries(v as AnyRec).map(([name, def]) => ({ name, ...(def as AnyRec) }));\n }\n return [];\n}\n\nfunction asStrings(v: unknown): string[] {\n return Array.isArray(v) ? v.filter((s): s is string => typeof s === 'string') : [];\n}\n\n/**\n * Chart families whose renderer needs a `chartConfig` measure mapping.\n * Single-value types (metric/kpi/gauge/…) plot their lone value and tabular\n * types (table/pivot) render every column, so they are exempt.\n */\nconst CHART_TYPES = new Set([\n 'bar', 'horizontal-bar', 'column',\n 'line', 'area',\n 'pie', 'donut', 'funnel',\n 'scatter', 'treemap', 'sankey', 'radar',\n]);\n\nfunction levenshtein(a: string, b: string): number {\n const m = a.length, n = b.length;\n let prev = Array.from({ length: n + 1 }, (_, j) => j);\n for (let i = 1; i <= m; i++) {\n const cur = [i];\n for (let j = 1; j <= n; j++) {\n cur[j] = Math.min(\n prev[j] + 1,\n cur[j - 1] + 1,\n prev[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1),\n );\n }\n prev = cur;\n }\n return prev[n];\n}\n\n/**\n * Nearest declared name for a typo'd/stale reference, or undefined when\n * nothing is close. Containment is checked first because the cutover's\n * canonical drift is base column → prefixed measure name (`amount` →\n * `sum_amount`), which is far in edit distance but obvious to a human.\n */\nfunction didYouMean(input: string, candidates: Iterable<string>): string | undefined {\n let best: string | undefined;\n let bestScore = Infinity;\n for (const c of candidates) {\n let score: number;\n if (input.length >= 3 && (c.includes(input) || input.includes(c))) {\n score = Math.abs(c.length - input.length);\n } else {\n const d = levenshtein(input, c);\n if (d > Math.max(2, Math.floor(input.length / 3))) continue;\n score = 100 + d;\n }\n if (score < bestScore) { bestScore = score; best = c; }\n }\n return best;\n}\n\nfunction suggest(input: string, candidates: Iterable<string>): string {\n const s = didYouMean(input, candidates);\n return s ? ` Did you mean \"${s}\"?` : '';\n}\n\nfunction list(names: Iterable<string>): string {\n const arr = [...names];\n return arr.length > 0 ? arr.join(', ') : '(none)';\n}\n\n/**\n * Validate every dashboard widget's dataset binding. Returns the list of\n * findings (empty = clean). Caller decides how to surface them: `error`\n * findings describe bindings the analytics service cannot satisfy and\n * should fail validate/build; `warning` findings are advisory and must\n * never fail the build on their own.\n */\nexport function validateWidgetBindings(stack: AnyRec): WidgetBindingFinding[] {\n const findings: WidgetBindingFinding[] = [];\n\n const datasets = new Map<string, AnyRec>();\n for (const ds of asArray(stack.datasets)) {\n if (typeof ds.name === 'string') datasets.set(ds.name, ds);\n }\n\n // ── (0) dataset measures aggregate their field coherently ──\n // A measure that SUMs a percentage/rate field produces a meaningless total\n // (it can exceed 100%); rates must AVG. This is a dataset-level defect (it\n // does not depend on any widget), so it is checked once over every dataset\n // whose object's field types are known. Advisory — the page still renders.\n const objectFieldTypes = new Map<string, Map<string, string>>();\n for (const o of asArray(stack.objects)) {\n if (typeof o.name !== 'string') continue;\n const fm = new Map<string, string>();\n for (const f of asArray(o.fields)) {\n if (typeof f.name === 'string' && typeof f.type === 'string') fm.set(f.name, f.type);\n }\n objectFieldTypes.set(o.name, fm);\n }\n const datasetList = asArray(stack.datasets);\n for (let i = 0; i < datasetList.length; i++) {\n const ds = datasetList[i];\n const fieldTypes = typeof ds.object === 'string' ? objectFieldTypes.get(ds.object) : undefined;\n if (!fieldTypes) continue; // cannot judge without the object's field types\n const dsMeasures = asArray(ds.measures);\n for (let k = 0; k < dsMeasures.length; k++) {\n const m = dsMeasures[k];\n const field = typeof m.field === 'string' ? m.field : undefined;\n const aggregate = typeof m.aggregate === 'string' ? m.aggregate : undefined;\n if (!field || !aggregate) continue; // count(*) and underivable measures are fine\n const ftype = fieldTypes.get(field);\n if (ftype && isIncoherentAggregate(aggregate, ftype)) {\n findings.push({\n severity: 'warning',\n rule: MEASURE_AGGREGATE_INCOHERENT,\n where: `dataset \"${typeof ds.name === 'string' ? ds.name : `(dataset ${i})`}\" › measure \"${typeof m.name === 'string' ? m.name : `(measure ${k})`}\"`,\n path: `datasets[${i}].measures[${k}]`,\n message:\n `measure \"${m.name}\" applies ${aggregate} to ${ftype} field \"${field}\" — ` +\n `summed percentages are meaningless (they can exceed 100%).`,\n hint:\n `Use aggregate \"avg\" for percentage/rate fields (or \"count\" of records). ` +\n `If a running total is genuinely intended, suppress with: ` +\n `suppressWarnings: ['${MEASURE_AGGREGATE_INCOHERENT}'] on the measure.`,\n });\n }\n }\n }\n\n const dashboards = asArray(stack.dashboards);\n for (let i = 0; i < dashboards.length; i++) {\n const dash = dashboards[i];\n const dashName = typeof dash.name === 'string' ? dash.name : `(dashboard ${i})`;\n const widgets = Array.isArray(dash.widgets) ? (dash.widgets as AnyRec[]) : [];\n\n for (let j = 0; j < widgets.length; j++) {\n const w = widgets[j];\n const widgetId = typeof w.id === 'string' ? w.id : `(widget ${j})`;\n const where = `dashboard \"${dashName}\" › widget \"${widgetId}\"`;\n const path = `dashboards[${i}].widgets[${j}]`;\n const suppressed = (rule: string): boolean =>\n Array.isArray(w.suppressWarnings) && w.suppressWarnings.includes(rule);\n const push = (f: Omit<WidgetBindingFinding, 'where' | 'path'>): void => {\n if (f.severity === 'warning' && suppressed(f.rule)) return;\n findings.push({ ...f, where, path });\n };\n\n // ── (a) dataset reference resolves ──\n const dsName = typeof w.dataset === 'string' ? w.dataset : undefined;\n const dataset = dsName ? datasets.get(dsName) : undefined;\n if (dsName && !dataset) {\n push({\n severity: 'error',\n rule: WIDGET_DATASET_UNKNOWN,\n message: `dataset \"${dsName}\" does not resolve to a declared dataset.`,\n hint:\n `Declared datasets: ${list(datasets.keys())}.${suggest(dsName, datasets.keys())} ` +\n `Define the dataset with defineDataset() or fix the reference (ADR-0021).`,\n });\n }\n // Without a resolved dataset there is nothing to check names against.\n if (!dataset) continue;\n\n const dimensionNames = new Set<string>();\n for (const d of asArray(dataset.dimensions)) {\n if (typeof d.name === 'string') dimensionNames.add(d.name);\n }\n const measures = new Map<string, AnyRec>();\n for (const m of asArray(dataset.measures)) {\n if (typeof m.name === 'string') measures.set(m.name, m);\n }\n\n // ── (b) every dimensions[] entry is a dataset dimension ──\n const dims = asStrings(w.dimensions);\n for (let k = 0; k < dims.length; k++) {\n if (dimensionNames.has(dims[k])) continue;\n push({\n severity: 'error',\n rule: WIDGET_DIMENSION_UNKNOWN,\n message:\n `dimensions[${k}] \"${dims[k]}\" is not a dimension of dataset ` +\n `\"${dsName}\" (declared dimensions: ${list(dimensionNames)}).`,\n hint:\n `Widgets select dataset dimensions BY NAME.${suggest(dims[k], dimensionNames)} ` +\n `Add the dimension to the dataset or fix the reference.`,\n });\n }\n\n // ── (c) every values[] entry is a dataset measure ──\n const values = asStrings(w.values);\n for (let k = 0; k < values.length; k++) {\n if (measures.has(values[k])) continue;\n push({\n severity: 'error',\n rule: WIDGET_MEASURE_UNKNOWN,\n message:\n `values[${k}] \"${values[k]}\" is not a measure of dataset ` +\n `\"${dsName}\" (declared measures: ${list(measures.keys())}).`,\n hint:\n `Widgets select dataset measures BY NAME, not by base column.` +\n `${suggest(values[k], measures.keys())} ` +\n `Add the measure to the dataset or fix the reference.`,\n });\n }\n\n // ── (d) chartConfig bindings resolve against the widget's selection ──\n const chartConfig = (w.chartConfig && typeof w.chartConfig === 'object')\n ? (w.chartConfig as AnyRec)\n : undefined;\n const isChartType = typeof w.type === 'string' && CHART_TYPES.has(w.type);\n\n if (chartConfig) {\n // The query result carries the widget's selected dimensions and\n // measures; resolve every chartConfig field against that shape.\n const selectedValues = new Set(values.filter((v) => measures.has(v)));\n\n const xAxis = (chartConfig.xAxis && typeof chartConfig.xAxis === 'object')\n ? (chartConfig.xAxis as AnyRec)\n : undefined;\n // A field naming an entry of the widget's own (already-validated)\n // selection is not re-reported here — rules (b)/(c) own that error.\n if (xAxis && typeof xAxis.field === 'string'\n && !dimensionNames.has(xAxis.field) && !dims.includes(xAxis.field)) {\n push({\n severity: 'error',\n rule: CHART_FIELD_UNKNOWN,\n message:\n `chartConfig.xAxis.field \"${xAxis.field}\" does not resolve to a ` +\n `dimension of dataset \"${dsName}\" (declared dimensions: ${list(dimensionNames)}).`,\n hint: `Point xAxis.field at a dataset dimension name.${suggest(xAxis.field, dimensionNames)}`,\n });\n }\n\n const measureField = (label: string, field: string): void => {\n if (values.includes(field)) return; // resolvable, or already errored via rule (c)\n const declaredButUnselected = measures.has(field);\n push({\n severity: 'error',\n rule: CHART_FIELD_UNKNOWN,\n message: declaredButUnselected\n ? `chartConfig.${label} \"${field}\" is a measure of dataset \"${dsName}\" ` +\n `but is not selected in the widget's values (${list(values)}), so the ` +\n `query result will not contain it.`\n : `chartConfig.${label} \"${field}\" does not resolve to a measure of ` +\n `dataset \"${dsName}\" (declared measures: ${list(measures.keys())}).`,\n hint: declaredButUnselected\n ? `Add \"${field}\" to the widget's values, or bind the chart to a selected measure.`\n : `Post-cutover data is keyed by the dataset's measure NAME, not the ` +\n `base column.${suggest(field, selectedValues.size > 0 ? selectedValues : measures.keys())}`,\n });\n };\n\n const yAxes = Array.isArray(chartConfig.yAxis) ? (chartConfig.yAxis as AnyRec[]) : [];\n for (let k = 0; k < yAxes.length; k++) {\n const field = yAxes[k]?.field;\n if (typeof field === 'string') measureField(`yAxis[${k}].field`, field);\n }\n const series = Array.isArray(chartConfig.series) ? (chartConfig.series as AnyRec[]) : [];\n for (let k = 0; k < series.length; k++) {\n const name = series[k]?.name;\n if (typeof name === 'string') measureField(`series[${k}].name`, name);\n }\n } else if (isChartType) {\n push({\n severity: 'warning',\n rule: CHART_CONFIG_MISSING,\n message:\n `chart-type widget ('${w.type}') has no chartConfig — the renderer ` +\n `cannot determine which measure to plot, so the series renders empty.`,\n hint:\n `Add chartConfig with xAxis.field set to a dimension (${list(dims)}) and ` +\n `yAxis[].field set to a measure name (${list(values)}). If the default ` +\n `rendering is intentional, suppress with: suppressWarnings: ['${CHART_CONFIG_MISSING}']`,\n });\n }\n\n // ── (e) table/pivot bound to a count-only, dimensionless selection ──\n if (w.type !== 'table' && w.type !== 'pivot') continue;\n // Grouped by at least one dimension → genuinely aggregated rows.\n if (dims.length > 0) continue;\n if (values.length === 0) continue;\n const resolved = values.map((v) => measures.get(v));\n // An unresolvable measure name already errored above — don't guess here.\n if (resolved.some((m) => !m)) continue;\n\n // Derived measures combine other measures; treat them as non-count even\n // when their (ignored) `aggregate` says otherwise.\n const countOnly = resolved.every((m) => m!.aggregate === 'count' && !m!.derived);\n if (!countOnly) continue;\n\n push({\n severity: 'warning',\n rule: TABLE_COUNT_ONLY,\n message:\n `a '${w.type}' widget bound to dataset \"${dsName}\" selects only count ` +\n `measure(s) (${values.join(', ')}) and no dimensions, so it renders a ` +\n `single summary row — not a per-record list.`,\n hint:\n `A flat record listing is not an analytics dataset. Model it as an ` +\n `object-bound ListView (ADR-0017) surfaced through app navigation, and ` +\n `use a 'metric' widget here if you only need the count. If a single-row ` +\n `table is intentional, add an explicit dimension or suppress with: ` +\n `suppressWarnings: ['${TABLE_COUNT_ONLY}']`,\n });\n }\n }\n\n return findings;\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Build-time expression validation (ADR-0032 §Decision 1a + 1b).\n *\n * Runs at `objectstack compile`, where the whole normalized stack is in hand —\n * so flow conditions can be checked against the *resolved* object schema\n * (field existence) in addition to CEL syntax. Uses the one shared validator\n * from `@objectstack/formula`, so the verdict matches `registerFlow` and the\n * agent `validate_expression` tool exactly.\n *\n * Scope (v1): flow predicates (start/decision `config.condition` + edge\n * `condition`), object validation-rule / formula predicates, and UI action\n * `visible` / `disabled` predicates. Each error is located (flow/object/action\n * + node/edge/field) with a corrective message.\n */\n\nimport { validateExpression } from '@objectstack/formula';\n\nexport interface ExprIssue {\n where: string;\n message: string;\n source: string;\n /**\n * `error` fails the build (e.g. a bare ref in a record-scoped formula). `warning`\n * is advisory and never fails it (e.g. a possible field typo in a flattened flow\n * condition, which might be a flow variable). Absent ⇒ treat as `error`.\n */\n severity?: 'error' | 'warning';\n}\n\ntype AnyRec = Record<string, unknown>;\n\n/** Coerce an `objects` collection (array or name-keyed map) to an array. */\nfunction asArray(v: unknown): AnyRec[] {\n if (Array.isArray(v)) return v as AnyRec[];\n if (v && typeof v === 'object') {\n return Object.entries(v as AnyRec).map(([name, def]) => ({ name, ...(def as AnyRec) }));\n }\n return [];\n}\n\n/** object name → set of its field names, for schema-aware field checks. */\nfunction buildFieldIndex(objects: AnyRec[]): Map<string, string[]> {\n const idx = new Map<string, string[]>();\n for (const obj of objects) {\n const name = typeof obj.name === 'string' ? obj.name : undefined;\n if (!name) continue;\n const fields = obj.fields;\n let names: string[] = [];\n if (Array.isArray(fields)) names = fields.map(f => (f as AnyRec).name).filter((n): n is string => typeof n === 'string');\n else if (fields && typeof fields === 'object') names = Object.keys(fields as AnyRec);\n idx.set(name, names);\n }\n return idx;\n}\n\n/**\n * Validate every predicate in the stack. Returns the list of issues (empty =\n * clean). Caller decides how to surface / whether to fail the build.\n */\nexport function validateStackExpressions(stack: AnyRec): ExprIssue[] {\n const issues: ExprIssue[] = [];\n const objects = asArray(stack.objects);\n const fieldIndex = buildFieldIndex(objects);\n\n const check = (\n where: string,\n raw: unknown,\n objectName?: string,\n scope: 'record' | 'flattened' = 'flattened',\n ): void => {\n if (raw == null) return;\n const fields = objectName ? fieldIndex.get(objectName) : undefined;\n const res = validateExpression('predicate', raw as string | { dialect?: string; source?: string },\n objectName ? { objectName, fields, scope } : { scope });\n for (const e of res.errors) issues.push({ where, message: e.message, source: e.source, severity: 'error' });\n for (const w of res.warnings) issues.push({ where, message: w.message, source: w.source, severity: 'warning' });\n };\n\n // ── Flows ──────────────────────────────────────────────────────────\n for (const flow of asArray(stack.flows)) {\n const flowName = typeof flow.name === 'string' ? flow.name : '(unnamed flow)';\n const nodes = Array.isArray(flow.nodes) ? (flow.nodes as AnyRec[]) : [];\n const edges = Array.isArray(flow.edges) ? (flow.edges as AnyRec[]) : [];\n // The record-change target object — `record.*` refs resolve against it.\n const startNode = nodes.find(n => n.type === 'start');\n const startCfg = (startNode?.config ?? {}) as AnyRec;\n const objectName = typeof startCfg.objectName === 'string' ? startCfg.objectName : undefined;\n\n for (const node of nodes) {\n const cfg = (node.config ?? {}) as AnyRec;\n check(`flow '${flowName}' · node '${node.id}' (${node.type}) condition`, cfg.condition, objectName);\n // #1870 — a `script` node must declare a callable target (`actionType` or\n // `function`). A node with neither is a silent no-op that otherwise passes\n // build. (Function *existence* isn't checkable here — functions are code,\n // not serialized into the artifact — so this is a structural check; the\n // runtime verifies the named function is actually registered.)\n if (node.type === 'script') {\n // `function` is canonical; `functionName` is an accepted alias.\n const fn =\n (typeof cfg.function === 'string' ? cfg.function.trim() : '') ||\n (typeof cfg.functionName === 'string' ? cfg.functionName.trim() : '');\n const action = typeof cfg.actionType === 'string' ? cfg.actionType.trim() : '';\n // Inline `config.script` (a JS body) is also a declared form — the\n // built-in runtime doesn't execute it (warned at run time), but the node\n // is not the empty no-op this check targets, so don't flag it.\n const inline = typeof cfg.script === 'string' ? cfg.script.trim() : '';\n if (!fn && !action && !inline) {\n issues.push({\n where: `flow '${flowName}' · node '${node.id}' (script) callable`,\n message:\n `script node declares neither \\`actionType\\` nor \\`function\\` — it would do nothing at runtime. ` +\n `Name a built-in action (e.g. \\`actionType: 'email'\\`) or a registered function ` +\n `(\\`function: 'my_fn'\\`, registered via \\`defineStack({ functions })\\`).`,\n source: JSON.stringify({ id: node.id, type: node.type, config: cfg }),\n });\n } else if (action === 'invoke_function' && !fn) {\n // `actionType: 'invoke_function'` is a marker that names no callable on\n // its own — the function name must be in `function`/`functionName`.\n issues.push({\n where: `flow '${flowName}' · node '${node.id}' (script) callable`,\n message:\n `script node uses \\`actionType: 'invoke_function'\\` but no \\`function\\` (or \\`functionName\\`) — ` +\n `it names no callable. Set \\`function: 'my_fn'\\` and register it via \\`defineStack({ functions })\\`.`,\n source: JSON.stringify({ id: node.id, type: node.type, config: cfg }),\n });\n }\n }\n }\n for (const edge of edges) {\n check(`flow '${flowName}' · edge '${edge.id}' (${edge.source}→${edge.target}) condition`, edge.condition, objectName);\n }\n }\n\n // ── Object validation-rule + formula predicates ────────────────────\n for (const obj of objects) {\n const objectName = typeof obj.name === 'string' ? obj.name : undefined;\n const validations = obj.validations ?? obj.validationRules;\n for (const rule of asArray(validations)) {\n const where = `object '${objectName}' · validation '${(rule.name as string) ?? '?'}'`;\n // Common predicate keys across rule shapes. Validation predicates are\n // `record`-scoped — no field flattening — so bare refs are flagged (#1928).\n check(where, rule.expression ?? rule.predicate ?? rule.condition ?? rule.formula, objectName, 'record');\n // `conditional` rules carry a nested `when` predicate (record-scoped).\n check(`${where} when`, (rule as AnyRec).when, objectName, 'record');\n }\n // Field-level formulas (computed fields) reference the same object.\n const fields = obj.fields;\n const fieldList = Array.isArray(fields)\n ? (fields as AnyRec[])\n : (fields && typeof fields === 'object' ? Object.values(fields as AnyRec) as AnyRec[] : []);\n\n // ── ADR-0062 D7 — reject `field.columnName` on external objects ──────\n // `field.columnName` (localField → physicalColumn) is the managed-object\n // mechanism; it is NOT applied by the driver's query pipeline for federated\n // objects, where `external.columnMap` (remoteColumn → localField) is the\n // authoritative — and inverse — mapping. Allowing both would be a silent\n // dual-source ambiguity, so reject `columnName` on any object that declares\n // an `external` binding (a federated object). Managed objects are untouched.\n if (obj.external != null) {\n const fieldEntries: Array<[string, AnyRec]> = Array.isArray(fields)\n ? (fields as AnyRec[]).map((f) => [((f as AnyRec)?.name as string) ?? '?', f as AnyRec])\n : (fields && typeof fields === 'object'\n ? (Object.entries(fields as AnyRec) as Array<[string, AnyRec]>)\n : []);\n for (const [fname, fdef] of fieldEntries) {\n if (fdef && typeof fdef === 'object' && (fdef as AnyRec).columnName != null) {\n issues.push({\n where: `object '${objectName}' · field '${fname}'`,\n message:\n `external object '${objectName}': field '${fname}' sets columnName='${String((fdef as AnyRec).columnName)}', ` +\n `which is not supported on federated objects (ADR-0062 D7). The driver's query pipeline ignores ` +\n `field.columnName for external objects; map remote columns via the datasource's external.columnMap instead.`,\n source: `columnName='${String((fdef as AnyRec).columnName)}'`,\n severity: 'error',\n });\n }\n }\n }\n\n for (const f of fieldList) {\n // Field-level conditional rules are server-enforced (rule-validator) and\n // record-scoped — a bare ref silently fails the rule (required/readonly\n // not enforced = data-integrity hole). #1928 class, same as actions.\n if (f && typeof f === 'object') {\n const fname = (f.name as string) ?? '?';\n for (const key of ['requiredWhen', 'readonlyWhen', 'conditionalRequired', 'visibleWhen'] as const) {\n check(`object '${objectName}' · field '${fname}' ${key}`, (f as AnyRec)[key], objectName, 'record');\n }\n }\n if (f && typeof f === 'object' && f.formula) {\n // formulas are `value` role (any return type), still CEL. They are\n // `record`-scoped — `record.<field>`, never bare — so flag bare refs (#1928).\n const res = validateExpression('value', f.formula as string | { dialect?: string; source?: string },\n objectName ? { objectName, fields: fieldIndex.get(objectName), scope: 'record' } : { scope: 'record' });\n const fieldWhere = `object '${objectName}' · field '${(f.name as string) ?? '?'}' formula`;\n for (const e of res.errors) issues.push({ where: fieldWhere, message: e.message, source: e.source, severity: 'error' });\n for (const w of res.warnings) issues.push({ where: fieldWhere, message: w.message, source: w.source, severity: 'warning' });\n }\n }\n }\n\n // ── Action `visible` / `disabled` predicates ───────────────────────\n // Record-scoped, same as validation rules: a record-header / row action's\n // `visible` is evaluated by ActionEngine against `{ record, recordId,\n // objectName, user, … }` with fail-closed semantics, so a BARE field ref\n // (`done` instead of `record.done`) throws and the action is silently hidden\n // on every record (the trap behind the #2183 \"Mark Done never hides\" hunt).\n // Flagging it here turns that into a build error with a corrective message.\n // `disabled` may be a boolean (skip) or a predicate (check).\n const seenActions = new Set<string>();\n const checkAction = (where: string, action: AnyRec, objectName?: string): void => {\n const obj = objectName\n ?? (typeof action.objectName === 'string' ? action.objectName : undefined)\n ?? (typeof action.object === 'string' ? action.object : undefined);\n const name = typeof action.name === 'string' ? action.name : '?';\n const key = `${obj ?? ''}:${name}`;\n if (seenActions.has(key)) return; // de-dup (actions are merged onto objects AND kept top-level)\n seenActions.add(key);\n check(`${where} · action '${name}' visible`, action.visible, obj, 'record');\n if (typeof action.disabled !== 'boolean') {\n check(`${where} · action '${name}' disabled`, action.disabled, obj, 'record');\n }\n };\n for (const action of asArray(stack.actions)) {\n checkAction('stack', action);\n }\n for (const obj of objects) {\n const objectName = typeof obj.name === 'string' ? obj.name : undefined;\n for (const action of asArray(obj.actions)) {\n checkAction(`object '${objectName}'`, action, objectName);\n }\n }\n\n // ── Sharing-rule predicates (security-critical, record-scoped) ─────\n // A criteria sharing rule's `condition` decides which rows a principal sees.\n // It is evaluated against the record, so a bare ref silently changes access.\n for (const rule of asArray(stack.sharingRules)) {\n const ruleObj = typeof rule.object === 'string' ? rule.object : undefined;\n const where = `sharingRule '${(rule.name as string) ?? '?'}'${ruleObj ? ` (${ruleObj})` : ''} condition`;\n check(where, rule.condition ?? rule.criteria ?? rule.predicate, ruleObj, 'record');\n }\n\n // ── Hook `condition` predicates (record-scoped gate) ───────────────\n // A lifecycle hook's `condition` skips the handler when false; it is\n // evaluated against the record, so a bare ref silently makes the hook\n // run on every record (or never) instead of the intended subset.\n for (const hook of asArray(stack.hooks)) {\n const hookObj = typeof hook.object === 'string' ? hook.object : undefined; // array targets → no single field set\n check(`hook '${(hook.name as string) ?? '?'}'${hookObj ? ` (${hookObj})` : ''} condition`, hook.condition, hookObj, 'record');\n }\n\n return issues;\n}\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n//\n// Build-time guardrail for ADR-0047 list-view navigation modes.\n//\n// A pure `(stack) => Finding[]` rule (ADR-0019), run from `os validate` and\n// reusable by AI authoring. It catches the \"wrong context\" authoring mistake\n// the type system alone cannot surface at author time on an object list view\n// (\"views\" mode — where the ViewTabBar owns the tab-bar role):\n// - `quickFilters` — never valid on an object list view;\n// - `userFilters` with `element: 'tabs'` (or carrying `tabs`) — the tab-bar\n// preset style is page-only; it would collide with the ViewTabBar.\n// A `dropdown` (value-chip) `userFilters` IS allowed on object views since the\n// ADR-0047 amendment (framework #2679 / objectui #2338) and is NOT flagged.\n//\n// Runs PRE-parse (on the normalizeStackInput output, before the\n// ObjectStackDefinition parse): the object-list schema (ObjectListViewSchema)\n// narrows `userFilters` to ObjectUserFiltersSchema (dropdown/toggle only), so a\n// post-parse stack has already had a `tabs` user-filter stripped and this rule\n// would never see it. The layering is deliberate — tsc rejects it at author\n// time, the schema strips it at runtime (no throw, back-compat), and this rule\n// reports it at `os validate` with a fix hint. See objectui #2338 and ADR-0047.\n\nexport type ListViewModeSeverity = 'error' | 'warning';\n\nexport interface ListViewModeFinding {\n severity: ListViewModeSeverity;\n rule: string;\n /** Human-readable location, e.g. `object \"task\" › listViews.my_pending`. */\n where: string;\n /** Config path, e.g. `objects[0].listViews.my_pending.userFilters`. */\n path: string;\n message: string;\n hint: string;\n}\n\n// Rule id (registry entry).\nexport const LIST_VIEW_FILTERS_IN_VIEWS_MODE = 'list-view-filters-in-views-mode';\n\ntype AnyRec = Record<string, unknown>;\n\n/** Coerce an array-or-name-keyed-map collection to an array (name injected). */\nfunction asArray(v: unknown): AnyRec[] {\n if (Array.isArray(v)) return v as AnyRec[];\n if (v && typeof v === 'object') {\n return Object.entries(v as AnyRec).map(([name, def]) => ({\n name,\n ...(def as AnyRec),\n }));\n }\n return [];\n}\n\n/** Emit a finding for each wrong-context filter control on a single list-view def. */\nfunction scanView(\n view: unknown,\n where: string,\n path: string,\n out: ListViewModeFinding[],\n): void {\n if (!view || typeof view !== 'object') return;\n const rec = view as AnyRec;\n\n // `quickFilters` is never valid on an object list view.\n if (rec.quickFilters != null) {\n out.push({\n severity: 'error',\n rule: LIST_VIEW_FILTERS_IN_VIEWS_MODE,\n where,\n path: `${path}.quickFilters`,\n message:\n '`quickFilters` is a page filters-mode control and is ignored on an object ' +\n 'list view (\"views\" mode) — the ViewTabBar owns nav here.',\n hint:\n 'Move `quickFilters` to a page list (InterfaceListPage, \"filters\" mode), or ' +\n 'remove it. See ADR-0047.',\n });\n }\n\n // `userFilters` is allowed on object views ONLY as `dropdown` (value chips).\n // The `tabs` preset style — or any `userFilters` carrying `tabs` — collides\n // with the ViewTabBar and stays page-only.\n const uf = rec.userFilters;\n if (uf && typeof uf === 'object') {\n const ufRec = uf as AnyRec;\n if (ufRec.element === 'tabs' || ufRec.tabs != null) {\n out.push({\n severity: 'error',\n rule: LIST_VIEW_FILTERS_IN_VIEWS_MODE,\n where,\n path: `${path}.userFilters`,\n message:\n '`userFilters` with `element: \"tabs\"` is page-only and is ignored on an ' +\n 'object list view (\"views\" mode) — it would collide with the ViewTabBar.',\n hint:\n 'Use `listViews` for named presets on an object (each becomes a segmented ' +\n 'tab), switch to `element: \"dropdown\"` for value chips, or move the `tabs` ' +\n 'filter to a page list (InterfaceListPage, \"filters\" mode). See ADR-0047.',\n });\n }\n }\n}\n\n/** Scan a `listViews` record (name → list-view def). */\nfunction scanListViews(\n listViews: unknown,\n wherePrefix: string,\n pathPrefix: string,\n out: ListViewModeFinding[],\n): void {\n if (!listViews || typeof listViews !== 'object') return;\n for (const [name, view] of Object.entries(listViews as AnyRec)) {\n scanView(\n view,\n `${wherePrefix} › listViews.${name}`,\n `${pathPrefix}.listViews.${name}`,\n out,\n );\n }\n}\n\n/**\n * Flag ADR-0047 \"views\" mode violations on an object's built-in named views or a\n * `defineView` default `list` / named `listViews`: `quickFilters`, or a `tabs`\n * `userFilters`. A `dropdown` `userFilters` is allowed and not flagged. Returns\n * the list of findings (empty = clean). Caller decides how to surface / whether\n * to fail the build.\n *\n * Feed the PRE-parse stack (normalizeStackInput output) — see file header.\n */\nexport function validateListViewMode(stack: AnyRec): ListViewModeFinding[] {\n const out: ListViewModeFinding[] = [];\n\n // Object built-in named views (object.zod.ts `listViews`).\n asArray(stack.objects).forEach((obj, i) => {\n const label = typeof obj.name === 'string' ? `object \"${obj.name}\"` : `objects[${i}]`;\n scanListViews(obj.listViews, label, `objects[${i}]`, out);\n });\n\n // `defineView` aggregates (stack `views`: default `list` + named `listViews`).\n asArray(stack.views).forEach((view, i) => {\n const named =\n typeof view.objectName === 'string'\n ? view.objectName\n : typeof view.name === 'string'\n ? view.name\n : undefined;\n const label = named ? `view \"${named}\"` : `views[${i}]`;\n scanView(view.list, `${label} › list`, `views[${i}].list`, out);\n scanListViews(view.listViews, label, `views[${i}]`, out);\n });\n\n return out;\n}\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n//\n// Build-time diagnostics for the SDUI scoped-styling model (ADR-0065).\n//\n// A pure `(stack) => Finding[]` rule (ADR-0019): the same bar holds for\n// hand-authored and AI-generated pages, run from `os validate`/`compile` and\n// reusable by AI authoring. It catches the deterministic ways a `responsiveStyles`\n// block silently fails or drifts — the class of mistake an AI author is most\n// likely to make — *before* render, with actionable hints it can self-correct on.\n//\n// What it does NOT catch: whether the result looks good. Visual/semantic quality\n// (contrast, balance, \"is it ugly\") is only catchable by rendering + a VLM gate,\n// which is a separate, render-time concern (ADR-0065 §Decision-5).\n\nexport type StyleSeverity = 'error' | 'warning';\n\nexport interface StyleFinding {\n severity: StyleSeverity;\n rule: string;\n /** Human-readable location, e.g. `page \"pricing\" › node \"plan_solo\"`. */\n where: string;\n /** Config path, e.g. `pages[0].regions[0].components[1]`. */\n path: string;\n message: string;\n hint: string;\n}\n\n// Rule ids (registry entries).\nexport const STYLE_NODE_MISSING_ID = 'style-node-missing-id';\nexport const STYLE_CLASSNAME_TAILWIND = 'style-classname-tailwind';\nexport const STYLE_RESPONSIVE_NO_BASE = 'style-responsive-no-base';\nexport const STYLE_UNKNOWN_CSS_PROPERTY = 'style-unknown-css-property';\nexport const STYLE_UNKNOWN_TOKEN = 'style-unknown-token';\n\ntype AnyRec = Record<string, unknown>;\n\nconst BREAKPOINTS = ['large', 'medium', 'small', 'xsmall'] as const;\n\n/** SDUI design-token palette (ADR-0065) + base theme tokens, referenced as\n * `var(--name)`. Authors should resolve values against these. Kept in sync with\n * `apps/console/src/index.css` / `@object-ui/components` `:root`. */\nconst KNOWN_TOKENS = new Set<string>([\n // SDUI tokens\n 'space-1', 'space-2', 'space-3', 'space-4', 'space-5', 'space-6', 'space-8', 'space-10', 'space-12',\n 'radius', 'radius-sm', 'radius-md', 'radius-lg', 'radius-xl',\n 'shadow-sm', 'shadow-md', 'shadow-lg',\n 'surface', 'surface-sunken', 'text-strong', 'text-muted', 'brand', 'brand-foreground', 'hairline',\n // Base theme tokens (shadcn) — usually wrapped as hsl(var(--x)).\n 'background', 'foreground', 'card', 'card-foreground', 'popover', 'popover-foreground',\n 'primary', 'primary-foreground', 'secondary', 'secondary-foreground',\n 'muted', 'muted-foreground', 'accent', 'accent-foreground',\n 'destructive', 'destructive-foreground', 'border', 'input', 'ring',\n 'success', 'success-foreground', 'warning', 'warning-foreground',\n 'chart-1', 'chart-2', 'chart-3', 'chart-4', 'chart-5',\n]);\n\n/** Common CSS properties (camelCase) an SDUI block realistically sets. Generous\n * on purpose: an unknown property is only a *warning* (typo catcher), never a\n * blocker. Custom properties (`--x`) are always allowed. */\nconst KNOWN_CSS_PROPERTIES = new Set<string>([\n 'display', 'position', 'top', 'right', 'bottom', 'left', 'inset', 'zIndex', 'overflow', 'overflowX', 'overflowY', 'visibility', 'boxSizing', 'float', 'clear',\n 'width', 'height', 'minWidth', 'minHeight', 'maxWidth', 'maxHeight', 'aspectRatio',\n 'margin', 'marginTop', 'marginRight', 'marginBottom', 'marginLeft', 'marginInline', 'marginBlock',\n 'padding', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft', 'paddingInline', 'paddingBlock',\n 'flex', 'flexDirection', 'flexWrap', 'flexGrow', 'flexShrink', 'flexBasis', 'alignItems', 'alignContent', 'alignSelf', 'justifyContent', 'justifyItems', 'justifySelf', 'gap', 'rowGap', 'columnGap', 'order', 'placeItems', 'placeContent',\n 'grid', 'gridTemplate', 'gridTemplateColumns', 'gridTemplateRows', 'gridTemplateAreas', 'gridColumn', 'gridRow', 'gridArea', 'gridAutoFlow', 'gridAutoColumns', 'gridAutoRows',\n 'color', 'backgroundColor', 'background', 'backgroundImage', 'backgroundSize', 'backgroundPosition', 'backgroundRepeat', 'backgroundClip', 'opacity', 'mixBlendMode',\n 'fontSize', 'fontWeight', 'fontFamily', 'fontStyle', 'lineHeight', 'letterSpacing', 'textAlign', 'textTransform', 'textDecoration', 'textOverflow', 'whiteSpace', 'wordBreak', 'overflowWrap', 'fontVariantNumeric', 'verticalAlign', 'textShadow',\n 'border', 'borderTop', 'borderRight', 'borderBottom', 'borderLeft', 'borderColor', 'borderWidth', 'borderStyle', 'borderRadius', 'borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomLeftRadius', 'borderBottomRightRadius', 'outline', 'outlineOffset',\n 'boxShadow', 'transform', 'transformOrigin', 'transition', 'transitionProperty', 'transitionDuration', 'transitionTimingFunction', 'transitionDelay', 'animation', 'filter', 'backdropFilter', 'willChange',\n 'cursor', 'pointerEvents', 'userSelect', 'objectFit', 'objectPosition', 'content',\n]);\n\nconst VAR_RE = /var\\(\\s*--([a-zA-Z0-9-]+)\\s*[,)]/g;\n\n// High-precision Tailwind-utility detection. A `className` in page metadata is\n// \"Tailwind-looking\" if any token is a responsive/state variant, an arbitrary\n// `[…]` value, a known utility stem followed by a Tailwind *value* (number /\n// fraction / size keyword), or a bare layout utility. Tuned to NOT trip on\n// ordinary custom class names (e.g. `my-custom-scope`, `os-s-plan_solo`).\nconst TW_VARIANT = /^(sm|md|lg|xl|2xl|hover|focus|active|disabled|dark|group-hover|peer-[a-z]+|first|last|odd|even):/;\nconst TW_STEM_VALUE = /^-?(p|m|px|py|pt|pb|pl|pr|mx|my|mt|mb|ml|mr|gap|gap-x|gap-y|space-x|space-y|w|h|min-w|max-w|min-h|max-h|size|text|leading|tracking|bg|border|rounded|shadow|ring|opacity|inset|top|bottom|left|right|z|order|col|row|grid-cols|grid-rows|basis)-(\\d+(\\.\\d+)?|\\d+\\/\\d+|px|full|auto|none|screen|min|max|fit|xs|sm|md|lg|xl|2xl|3xl|4xl|5xl|6xl)$/;\nconst TW_BARE = /^(flex|grid|block|inline|inline-block|inline-flex|hidden|contents|table|flow-root|grow|shrink|truncate|italic|underline|uppercase|lowercase|capitalize|antialiased|absolute|relative|fixed|sticky|static|isolate|flex-col|flex-row|flex-wrap|flex-nowrap|items-center|items-start|items-end|items-stretch|justify-center|justify-between|justify-around|justify-start|justify-end|text-center|text-left|text-right|font-bold|font-semibold|font-medium|font-normal|tabular-nums)$/;\n\nfunction looksLikeTailwind(className: string): boolean {\n return className.split(/\\s+/).some((tok) => {\n if (!tok) return false;\n if (TW_VARIANT.test(tok)) return true;\n if (/\\[[^\\]]+\\]/.test(tok)) return true; // arbitrary value, e.g. p-[13px]\n if (TW_STEM_VALUE.test(tok)) return true;\n if (TW_BARE.test(tok)) return true;\n return false;\n });\n}\n\nfunction asArray(v: unknown): AnyRec[] {\n if (Array.isArray(v)) return v as AnyRec[];\n if (v && typeof v === 'object') {\n return Object.entries(v as AnyRec).map(([name, def]) => ({ name, ...(def as AnyRec) }));\n }\n return [];\n}\n\n/** Child nodes can hang off `children`, `properties.children`, `body`, or\n * `properties.body` depending on block type — collect them all. */\nfunction childrenOf(node: AnyRec): AnyRec[] {\n const props = (node.properties as AnyRec) ?? {};\n const out: AnyRec[] = [];\n for (const c of [node.children, props.children, node.body, props.body]) {\n if (Array.isArray(c)) out.push(...(c.filter((x) => x && typeof x === 'object') as AnyRec[]));\n }\n return out;\n}\n\nfunction checkNode(node: AnyRec, pageName: string, path: string, findings: StyleFinding[]): void {\n const id = typeof node.id === 'string' ? node.id : undefined;\n const type = typeof node.type === 'string' ? node.type : 'node';\n const where = `page \"${pageName}\" › ${id ? `node \"${id}\"` : `<${type}>`}`;\n const rs = node.responsiveStyles as AnyRec | undefined;\n const hasRs = !!rs && typeof rs === 'object' && BREAKPOINTS.some((b) => rs[b]);\n\n // (1) responsiveStyles needs an id to scope to — else the CSS is dropped.\n if (hasRs && !id) {\n findings.push({\n severity: 'error', rule: STYLE_NODE_MISSING_ID, where, path,\n message: `Node has responsiveStyles but no \\`id\\`; scoped CSS cannot be generated and the styles are silently dropped.`,\n hint: `Add a stable \\`id\\` to this node.`,\n });\n }\n\n // (2) responsive breakpoint without a `large` base → unstyled at desktop.\n if (hasRs && !rs!.large && BREAKPOINTS.slice(1).some((b) => rs![b])) {\n findings.push({\n severity: 'warning', rule: STYLE_RESPONSIVE_NO_BASE, where, path,\n message: `responsiveStyles sets a smaller breakpoint but no \\`large\\` base; the node is unstyled at desktop width.`,\n hint: `Put the unconditional/base styles under \\`responsiveStyles.large\\` (desktop-first).`,\n });\n }\n\n // (3) className that looks like Tailwind → won't render from metadata.\n if (typeof node.className === 'string' && node.className.trim() && looksLikeTailwind(node.className)) {\n findings.push({\n severity: 'warning', rule: STYLE_CLASSNAME_TAILWIND, where, path,\n message: `\\`className\\` contains Tailwind-looking utilities (\"${node.className.trim().slice(0, 60)}\"); these are not compiled from metadata and will silently do nothing.`,\n hint: `Style this node with \\`responsiveStyles\\` + design tokens instead of \\`className\\` (ADR-0065).`,\n });\n }\n\n // (4)+(5) unknown CSS property / unknown token inside each breakpoint map.\n if (rs && typeof rs === 'object') {\n for (const bp of BREAKPOINTS) {\n const map = rs[bp] as AnyRec | undefined;\n if (!map || typeof map !== 'object') continue;\n for (const [prop, value] of Object.entries(map)) {\n if (!prop.startsWith('--') && !KNOWN_CSS_PROPERTIES.has(prop)) {\n findings.push({\n severity: 'warning', rule: STYLE_UNKNOWN_CSS_PROPERTY, where, path: `${path}.responsiveStyles.${bp}`,\n message: `Unknown CSS property \"${prop}\" (typo?); if unintended it will not apply.`,\n hint: `Use a camelCase CSS property name (e.g. \\`flexDirection\\`, \\`backgroundColor\\`).`,\n });\n }\n if (typeof value === 'string') {\n let m: RegExpExecArray | null;\n VAR_RE.lastIndex = 0;\n while ((m = VAR_RE.exec(value))) {\n const token = m[1];\n if (!KNOWN_TOKENS.has(token) && !token.startsWith('tw-')) {\n findings.push({\n severity: 'warning', rule: STYLE_UNKNOWN_TOKEN, where, path: `${path}.responsiveStyles.${bp}.${prop}`,\n message: `References unknown design token \\`var(--${token})\\` (typo?); it will not resolve.`,\n hint: `Use a token from the ADR-0065 palette (e.g. \\`var(--space-6)\\`, \\`var(--surface)\\`, \\`hsl(var(--primary))\\`).`,\n });\n }\n }\n }\n }\n }\n }\n\n // Recurse.\n const kids = childrenOf(node);\n for (let i = 0; i < kids.length; i++) {\n checkNode(kids[i], pageName, `${path}.children[${i}]`, findings);\n }\n}\n\n/**\n * Validate every page's component tree for SDUI styling correctness (ADR-0065).\n * Returns findings (empty = clean). `error` findings describe styles that are\n * silently dropped and should fail validate/build; `warning` findings are\n * advisory (typos, drift, footguns).\n */\nexport function validateResponsiveStyles(stack: AnyRec): StyleFinding[] {\n const findings: StyleFinding[] = [];\n const pages = asArray(stack.pages);\n for (let p = 0; p < pages.length; p++) {\n const page = pages[p];\n const pageName = typeof page.name === 'string' ? page.name : `pages[${p}]`;\n const regions = asArray(page.regions);\n for (let r = 0; r < regions.length; r++) {\n const components = asArray(regions[r].components);\n for (let c = 0; c < components.length; c++) {\n checkNode(components[c], pageName, `pages[${p}].regions[${r}].components[${c}]`, findings);\n }\n }\n }\n return findings;\n}\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n//\n// Build-time diagnostics for AI-authored HTML-source pages (ADR-0080).\n//\n// Applies to `kind:'html'` (and its deprecated alias `kind:'jsx'`) — the tier\n// whose `source` is constrained JSX/HTML parsed (never executed) to the tree.\n// `kind:'react'` (ADR-0081) is intentionally NOT linted here: its source is\n// real JavaScript, not constrained JSX, so the constrained parser would\n// false-error on hooks / expressions.\n//\n// A pure `(stack) => Finding[]` rule (ADR-0019), run from `os validate` / `os\n// build`. An html page's `source` is a constrained JSX/Tailwind string\n// compiled (parsed, never executed) to the SDUI tree at save time. This gate\n// parses it at author time so malformed source fails loudly (ADR-0078) instead\n// of being stored and breaking only at render.\n//\n// Scope: parse-level — syntax, tag matching, and forbidden constructs (event\n// handlers, dangerouslySetInnerHTML). Full component/prop whitelist validation\n// needs the registry manifest (a cross-repo artifact); when that is wired,\n// thread it through `compile()` here. Until then this catches the structural\n// class of error an AI author is most likely to emit.\n\nimport { parseJsx, compile, type Manifest } from '@objectstack/sdui-parser';\n\nexport type JsxPageSeverity = 'error' | 'warning';\n\nexport interface JsxPageFinding {\n severity: JsxPageSeverity;\n rule: string;\n /** Human-readable location, e.g. `page \"command_center\" › <flex>`. */\n where: string;\n /** Config path, e.g. `pages[3].source`. */\n path: string;\n message: string;\n hint: string;\n}\n\ntype AnyRec = Record<string, unknown>;\nconst asArray = (v: unknown): AnyRec[] => (Array.isArray(v) ? (v as AnyRec[]) : []);\n\nexport function validateJsxPages(stack: AnyRec, opts: { manifest?: Manifest } = {}): JsxPageFinding[] {\n const findings: JsxPageFinding[] = [];\n const pages = asArray(stack.pages);\n for (let p = 0; p < pages.length; p++) {\n const page = pages[p];\n // html tier (+ deprecated 'jsx' alias). react pages are not constrained JSX.\n if (!page || (page.kind !== 'html' && page.kind !== 'jsx')) continue;\n const name = String(page.name ?? `#${p}`);\n const source = page.source;\n if (typeof source !== 'string' || source.trim() === '') {\n // (PageSchema's superRefine also covers this; keep it for the build path.)\n findings.push({\n severity: 'error',\n rule: 'jsx-page-empty-source',\n where: `page \"${name}\"`,\n path: `pages[${p}].source`,\n message: `kind:'${page.kind}' page has no \\`source\\`.`,\n hint: 'Author the page as a constrained JSX/Tailwind string in `source`.',\n });\n continue;\n }\n // With a component manifest, do full validation (unknown component, missing/\n // wrong prop, bad enum, bindings); without it, parse-level (syntax/structure).\n const { diagnostics } = opts.manifest ? compile(source, opts.manifest) : parseJsx(source);\n for (const d of diagnostics) {\n findings.push({\n severity: d.severity,\n rule: `jsx-${d.code}`,\n where: d.tag ? `page \"${name}\" › <${d.tag}>` : `page \"${name}\"`,\n path: `pages[${p}].source`,\n message: d.message,\n hint: 'The source is parsed (never executed) and compiled to the SDUI tree at save time — fix the JSX.',\n });\n }\n }\n return findings;\n}\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n//\n// Build-time syntax gate for `kind:'react'` pages (ADR-0081).\n//\n// A react page's `source` is REAL JavaScript/JSX executed at render by the\n// runtime — so the constrained JSX parser (validate-jsx-pages) cannot check it.\n// We instead transpile it with Sucrase (the same transpiler the runtime uses),\n// transpile-ONLY — never executed — to surface syntax errors at `os build`\n// instead of at render (ADR-0078: fail loudly at author time). It does NOT\n// validate runtime behaviour (a transpiling page can still throw at render);\n// the render-time error boundary owns that.\n\nimport { createRequire } from 'node:module';\nimport type { transform as sucraseTransform } from 'sucrase';\n\n// Sucrase must NOT be imported at module top level: it is ~1.5 MB of CJS\n// (~16 ms cold require), and @objectstack/lint sits on the kernel boot path —\n// while this gate only runs when a `kind:'react'` page is actually validated\n// (rare, trusted tier). Same boot-path contract as the TypeScript compiler in\n// validate-react-page-props.ts: loaded lazily, on first use, staying a regular\n// dependency in package.json. Guarded by lazy-deps.test.ts.\n//\n// `node:module` is a Node builtin, untouched by esbuild/tsup, so the static\n// `createRequire` import survives bundling; the `createRequire(...)` call is\n// deferred because `import.meta.url` is rewritten to an empty stub in the CJS\n// build (same pattern as driver-sqlite-wasm's knex-wasm-dialect).\nlet cachedTransform: typeof sucraseTransform | null = null;\nfunction loadSucraseTransform(): typeof sucraseTransform {\n if (cachedTransform) return cachedTransform;\n const anchor =\n typeof import.meta !== 'undefined' && import.meta.url\n ? import.meta.url\n : typeof __filename !== 'undefined'\n ? __filename\n : process.cwd() + '/';\n try {\n cachedTransform = (createRequire(anchor)('sucrase') as { transform: typeof sucraseTransform }).transform;\n } catch (err) {\n throw new Error(\n `@objectstack/lint: validating a kind:'react' page requires the \"sucrase\" package, which could not be loaded ` +\n `(${err instanceof Error ? err.message : String(err)}). It is a declared dependency of @objectstack/lint — ` +\n `if this deployment prunes packages, keep \"sucrase\" in the image; it is only loaded when a react-source page is validated.`,\n );\n }\n return cachedTransform;\n}\n\nexport type ReactPageSeverity = 'error' | 'warning';\n\nexport interface ReactPageFinding {\n severity: ReactPageSeverity;\n rule: string;\n where: string;\n path: string;\n message: string;\n hint: string;\n}\n\ntype AnyRec = Record<string, unknown>;\nconst asArray = (v: unknown): AnyRec[] => (Array.isArray(v) ? (v as AnyRec[]) : []);\n\nexport function validateReactPages(stack: AnyRec): ReactPageFinding[] {\n const findings: ReactPageFinding[] = [];\n const pages = asArray(stack.pages);\n for (let p = 0; p < pages.length; p++) {\n const page = pages[p];\n if (!page || page.kind !== 'react') continue;\n const name = String(page.name ?? `#${p}`);\n const source = page.source;\n if (typeof source !== 'string' || source.trim() === '') {\n findings.push({\n severity: 'error',\n rule: 'react-page-empty-source',\n where: `page \"${name}\"`,\n path: `pages[${p}].source`,\n message: \"kind:'react' page has no `source`.\",\n hint: 'Author the page as a real React component string in `source`.',\n });\n continue;\n }\n // Outside the try below on purpose: a missing transpiler must surface as\n // an error, not be swallowed as a syntax finding.\n const transform = loadSucraseTransform();\n try {\n // transpile-only (no eval) — catches syntax errors, unterminated JSX, etc.\n transform(source, { transforms: ['jsx', 'typescript'], production: true });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n findings.push({\n severity: 'error',\n rule: 'react-page-syntax',\n where: `page \"${name}\"`,\n path: `pages[${p}].source`,\n message: `kind:'react' source has a syntax error: ${message.split('\\n')[0]}`,\n hint: 'The source is transpiled (never executed) at build to catch syntax errors early — fix the JS/JSX.',\n });\n }\n }\n return findings;\n}\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n//\n// Build-time prop check for `kind:'react'` pages (ADR-0081 Phase 2). The syntax\n// gate (validate-react-pages) confirms the source parses; this confirms the\n// AUTHOR USED THE COMPONENT CONTRACT correctly — it parses the real JSX with the\n// TypeScript compiler, finds usages of the injected blocks (<ObjectForm>,\n// <ListView>, …), and checks each against the react-tier contract\n// (REACT_BLOCKS in @objectstack/spec):\n//\n// - missing a required binding prop (e.g. <ObjectForm> with no objectName)\n// → error. (Only the React-enforceable overlay props are required-checked;\n// a spread `{...props}` escapes the check since props may come from it.)\n// - a prop that is a near-miss (edit distance ≤ 2) of a known prop\n// (e.g. `onSucces` → `onSuccess`) → warning. We do NOT flag arbitrary\n// unknown props (the contract's data props are a curated subset) — only the\n// likely typos, to keep false positives near zero.\n\nimport { createRequire } from 'node:module';\nimport type ts from 'typescript';\nimport { REACT_BLOCKS } from '@objectstack/spec/ui';\n\n// The TypeScript compiler must NOT be imported at module top level: it is\n// ~9 MB of CJS (~70 ms+ to parse, worse on container cold starts), and\n// @objectstack/lint sits on the kernel boot path — while this gate only runs\n// when a `kind:'react'` page is actually validated (rare, trusted tier). An\n// eager import also hard-crashes boot in deployments that prune the package\n// from the image (cloud's Docker pruner did exactly that). So the compiler is\n// loaded lazily, on first use, and stays a regular dependency in package.json.\n// Guarded by lazy-deps.test.ts.\n//\n// `node:module` is a Node builtin, untouched by esbuild/tsup, so the static\n// `createRequire` import survives bundling; the `createRequire(...)` call is\n// deferred because `import.meta.url` is rewritten to an empty stub in the CJS\n// build (same pattern as driver-sqlite-wasm's knex-wasm-dialect).\nlet cachedTs: typeof ts | null = null;\nfunction loadTypeScript(): typeof ts {\n if (cachedTs) return cachedTs;\n const anchor =\n typeof import.meta !== 'undefined' && import.meta.url\n ? import.meta.url\n : typeof __filename !== 'undefined'\n ? __filename\n : process.cwd() + '/';\n try {\n cachedTs = createRequire(anchor)('typescript') as typeof ts;\n } catch (err) {\n throw new Error(\n `@objectstack/lint: validating a kind:'react' page requires the \"typescript\" package, which could not be loaded ` +\n `(${err instanceof Error ? err.message : String(err)}). It is a declared dependency of @objectstack/lint — ` +\n `if this deployment prunes packages, keep \"typescript\" in the image; it is only loaded when a react-source page is validated.`,\n );\n }\n return cachedTs;\n}\n\nexport type ReactPropSeverity = 'error' | 'warning';\n\nexport interface ReactPropFinding {\n severity: ReactPropSeverity;\n rule: string;\n where: string;\n path: string;\n message: string;\n hint: string;\n}\n\ntype AnyRec = Record<string, unknown>;\nconst asArray = (v: unknown): AnyRec[] => (Array.isArray(v) ? (v as AnyRec[]) : []);\n\ninterface BlockSpec {\n requiredBindings: string[];\n knownProps: Set<string>;\n}\nconst BLOCKS: Map<string, BlockSpec> = new Map(\n (REACT_BLOCKS as Array<{ tag: string; interactions: Array<{ name: string; required?: boolean }> }>).map((b) => [\n b.tag,\n {\n requiredBindings: b.interactions.filter((i) => i.required).map((i) => i.name),\n knownProps: new Set(b.interactions.map((i) => i.name)),\n },\n ]),\n);\n\nfunction editDistance(a: string, b: string, cap = 2): number {\n if (Math.abs(a.length - b.length) > cap) return cap + 1;\n const dp = Array.from({ length: a.length + 1 }, (_, i) => i);\n for (let j = 1; j <= b.length; j++) {\n let prev = dp[0];\n dp[0] = j;\n for (let i = 1; i <= a.length; i++) {\n const tmp = dp[i];\n dp[i] = Math.min(dp[i] + 1, dp[i - 1] + 1, prev + (a[i - 1] === b[j - 1] ? 0 : 1));\n prev = tmp;\n }\n }\n return dp[a.length];\n}\n\nfunction nearestKnown(prop: string, known: Set<string>): string | null {\n if (known.has(prop)) return null;\n let best: string | null = null;\n let bestD = 3;\n for (const k of known) {\n const d = editDistance(prop, k);\n if (d < bestD) { bestD = d; best = k; }\n }\n return bestD <= 2 ? best : null;\n}\n\nexport function validateReactPageProps(stack: AnyRec): ReactPropFinding[] {\n const findings: ReactPropFinding[] = [];\n const pages = asArray(stack.pages);\n for (let p = 0; p < pages.length; p++) {\n const page = pages[p];\n if (!page || page.kind !== 'react') continue;\n const source = page.source;\n if (typeof source !== 'string' || source.trim() === '') continue;\n const name = String(page.name ?? `#${p}`);\n\n // Outside the try below on purpose: a missing compiler must surface as an\n // error, not be swallowed as \"unparseable source\".\n const tsc = loadTypeScript();\n\n let sf: ts.SourceFile;\n try {\n sf = tsc.createSourceFile('page.tsx', source, tsc.ScriptTarget.Latest, true, tsc.ScriptKind.TSX);\n } catch {\n continue; // the syntax gate reports unparseable sources\n }\n\n const visit = (node: ts.Node): void => {\n if (tsc.isJsxOpeningElement(node) || tsc.isJsxSelfClosingElement(node)) {\n const tag = node.tagName.getText(sf);\n const block = BLOCKS.get(tag);\n if (block) {\n let hasSpread = false;\n const used = new Set<string>();\n for (const a of node.attributes.properties) {\n if (tsc.isJsxSpreadAttribute(a)) { hasSpread = true; continue; }\n if (tsc.isJsxAttribute(a)) used.add(a.name.getText(sf));\n }\n const where = `page \"${name}\" › <${tag}>`;\n const path = `pages[${p}].source`;\n if (!hasSpread) {\n for (const req of block.requiredBindings) {\n if (!used.has(req)) {\n findings.push({\n severity: 'error',\n rule: 'react-prop-missing-required',\n where, path,\n message: `<${tag}> is missing the required prop \"${req}\".`,\n hint: `Pass ${req}={…}. See the react-tier component contract.`,\n });\n }\n }\n }\n for (const u of used) {\n const near = nearestKnown(u, block.knownProps);\n if (near) {\n findings.push({\n severity: 'warning',\n rule: 'react-prop-typo',\n where, path,\n message: `<${tag}> has prop \"${u}\" — did you mean \"${near}\"?`,\n hint: 'Likely a typo of a contract prop. Fix it or remove it.',\n });\n }\n }\n }\n }\n tsc.forEachChild(node, visit);\n };\n visit(sf);\n }\n return findings;\n}\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n//\n// Build-time guardrail for SDUI source-tier page styling (ADR-0065 / ADR-0080 /\n// ADR-0081). A `kind:'html'` or `kind:'react'` page's `source` is RUNTIME\n// metadata — the console's build-time Tailwind only scans the renderer's own\n// source, never an authored page string. So a Tailwind `className` in page\n// source silently produces NO CSS (the exact ADR-0065 failure: styling that\n// \"works only by coincidence\" when the class happens to be one objectui already\n// ships). This rule flags authored `className` attributes in source-tier pages\n// before render, with the actionable fix.\n//\n// It is the styling counterpart to the react-prop gate: a pure\n// `(stack) => Finding[]` rule (ADR-0019), run from `os validate`/`compile` and\n// reusable by AI authoring so the agent self-corrects.\n\nexport type SourceStyleSeverity = 'error' | 'warning';\n\nexport interface SourceStyleFinding {\n severity: SourceStyleSeverity;\n rule: string;\n where: string;\n path: string;\n message: string;\n hint: string;\n}\n\nexport const PAGE_SOURCE_CLASSNAME = 'page-source-className-tailwind';\n\ntype AnyRec = Record<string, unknown>;\nconst asArray = (v: unknown): AnyRec[] => (Array.isArray(v) ? (v as AnyRec[]) : []);\n\n// `className=` as a JSX attribute: name, optional ws, `=`, then `\"`/`'`/`{`.\nconst CLASSNAME_ATTR = /\\bclassName\\s*=\\s*[\"'{]/g;\n\nexport function validatePageSourceStyling(stack: AnyRec): SourceStyleFinding[] {\n const findings: SourceStyleFinding[] = [];\n const pages = asArray(stack.pages);\n for (let p = 0; p < pages.length; p++) {\n const page = pages[p];\n if (!page) continue;\n const kind = page.kind;\n if (kind !== 'html' && kind !== 'react' && kind !== 'jsx') continue;\n const source = page.source;\n if (typeof source !== 'string' || source.trim() === '') continue;\n const name = String(page.name ?? `#${p}`);\n\n CLASSNAME_ATTR.lastIndex = 0;\n let count = 0;\n while (CLASSNAME_ATTR.exec(source) !== null) count++;\n if (count === 0) continue;\n\n findings.push({\n severity: 'warning',\n rule: PAGE_SOURCE_CLASSNAME,\n where: `page \"${name}\"`,\n path: `pages[${p}].source`,\n message: `${count} \\`className\\` attribute${count > 1 ? 's' : ''} in ${String(kind)}-source page — Tailwind utilities in page source silently produce no CSS (the build never scans authored metadata; ADR-0065).`,\n hint:\n kind === 'react'\n ? \"Style with inline style={{}} using hsl(var(--token)) theme colors (e.g. color:'hsl(var(--foreground))', background:'hsl(var(--card))'); render drawer/modal via <ObjectForm formType=\\\"drawer\\\"|\\\"modal\\\"> instead of hand-rolled overlays.\"\n : \"Lay out with the components' structured props (<flex direction gap>, <grid columns>) and add CSS via a JSON style object style={{\\\"color\\\":\\\"hsl(var(--foreground))\\\"}}; do not use Tailwind className.\",\n });\n }\n return findings;\n}\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { objectTitleCompleteness } from '@objectstack/spec/data';\nimport type { DisplayNameObjectMeta } from '@objectstack/spec/data';\n\n/**\n * Build-time record-title diagnostics (ADR-0079).\n *\n * A record's human title is a structural invariant: every object resolves a\n * primary title from a real STORED field via `nameField` (the canonical\n * pointer; `displayNameField` is the deprecated alias) or a deterministic\n * derivation. Two authoring smells are flagged here so `os build`/`os lint`,\n * the MCP authoring surface, and hand-authoring all get the coverage cloud\n * graph-lint already has (the ADR-0078 \"not cloud-only\" principle):\n *\n * - `title-format-retired` — the object declares a `titleFormat`. That field\n * is a RENDER-ONLY template the server can neither return nor query; ADR-0079\n * retires it in favour of `nameField`. The schema still parses it (existing\n * metadata keeps loading), so this is advisory, not an error.\n * - `title-unresolvable` — `objectTitleCompleteness` reports `status: 'none'`:\n * no `nameField`/`displayNameField` pointer and no title-eligible field to\n * derive one from. Records will have no meaningful title (the runtime falls\n * back to the auto-provisioned primary / `Record #<id>` floor), so this is a\n * warning, not an error — nothing is fully broken.\n *\n * Both are warnings: the auto-provision transform and the id floor mean a\n * green build never ships a fully title-less object. Reuses the shared spec\n * predicate (`@objectstack/spec/data` → display-name) so cloud and framework\n * classify titles identically.\n */\n\nexport const TITLE_FORMAT_RETIRED = 'title-format-retired';\nexport const TITLE_UNRESOLVABLE = 'title-unresolvable';\n\nexport type RecordTitleSeverity = 'error' | 'warning';\n\nexport interface RecordTitleFinding {\n /** Always `warning` today — both rules are advisory (see module note). */\n severity: RecordTitleSeverity;\n /** Diagnostic rule id (registry entry), e.g. `title-format-retired`. */\n rule: string;\n /** Human-readable location, e.g. `object \"invoice\"`. */\n where: string;\n /** Config path, e.g. `objects[3]`. */\n path: string;\n /** What is wrong. */\n message: string;\n /** How to fix it. */\n hint: string;\n}\n\ntype AnyRec = Record<string, unknown>;\n\n/** Coerce a collection (array or name-keyed map) to an array of records. */\nfunction asArray(v: unknown): AnyRec[] {\n if (Array.isArray(v)) return v as AnyRec[];\n if (v && typeof v === 'object') {\n return Object.entries(v as AnyRec).map(([name, def]) => ({ name, ...(def as AnyRec) }));\n }\n return [];\n}\n\n/**\n * Validate every object's record-title declaration. Returns the list of\n * findings (empty = clean). Both rules are advisory (`warning`): the caller\n * must never fail the build on them alone — auto-provision + the `Record #<id>`\n * floor guarantee a resolvable title at runtime.\n */\nexport function validateRecordTitle(stack: AnyRec): RecordTitleFinding[] {\n const findings: RecordTitleFinding[] = [];\n\n const objects = asArray(stack.objects);\n for (let i = 0; i < objects.length; i++) {\n const obj = objects[i];\n const objName = typeof obj.name === 'string' ? obj.name : `(object ${i})`;\n const where = `object \"${objName}\"`;\n const path = `objects[${i}]`;\n\n // ── (a) titleFormat is retired (ADR-0079) ──\n // Render-only template the server cannot return or query. Still parsed by\n // the schema for back-compat, so advisory.\n if (obj.titleFormat !== undefined && obj.titleFormat !== null && obj.titleFormat !== '') {\n findings.push({\n severity: 'warning',\n rule: TITLE_FORMAT_RETIRED,\n where,\n path,\n message:\n `${objName}: titleFormat is retired (ADR-0079) — migrate to nameField ` +\n `(single field) or a formula field designated nameField`,\n hint:\n `titleFormat is a render-only template the server cannot return or ` +\n `query, and an explicit nameField now takes precedence. For a ` +\n `single-field title set nameField: '<field>'. For a composite title, ` +\n `add a formula field (returnType: 'text') and designate it via ` +\n `nameField.`,\n });\n }\n\n // ── (b) no resolvable title (status: 'none') ──\n // Reuse the shared spec predicate so cloud graph-lint and framework lint\n // classify titles identically. `none` = no pointer AND nothing derivable.\n const completeness = objectTitleCompleteness(obj as DisplayNameObjectMeta);\n if (completeness.status === 'none') {\n findings.push({\n severity: 'warning',\n rule: TITLE_UNRESOLVABLE,\n where,\n path,\n message:\n `${objName}: no resolvable record title — records will have no ` +\n `meaningful name (no nameField and no title-eligible field to derive one)`,\n hint:\n `Set nameField to a text/email field (or a formula field with ` +\n `returnType: 'text'), or add a text field named \"name\"/\"title\". The ` +\n `runtime auto-provisions a primary and falls back to \"Record #<id>\", ` +\n `but an explicit title is far more useful.`,\n });\n }\n }\n\n return findings;\n}\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Build-time semantic-role diagnostics (ADR-0085).\n *\n * The object-level semantic roles (`stageField`, `highlightFields` /\n * deprecated `compactLayout`, `fieldGroups` + `Field.group`) are pointers\n * into the object's own field map. A dangling pointer is Zod-valid but\n * silently inert at render time — the exact \"parsed, unmarked, silently\n * inert\" shape ADR-0078 prohibits — so the completeness lint flags it here,\n * uniformly for `os build`/`os validate`, MCP authoring and hand authors.\n *\n * All three rules are warnings, not errors: every consumer degrades\n * gracefully (an unknown `Field.group` renders in the ungrouped bucket, an\n * unknown highlight name is skipped, an unknown `stageField` falls back to\n * heuristics), so nothing is fully broken — but the author almost certainly\n * typo'd a name and should be told at author time, not discover it by\n * staring at an unchanged page.\n */\n\nexport const FIELD_GROUP_UNDECLARED = 'field-group-undeclared';\nexport const FIELD_GROUP_EMPTY = 'field-group-empty';\nexport const SEMANTIC_ROLE_FIELD_UNKNOWN = 'semantic-role-field-unknown';\n\nexport type SemanticRoleSeverity = 'error' | 'warning';\n\nexport interface SemanticRoleFinding {\n /** Always `warning` today — all three rules are advisory (see module note). */\n severity: SemanticRoleSeverity;\n /** Diagnostic rule id, e.g. `field-group-undeclared`. */\n rule: string;\n /** Human-readable location, e.g. `object \"invoice\"`. */\n where: string;\n /** Config path, e.g. `objects[3]`. */\n path: string;\n /** What is wrong. */\n message: string;\n /** How to fix it. */\n hint: string;\n}\n\ntype AnyRec = Record<string, unknown>;\n\n/** Coerce a collection (array or name-keyed map) to an array of records. */\nfunction asArray(v: unknown): AnyRec[] {\n if (Array.isArray(v)) return v as AnyRec[];\n if (v && typeof v === 'object') {\n return Object.entries(v as AnyRec).map(([name, def]) => ({ name, ...(def as AnyRec) }));\n }\n return [];\n}\n\n/**\n * Validate every object's semantic-role pointers. Returns the list of\n * findings (empty = clean). Advisory only — the caller must never fail the\n * build on these alone.\n */\nexport function validateSemanticRoles(stack: AnyRec): SemanticRoleFinding[] {\n const findings: SemanticRoleFinding[] = [];\n\n const objects = asArray(stack.objects);\n for (let i = 0; i < objects.length; i++) {\n const obj = objects[i];\n if (!obj || typeof obj !== 'object') continue; // tolerate junk entries\n const objName = typeof obj.name === 'string' ? obj.name : `(object ${i})`;\n const where = `object \"${objName}\"`;\n const path = `objects[${i}]`;\n\n const fields = (obj.fields && typeof obj.fields === 'object' && !Array.isArray(obj.fields))\n ? (obj.fields as Record<string, AnyRec | undefined>)\n : {};\n const fieldNames = new Set(Object.keys(fields));\n\n // ── (a) Field.group → declared fieldGroups[].key ──\n const declaredGroups = new Set(\n (Array.isArray(obj.fieldGroups) ? obj.fieldGroups : [])\n .filter((g): g is AnyRec => !!g && typeof g === 'object')\n .map((g) => g.key)\n .filter((k): k is string => typeof k === 'string' && k.length > 0),\n );\n const referencedGroups = new Set<string>();\n for (const [fname, f] of Object.entries(fields)) {\n const g = f?.group;\n if (typeof g !== 'string' || g.length === 0) continue;\n referencedGroups.add(g);\n if (!declaredGroups.has(g)) {\n findings.push({\n severity: 'warning',\n rule: FIELD_GROUP_UNDECLARED,\n where,\n path: `${path}.fields.${fname}.group`,\n message:\n `${objName}.${fname}: group \"${g}\" is not declared in fieldGroups — ` +\n `the field renders in the ungrouped bucket, not under \"${g}\"`,\n hint:\n `Declare { key: '${g}', label: '…' } in ${objName}.fieldGroups, or fix ` +\n `the field's group reference. Group keys are snake_case and must match exactly.`,\n });\n }\n }\n\n // ── (b) declared group no field references ──\n for (const key of declaredGroups) {\n if (!referencedGroups.has(key)) {\n findings.push({\n severity: 'warning',\n rule: FIELD_GROUP_EMPTY,\n where,\n path: `${path}.fieldGroups`,\n message:\n `${objName}: fieldGroups declares \"${key}\" but no field references it — ` +\n `the group never renders`,\n hint:\n `Assign at least one field via group: '${key}', or remove the unused ` +\n `group declaration.`,\n });\n }\n }\n\n // ── (c) semantic-role pointers name real fields ──\n const stage = obj.stageField;\n if (typeof stage === 'string' && stage.length > 0 && !fieldNames.has(stage)) {\n findings.push({\n severity: 'warning',\n rule: SEMANTIC_ROLE_FIELD_UNKNOWN,\n where,\n path: `${path}.stageField`,\n message:\n `${objName}: stageField \"${stage}\" is not a field on this object — ` +\n `consumers fall back to heuristic stage detection`,\n hint:\n `Point stageField at an existing select/status field, or set ` +\n `stageField: false to declare the object has no linear lifecycle.`,\n });\n }\n\n const highlights = Array.isArray(obj.highlightFields)\n ? obj.highlightFields\n : Array.isArray(obj.compactLayout) // deprecated alias (pre-normalization input)\n ? obj.compactLayout\n : [];\n for (const entry of highlights) {\n if (typeof entry !== 'string' || entry.length === 0 || fieldNames.has(entry)) continue;\n findings.push({\n severity: 'warning',\n rule: SEMANTIC_ROLE_FIELD_UNKNOWN,\n where,\n path: `${path}.highlightFields`,\n message:\n `${objName}: highlightFields entry \"${entry}\" is not a field on this ` +\n `object — it is silently skipped by every consumer`,\n hint:\n `Fix the field name (highlightFields drives default columns, cards, ` +\n `previews and the detail highlight strip, in order).`,\n });\n }\n }\n\n return findings;\n}\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Build-time form-layout diagnostics (#2578).\n *\n * Authored form views carry field references and column-layout hints that are\n * Zod-valid but can be silently wrong at render time — the \"parsed, unmarked,\n * silently inert\" shape ADR-0078 prohibits. This lint catches the two that\n * matter for multi-column, AI-authored forms, uniformly for `os build` /\n * `os validate`, MCP authoring and hand authors (ADR-0019).\n *\n * Both rules are warnings, not errors — nothing is fully broken (an unknown\n * field name is skipped; an over-wide colSpan is clamped) — but each is almost\n * certainly an authoring mistake worth surfacing at author time:\n *\n * - `form-field-unknown` — a section references a field that is not on the\n * form's bound object, so the field silently does not render.\n * - `absolute-colspan-discouraged` — a field uses the absolute `colSpan`. Under\n * a per-surface DERIVED column count (mobile 1 / modal 2 / page 3-4) a fixed\n * span only lines up at the one width the author imagined; the renderer\n * clamps it. The robust primitive is the relative `span: 'full'`.\n *\n * Scope: top-level form `views` (a `sections` array). Forms embedded inside\n * page component trees are a follow-up — the walker deliberately stays shallow\n * so it never guesses at an arbitrary component's object binding.\n */\n\nexport const FORM_FIELD_UNKNOWN = 'form-field-unknown';\nexport const FORM_COLSPAN_ABSOLUTE = 'absolute-colspan-discouraged';\n\nexport type FormLayoutSeverity = 'error' | 'warning';\n\nexport interface FormLayoutFinding {\n /** Always `warning` today — both rules are advisory (see module note). */\n severity: FormLayoutSeverity;\n /** Diagnostic rule id, e.g. `form-field-unknown`. */\n rule: string;\n /** Human-readable location, e.g. `view \"contract_form\"`. */\n where: string;\n /** Config path, e.g. `views[2].sections[0].fields[3]`. */\n path: string;\n /** What is wrong. */\n message: string;\n /** How to fix it. */\n hint: string;\n}\n\ntype AnyRec = Record<string, unknown>;\n\n/** Coerce a collection (array or name-keyed map) to an array of records. */\nfunction asArray(v: unknown): AnyRec[] {\n if (Array.isArray(v)) return v as AnyRec[];\n if (v && typeof v === 'object') {\n return Object.entries(v as AnyRec).map(([name, def]) => ({ name, ...(def as AnyRec) }));\n }\n return [];\n}\n\n/** A section field entry is either a bare field name or `{ field, colSpan, … }`. */\nfunction fieldNameOf(entry: unknown): string | null {\n if (typeof entry === 'string') return entry.length > 0 ? entry : null;\n if (entry && typeof entry === 'object' && !Array.isArray(entry)) {\n const f = (entry as AnyRec).field;\n return typeof f === 'string' && f.length > 0 ? f : null;\n }\n return null;\n}\n\n/** The object a form view binds to: `data.object` (canonical) or `objectName`. */\nfunction boundObject(view: AnyRec): string | undefined {\n const data = view.data;\n if (data && typeof data === 'object' && typeof (data as AnyRec).object === 'string') {\n return (data as AnyRec).object as string;\n }\n return typeof view.objectName === 'string' ? (view.objectName as string) : undefined;\n}\n\n/**\n * Validate authored form-view layout. Returns findings (empty = clean).\n * Advisory only — the caller must never fail the build on these alone.\n */\nexport function validateFormLayout(stack: AnyRec): FormLayoutFinding[] {\n const findings: FormLayoutFinding[] = [];\n\n // object name → its field-name set, for reference checking.\n const objectFields = new Map<string, Set<string>>();\n for (const obj of asArray(stack.objects)) {\n const name = typeof obj.name === 'string' ? obj.name : undefined;\n if (!name) continue;\n const fields = (obj.fields && typeof obj.fields === 'object' && !Array.isArray(obj.fields))\n ? Object.keys(obj.fields as AnyRec)\n : [];\n objectFields.set(name, new Set(fields));\n }\n\n const views = asArray(stack.views);\n for (let i = 0; i < views.length; i++) {\n const view = views[i];\n if (!view || typeof view !== 'object') continue;\n const sections = Array.isArray(view.sections) ? view.sections : null;\n if (!sections) continue; // only form views carry a sections array\n\n const viewName = typeof view.name === 'string' ? view.name : `(view ${i})`;\n const objName = boundObject(view);\n // Only reference-check when the bound object resolves; otherwise we can't.\n const known = objName ? objectFields.get(objName) : undefined;\n const where = `view \"${viewName}\"`;\n const base = `views[${i}]`;\n\n for (let s = 0; s < sections.length; s++) {\n const sec = sections[s];\n const secFields = sec && typeof sec === 'object' && Array.isArray((sec as AnyRec).fields)\n ? ((sec as AnyRec).fields as unknown[])\n : [];\n for (let f = 0; f < secFields.length; f++) {\n const entry = secFields[f];\n const fname = fieldNameOf(entry);\n const fpath = `${base}.sections[${s}].fields[${f}]`;\n\n // ── (a) section field references a real field on the bound object ──\n if (fname && known && !known.has(fname)) {\n findings.push({\n severity: 'warning',\n rule: FORM_FIELD_UNKNOWN,\n where,\n path: fpath,\n message:\n `${viewName}: field \"${fname}\" is not a field on object \"${objName}\" — ` +\n `it is silently skipped and never renders on the form`,\n hint:\n `Fix the field name, or add \"${fname}\" to ${objName}. Section field ` +\n `references must match the object's field names exactly.`,\n });\n }\n\n // ── (b) absolute colSpan → steer to the surface-independent span ──\n const colSpan = entry && typeof entry === 'object' && !Array.isArray(entry)\n ? (entry as AnyRec).colSpan\n : undefined;\n if (colSpan != null) {\n findings.push({\n severity: 'warning',\n rule: FORM_COLSPAN_ABSOLUTE,\n where,\n path: `${fpath}.colSpan`,\n message:\n `${viewName}: field \"${fname ?? '?'}\" sets absolute colSpan ${String(colSpan)} — ` +\n `the form's column count is derived per surface (mobile 1 / modal 2 / page 3-4), ` +\n `so a fixed span only aligns at one width`,\n hint:\n `Prefer span: 'full' (whole row at any column count), or omit for auto ` +\n `width. The renderer clamps colSpan to the current column count.`,\n });\n }\n }\n }\n }\n\n return findings;\n}\n"],"mappings":"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","names":["asArray","asArray","asArray","asArray","asArray","createRequire","asArray","asArray","asArray","asArray","asArray"]}
|
|
1
|
+
{"version":3,"sources":["../src/validate-widget-bindings.ts","../src/validate-expressions.ts","../src/validate-list-view-mode.ts","../src/validate-responsive-styles.ts","../src/validate-jsx-pages.ts","../src/validate-react-pages.ts","../src/validate-react-page-props.ts","../src/validate-page-source-styling.ts","../src/validate-record-title.ts","../src/validate-semantic-roles.ts","../src/validate-form-layout.ts","../src/validate-capability-references.ts","../src/validate-security-posture.ts","../src/build-access-matrix.ts"],"sourcesContent":["// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { isIncoherentAggregate } from '@objectstack/spec/data';\n\n/**\n * Build-time dashboard widget binding diagnostics (issues #1719, #1721).\n *\n * Runs at `objectstack validate`/`compile`/`build` AFTER the stack has been\n * schema-parsed, so every widget's `dataset` reference can be linked to its\n * `defineDataset` and each entry in `dimensions`/`values` resolved to a\n * declared dimension/measure. This is the semantic/cross-reference phase —\n * the rules here cannot run during plain Zod parsing of the raw widget\n * literal (the dataset may even live in another package of the stack).\n *\n * Reference-integrity rules (#1721) — severity `error`, the page is broken:\n *\n * - `widget-dataset-unknown` — `dataset` does not resolve to a declared\n * `Dataset`.\n * - `widget-dimension-unknown` — a `dimensions[]` entry is not a dimension\n * name on the bound dataset.\n * - `widget-measure-unknown` — a `values[]` entry is not a measure name on\n * the bound dataset.\n * - `chart-field-unknown` — a `chartConfig` binding names a field the query\n * result will not contain: `xAxis.field` must be one of the widget's\n * dimensions (or a dataset dimension), and each `yAxis[].field` /\n * `series[].name` must be one of the widget's selected measures\n * (`values`). Post-cutover (ADR-0021) the result rows are keyed by\n * measure NAME (e.g. `sum_amount`), not the base column (`amount`) — a\n * stale base-column reference renders the axis but an empty series.\n *\n * Advisory rules — severity `warning`, build stays green:\n *\n * - `chart-config-missing` — a chart-type widget (bar/line/pie/…) has no\n * `chartConfig`, so the renderer cannot tell which measure to plot.\n * - `table-count-only` (#1719) — a `table`/`pivot` widget whose selected\n * measures are ALL `aggregate: 'count'` and which declares no\n * `dimensions` asks the analytics service for a single summary row. That\n * is the shape a `metric` widget wants — for a table it almost always\n * means the author wanted a per-record listing, which is not an\n * analytics dataset at all (model it as an object-bound ListView,\n * ADR-0017). Evaluated on the WIDGET's binding, not the dataset.\n * - `measure-aggregate-incoherent` — a dataset measure aggregates its field\n * in a way that produces a meaningless number: today, SUM (or\n * `count_distinct`) of a `percent`/rate field, whose total routinely\n * exceeds 100%. Rates must AVG. Checked once per dataset (independent of\n * any widget) when the bound object's field types are known.\n *\n * Warnings can be deliberately suppressed per widget via\n * `suppressWarnings: ['<rule-id>']`; errors cannot — they describe a\n * binding the analytics service cannot satisfy.\n */\n\nexport const WIDGET_DATASET_UNKNOWN = 'widget-dataset-unknown';\nexport const WIDGET_DIMENSION_UNKNOWN = 'widget-dimension-unknown';\nexport const WIDGET_MEASURE_UNKNOWN = 'widget-measure-unknown';\nexport const CHART_FIELD_UNKNOWN = 'chart-field-unknown';\nexport const CHART_CONFIG_MISSING = 'chart-config-missing';\nexport const TABLE_COUNT_ONLY = 'table-count-only';\nexport const MEASURE_AGGREGATE_INCOHERENT = 'measure-aggregate-incoherent';\n\nexport type WidgetBindingSeverity = 'error' | 'warning';\n\nexport interface WidgetBindingFinding {\n /** `error` = unresolvable binding (broken page); `warning` = advisory. */\n severity: WidgetBindingSeverity;\n /** Diagnostic rule id (registry entry), e.g. `widget-measure-unknown`. */\n rule: string;\n /** Human-readable location, e.g. `dashboard \"x\" › widget \"y\"`. */\n where: string;\n /** Config path, e.g. `dashboards[0].widgets[3]`. */\n path: string;\n /** What is wrong. */\n message: string;\n /** How to fix (or deliberately suppress) it. */\n hint: string;\n}\n\ntype AnyRec = Record<string, unknown>;\n\n/** Coerce a collection (array or name-keyed map) to an array. */\nfunction asArray(v: unknown): AnyRec[] {\n if (Array.isArray(v)) return v as AnyRec[];\n if (v && typeof v === 'object') {\n return Object.entries(v as AnyRec).map(([name, def]) => ({ name, ...(def as AnyRec) }));\n }\n return [];\n}\n\nfunction asStrings(v: unknown): string[] {\n return Array.isArray(v) ? v.filter((s): s is string => typeof s === 'string') : [];\n}\n\n/**\n * Chart families whose renderer needs a `chartConfig` measure mapping.\n * Single-value types (metric/kpi/gauge/…) plot their lone value and tabular\n * types (table/pivot) render every column, so they are exempt.\n */\nconst CHART_TYPES = new Set([\n 'bar', 'horizontal-bar', 'column',\n 'line', 'area',\n 'pie', 'donut', 'funnel',\n 'scatter', 'treemap', 'sankey', 'radar',\n]);\n\nfunction levenshtein(a: string, b: string): number {\n const m = a.length, n = b.length;\n let prev = Array.from({ length: n + 1 }, (_, j) => j);\n for (let i = 1; i <= m; i++) {\n const cur = [i];\n for (let j = 1; j <= n; j++) {\n cur[j] = Math.min(\n prev[j] + 1,\n cur[j - 1] + 1,\n prev[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1),\n );\n }\n prev = cur;\n }\n return prev[n];\n}\n\n/**\n * Nearest declared name for a typo'd/stale reference, or undefined when\n * nothing is close. Containment is checked first because the cutover's\n * canonical drift is base column → prefixed measure name (`amount` →\n * `sum_amount`), which is far in edit distance but obvious to a human.\n */\nfunction didYouMean(input: string, candidates: Iterable<string>): string | undefined {\n let best: string | undefined;\n let bestScore = Infinity;\n for (const c of candidates) {\n let score: number;\n if (input.length >= 3 && (c.includes(input) || input.includes(c))) {\n score = Math.abs(c.length - input.length);\n } else {\n const d = levenshtein(input, c);\n if (d > Math.max(2, Math.floor(input.length / 3))) continue;\n score = 100 + d;\n }\n if (score < bestScore) { bestScore = score; best = c; }\n }\n return best;\n}\n\nfunction suggest(input: string, candidates: Iterable<string>): string {\n const s = didYouMean(input, candidates);\n return s ? ` Did you mean \"${s}\"?` : '';\n}\n\nfunction list(names: Iterable<string>): string {\n const arr = [...names];\n return arr.length > 0 ? arr.join(', ') : '(none)';\n}\n\n/**\n * Validate every dashboard widget's dataset binding. Returns the list of\n * findings (empty = clean). Caller decides how to surface them: `error`\n * findings describe bindings the analytics service cannot satisfy and\n * should fail validate/build; `warning` findings are advisory and must\n * never fail the build on their own.\n */\nexport function validateWidgetBindings(stack: AnyRec): WidgetBindingFinding[] {\n const findings: WidgetBindingFinding[] = [];\n\n const datasets = new Map<string, AnyRec>();\n for (const ds of asArray(stack.datasets)) {\n if (typeof ds.name === 'string') datasets.set(ds.name, ds);\n }\n\n // ── (0) dataset measures aggregate their field coherently ──\n // A measure that SUMs a percentage/rate field produces a meaningless total\n // (it can exceed 100%); rates must AVG. This is a dataset-level defect (it\n // does not depend on any widget), so it is checked once over every dataset\n // whose object's field types are known. Advisory — the page still renders.\n const objectFieldTypes = new Map<string, Map<string, string>>();\n for (const o of asArray(stack.objects)) {\n if (typeof o.name !== 'string') continue;\n const fm = new Map<string, string>();\n for (const f of asArray(o.fields)) {\n if (typeof f.name === 'string' && typeof f.type === 'string') fm.set(f.name, f.type);\n }\n objectFieldTypes.set(o.name, fm);\n }\n const datasetList = asArray(stack.datasets);\n for (let i = 0; i < datasetList.length; i++) {\n const ds = datasetList[i];\n const fieldTypes = typeof ds.object === 'string' ? objectFieldTypes.get(ds.object) : undefined;\n if (!fieldTypes) continue; // cannot judge without the object's field types\n const dsMeasures = asArray(ds.measures);\n for (let k = 0; k < dsMeasures.length; k++) {\n const m = dsMeasures[k];\n const field = typeof m.field === 'string' ? m.field : undefined;\n const aggregate = typeof m.aggregate === 'string' ? m.aggregate : undefined;\n if (!field || !aggregate) continue; // count(*) and underivable measures are fine\n const ftype = fieldTypes.get(field);\n if (ftype && isIncoherentAggregate(aggregate, ftype)) {\n findings.push({\n severity: 'warning',\n rule: MEASURE_AGGREGATE_INCOHERENT,\n where: `dataset \"${typeof ds.name === 'string' ? ds.name : `(dataset ${i})`}\" › measure \"${typeof m.name === 'string' ? m.name : `(measure ${k})`}\"`,\n path: `datasets[${i}].measures[${k}]`,\n message:\n `measure \"${m.name}\" applies ${aggregate} to ${ftype} field \"${field}\" — ` +\n `summed percentages are meaningless (they can exceed 100%).`,\n hint:\n `Use aggregate \"avg\" for percentage/rate fields (or \"count\" of records). ` +\n `If a running total is genuinely intended, suppress with: ` +\n `suppressWarnings: ['${MEASURE_AGGREGATE_INCOHERENT}'] on the measure.`,\n });\n }\n }\n }\n\n const dashboards = asArray(stack.dashboards);\n for (let i = 0; i < dashboards.length; i++) {\n const dash = dashboards[i];\n const dashName = typeof dash.name === 'string' ? dash.name : `(dashboard ${i})`;\n const widgets = Array.isArray(dash.widgets) ? (dash.widgets as AnyRec[]) : [];\n\n for (let j = 0; j < widgets.length; j++) {\n const w = widgets[j];\n const widgetId = typeof w.id === 'string' ? w.id : `(widget ${j})`;\n const where = `dashboard \"${dashName}\" › widget \"${widgetId}\"`;\n const path = `dashboards[${i}].widgets[${j}]`;\n const suppressed = (rule: string): boolean =>\n Array.isArray(w.suppressWarnings) && w.suppressWarnings.includes(rule);\n const push = (f: Omit<WidgetBindingFinding, 'where' | 'path'>): void => {\n if (f.severity === 'warning' && suppressed(f.rule)) return;\n findings.push({ ...f, where, path });\n };\n\n // ── (a) dataset reference resolves ──\n const dsName = typeof w.dataset === 'string' ? w.dataset : undefined;\n const dataset = dsName ? datasets.get(dsName) : undefined;\n if (dsName && !dataset) {\n push({\n severity: 'error',\n rule: WIDGET_DATASET_UNKNOWN,\n message: `dataset \"${dsName}\" does not resolve to a declared dataset.`,\n hint:\n `Declared datasets: ${list(datasets.keys())}.${suggest(dsName, datasets.keys())} ` +\n `Define the dataset with defineDataset() or fix the reference (ADR-0021).`,\n });\n }\n // Without a resolved dataset there is nothing to check names against.\n if (!dataset) continue;\n\n const dimensionNames = new Set<string>();\n for (const d of asArray(dataset.dimensions)) {\n if (typeof d.name === 'string') dimensionNames.add(d.name);\n }\n const measures = new Map<string, AnyRec>();\n for (const m of asArray(dataset.measures)) {\n if (typeof m.name === 'string') measures.set(m.name, m);\n }\n\n // ── (b) every dimensions[] entry is a dataset dimension ──\n const dims = asStrings(w.dimensions);\n for (let k = 0; k < dims.length; k++) {\n if (dimensionNames.has(dims[k])) continue;\n push({\n severity: 'error',\n rule: WIDGET_DIMENSION_UNKNOWN,\n message:\n `dimensions[${k}] \"${dims[k]}\" is not a dimension of dataset ` +\n `\"${dsName}\" (declared dimensions: ${list(dimensionNames)}).`,\n hint:\n `Widgets select dataset dimensions BY NAME.${suggest(dims[k], dimensionNames)} ` +\n `Add the dimension to the dataset or fix the reference.`,\n });\n }\n\n // ── (c) every values[] entry is a dataset measure ──\n const values = asStrings(w.values);\n for (let k = 0; k < values.length; k++) {\n if (measures.has(values[k])) continue;\n push({\n severity: 'error',\n rule: WIDGET_MEASURE_UNKNOWN,\n message:\n `values[${k}] \"${values[k]}\" is not a measure of dataset ` +\n `\"${dsName}\" (declared measures: ${list(measures.keys())}).`,\n hint:\n `Widgets select dataset measures BY NAME, not by base column.` +\n `${suggest(values[k], measures.keys())} ` +\n `Add the measure to the dataset or fix the reference.`,\n });\n }\n\n // ── (d) chartConfig bindings resolve against the widget's selection ──\n const chartConfig = (w.chartConfig && typeof w.chartConfig === 'object')\n ? (w.chartConfig as AnyRec)\n : undefined;\n const isChartType = typeof w.type === 'string' && CHART_TYPES.has(w.type);\n\n if (chartConfig) {\n // The query result carries the widget's selected dimensions and\n // measures; resolve every chartConfig field against that shape.\n const selectedValues = new Set(values.filter((v) => measures.has(v)));\n\n const xAxis = (chartConfig.xAxis && typeof chartConfig.xAxis === 'object')\n ? (chartConfig.xAxis as AnyRec)\n : undefined;\n // A field naming an entry of the widget's own (already-validated)\n // selection is not re-reported here — rules (b)/(c) own that error.\n if (xAxis && typeof xAxis.field === 'string'\n && !dimensionNames.has(xAxis.field) && !dims.includes(xAxis.field)) {\n push({\n severity: 'error',\n rule: CHART_FIELD_UNKNOWN,\n message:\n `chartConfig.xAxis.field \"${xAxis.field}\" does not resolve to a ` +\n `dimension of dataset \"${dsName}\" (declared dimensions: ${list(dimensionNames)}).`,\n hint: `Point xAxis.field at a dataset dimension name.${suggest(xAxis.field, dimensionNames)}`,\n });\n }\n\n const measureField = (label: string, field: string): void => {\n if (values.includes(field)) return; // resolvable, or already errored via rule (c)\n const declaredButUnselected = measures.has(field);\n push({\n severity: 'error',\n rule: CHART_FIELD_UNKNOWN,\n message: declaredButUnselected\n ? `chartConfig.${label} \"${field}\" is a measure of dataset \"${dsName}\" ` +\n `but is not selected in the widget's values (${list(values)}), so the ` +\n `query result will not contain it.`\n : `chartConfig.${label} \"${field}\" does not resolve to a measure of ` +\n `dataset \"${dsName}\" (declared measures: ${list(measures.keys())}).`,\n hint: declaredButUnselected\n ? `Add \"${field}\" to the widget's values, or bind the chart to a selected measure.`\n : `Post-cutover data is keyed by the dataset's measure NAME, not the ` +\n `base column.${suggest(field, selectedValues.size > 0 ? selectedValues : measures.keys())}`,\n });\n };\n\n const yAxes = Array.isArray(chartConfig.yAxis) ? (chartConfig.yAxis as AnyRec[]) : [];\n for (let k = 0; k < yAxes.length; k++) {\n const field = yAxes[k]?.field;\n if (typeof field === 'string') measureField(`yAxis[${k}].field`, field);\n }\n const series = Array.isArray(chartConfig.series) ? (chartConfig.series as AnyRec[]) : [];\n for (let k = 0; k < series.length; k++) {\n const name = series[k]?.name;\n if (typeof name === 'string') measureField(`series[${k}].name`, name);\n }\n } else if (isChartType) {\n push({\n severity: 'warning',\n rule: CHART_CONFIG_MISSING,\n message:\n `chart-type widget ('${w.type}') has no chartConfig — the renderer ` +\n `cannot determine which measure to plot, so the series renders empty.`,\n hint:\n `Add chartConfig with xAxis.field set to a dimension (${list(dims)}) and ` +\n `yAxis[].field set to a measure name (${list(values)}). If the default ` +\n `rendering is intentional, suppress with: suppressWarnings: ['${CHART_CONFIG_MISSING}']`,\n });\n }\n\n // ── (e) table/pivot bound to a count-only, dimensionless selection ──\n if (w.type !== 'table' && w.type !== 'pivot') continue;\n // Grouped by at least one dimension → genuinely aggregated rows.\n if (dims.length > 0) continue;\n if (values.length === 0) continue;\n const resolved = values.map((v) => measures.get(v));\n // An unresolvable measure name already errored above — don't guess here.\n if (resolved.some((m) => !m)) continue;\n\n // Derived measures combine other measures; treat them as non-count even\n // when their (ignored) `aggregate` says otherwise.\n const countOnly = resolved.every((m) => m!.aggregate === 'count' && !m!.derived);\n if (!countOnly) continue;\n\n push({\n severity: 'warning',\n rule: TABLE_COUNT_ONLY,\n message:\n `a '${w.type}' widget bound to dataset \"${dsName}\" selects only count ` +\n `measure(s) (${values.join(', ')}) and no dimensions, so it renders a ` +\n `single summary row — not a per-record list.`,\n hint:\n `A flat record listing is not an analytics dataset. Model it as an ` +\n `object-bound ListView (ADR-0017) surfaced through app navigation, and ` +\n `use a 'metric' widget here if you only need the count. If a single-row ` +\n `table is intentional, add an explicit dimension or suppress with: ` +\n `suppressWarnings: ['${TABLE_COUNT_ONLY}']`,\n });\n }\n }\n\n return findings;\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Build-time expression validation (ADR-0032 §Decision 1a + 1b).\n *\n * Runs at `objectstack compile`, where the whole normalized stack is in hand —\n * so flow conditions can be checked against the *resolved* object schema\n * (field existence) in addition to CEL syntax. Uses the one shared validator\n * from `@objectstack/formula`, so the verdict matches `registerFlow` and the\n * agent `validate_expression` tool exactly.\n *\n * Scope (v1): flow predicates (start/decision `config.condition` + edge\n * `condition`), object validation-rule / formula predicates, and UI action\n * `visible` / `disabled` predicates. Each error is located (flow/object/action\n * + node/edge/field) with a corrective message.\n */\n\nimport { validateExpression } from '@objectstack/formula';\n\nexport interface ExprIssue {\n where: string;\n message: string;\n source: string;\n /**\n * `error` fails the build (e.g. a bare ref in a record-scoped formula). `warning`\n * is advisory and never fails it (e.g. a possible field typo in a flattened flow\n * condition, which might be a flow variable). Absent ⇒ treat as `error`.\n */\n severity?: 'error' | 'warning';\n}\n\ntype AnyRec = Record<string, unknown>;\n\n/** Coerce an `objects` collection (array or name-keyed map) to an array. */\nfunction asArray(v: unknown): AnyRec[] {\n if (Array.isArray(v)) return v as AnyRec[];\n if (v && typeof v === 'object') {\n return Object.entries(v as AnyRec).map(([name, def]) => ({ name, ...(def as AnyRec) }));\n }\n return [];\n}\n\n/** object name → set of its field names, for schema-aware field checks. */\nfunction buildFieldIndex(objects: AnyRec[]): Map<string, string[]> {\n const idx = new Map<string, string[]>();\n for (const obj of objects) {\n const name = typeof obj.name === 'string' ? obj.name : undefined;\n if (!name) continue;\n const fields = obj.fields;\n let names: string[] = [];\n if (Array.isArray(fields)) names = fields.map(f => (f as AnyRec).name).filter((n): n is string => typeof n === 'string');\n else if (fields && typeof fields === 'object') names = Object.keys(fields as AnyRec);\n idx.set(name, names);\n }\n return idx;\n}\n\n/**\n * Validate every predicate in the stack. Returns the list of issues (empty =\n * clean). Caller decides how to surface / whether to fail the build.\n */\nexport function validateStackExpressions(stack: AnyRec): ExprIssue[] {\n const issues: ExprIssue[] = [];\n const objects = asArray(stack.objects);\n const fieldIndex = buildFieldIndex(objects);\n\n const check = (\n where: string,\n raw: unknown,\n objectName?: string,\n scope: 'record' | 'flattened' = 'flattened',\n ): void => {\n if (raw == null) return;\n const fields = objectName ? fieldIndex.get(objectName) : undefined;\n const res = validateExpression('predicate', raw as string | { dialect?: string; source?: string },\n objectName ? { objectName, fields, scope } : { scope });\n for (const e of res.errors) issues.push({ where, message: e.message, source: e.source, severity: 'error' });\n for (const w of res.warnings) issues.push({ where, message: w.message, source: w.source, severity: 'warning' });\n };\n\n // ── Flows ──────────────────────────────────────────────────────────\n for (const flow of asArray(stack.flows)) {\n const flowName = typeof flow.name === 'string' ? flow.name : '(unnamed flow)';\n const nodes = Array.isArray(flow.nodes) ? (flow.nodes as AnyRec[]) : [];\n const edges = Array.isArray(flow.edges) ? (flow.edges as AnyRec[]) : [];\n // The record-change target object — `record.*` refs resolve against it.\n const startNode = nodes.find(n => n.type === 'start');\n const startCfg = (startNode?.config ?? {}) as AnyRec;\n const objectName = typeof startCfg.objectName === 'string' ? startCfg.objectName : undefined;\n\n for (const node of nodes) {\n const cfg = (node.config ?? {}) as AnyRec;\n check(`flow '${flowName}' · node '${node.id}' (${node.type}) condition`, cfg.condition, objectName);\n // #1870 — a `script` node must declare a callable target (`actionType` or\n // `function`). A node with neither is a silent no-op that otherwise passes\n // build. (Function *existence* isn't checkable here — functions are code,\n // not serialized into the artifact — so this is a structural check; the\n // runtime verifies the named function is actually registered.)\n if (node.type === 'script') {\n // `function` is canonical; `functionName` is an accepted alias.\n const fn =\n (typeof cfg.function === 'string' ? cfg.function.trim() : '') ||\n (typeof cfg.functionName === 'string' ? cfg.functionName.trim() : '');\n const action = typeof cfg.actionType === 'string' ? cfg.actionType.trim() : '';\n // Inline `config.script` (a JS body) is also a declared form — the\n // built-in runtime doesn't execute it (warned at run time), but the node\n // is not the empty no-op this check targets, so don't flag it.\n const inline = typeof cfg.script === 'string' ? cfg.script.trim() : '';\n if (!fn && !action && !inline) {\n issues.push({\n where: `flow '${flowName}' · node '${node.id}' (script) callable`,\n message:\n `script node declares neither \\`actionType\\` nor \\`function\\` — it would do nothing at runtime. ` +\n `Name a built-in action (e.g. \\`actionType: 'email'\\`) or a registered function ` +\n `(\\`function: 'my_fn'\\`, registered via \\`defineStack({ functions })\\`).`,\n source: JSON.stringify({ id: node.id, type: node.type, config: cfg }),\n });\n } else if (action === 'invoke_function' && !fn) {\n // `actionType: 'invoke_function'` is a marker that names no callable on\n // its own — the function name must be in `function`/`functionName`.\n issues.push({\n where: `flow '${flowName}' · node '${node.id}' (script) callable`,\n message:\n `script node uses \\`actionType: 'invoke_function'\\` but no \\`function\\` (or \\`functionName\\`) — ` +\n `it names no callable. Set \\`function: 'my_fn'\\` and register it via \\`defineStack({ functions })\\`.`,\n source: JSON.stringify({ id: node.id, type: node.type, config: cfg }),\n });\n }\n }\n }\n for (const edge of edges) {\n check(`flow '${flowName}' · edge '${edge.id}' (${edge.source}→${edge.target}) condition`, edge.condition, objectName);\n }\n }\n\n // ── Object validation-rule + formula predicates ────────────────────\n for (const obj of objects) {\n const objectName = typeof obj.name === 'string' ? obj.name : undefined;\n const validations = obj.validations ?? obj.validationRules;\n for (const rule of asArray(validations)) {\n const where = `object '${objectName}' · validation '${(rule.name as string) ?? '?'}'`;\n // Common predicate keys across rule shapes. Validation predicates are\n // `record`-scoped — no field flattening — so bare refs are flagged (#1928).\n check(where, rule.expression ?? rule.predicate ?? rule.condition ?? rule.formula, objectName, 'record');\n // `conditional` rules carry a nested `when` predicate (record-scoped).\n check(`${where} when`, (rule as AnyRec).when, objectName, 'record');\n }\n // Field-level formulas (computed fields) reference the same object.\n const fields = obj.fields;\n const fieldList = Array.isArray(fields)\n ? (fields as AnyRec[])\n : (fields && typeof fields === 'object' ? Object.values(fields as AnyRec) as AnyRec[] : []);\n\n // ── ADR-0062 D7 — reject `field.columnName` on external objects ──────\n // `field.columnName` (localField → physicalColumn) is the managed-object\n // mechanism; it is NOT applied by the driver's query pipeline for federated\n // objects, where `external.columnMap` (remoteColumn → localField) is the\n // authoritative — and inverse — mapping. Allowing both would be a silent\n // dual-source ambiguity, so reject `columnName` on any object that declares\n // an `external` binding (a federated object). Managed objects are untouched.\n if (obj.external != null) {\n const fieldEntries: Array<[string, AnyRec]> = Array.isArray(fields)\n ? (fields as AnyRec[]).map((f) => [((f as AnyRec)?.name as string) ?? '?', f as AnyRec])\n : (fields && typeof fields === 'object'\n ? (Object.entries(fields as AnyRec) as Array<[string, AnyRec]>)\n : []);\n for (const [fname, fdef] of fieldEntries) {\n if (fdef && typeof fdef === 'object' && (fdef as AnyRec).columnName != null) {\n issues.push({\n where: `object '${objectName}' · field '${fname}'`,\n message:\n `external object '${objectName}': field '${fname}' sets columnName='${String((fdef as AnyRec).columnName)}', ` +\n `which is not supported on federated objects (ADR-0062 D7). The driver's query pipeline ignores ` +\n `field.columnName for external objects; map remote columns via the datasource's external.columnMap instead.`,\n source: `columnName='${String((fdef as AnyRec).columnName)}'`,\n severity: 'error',\n });\n }\n }\n }\n\n for (const f of fieldList) {\n // Field-level conditional rules are server-enforced (rule-validator) and\n // record-scoped — a bare ref silently fails the rule (required/readonly\n // not enforced = data-integrity hole). #1928 class, same as actions.\n if (f && typeof f === 'object') {\n const fname = (f.name as string) ?? '?';\n for (const key of ['requiredWhen', 'readonlyWhen', 'conditionalRequired', 'visibleWhen'] as const) {\n check(`object '${objectName}' · field '${fname}' ${key}`, (f as AnyRec)[key], objectName, 'record');\n }\n }\n if (f && typeof f === 'object' && f.formula) {\n // formulas are `value` role (any return type), still CEL. They are\n // `record`-scoped — `record.<field>`, never bare — so flag bare refs (#1928).\n const res = validateExpression('value', f.formula as string | { dialect?: string; source?: string },\n objectName ? { objectName, fields: fieldIndex.get(objectName), scope: 'record' } : { scope: 'record' });\n const fieldWhere = `object '${objectName}' · field '${(f.name as string) ?? '?'}' formula`;\n for (const e of res.errors) issues.push({ where: fieldWhere, message: e.message, source: e.source, severity: 'error' });\n for (const w of res.warnings) issues.push({ where: fieldWhere, message: w.message, source: w.source, severity: 'warning' });\n }\n }\n }\n\n // ── Action `visible` / `disabled` predicates ───────────────────────\n // Record-scoped, same as validation rules: a record-header / row action's\n // `visible` is evaluated by ActionEngine against `{ record, recordId,\n // objectName, user, … }` with fail-closed semantics, so a BARE field ref\n // (`done` instead of `record.done`) throws and the action is silently hidden\n // on every record (the trap behind the #2183 \"Mark Done never hides\" hunt).\n // Flagging it here turns that into a build error with a corrective message.\n // `disabled` may be a boolean (skip) or a predicate (check).\n const seenActions = new Set<string>();\n const checkAction = (where: string, action: AnyRec, objectName?: string): void => {\n const obj = objectName\n ?? (typeof action.objectName === 'string' ? action.objectName : undefined)\n ?? (typeof action.object === 'string' ? action.object : undefined);\n const name = typeof action.name === 'string' ? action.name : '?';\n const key = `${obj ?? ''}:${name}`;\n if (seenActions.has(key)) return; // de-dup (actions are merged onto objects AND kept top-level)\n seenActions.add(key);\n check(`${where} · action '${name}' visible`, action.visible, obj, 'record');\n if (typeof action.disabled !== 'boolean') {\n check(`${where} · action '${name}' disabled`, action.disabled, obj, 'record');\n }\n };\n for (const action of asArray(stack.actions)) {\n checkAction('stack', action);\n }\n for (const obj of objects) {\n const objectName = typeof obj.name === 'string' ? obj.name : undefined;\n for (const action of asArray(obj.actions)) {\n checkAction(`object '${objectName}'`, action, objectName);\n }\n }\n\n // ── Sharing-rule predicates (security-critical, record-scoped) ─────\n // A criteria sharing rule's `condition` decides which rows a principal sees.\n // It is evaluated against the record, so a bare ref silently changes access.\n for (const rule of asArray(stack.sharingRules)) {\n const ruleObj = typeof rule.object === 'string' ? rule.object : undefined;\n const where = `sharingRule '${(rule.name as string) ?? '?'}'${ruleObj ? ` (${ruleObj})` : ''} condition`;\n check(where, rule.condition ?? rule.criteria ?? rule.predicate, ruleObj, 'record');\n }\n\n // ── Hook `condition` predicates (record-scoped gate) ───────────────\n // A lifecycle hook's `condition` skips the handler when false; it is\n // evaluated against the record, so a bare ref silently makes the hook\n // run on every record (or never) instead of the intended subset.\n for (const hook of asArray(stack.hooks)) {\n const hookObj = typeof hook.object === 'string' ? hook.object : undefined; // array targets → no single field set\n check(`hook '${(hook.name as string) ?? '?'}'${hookObj ? ` (${hookObj})` : ''} condition`, hook.condition, hookObj, 'record');\n }\n\n return issues;\n}\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n//\n// Build-time guardrail for ADR-0047 list-view navigation modes.\n//\n// A pure `(stack) => Finding[]` rule (ADR-0019), run from `os validate` and\n// reusable by AI authoring. It catches the \"wrong context\" authoring mistake\n// the type system alone cannot surface at author time on an object list view\n// (\"views\" mode — where the ViewTabBar owns the tab-bar role):\n// - `quickFilters` — never valid on an object list view;\n// - `userFilters` with `element: 'tabs'` (or carrying `tabs`) — the tab-bar\n// preset style is page-only; it would collide with the ViewTabBar.\n// A `dropdown` (value-chip) `userFilters` IS allowed on object views since the\n// ADR-0047 amendment (framework #2679 / objectui #2338) and is NOT flagged.\n//\n// Runs PRE-parse (on the normalizeStackInput output, before the\n// ObjectStackDefinition parse): the object-list schema (ObjectListViewSchema)\n// narrows `userFilters` to ObjectUserFiltersSchema (dropdown/toggle only), so a\n// post-parse stack has already had a `tabs` user-filter stripped and this rule\n// would never see it. The layering is deliberate — tsc rejects it at author\n// time, the schema strips it at runtime (no throw, back-compat), and this rule\n// reports it at `os validate` with a fix hint. See objectui #2338 and ADR-0047.\n\nexport type ListViewModeSeverity = 'error' | 'warning';\n\nexport interface ListViewModeFinding {\n severity: ListViewModeSeverity;\n rule: string;\n /** Human-readable location, e.g. `object \"task\" › listViews.my_pending`. */\n where: string;\n /** Config path, e.g. `objects[0].listViews.my_pending.userFilters`. */\n path: string;\n message: string;\n hint: string;\n}\n\n// Rule id (registry entry).\nexport const LIST_VIEW_FILTERS_IN_VIEWS_MODE = 'list-view-filters-in-views-mode';\n\ntype AnyRec = Record<string, unknown>;\n\n/** Coerce an array-or-name-keyed-map collection to an array (name injected). */\nfunction asArray(v: unknown): AnyRec[] {\n if (Array.isArray(v)) return v as AnyRec[];\n if (v && typeof v === 'object') {\n return Object.entries(v as AnyRec).map(([name, def]) => ({\n name,\n ...(def as AnyRec),\n }));\n }\n return [];\n}\n\n/** Emit a finding for each wrong-context filter control on a single list-view def. */\nfunction scanView(\n view: unknown,\n where: string,\n path: string,\n out: ListViewModeFinding[],\n): void {\n if (!view || typeof view !== 'object') return;\n const rec = view as AnyRec;\n\n // `quickFilters` is never valid on an object list view.\n if (rec.quickFilters != null) {\n out.push({\n severity: 'error',\n rule: LIST_VIEW_FILTERS_IN_VIEWS_MODE,\n where,\n path: `${path}.quickFilters`,\n message:\n '`quickFilters` is a page filters-mode control and is ignored on an object ' +\n 'list view (\"views\" mode) — the ViewTabBar owns nav here.',\n hint:\n 'Move `quickFilters` to a page list (InterfaceListPage, \"filters\" mode), or ' +\n 'remove it. See ADR-0047.',\n });\n }\n\n // `userFilters` is allowed on object views ONLY as `dropdown` (value chips).\n // The `tabs` preset style — or any `userFilters` carrying `tabs` — collides\n // with the ViewTabBar and stays page-only.\n const uf = rec.userFilters;\n if (uf && typeof uf === 'object') {\n const ufRec = uf as AnyRec;\n if (ufRec.element === 'tabs' || ufRec.tabs != null) {\n out.push({\n severity: 'error',\n rule: LIST_VIEW_FILTERS_IN_VIEWS_MODE,\n where,\n path: `${path}.userFilters`,\n message:\n '`userFilters` with `element: \"tabs\"` is page-only and is ignored on an ' +\n 'object list view (\"views\" mode) — it would collide with the ViewTabBar.',\n hint:\n 'Use `listViews` for named presets on an object (each becomes a segmented ' +\n 'tab), switch to `element: \"dropdown\"` for value chips, or move the `tabs` ' +\n 'filter to a page list (InterfaceListPage, \"filters\" mode). See ADR-0047.',\n });\n }\n }\n}\n\n/** Scan a `listViews` record (name → list-view def). */\nfunction scanListViews(\n listViews: unknown,\n wherePrefix: string,\n pathPrefix: string,\n out: ListViewModeFinding[],\n): void {\n if (!listViews || typeof listViews !== 'object') return;\n for (const [name, view] of Object.entries(listViews as AnyRec)) {\n scanView(\n view,\n `${wherePrefix} › listViews.${name}`,\n `${pathPrefix}.listViews.${name}`,\n out,\n );\n }\n}\n\n/**\n * Flag ADR-0047 \"views\" mode violations on an object's built-in named views or a\n * `defineView` default `list` / named `listViews`: `quickFilters`, or a `tabs`\n * `userFilters`. A `dropdown` `userFilters` is allowed and not flagged. Returns\n * the list of findings (empty = clean). Caller decides how to surface / whether\n * to fail the build.\n *\n * Feed the PRE-parse stack (normalizeStackInput output) — see file header.\n */\nexport function validateListViewMode(stack: AnyRec): ListViewModeFinding[] {\n const out: ListViewModeFinding[] = [];\n\n // Object built-in named views (object.zod.ts `listViews`).\n asArray(stack.objects).forEach((obj, i) => {\n const label = typeof obj.name === 'string' ? `object \"${obj.name}\"` : `objects[${i}]`;\n scanListViews(obj.listViews, label, `objects[${i}]`, out);\n });\n\n // `defineView` aggregates (stack `views`: default `list` + named `listViews`).\n asArray(stack.views).forEach((view, i) => {\n const named =\n typeof view.objectName === 'string'\n ? view.objectName\n : typeof view.name === 'string'\n ? view.name\n : undefined;\n const label = named ? `view \"${named}\"` : `views[${i}]`;\n scanView(view.list, `${label} › list`, `views[${i}].list`, out);\n scanListViews(view.listViews, label, `views[${i}]`, out);\n });\n\n return out;\n}\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n//\n// Build-time diagnostics for the SDUI scoped-styling model (ADR-0065).\n//\n// A pure `(stack) => Finding[]` rule (ADR-0019): the same bar holds for\n// hand-authored and AI-generated pages, run from `os validate`/`compile` and\n// reusable by AI authoring. It catches the deterministic ways a `responsiveStyles`\n// block silently fails or drifts — the class of mistake an AI author is most\n// likely to make — *before* render, with actionable hints it can self-correct on.\n//\n// What it does NOT catch: whether the result looks good. Visual/semantic quality\n// (contrast, balance, \"is it ugly\") is only catchable by rendering + a VLM gate,\n// which is a separate, render-time concern (ADR-0065 §Decision-5).\n\nexport type StyleSeverity = 'error' | 'warning';\n\nexport interface StyleFinding {\n severity: StyleSeverity;\n rule: string;\n /** Human-readable location, e.g. `page \"pricing\" › node \"plan_solo\"`. */\n where: string;\n /** Config path, e.g. `pages[0].regions[0].components[1]`. */\n path: string;\n message: string;\n hint: string;\n}\n\n// Rule ids (registry entries).\nexport const STYLE_NODE_MISSING_ID = 'style-node-missing-id';\nexport const STYLE_CLASSNAME_TAILWIND = 'style-classname-tailwind';\nexport const STYLE_RESPONSIVE_NO_BASE = 'style-responsive-no-base';\nexport const STYLE_UNKNOWN_CSS_PROPERTY = 'style-unknown-css-property';\nexport const STYLE_UNKNOWN_TOKEN = 'style-unknown-token';\n\ntype AnyRec = Record<string, unknown>;\n\nconst BREAKPOINTS = ['large', 'medium', 'small', 'xsmall'] as const;\n\n/** SDUI design-token palette (ADR-0065) + base theme tokens, referenced as\n * `var(--name)`. Authors should resolve values against these. Kept in sync with\n * `apps/console/src/index.css` / `@object-ui/components` `:root`. */\nconst KNOWN_TOKENS = new Set<string>([\n // SDUI tokens\n 'space-1', 'space-2', 'space-3', 'space-4', 'space-5', 'space-6', 'space-8', 'space-10', 'space-12',\n 'radius', 'radius-sm', 'radius-md', 'radius-lg', 'radius-xl',\n 'shadow-sm', 'shadow-md', 'shadow-lg',\n 'surface', 'surface-sunken', 'text-strong', 'text-muted', 'brand', 'brand-foreground', 'hairline',\n // Base theme tokens (shadcn) — usually wrapped as hsl(var(--x)).\n 'background', 'foreground', 'card', 'card-foreground', 'popover', 'popover-foreground',\n 'primary', 'primary-foreground', 'secondary', 'secondary-foreground',\n 'muted', 'muted-foreground', 'accent', 'accent-foreground',\n 'destructive', 'destructive-foreground', 'border', 'input', 'ring',\n 'success', 'success-foreground', 'warning', 'warning-foreground',\n 'chart-1', 'chart-2', 'chart-3', 'chart-4', 'chart-5',\n]);\n\n/** Common CSS properties (camelCase) an SDUI block realistically sets. Generous\n * on purpose: an unknown property is only a *warning* (typo catcher), never a\n * blocker. Custom properties (`--x`) are always allowed. */\nconst KNOWN_CSS_PROPERTIES = new Set<string>([\n 'display', 'position', 'top', 'right', 'bottom', 'left', 'inset', 'zIndex', 'overflow', 'overflowX', 'overflowY', 'visibility', 'boxSizing', 'float', 'clear',\n 'width', 'height', 'minWidth', 'minHeight', 'maxWidth', 'maxHeight', 'aspectRatio',\n 'margin', 'marginTop', 'marginRight', 'marginBottom', 'marginLeft', 'marginInline', 'marginBlock',\n 'padding', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft', 'paddingInline', 'paddingBlock',\n 'flex', 'flexDirection', 'flexWrap', 'flexGrow', 'flexShrink', 'flexBasis', 'alignItems', 'alignContent', 'alignSelf', 'justifyContent', 'justifyItems', 'justifySelf', 'gap', 'rowGap', 'columnGap', 'order', 'placeItems', 'placeContent',\n 'grid', 'gridTemplate', 'gridTemplateColumns', 'gridTemplateRows', 'gridTemplateAreas', 'gridColumn', 'gridRow', 'gridArea', 'gridAutoFlow', 'gridAutoColumns', 'gridAutoRows',\n 'color', 'backgroundColor', 'background', 'backgroundImage', 'backgroundSize', 'backgroundPosition', 'backgroundRepeat', 'backgroundClip', 'opacity', 'mixBlendMode',\n 'fontSize', 'fontWeight', 'fontFamily', 'fontStyle', 'lineHeight', 'letterSpacing', 'textAlign', 'textTransform', 'textDecoration', 'textOverflow', 'whiteSpace', 'wordBreak', 'overflowWrap', 'fontVariantNumeric', 'verticalAlign', 'textShadow',\n 'border', 'borderTop', 'borderRight', 'borderBottom', 'borderLeft', 'borderColor', 'borderWidth', 'borderStyle', 'borderRadius', 'borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomLeftRadius', 'borderBottomRightRadius', 'outline', 'outlineOffset',\n 'boxShadow', 'transform', 'transformOrigin', 'transition', 'transitionProperty', 'transitionDuration', 'transitionTimingFunction', 'transitionDelay', 'animation', 'filter', 'backdropFilter', 'willChange',\n 'cursor', 'pointerEvents', 'userSelect', 'objectFit', 'objectPosition', 'content',\n]);\n\nconst VAR_RE = /var\\(\\s*--([a-zA-Z0-9-]+)\\s*[,)]/g;\n\n// High-precision Tailwind-utility detection. A `className` in page metadata is\n// \"Tailwind-looking\" if any token is a responsive/state variant, an arbitrary\n// `[…]` value, a known utility stem followed by a Tailwind *value* (number /\n// fraction / size keyword), or a bare layout utility. Tuned to NOT trip on\n// ordinary custom class names (e.g. `my-custom-scope`, `os-s-plan_solo`).\nconst TW_VARIANT = /^(sm|md|lg|xl|2xl|hover|focus|active|disabled|dark|group-hover|peer-[a-z]+|first|last|odd|even):/;\nconst TW_STEM_VALUE = /^-?(p|m|px|py|pt|pb|pl|pr|mx|my|mt|mb|ml|mr|gap|gap-x|gap-y|space-x|space-y|w|h|min-w|max-w|min-h|max-h|size|text|leading|tracking|bg|border|rounded|shadow|ring|opacity|inset|top|bottom|left|right|z|order|col|row|grid-cols|grid-rows|basis)-(\\d+(\\.\\d+)?|\\d+\\/\\d+|px|full|auto|none|screen|min|max|fit|xs|sm|md|lg|xl|2xl|3xl|4xl|5xl|6xl)$/;\nconst TW_BARE = /^(flex|grid|block|inline|inline-block|inline-flex|hidden|contents|table|flow-root|grow|shrink|truncate|italic|underline|uppercase|lowercase|capitalize|antialiased|absolute|relative|fixed|sticky|static|isolate|flex-col|flex-row|flex-wrap|flex-nowrap|items-center|items-start|items-end|items-stretch|justify-center|justify-between|justify-around|justify-start|justify-end|text-center|text-left|text-right|font-bold|font-semibold|font-medium|font-normal|tabular-nums)$/;\n\nfunction looksLikeTailwind(className: string): boolean {\n return className.split(/\\s+/).some((tok) => {\n if (!tok) return false;\n if (TW_VARIANT.test(tok)) return true;\n if (/\\[[^\\]]+\\]/.test(tok)) return true; // arbitrary value, e.g. p-[13px]\n if (TW_STEM_VALUE.test(tok)) return true;\n if (TW_BARE.test(tok)) return true;\n return false;\n });\n}\n\nfunction asArray(v: unknown): AnyRec[] {\n if (Array.isArray(v)) return v as AnyRec[];\n if (v && typeof v === 'object') {\n return Object.entries(v as AnyRec).map(([name, def]) => ({ name, ...(def as AnyRec) }));\n }\n return [];\n}\n\n/** Child nodes can hang off `children`, `properties.children`, `body`, or\n * `properties.body` depending on block type — collect them all. */\nfunction childrenOf(node: AnyRec): AnyRec[] {\n const props = (node.properties as AnyRec) ?? {};\n const out: AnyRec[] = [];\n for (const c of [node.children, props.children, node.body, props.body]) {\n if (Array.isArray(c)) out.push(...(c.filter((x) => x && typeof x === 'object') as AnyRec[]));\n }\n return out;\n}\n\nfunction checkNode(node: AnyRec, pageName: string, path: string, findings: StyleFinding[]): void {\n const id = typeof node.id === 'string' ? node.id : undefined;\n const type = typeof node.type === 'string' ? node.type : 'node';\n const where = `page \"${pageName}\" › ${id ? `node \"${id}\"` : `<${type}>`}`;\n const rs = node.responsiveStyles as AnyRec | undefined;\n const hasRs = !!rs && typeof rs === 'object' && BREAKPOINTS.some((b) => rs[b]);\n\n // (1) responsiveStyles needs an id to scope to — else the CSS is dropped.\n if (hasRs && !id) {\n findings.push({\n severity: 'error', rule: STYLE_NODE_MISSING_ID, where, path,\n message: `Node has responsiveStyles but no \\`id\\`; scoped CSS cannot be generated and the styles are silently dropped.`,\n hint: `Add a stable \\`id\\` to this node.`,\n });\n }\n\n // (2) responsive breakpoint without a `large` base → unstyled at desktop.\n if (hasRs && !rs!.large && BREAKPOINTS.slice(1).some((b) => rs![b])) {\n findings.push({\n severity: 'warning', rule: STYLE_RESPONSIVE_NO_BASE, where, path,\n message: `responsiveStyles sets a smaller breakpoint but no \\`large\\` base; the node is unstyled at desktop width.`,\n hint: `Put the unconditional/base styles under \\`responsiveStyles.large\\` (desktop-first).`,\n });\n }\n\n // (3) className that looks like Tailwind → won't render from metadata.\n if (typeof node.className === 'string' && node.className.trim() && looksLikeTailwind(node.className)) {\n findings.push({\n severity: 'warning', rule: STYLE_CLASSNAME_TAILWIND, where, path,\n message: `\\`className\\` contains Tailwind-looking utilities (\"${node.className.trim().slice(0, 60)}\"); these are not compiled from metadata and will silently do nothing.`,\n hint: `Style this node with \\`responsiveStyles\\` + design tokens instead of \\`className\\` (ADR-0065).`,\n });\n }\n\n // (4)+(5) unknown CSS property / unknown token inside each breakpoint map.\n if (rs && typeof rs === 'object') {\n for (const bp of BREAKPOINTS) {\n const map = rs[bp] as AnyRec | undefined;\n if (!map || typeof map !== 'object') continue;\n for (const [prop, value] of Object.entries(map)) {\n if (!prop.startsWith('--') && !KNOWN_CSS_PROPERTIES.has(prop)) {\n findings.push({\n severity: 'warning', rule: STYLE_UNKNOWN_CSS_PROPERTY, where, path: `${path}.responsiveStyles.${bp}`,\n message: `Unknown CSS property \"${prop}\" (typo?); if unintended it will not apply.`,\n hint: `Use a camelCase CSS property name (e.g. \\`flexDirection\\`, \\`backgroundColor\\`).`,\n });\n }\n if (typeof value === 'string') {\n let m: RegExpExecArray | null;\n VAR_RE.lastIndex = 0;\n while ((m = VAR_RE.exec(value))) {\n const token = m[1];\n if (!KNOWN_TOKENS.has(token) && !token.startsWith('tw-')) {\n findings.push({\n severity: 'warning', rule: STYLE_UNKNOWN_TOKEN, where, path: `${path}.responsiveStyles.${bp}.${prop}`,\n message: `References unknown design token \\`var(--${token})\\` (typo?); it will not resolve.`,\n hint: `Use a token from the ADR-0065 palette (e.g. \\`var(--space-6)\\`, \\`var(--surface)\\`, \\`hsl(var(--primary))\\`).`,\n });\n }\n }\n }\n }\n }\n }\n\n // Recurse.\n const kids = childrenOf(node);\n for (let i = 0; i < kids.length; i++) {\n checkNode(kids[i], pageName, `${path}.children[${i}]`, findings);\n }\n}\n\n/**\n * Validate every page's component tree for SDUI styling correctness (ADR-0065).\n * Returns findings (empty = clean). `error` findings describe styles that are\n * silently dropped and should fail validate/build; `warning` findings are\n * advisory (typos, drift, footguns).\n */\nexport function validateResponsiveStyles(stack: AnyRec): StyleFinding[] {\n const findings: StyleFinding[] = [];\n const pages = asArray(stack.pages);\n for (let p = 0; p < pages.length; p++) {\n const page = pages[p];\n const pageName = typeof page.name === 'string' ? page.name : `pages[${p}]`;\n const regions = asArray(page.regions);\n for (let r = 0; r < regions.length; r++) {\n const components = asArray(regions[r].components);\n for (let c = 0; c < components.length; c++) {\n checkNode(components[c], pageName, `pages[${p}].regions[${r}].components[${c}]`, findings);\n }\n }\n }\n return findings;\n}\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n//\n// Build-time diagnostics for AI-authored HTML-source pages (ADR-0080).\n//\n// Applies to `kind:'html'` (and its deprecated alias `kind:'jsx'`) — the tier\n// whose `source` is constrained JSX/HTML parsed (never executed) to the tree.\n// `kind:'react'` (ADR-0081) is intentionally NOT linted here: its source is\n// real JavaScript, not constrained JSX, so the constrained parser would\n// false-error on hooks / expressions.\n//\n// A pure `(stack) => Finding[]` rule (ADR-0019), run from `os validate` / `os\n// build`. An html page's `source` is a constrained JSX/Tailwind string\n// compiled (parsed, never executed) to the SDUI tree at save time. This gate\n// parses it at author time so malformed source fails loudly (ADR-0078) instead\n// of being stored and breaking only at render.\n//\n// Scope: parse-level — syntax, tag matching, and forbidden constructs (event\n// handlers, dangerouslySetInnerHTML). Full component/prop whitelist validation\n// needs the registry manifest (a cross-repo artifact); when that is wired,\n// thread it through `compile()` here. Until then this catches the structural\n// class of error an AI author is most likely to emit.\n\nimport { parseJsx, compile, type Manifest } from '@objectstack/sdui-parser';\n\nexport type JsxPageSeverity = 'error' | 'warning';\n\nexport interface JsxPageFinding {\n severity: JsxPageSeverity;\n rule: string;\n /** Human-readable location, e.g. `page \"command_center\" › <flex>`. */\n where: string;\n /** Config path, e.g. `pages[3].source`. */\n path: string;\n message: string;\n hint: string;\n}\n\ntype AnyRec = Record<string, unknown>;\nconst asArray = (v: unknown): AnyRec[] => (Array.isArray(v) ? (v as AnyRec[]) : []);\n\nexport function validateJsxPages(stack: AnyRec, opts: { manifest?: Manifest } = {}): JsxPageFinding[] {\n const findings: JsxPageFinding[] = [];\n const pages = asArray(stack.pages);\n for (let p = 0; p < pages.length; p++) {\n const page = pages[p];\n // html tier (+ deprecated 'jsx' alias). react pages are not constrained JSX.\n if (!page || (page.kind !== 'html' && page.kind !== 'jsx')) continue;\n const name = String(page.name ?? `#${p}`);\n const source = page.source;\n if (typeof source !== 'string' || source.trim() === '') {\n // (PageSchema's superRefine also covers this; keep it for the build path.)\n findings.push({\n severity: 'error',\n rule: 'jsx-page-empty-source',\n where: `page \"${name}\"`,\n path: `pages[${p}].source`,\n message: `kind:'${page.kind}' page has no \\`source\\`.`,\n hint: 'Author the page as a constrained JSX/Tailwind string in `source`.',\n });\n continue;\n }\n // With a component manifest, do full validation (unknown component, missing/\n // wrong prop, bad enum, bindings); without it, parse-level (syntax/structure).\n const { diagnostics } = opts.manifest ? compile(source, opts.manifest) : parseJsx(source);\n for (const d of diagnostics) {\n findings.push({\n severity: d.severity,\n rule: `jsx-${d.code}`,\n where: d.tag ? `page \"${name}\" › <${d.tag}>` : `page \"${name}\"`,\n path: `pages[${p}].source`,\n message: d.message,\n hint: 'The source is parsed (never executed) and compiled to the SDUI tree at save time — fix the JSX.',\n });\n }\n }\n return findings;\n}\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n//\n// Build-time syntax gate for `kind:'react'` pages (ADR-0081).\n//\n// A react page's `source` is REAL JavaScript/JSX executed at render by the\n// runtime — so the constrained JSX parser (validate-jsx-pages) cannot check it.\n// We instead transpile it with Sucrase (the same transpiler the runtime uses),\n// transpile-ONLY — never executed — to surface syntax errors at `os build`\n// instead of at render (ADR-0078: fail loudly at author time). It does NOT\n// validate runtime behaviour (a transpiling page can still throw at render);\n// the render-time error boundary owns that.\n\nimport { createRequire } from 'node:module';\nimport type { transform as sucraseTransform } from 'sucrase';\n\n// Sucrase must NOT be imported at module top level: it is ~1.5 MB of CJS\n// (~16 ms cold require), and @objectstack/lint sits on the kernel boot path —\n// while this gate only runs when a `kind:'react'` page is actually validated\n// (rare, trusted tier). Same boot-path contract as the TypeScript compiler in\n// validate-react-page-props.ts: loaded lazily, on first use, staying a regular\n// dependency in package.json. Guarded by lazy-deps.test.ts.\n//\n// `node:module` is a Node builtin, untouched by esbuild/tsup, so the static\n// `createRequire` import survives bundling; the `createRequire(...)` call is\n// deferred because `import.meta.url` is rewritten to an empty stub in the CJS\n// build (same pattern as driver-sqlite-wasm's knex-wasm-dialect).\nlet cachedTransform: typeof sucraseTransform | null = null;\nfunction loadSucraseTransform(): typeof sucraseTransform {\n if (cachedTransform) return cachedTransform;\n const anchor =\n typeof import.meta !== 'undefined' && import.meta.url\n ? import.meta.url\n : typeof __filename !== 'undefined'\n ? __filename\n : process.cwd() + '/';\n try {\n cachedTransform = (createRequire(anchor)('sucrase') as { transform: typeof sucraseTransform }).transform;\n } catch (err) {\n throw new Error(\n `@objectstack/lint: validating a kind:'react' page requires the \"sucrase\" package, which could not be loaded ` +\n `(${err instanceof Error ? err.message : String(err)}). It is a declared dependency of @objectstack/lint — ` +\n `if this deployment prunes packages, keep \"sucrase\" in the image; it is only loaded when a react-source page is validated.`,\n );\n }\n return cachedTransform;\n}\n\nexport type ReactPageSeverity = 'error' | 'warning';\n\nexport interface ReactPageFinding {\n severity: ReactPageSeverity;\n rule: string;\n where: string;\n path: string;\n message: string;\n hint: string;\n}\n\ntype AnyRec = Record<string, unknown>;\nconst asArray = (v: unknown): AnyRec[] => (Array.isArray(v) ? (v as AnyRec[]) : []);\n\nexport function validateReactPages(stack: AnyRec): ReactPageFinding[] {\n const findings: ReactPageFinding[] = [];\n const pages = asArray(stack.pages);\n for (let p = 0; p < pages.length; p++) {\n const page = pages[p];\n if (!page || page.kind !== 'react') continue;\n const name = String(page.name ?? `#${p}`);\n const source = page.source;\n if (typeof source !== 'string' || source.trim() === '') {\n findings.push({\n severity: 'error',\n rule: 'react-page-empty-source',\n where: `page \"${name}\"`,\n path: `pages[${p}].source`,\n message: \"kind:'react' page has no `source`.\",\n hint: 'Author the page as a real React component string in `source`.',\n });\n continue;\n }\n // Outside the try below on purpose: a missing transpiler must surface as\n // an error, not be swallowed as a syntax finding.\n const transform = loadSucraseTransform();\n try {\n // transpile-only (no eval) — catches syntax errors, unterminated JSX, etc.\n transform(source, { transforms: ['jsx', 'typescript'], production: true });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n findings.push({\n severity: 'error',\n rule: 'react-page-syntax',\n where: `page \"${name}\"`,\n path: `pages[${p}].source`,\n message: `kind:'react' source has a syntax error: ${message.split('\\n')[0]}`,\n hint: 'The source is transpiled (never executed) at build to catch syntax errors early — fix the JS/JSX.',\n });\n }\n }\n return findings;\n}\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n//\n// Build-time prop check for `kind:'react'` pages (ADR-0081 Phase 2). The syntax\n// gate (validate-react-pages) confirms the source parses; this confirms the\n// AUTHOR USED THE COMPONENT CONTRACT correctly — it parses the real JSX with the\n// TypeScript compiler, finds usages of the injected blocks (<ObjectForm>,\n// <ListView>, …), and checks each against the react-tier contract\n// (REACT_BLOCKS in @objectstack/spec):\n//\n// - missing a required binding prop (e.g. <ObjectForm> with no objectName)\n// → error. (Only the React-enforceable overlay props are required-checked;\n// a spread `{...props}` escapes the check since props may come from it.)\n// - a prop that is a near-miss (edit distance ≤ 2) of a known prop\n// (e.g. `onSucces` → `onSuccess`) → warning. We do NOT flag arbitrary\n// unknown props (the contract's data props are a curated subset) — only the\n// likely typos, to keep false positives near zero.\n\nimport { createRequire } from 'node:module';\nimport type ts from 'typescript';\nimport { REACT_BLOCKS } from '@objectstack/spec/ui';\n\n// The TypeScript compiler must NOT be imported at module top level: it is\n// ~9 MB of CJS (~70 ms+ to parse, worse on container cold starts), and\n// @objectstack/lint sits on the kernel boot path — while this gate only runs\n// when a `kind:'react'` page is actually validated (rare, trusted tier). An\n// eager import also hard-crashes boot in deployments that prune the package\n// from the image (cloud's Docker pruner did exactly that). So the compiler is\n// loaded lazily, on first use, and stays a regular dependency in package.json.\n// Guarded by lazy-deps.test.ts.\n//\n// `node:module` is a Node builtin, untouched by esbuild/tsup, so the static\n// `createRequire` import survives bundling; the `createRequire(...)` call is\n// deferred because `import.meta.url` is rewritten to an empty stub in the CJS\n// build (same pattern as driver-sqlite-wasm's knex-wasm-dialect).\nlet cachedTs: typeof ts | null = null;\nfunction loadTypeScript(): typeof ts {\n if (cachedTs) return cachedTs;\n const anchor =\n typeof import.meta !== 'undefined' && import.meta.url\n ? import.meta.url\n : typeof __filename !== 'undefined'\n ? __filename\n : process.cwd() + '/';\n try {\n cachedTs = createRequire(anchor)('typescript') as typeof ts;\n } catch (err) {\n throw new Error(\n `@objectstack/lint: validating a kind:'react' page requires the \"typescript\" package, which could not be loaded ` +\n `(${err instanceof Error ? err.message : String(err)}). It is a declared dependency of @objectstack/lint — ` +\n `if this deployment prunes packages, keep \"typescript\" in the image; it is only loaded when a react-source page is validated.`,\n );\n }\n return cachedTs;\n}\n\nexport type ReactPropSeverity = 'error' | 'warning';\n\nexport interface ReactPropFinding {\n severity: ReactPropSeverity;\n rule: string;\n where: string;\n path: string;\n message: string;\n hint: string;\n}\n\ntype AnyRec = Record<string, unknown>;\nconst asArray = (v: unknown): AnyRec[] => (Array.isArray(v) ? (v as AnyRec[]) : []);\n\ninterface BlockSpec {\n requiredBindings: string[];\n knownProps: Set<string>;\n}\nconst BLOCKS: Map<string, BlockSpec> = new Map(\n (REACT_BLOCKS as Array<{ tag: string; interactions: Array<{ name: string; required?: boolean }> }>).map((b) => [\n b.tag,\n {\n requiredBindings: b.interactions.filter((i) => i.required).map((i) => i.name),\n knownProps: new Set(b.interactions.map((i) => i.name)),\n },\n ]),\n);\n\nfunction editDistance(a: string, b: string, cap = 2): number {\n if (Math.abs(a.length - b.length) > cap) return cap + 1;\n const dp = Array.from({ length: a.length + 1 }, (_, i) => i);\n for (let j = 1; j <= b.length; j++) {\n let prev = dp[0];\n dp[0] = j;\n for (let i = 1; i <= a.length; i++) {\n const tmp = dp[i];\n dp[i] = Math.min(dp[i] + 1, dp[i - 1] + 1, prev + (a[i - 1] === b[j - 1] ? 0 : 1));\n prev = tmp;\n }\n }\n return dp[a.length];\n}\n\nfunction nearestKnown(prop: string, known: Set<string>): string | null {\n if (known.has(prop)) return null;\n let best: string | null = null;\n let bestD = 3;\n for (const k of known) {\n const d = editDistance(prop, k);\n if (d < bestD) { bestD = d; best = k; }\n }\n return bestD <= 2 ? best : null;\n}\n\nexport function validateReactPageProps(stack: AnyRec): ReactPropFinding[] {\n const findings: ReactPropFinding[] = [];\n const pages = asArray(stack.pages);\n for (let p = 0; p < pages.length; p++) {\n const page = pages[p];\n if (!page || page.kind !== 'react') continue;\n const source = page.source;\n if (typeof source !== 'string' || source.trim() === '') continue;\n const name = String(page.name ?? `#${p}`);\n\n // Outside the try below on purpose: a missing compiler must surface as an\n // error, not be swallowed as \"unparseable source\".\n const tsc = loadTypeScript();\n\n let sf: ts.SourceFile;\n try {\n sf = tsc.createSourceFile('page.tsx', source, tsc.ScriptTarget.Latest, true, tsc.ScriptKind.TSX);\n } catch {\n continue; // the syntax gate reports unparseable sources\n }\n\n const visit = (node: ts.Node): void => {\n if (tsc.isJsxOpeningElement(node) || tsc.isJsxSelfClosingElement(node)) {\n const tag = node.tagName.getText(sf);\n const block = BLOCKS.get(tag);\n if (block) {\n let hasSpread = false;\n const used = new Set<string>();\n for (const a of node.attributes.properties) {\n if (tsc.isJsxSpreadAttribute(a)) { hasSpread = true; continue; }\n if (tsc.isJsxAttribute(a)) used.add(a.name.getText(sf));\n }\n const where = `page \"${name}\" › <${tag}>`;\n const path = `pages[${p}].source`;\n if (!hasSpread) {\n for (const req of block.requiredBindings) {\n if (!used.has(req)) {\n findings.push({\n severity: 'error',\n rule: 'react-prop-missing-required',\n where, path,\n message: `<${tag}> is missing the required prop \"${req}\".`,\n hint: `Pass ${req}={…}. See the react-tier component contract.`,\n });\n }\n }\n }\n for (const u of used) {\n const near = nearestKnown(u, block.knownProps);\n if (near) {\n findings.push({\n severity: 'warning',\n rule: 'react-prop-typo',\n where, path,\n message: `<${tag}> has prop \"${u}\" — did you mean \"${near}\"?`,\n hint: 'Likely a typo of a contract prop. Fix it or remove it.',\n });\n }\n }\n }\n }\n tsc.forEachChild(node, visit);\n };\n visit(sf);\n }\n return findings;\n}\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n//\n// Build-time guardrail for SDUI source-tier page styling (ADR-0065 / ADR-0080 /\n// ADR-0081). A `kind:'html'` or `kind:'react'` page's `source` is RUNTIME\n// metadata — the console's build-time Tailwind only scans the renderer's own\n// source, never an authored page string. So a Tailwind `className` in page\n// source silently produces NO CSS (the exact ADR-0065 failure: styling that\n// \"works only by coincidence\" when the class happens to be one objectui already\n// ships). This rule flags authored `className` attributes in source-tier pages\n// before render, with the actionable fix.\n//\n// It is the styling counterpart to the react-prop gate: a pure\n// `(stack) => Finding[]` rule (ADR-0019), run from `os validate`/`compile` and\n// reusable by AI authoring so the agent self-corrects.\n\nexport type SourceStyleSeverity = 'error' | 'warning';\n\nexport interface SourceStyleFinding {\n severity: SourceStyleSeverity;\n rule: string;\n where: string;\n path: string;\n message: string;\n hint: string;\n}\n\nexport const PAGE_SOURCE_CLASSNAME = 'page-source-className-tailwind';\n\ntype AnyRec = Record<string, unknown>;\nconst asArray = (v: unknown): AnyRec[] => (Array.isArray(v) ? (v as AnyRec[]) : []);\n\n// `className=` as a JSX attribute: name, optional ws, `=`, then `\"`/`'`/`{`.\nconst CLASSNAME_ATTR = /\\bclassName\\s*=\\s*[\"'{]/g;\n\nexport function validatePageSourceStyling(stack: AnyRec): SourceStyleFinding[] {\n const findings: SourceStyleFinding[] = [];\n const pages = asArray(stack.pages);\n for (let p = 0; p < pages.length; p++) {\n const page = pages[p];\n if (!page) continue;\n const kind = page.kind;\n if (kind !== 'html' && kind !== 'react' && kind !== 'jsx') continue;\n const source = page.source;\n if (typeof source !== 'string' || source.trim() === '') continue;\n const name = String(page.name ?? `#${p}`);\n\n CLASSNAME_ATTR.lastIndex = 0;\n let count = 0;\n while (CLASSNAME_ATTR.exec(source) !== null) count++;\n if (count === 0) continue;\n\n findings.push({\n severity: 'warning',\n rule: PAGE_SOURCE_CLASSNAME,\n where: `page \"${name}\"`,\n path: `pages[${p}].source`,\n message: `${count} \\`className\\` attribute${count > 1 ? 's' : ''} in ${String(kind)}-source page — Tailwind utilities in page source silently produce no CSS (the build never scans authored metadata; ADR-0065).`,\n hint:\n kind === 'react'\n ? \"Style with inline style={{}} using hsl(var(--token)) theme colors (e.g. color:'hsl(var(--foreground))', background:'hsl(var(--card))'); render drawer/modal via <ObjectForm formType=\\\"drawer\\\"|\\\"modal\\\"> instead of hand-rolled overlays.\"\n : \"Lay out with the components' structured props (<flex direction gap>, <grid columns>) and add CSS via a JSON style object style={{\\\"color\\\":\\\"hsl(var(--foreground))\\\"}}; do not use Tailwind className.\",\n });\n }\n return findings;\n}\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { objectTitleCompleteness } from '@objectstack/spec/data';\nimport type { DisplayNameObjectMeta } from '@objectstack/spec/data';\n\n/**\n * Build-time record-title diagnostics (ADR-0079).\n *\n * A record's human title is a structural invariant: every object resolves a\n * primary title from a real STORED field via `nameField` (the canonical\n * pointer; `displayNameField` is the deprecated alias) or a deterministic\n * derivation. Two authoring smells are flagged here so `os build`/`os lint`,\n * the MCP authoring surface, and hand-authoring all get the coverage cloud\n * graph-lint already has (the ADR-0078 \"not cloud-only\" principle):\n *\n * - `title-format-retired` — the object declares a `titleFormat`. That field\n * is a RENDER-ONLY template the server can neither return nor query; ADR-0079\n * retires it in favour of `nameField`. The schema still parses it (existing\n * metadata keeps loading), so this is advisory, not an error.\n * - `title-unresolvable` — `objectTitleCompleteness` reports `status: 'none'`:\n * no `nameField`/`displayNameField` pointer and no title-eligible field to\n * derive one from. Records will have no meaningful title (the runtime falls\n * back to the auto-provisioned primary / `Record #<id>` floor), so this is a\n * warning, not an error — nothing is fully broken.\n *\n * Both are warnings: the auto-provision transform and the id floor mean a\n * green build never ships a fully title-less object. Reuses the shared spec\n * predicate (`@objectstack/spec/data` → display-name) so cloud and framework\n * classify titles identically.\n */\n\nexport const TITLE_FORMAT_RETIRED = 'title-format-retired';\nexport const TITLE_UNRESOLVABLE = 'title-unresolvable';\n\nexport type RecordTitleSeverity = 'error' | 'warning';\n\nexport interface RecordTitleFinding {\n /** Always `warning` today — both rules are advisory (see module note). */\n severity: RecordTitleSeverity;\n /** Diagnostic rule id (registry entry), e.g. `title-format-retired`. */\n rule: string;\n /** Human-readable location, e.g. `object \"invoice\"`. */\n where: string;\n /** Config path, e.g. `objects[3]`. */\n path: string;\n /** What is wrong. */\n message: string;\n /** How to fix it. */\n hint: string;\n}\n\ntype AnyRec = Record<string, unknown>;\n\n/** Coerce a collection (array or name-keyed map) to an array of records. */\nfunction asArray(v: unknown): AnyRec[] {\n if (Array.isArray(v)) return v as AnyRec[];\n if (v && typeof v === 'object') {\n return Object.entries(v as AnyRec).map(([name, def]) => ({ name, ...(def as AnyRec) }));\n }\n return [];\n}\n\n/**\n * Validate every object's record-title declaration. Returns the list of\n * findings (empty = clean). Both rules are advisory (`warning`): the caller\n * must never fail the build on them alone — auto-provision + the `Record #<id>`\n * floor guarantee a resolvable title at runtime.\n */\nexport function validateRecordTitle(stack: AnyRec): RecordTitleFinding[] {\n const findings: RecordTitleFinding[] = [];\n\n const objects = asArray(stack.objects);\n for (let i = 0; i < objects.length; i++) {\n const obj = objects[i];\n const objName = typeof obj.name === 'string' ? obj.name : `(object ${i})`;\n const where = `object \"${objName}\"`;\n const path = `objects[${i}]`;\n\n // ── (a) titleFormat is retired (ADR-0079) ──\n // Render-only template the server cannot return or query. Still parsed by\n // the schema for back-compat, so advisory.\n if (obj.titleFormat !== undefined && obj.titleFormat !== null && obj.titleFormat !== '') {\n findings.push({\n severity: 'warning',\n rule: TITLE_FORMAT_RETIRED,\n where,\n path,\n message:\n `${objName}: titleFormat is retired (ADR-0079) — migrate to nameField ` +\n `(single field) or a formula field designated nameField`,\n hint:\n `titleFormat is a render-only template the server cannot return or ` +\n `query, and an explicit nameField now takes precedence. For a ` +\n `single-field title set nameField: '<field>'. For a composite title, ` +\n `add a formula field (returnType: 'text') and designate it via ` +\n `nameField.`,\n });\n }\n\n // ── (b) no resolvable title (status: 'none') ──\n // Reuse the shared spec predicate so cloud graph-lint and framework lint\n // classify titles identically. `none` = no pointer AND nothing derivable.\n const completeness = objectTitleCompleteness(obj as DisplayNameObjectMeta);\n if (completeness.status === 'none') {\n findings.push({\n severity: 'warning',\n rule: TITLE_UNRESOLVABLE,\n where,\n path,\n message:\n `${objName}: no resolvable record title — records will have no ` +\n `meaningful name (no nameField and no title-eligible field to derive one)`,\n hint:\n `Set nameField to a text/email field (or a formula field with ` +\n `returnType: 'text'), or add a text field named \"name\"/\"title\". The ` +\n `runtime auto-provisions a primary and falls back to \"Record #<id>\", ` +\n `but an explicit title is far more useful.`,\n });\n }\n }\n\n return findings;\n}\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Build-time semantic-role diagnostics (ADR-0085).\n *\n * The object-level semantic roles (`stageField`, `highlightFields` /\n * deprecated `compactLayout`, `fieldGroups` + `Field.group`) are pointers\n * into the object's own field map. A dangling pointer is Zod-valid but\n * silently inert at render time — the exact \"parsed, unmarked, silently\n * inert\" shape ADR-0078 prohibits — so the completeness lint flags it here,\n * uniformly for `os build`/`os validate`, MCP authoring and hand authors.\n *\n * All three rules are warnings, not errors: every consumer degrades\n * gracefully (an unknown `Field.group` renders in the ungrouped bucket, an\n * unknown highlight name is skipped, an unknown `stageField` falls back to\n * heuristics), so nothing is fully broken — but the author almost certainly\n * typo'd a name and should be told at author time, not discover it by\n * staring at an unchanged page.\n */\n\nexport const FIELD_GROUP_UNDECLARED = 'field-group-undeclared';\nexport const FIELD_GROUP_EMPTY = 'field-group-empty';\nexport const SEMANTIC_ROLE_FIELD_UNKNOWN = 'semantic-role-field-unknown';\n\nexport type SemanticRoleSeverity = 'error' | 'warning';\n\nexport interface SemanticRoleFinding {\n /** Always `warning` today — all three rules are advisory (see module note). */\n severity: SemanticRoleSeverity;\n /** Diagnostic rule id, e.g. `field-group-undeclared`. */\n rule: string;\n /** Human-readable location, e.g. `object \"invoice\"`. */\n where: string;\n /** Config path, e.g. `objects[3]`. */\n path: string;\n /** What is wrong. */\n message: string;\n /** How to fix it. */\n hint: string;\n}\n\ntype AnyRec = Record<string, unknown>;\n\n/** Coerce a collection (array or name-keyed map) to an array of records. */\nfunction asArray(v: unknown): AnyRec[] {\n if (Array.isArray(v)) return v as AnyRec[];\n if (v && typeof v === 'object') {\n return Object.entries(v as AnyRec).map(([name, def]) => ({ name, ...(def as AnyRec) }));\n }\n return [];\n}\n\n/**\n * Validate every object's semantic-role pointers. Returns the list of\n * findings (empty = clean). Advisory only — the caller must never fail the\n * build on these alone.\n */\nexport function validateSemanticRoles(stack: AnyRec): SemanticRoleFinding[] {\n const findings: SemanticRoleFinding[] = [];\n\n const objects = asArray(stack.objects);\n for (let i = 0; i < objects.length; i++) {\n const obj = objects[i];\n if (!obj || typeof obj !== 'object') continue; // tolerate junk entries\n const objName = typeof obj.name === 'string' ? obj.name : `(object ${i})`;\n const where = `object \"${objName}\"`;\n const path = `objects[${i}]`;\n\n const fields = (obj.fields && typeof obj.fields === 'object' && !Array.isArray(obj.fields))\n ? (obj.fields as Record<string, AnyRec | undefined>)\n : {};\n const fieldNames = new Set(Object.keys(fields));\n\n // ── (a) Field.group → declared fieldGroups[].key ──\n const declaredGroups = new Set(\n (Array.isArray(obj.fieldGroups) ? obj.fieldGroups : [])\n .filter((g): g is AnyRec => !!g && typeof g === 'object')\n .map((g) => g.key)\n .filter((k): k is string => typeof k === 'string' && k.length > 0),\n );\n const referencedGroups = new Set<string>();\n for (const [fname, f] of Object.entries(fields)) {\n const g = f?.group;\n if (typeof g !== 'string' || g.length === 0) continue;\n referencedGroups.add(g);\n if (!declaredGroups.has(g)) {\n findings.push({\n severity: 'warning',\n rule: FIELD_GROUP_UNDECLARED,\n where,\n path: `${path}.fields.${fname}.group`,\n message:\n `${objName}.${fname}: group \"${g}\" is not declared in fieldGroups — ` +\n `the field renders in the ungrouped bucket, not under \"${g}\"`,\n hint:\n `Declare { key: '${g}', label: '…' } in ${objName}.fieldGroups, or fix ` +\n `the field's group reference. Group keys are snake_case and must match exactly.`,\n });\n }\n }\n\n // ── (b) declared group no field references ──\n for (const key of declaredGroups) {\n if (!referencedGroups.has(key)) {\n findings.push({\n severity: 'warning',\n rule: FIELD_GROUP_EMPTY,\n where,\n path: `${path}.fieldGroups`,\n message:\n `${objName}: fieldGroups declares \"${key}\" but no field references it — ` +\n `the group never renders`,\n hint:\n `Assign at least one field via group: '${key}', or remove the unused ` +\n `group declaration.`,\n });\n }\n }\n\n // ── (c) semantic-role pointers name real fields ──\n const stage = obj.stageField;\n if (typeof stage === 'string' && stage.length > 0 && !fieldNames.has(stage)) {\n findings.push({\n severity: 'warning',\n rule: SEMANTIC_ROLE_FIELD_UNKNOWN,\n where,\n path: `${path}.stageField`,\n message:\n `${objName}: stageField \"${stage}\" is not a field on this object — ` +\n `consumers fall back to heuristic stage detection`,\n hint:\n `Point stageField at an existing select/status field, or set ` +\n `stageField: false to declare the object has no linear lifecycle.`,\n });\n }\n\n const highlights = Array.isArray(obj.highlightFields)\n ? obj.highlightFields\n : Array.isArray(obj.compactLayout) // deprecated alias (pre-normalization input)\n ? obj.compactLayout\n : [];\n for (const entry of highlights) {\n if (typeof entry !== 'string' || entry.length === 0 || fieldNames.has(entry)) continue;\n findings.push({\n severity: 'warning',\n rule: SEMANTIC_ROLE_FIELD_UNKNOWN,\n where,\n path: `${path}.highlightFields`,\n message:\n `${objName}: highlightFields entry \"${entry}\" is not a field on this ` +\n `object — it is silently skipped by every consumer`,\n hint:\n `Fix the field name (highlightFields drives default columns, cards, ` +\n `previews and the detail highlight strip, in order).`,\n });\n }\n }\n\n return findings;\n}\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Build-time form-layout diagnostics (#2578).\n *\n * Authored form views carry field references and column-layout hints that are\n * Zod-valid but can be silently wrong at render time — the \"parsed, unmarked,\n * silently inert\" shape ADR-0078 prohibits. This lint catches the two that\n * matter for multi-column, AI-authored forms, uniformly for `os build` /\n * `os validate`, MCP authoring and hand authors (ADR-0019).\n *\n * Both rules are warnings, not errors — nothing is fully broken (an unknown\n * field name is skipped; an over-wide colSpan is clamped) — but each is almost\n * certainly an authoring mistake worth surfacing at author time:\n *\n * - `form-field-unknown` — a section references a field that is not on the\n * form's bound object, so the field silently does not render.\n * - `absolute-colspan-discouraged` — a field uses the absolute `colSpan`. Under\n * a per-surface DERIVED column count (mobile 1 / modal 2 / page 3-4) a fixed\n * span only lines up at the one width the author imagined; the renderer\n * clamps it. The robust primitive is the relative `span: 'full'`.\n *\n * Scope: top-level form `views` (a `sections` array). Forms embedded inside\n * page component trees are a follow-up — the walker deliberately stays shallow\n * so it never guesses at an arbitrary component's object binding.\n */\n\nexport const FORM_FIELD_UNKNOWN = 'form-field-unknown';\nexport const FORM_COLSPAN_ABSOLUTE = 'absolute-colspan-discouraged';\n\nexport type FormLayoutSeverity = 'error' | 'warning';\n\nexport interface FormLayoutFinding {\n /** Always `warning` today — both rules are advisory (see module note). */\n severity: FormLayoutSeverity;\n /** Diagnostic rule id, e.g. `form-field-unknown`. */\n rule: string;\n /** Human-readable location, e.g. `view \"contract_form\"`. */\n where: string;\n /** Config path, e.g. `views[2].sections[0].fields[3]`. */\n path: string;\n /** What is wrong. */\n message: string;\n /** How to fix it. */\n hint: string;\n}\n\ntype AnyRec = Record<string, unknown>;\n\n/** Coerce a collection (array or name-keyed map) to an array of records. */\nfunction asArray(v: unknown): AnyRec[] {\n if (Array.isArray(v)) return v as AnyRec[];\n if (v && typeof v === 'object') {\n return Object.entries(v as AnyRec).map(([name, def]) => ({ name, ...(def as AnyRec) }));\n }\n return [];\n}\n\n/** A section field entry is either a bare field name or `{ field, colSpan, … }`. */\nfunction fieldNameOf(entry: unknown): string | null {\n if (typeof entry === 'string') return entry.length > 0 ? entry : null;\n if (entry && typeof entry === 'object' && !Array.isArray(entry)) {\n const f = (entry as AnyRec).field;\n return typeof f === 'string' && f.length > 0 ? f : null;\n }\n return null;\n}\n\n/** The object a form view binds to: `data.object` (canonical) or `objectName`. */\nfunction boundObject(view: AnyRec): string | undefined {\n const data = view.data;\n if (data && typeof data === 'object' && typeof (data as AnyRec).object === 'string') {\n return (data as AnyRec).object as string;\n }\n return typeof view.objectName === 'string' ? (view.objectName as string) : undefined;\n}\n\n/**\n * Validate authored form-view layout. Returns findings (empty = clean).\n * Advisory only — the caller must never fail the build on these alone.\n */\nexport function validateFormLayout(stack: AnyRec): FormLayoutFinding[] {\n const findings: FormLayoutFinding[] = [];\n\n // object name → its field-name set, for reference checking.\n const objectFields = new Map<string, Set<string>>();\n for (const obj of asArray(stack.objects)) {\n const name = typeof obj.name === 'string' ? obj.name : undefined;\n if (!name) continue;\n const fields = (obj.fields && typeof obj.fields === 'object' && !Array.isArray(obj.fields))\n ? Object.keys(obj.fields as AnyRec)\n : [];\n objectFields.set(name, new Set(fields));\n }\n\n const views = asArray(stack.views);\n for (let i = 0; i < views.length; i++) {\n const view = views[i];\n if (!view || typeof view !== 'object') continue;\n const sections = Array.isArray(view.sections) ? view.sections : null;\n if (!sections) continue; // only form views carry a sections array\n\n const viewName = typeof view.name === 'string' ? view.name : `(view ${i})`;\n const objName = boundObject(view);\n // Only reference-check when the bound object resolves; otherwise we can't.\n const known = objName ? objectFields.get(objName) : undefined;\n const where = `view \"${viewName}\"`;\n const base = `views[${i}]`;\n\n for (let s = 0; s < sections.length; s++) {\n const sec = sections[s];\n const secFields = sec && typeof sec === 'object' && Array.isArray((sec as AnyRec).fields)\n ? ((sec as AnyRec).fields as unknown[])\n : [];\n for (let f = 0; f < secFields.length; f++) {\n const entry = secFields[f];\n const fname = fieldNameOf(entry);\n const fpath = `${base}.sections[${s}].fields[${f}]`;\n\n // ── (a) section field references a real field on the bound object ──\n if (fname && known && !known.has(fname)) {\n findings.push({\n severity: 'warning',\n rule: FORM_FIELD_UNKNOWN,\n where,\n path: fpath,\n message:\n `${viewName}: field \"${fname}\" is not a field on object \"${objName}\" — ` +\n `it is silently skipped and never renders on the form`,\n hint:\n `Fix the field name, or add \"${fname}\" to ${objName}. Section field ` +\n `references must match the object's field names exactly.`,\n });\n }\n\n // ── (b) absolute colSpan → steer to the surface-independent span ──\n const colSpan = entry && typeof entry === 'object' && !Array.isArray(entry)\n ? (entry as AnyRec).colSpan\n : undefined;\n if (colSpan != null) {\n findings.push({\n severity: 'warning',\n rule: FORM_COLSPAN_ABSOLUTE,\n where,\n path: `${fpath}.colSpan`,\n message:\n `${viewName}: field \"${fname ?? '?'}\" sets absolute colSpan ${String(colSpan)} — ` +\n `the form's column count is derived per surface (mobile 1 / modal 2 / page 3-4), ` +\n `so a fixed span only aligns at one width`,\n hint:\n `Prefer span: 'full' (whole row at any column count), or omit for auto ` +\n `width. The renderer clamps colSpan to the current column count.`,\n });\n }\n }\n }\n }\n\n return findings;\n}\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * [ADR-0066 ⑨] Authoring-time validation for capability references.\n *\n * `requiredPermissions` (on objects, fields, apps, and actions) and\n * `systemPermissions` (on permission sets) are free capability strings. A typo\n * — `mange_users` for `manage_users` — is Zod-valid and fails CLOSED at runtime\n * (the caller is denied), which is the safe direction but UNDISCOVERABLE: nothing\n * tells the author the referenced capability exists nowhere. This rule closes\n * that gap by resolving every `requiredPermissions` reference against the set of\n * capabilities known at author time and warning on the unresolved ones —\n * \"reject at the producer\" (Prime Directive / ADR-0049 honesty).\n *\n * The author-time \"known\" set is:\n * 1. the built-in platform capabilities (`PLATFORM_CAPABILITY_NAMES`),\n * 2. every capability a permission set in this stack GRANTS via\n * `systemPermissions` (granting a capability is what declares it — mirrors\n * the runtime `bootstrapSystemCapabilities` derived-defaults rule), and\n * 3. any `sys_capability` row shipped as seed data.\n *\n * WARNING, not error: a single package's lint cannot see capabilities declared\n * by OTHER installed packages, and the reference fails closed at runtime anyway,\n * so a dangling reference is \"almost certainly a typo\" — surface it, don't break\n * the build. Assignment (`systemPermissions`) is NOT flagged: it is the\n * declaration side, and a package legitimately introduces new capabilities there.\n */\n\nimport { PLATFORM_CAPABILITY_NAMES } from '@objectstack/spec/security';\n\nexport const CAPABILITY_REFERENCE_UNKNOWN = 'capability-reference-unknown';\n\nexport type CapabilityRefSeverity = 'error' | 'warning';\n\nexport interface CapabilityRefFinding {\n /** Always `warning` — the reference fails closed at runtime (see module note). */\n severity: CapabilityRefSeverity;\n /** Diagnostic rule id. */\n rule: string;\n /** Human-readable location, e.g. `object \"sys_license\"`. */\n where: string;\n /** Config path, e.g. `objects[3].requiredPermissions`. */\n path: string;\n /** What is wrong. */\n message: string;\n /** How to fix it. */\n hint: string;\n}\n\ntype AnyRec = Record<string, unknown>;\n\n/** Coerce a collection (array or name-keyed map) to an array of records. */\nfunction asArray(v: unknown): AnyRec[] {\n if (Array.isArray(v)) return v as AnyRec[];\n if (v && typeof v === 'object') {\n return Object.entries(v as AnyRec).map(([name, def]) => ({ name, ...(def as AnyRec) }));\n }\n return [];\n}\n\n/** The capability strings in a `string[]` value. */\nfunction asCapArray(v: unknown): string[] {\n return Array.isArray(v) ? v.filter((s): s is string => typeof s === 'string' && s.length > 0) : [];\n}\n\n/**\n * Flatten an object-level `requiredPermissions` — either a `string[]` (all\n * operations) or a per-operation `{ read, create, update, delete }` map (ADR-0066\n * ⑤) — into `[{ cap, key }]`, where `key` is the map key (or `undefined` for the\n * array form) so a finding can point at the exact operation slice.\n */\nfunction flattenObjectRequired(v: unknown): Array<{ cap: string; key?: string }> {\n if (Array.isArray(v)) return asCapArray(v).map((cap) => ({ cap }));\n if (v && typeof v === 'object') {\n const out: Array<{ cap: string; key?: string }> = [];\n for (const [key, val] of Object.entries(v as AnyRec)) {\n for (const cap of asCapArray(val)) out.push({ cap, key });\n }\n return out;\n }\n return [];\n}\n\n/**\n * Validate every capability reference in a stack. Returns findings (empty =\n * clean). Advisory only — callers must not fail the build on these alone.\n */\nexport function validateCapabilityReferences(stack: AnyRec): CapabilityRefFinding[] {\n const findings: CapabilityRefFinding[] = [];\n if (!stack || typeof stack !== 'object') return findings;\n\n // ── Build the author-time \"known capability\" set ──\n const known = new Set<string>(PLATFORM_CAPABILITY_NAMES);\n for (const ps of asArray(stack.permissions)) {\n for (const cap of asCapArray(ps.systemPermissions)) known.add(cap);\n }\n for (const seed of asArray(stack.data)) {\n if (seed.object !== 'sys_capability') continue;\n for (const rec of Array.isArray(seed.records) ? seed.records : []) {\n const name = (rec as AnyRec | null)?.name;\n if (typeof name === 'string' && name.length > 0) known.add(name);\n }\n }\n\n const hint =\n 'Fix the capability name, declare it on a permission set’s systemPermissions, ' +\n 'ship a sys_capability seed row, or ignore this if the capability is provided by ' +\n 'another installed package (references fail closed at runtime).';\n\n const flag = (cap: string, where: string, path: string) => {\n if (known.has(cap)) return;\n findings.push({\n severity: 'warning',\n rule: CAPABILITY_REFERENCE_UNKNOWN,\n where,\n path,\n message:\n `requiredPermissions references capability \"${cap}\" which is registered ` +\n `nowhere — no built-in capability, no permission set in this package grants ` +\n `it via systemPermissions, and no sys_capability seed declares it`,\n hint,\n });\n };\n\n // ── Objects (D3) + their fields (D3) + embedded actions (D4) ──\n const objects = asArray(stack.objects);\n for (let i = 0; i < objects.length; i++) {\n const obj = objects[i];\n if (!obj || typeof obj !== 'object') continue;\n const objName = typeof obj.name === 'string' ? obj.name : `(object ${i})`;\n const objPath = `objects[${i}]`;\n\n for (const { cap, key } of flattenObjectRequired(obj.requiredPermissions)) {\n flag(cap, `object \"${objName}\"`, `${objPath}.requiredPermissions${key ? `.${key}` : ''}`);\n }\n\n const fields = asArray(obj.fields);\n for (const f of fields) {\n const fname = typeof f.name === 'string' ? f.name : '(field)';\n for (const cap of asCapArray(f.requiredPermissions)) {\n flag(cap, `field \"${objName}.${fname}\"`, `${objPath}.fields.${fname}.requiredPermissions`);\n }\n }\n\n for (const [ai, action] of asArray(obj.actions).entries()) {\n const aName = typeof action.name === 'string' ? action.name : `(action ${ai})`;\n for (const cap of asCapArray(action.requiredPermissions)) {\n flag(cap, `action \"${objName}.${aName}\"`, `${objPath}.actions[${ai}].requiredPermissions`);\n }\n }\n }\n\n // ── Top-level actions (D4) ──\n for (const [i, action] of asArray(stack.actions).entries()) {\n const aName = typeof action.name === 'string' ? action.name : `(action ${i})`;\n for (const cap of asCapArray(action.requiredPermissions)) {\n flag(cap, `action \"${aName}\"`, `actions[${i}].requiredPermissions`);\n }\n }\n\n // ── Apps: requiredPermissions can appear at the app, area/tab, and nav-item\n // (recursively through groups) levels. Walk each app subtree. ──\n const apps = asArray(stack.apps);\n for (let i = 0; i < apps.length; i++) {\n const app = apps[i];\n if (!app || typeof app !== 'object') continue;\n const appName = typeof app.name === 'string' ? app.name : `(app ${i})`;\n const walk = (node: unknown, path: string) => {\n if (!node || typeof node !== 'object') return;\n if (Array.isArray(node)) {\n node.forEach((child, ci) => walk(child, `${path}[${ci}]`));\n return;\n }\n const rec = node as AnyRec;\n for (const cap of asCapArray(rec.requiredPermissions)) {\n flag(cap, `app \"${appName}\"`, `${path}.requiredPermissions`);\n }\n // Recurse only into the sub-structures that carry requiredPermissions.\n if (rec.navigation) walk(rec.navigation, `${path}.navigation`);\n if (rec.areas) walk(rec.areas, `${path}.areas`);\n if (rec.tabs) walk(rec.tabs, `${path}.tabs`);\n if (rec.children) walk(rec.children, `${path}.children`);\n if (rec.items) walk(rec.items, `${path}.items`);\n };\n walk(app, `apps[${i}]`);\n }\n\n return findings;\n}\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * [ADR-0090 D7] Security-domain publish linter.\n *\n * Every rule here is traceable to an observed failure class (the taxonomy\n * grows by incident, per the ADR):\n *\n * | Rule | Origin |\n * |-----------------------------------------|---------------------------------|\n * | security-owd-unset (error) | objectui#2348 leave_request 事故 |\n * | security-owd-alias (error) | ADR-0090 D4 canonical enum |\n * | security-external-wider (error) | ADR-0090 D11 external ≤ internal|\n * | security-wildcard-vama (error) | ADR-0066 superuser wildcard |\n * | security-anchor-high-privilege(error) | ADR-0090 D5/D9 anchors |\n * | security-role-word (error) | ADR-0090 D3 vocabulary freeze |\n * | security-private-no-readscope (info) | admin-intent mismatch class |\n *\n * Per ADR-0049 discipline these are NOT advisory security: every `error` rule\n * mirrors a runtime enforcement point (D1 fail-closed OWD default, D4 zod\n * enum + fail-closed evaluator, D5/D9 anchor binding gate, D3 rename wave) —\n * the lint moves the failure from runtime-deny to author-time fix-it.\n *\n * Pure `(stack) => Finding[]`; accepts the NORMALIZED stack input (works both\n * pre- and post-zod-parse, so `os lint` catches what the zod gate would\n * reject in `os compile` — with a better message).\n */\n\nimport { describeAnchorForbiddenBits } from '@objectstack/spec/security';\n\nexport const SECURITY_OWD_UNSET = 'security-owd-unset';\nexport const SECURITY_OWD_ALIAS = 'security-owd-alias';\nexport const SECURITY_EXTERNAL_WIDER = 'security-external-wider-than-internal';\nexport const SECURITY_WILDCARD_VAMA = 'security-wildcard-vama';\nexport const SECURITY_ANCHOR_HIGH_PRIVILEGE = 'security-anchor-high-privilege';\nexport const SECURITY_ROLE_WORD = 'security-role-word';\nexport const SECURITY_PRIVATE_NO_READSCOPE = 'security-private-no-readscope';\n\nexport type SecuritySeverity = 'error' | 'warning' | 'info';\n\nexport interface SecurityFinding {\n severity: SecuritySeverity;\n /** Diagnostic rule id (`security-*`). */\n rule: string;\n /** Human-readable location, e.g. `object \"leave_request\"`. */\n where: string;\n /** Config path, e.g. `objects[3].sharingModel`. */\n path: string;\n /** What is wrong. */\n message: string;\n /** How to fix it. */\n hint: string;\n}\n\ntype AnyRec = Record<string, unknown>;\n\nconst CANONICAL_OWD = ['private', 'public_read', 'public_read_write', 'controlled_by_parent'] as const;\n/** [ADR-0090 D4] Legacy alias → canonical fix-it mapping. */\nconst OWD_ALIAS_FIX: Record<string, string> = {\n read: 'public_read',\n read_write: 'public_read_write',\n full: 'public_read_write',\n public: 'public_read_write',\n};\n/** D11 ordering for external ≤ internal (controlled_by_parent excluded). */\nconst OWD_WIDTH: Record<string, number> = {\n private: 0,\n public_read: 1,\n public_read_write: 2,\n};\n\n/** Coerce a collection (array or name-keyed map) to an array of records. */\nfunction asArray(v: unknown): AnyRec[] {\n if (Array.isArray(v)) return v as AnyRec[];\n if (v && typeof v === 'object') {\n return Object.entries(v as AnyRec).map(([name, def]) => ({ name, ...(def as AnyRec) }));\n }\n return [];\n}\n\nfunction owdOf(obj: AnyRec): unknown {\n return obj.sharingModel ?? (obj.security as AnyRec | undefined)?.sharingModel;\n}\n\nfunction isSystemObject(obj: AnyRec): boolean {\n return obj.isSystem === true || String(obj.name ?? '').startsWith('sys_');\n}\n\n/** snake_case identifier contains the reserved token `role`/`roles`. */\nfunction identifierHasRoleToken(name: unknown): boolean {\n if (typeof name !== 'string') return false;\n return name\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .some((tok) => tok === 'role' || tok === 'roles');\n}\n\n/** Free-text label contains the whole word `role(s)` (case-insensitive). */\nfunction labelHasRoleWord(label: unknown): boolean {\n if (typeof label !== 'string') return false;\n return /\\brole(s)?\\b/i.test(label);\n}\n\n/**\n * Validate the security posture of a stack. Returns findings (empty = clean).\n * `error` findings gate the build in `os compile`; `info` is advisory.\n */\nexport function validateSecurityPosture(stack: AnyRec): SecurityFinding[] {\n const findings: SecurityFinding[] = [];\n if (!stack || typeof stack !== 'object') return findings;\n\n const objects = asArray(stack.objects);\n const permissionSets = asArray(stack.permissions);\n\n // ── D1/D4/D11: per-object OWD posture ────────────────────────────────\n for (let i = 0; i < objects.length; i++) {\n const obj = objects[i];\n if (!obj || typeof obj !== 'object') continue;\n const objName = typeof obj.name === 'string' ? obj.name : `(object ${i})`;\n const objPath = `objects[${i}]`;\n const owd = owdOf(obj);\n const external = obj.externalSharingModel;\n\n if (!isSystemObject(obj)) {\n if (owd == null) {\n findings.push({\n severity: 'error',\n rule: SECURITY_OWD_UNSET,\n where: `object \"${objName}\"`,\n path: `${objPath}.sharingModel`,\n message:\n `custom object \"${objName}\" declares no sharingModel (OWD). The runtime fails ` +\n `CLOSED to 'private' (ADR-0090 D1), but the baseline must be an authored decision, ` +\n `not an accident — this is the exact shape of the leave_request incident (objectui#2348).`,\n hint:\n `Declare sharingModel explicitly: 'private' (owner + shares; recommended default), ` +\n `'public_read', 'public_read_write', or 'controlled_by_parent' (master-detail children).`,\n });\n } else if (typeof owd === 'string' && OWD_ALIAS_FIX[owd]) {\n findings.push({\n severity: 'error',\n rule: SECURITY_OWD_ALIAS,\n where: `object \"${objName}\"`,\n path: `${objPath}.sharingModel`,\n message:\n `sharingModel '${owd}' is a retired alias (ADR-0090 D4). The runtime fails CLOSED ` +\n `to 'private' on unknown values, so this object is NOT ${owd === 'read' ? 'readable' : 'writable'} org-wide.`,\n hint: `Replace with the canonical value: sharingModel: '${OWD_ALIAS_FIX[owd]}'.`,\n });\n } else if (typeof owd === 'string' && !(CANONICAL_OWD as readonly string[]).includes(owd)) {\n findings.push({\n severity: 'error',\n rule: SECURITY_OWD_ALIAS,\n where: `object \"${objName}\"`,\n path: `${objPath}.sharingModel`,\n message:\n `sharingModel '${owd}' is not a canonical OWD value; the runtime fails CLOSED to 'private'.`,\n hint: `Use one of: ${CANONICAL_OWD.join(', ')}.`,\n });\n }\n }\n\n // D11: external dial present on any object (system included) must obey\n // external ≤ internal. controlled_by_parent inherits the master's pair.\n if (typeof external === 'string') {\n if (OWD_ALIAS_FIX[external]) {\n findings.push({\n severity: 'error',\n rule: SECURITY_OWD_ALIAS,\n where: `object \"${objName}\"`,\n path: `${objPath}.externalSharingModel`,\n message: `externalSharingModel '${external}' is a retired alias (ADR-0090 D4).`,\n hint: `Replace with the canonical value: externalSharingModel: '${OWD_ALIAS_FIX[external]}'.`,\n });\n } else if (\n typeof owd === 'string' &&\n external in OWD_WIDTH &&\n owd in OWD_WIDTH &&\n OWD_WIDTH[external] > OWD_WIDTH[owd]\n ) {\n findings.push({\n severity: 'error',\n rule: SECURITY_EXTERNAL_WIDER,\n where: `object \"${objName}\"`,\n path: `${objPath}.externalSharingModel`,\n message:\n `externalSharingModel '${external}' is WIDER than the internal sharingModel '${owd}' — ` +\n `the external baseline must never exceed the internal one (ADR-0090 D11).`,\n hint: `Narrow externalSharingModel to '${owd}' or below (ordering: private < public_read < public_read_write).`,\n });\n }\n }\n }\n\n // ── ADR-0066 / D5/D9: permission-set posture ─────────────────────────\n for (let i = 0; i < permissionSets.length; i++) {\n const ps = permissionSets[i];\n if (!ps || typeof ps !== 'object') continue;\n const psName = typeof ps.name === 'string' ? ps.name : `(permission set ${i})`;\n const psPath = `permissions[${i}]`;\n const objectsMap = (ps.objects && typeof ps.objects === 'object' ? ps.objects : {}) as AnyRec;\n\n const wildcard = objectsMap['*'] as AnyRec | undefined;\n if (wildcard && (wildcard.viewAllRecords === true || wildcard.modifyAllRecords === true)) {\n findings.push({\n severity: 'error',\n rule: SECURITY_WILDCARD_VAMA,\n where: `permission set \"${psName}\"`,\n path: `${psPath}.objects.*`,\n message:\n `'*' wildcard carrying View All / Modify All Data — a package-authored superuser. ` +\n `Only the platform's own admin set may combine the wildcard with VAMA (ADR-0066).`,\n hint:\n `Enumerate the objects this set really needs, or drop viewAllRecords/modifyAllRecords ` +\n `from the wildcard entry. App-level admins belong in an ordinary set the customer binds ` +\n `to a position of their choosing (ADR-0090 D9).`,\n });\n }\n\n // D5: an isDefault set is a SUGGESTED binding to the `everyone` anchor —\n // hold it to the anchor tier at author time (the runtime gate enforces the\n // same predicate at bind time; this moves the failure to the author).\n if (ps.isDefault === true) {\n const offending = describeAnchorForbiddenBits(ps, 'everyone');\n if (offending) {\n findings.push({\n severity: 'error',\n rule: SECURITY_ANCHOR_HIGH_PRIVILEGE,\n where: `permission set \"${psName}\"`,\n path: `${psPath}.isDefault`,\n message:\n `isDefault:true suggests binding this set to the 'everyone' audience anchor, but it ` +\n `carries ${offending} — the runtime will refuse the binding (ADR-0090 D5/D9).`,\n hint:\n `Split the powerful bits into a separate set granted through ordinary positions, and ` +\n `keep the everyone-suggested set low-privilege.`,\n });\n }\n }\n }\n\n // ── D3: the word \"role\" is reserved-forbidden ────────────────────────\n // Scope: security-relevant identifiers/labels (objects, fields, actions,\n // permission sets, positions, apps). Pages/views/components are NOT\n // scanned — `role` there is HTML/ARIA semantics, not permission vocabulary.\n // The sole platform exception (better-auth `sys_member.role`) is a system\n // object, which app stacks never author.\n const flagRole = (kind: string, name: unknown, label: unknown, where: string, path: string) => {\n if (identifierHasRoleToken(name)) {\n findings.push({\n severity: 'error',\n rule: SECURITY_ROLE_WORD,\n where,\n path,\n message:\n `${kind} name \"${String(name)}\" uses the reserved word \"role\" — the platform vocabulary ` +\n `is permission_set (capability), position (distribution), business_unit (hierarchy) (ADR-0090 D3).`,\n hint: `Rename using 'position' for distribution groups or a domain word (e.g. 'function', 'duty').`,\n });\n } else if (labelHasRoleWord(label)) {\n findings.push({\n severity: 'error',\n rule: SECURITY_ROLE_WORD,\n where,\n path: `${path.replace(/\\.name$/, '')}.label`,\n message: `${kind} label \"${String(label)}\" uses the reserved word \"role\" (ADR-0090 D3).`,\n hint: `Relabel with 'Position' (distribution) or a domain word — admins must meet ONE vocabulary.`,\n });\n }\n };\n\n for (let i = 0; i < objects.length; i++) {\n const obj = objects[i];\n if (!obj || typeof obj !== 'object' || isSystemObject(obj)) continue;\n const objName = typeof obj.name === 'string' ? obj.name : `(object ${i})`;\n flagRole('object', obj.name, obj.label, `object \"${objName}\"`, `objects[${i}].name`);\n for (const f of asArray(obj.fields)) {\n flagRole('field', f.name, f.label, `field \"${objName}.${String(f.name ?? '?')}\"`, `objects[${i}].fields.${String(f.name ?? '?')}.name`);\n }\n for (const [ai, action] of asArray(obj.actions).entries()) {\n flagRole('action', action.name, action.label, `action \"${objName}.${String(action.name ?? '?')}\"`, `objects[${i}].actions[${ai}].name`);\n }\n }\n for (let i = 0; i < permissionSets.length; i++) {\n const ps = permissionSets[i];\n if (!ps || typeof ps !== 'object') continue;\n flagRole('permission set', ps.name, ps.label, `permission set \"${String(ps.name ?? i)}\"`, `permissions[${i}].name`);\n }\n for (const [i, pos] of asArray(stack.positions).entries()) {\n flagRole('position', pos.name, pos.label, `position \"${String(pos.name ?? i)}\"`, `positions[${i}].name`);\n }\n for (const [i, app] of asArray(stack.apps).entries()) {\n flagRole('app', app.name, app.label, `app \"${String(app.name ?? i)}\"`, `apps[${i}].name`);\n }\n\n // ── Admin-intent mismatch: private object, plain read, no depth ──────\n // An object whose baseline is private (explicit or D1-defaulted) where a set\n // grants allowRead with neither readScope nor viewAllRecords: every reader\n // sees ONLY their own records. Legitimate (personal to-dos) often enough\n // that this stays `info` — but it is the #1 \"why can't 李四 see the data\"\n // support class, so say it out loud at author time.\n const privateObjects = new Set(\n objects\n .filter((o) => o && typeof o === 'object' && !isSystemObject(o))\n .filter((o) => {\n const owd = owdOf(o);\n return owd == null || owd === 'private';\n })\n .map((o) => String(o.name ?? '')),\n );\n if (privateObjects.size > 0) {\n for (let i = 0; i < permissionSets.length; i++) {\n const ps = permissionSets[i];\n if (!ps || typeof ps !== 'object') continue;\n const psName = typeof ps.name === 'string' ? ps.name : `(permission set ${i})`;\n const objectsMap = (ps.objects && typeof ps.objects === 'object' ? ps.objects : {}) as AnyRec;\n for (const [objName, rawPerm] of Object.entries(objectsMap)) {\n if (!privateObjects.has(objName)) continue;\n const p = (rawPerm ?? {}) as AnyRec;\n if (p.allowRead === true && p.readScope == null && p.viewAllRecords !== true) {\n findings.push({\n severity: 'info',\n rule: SECURITY_PRIVATE_NO_READSCOPE,\n where: `permission set \"${psName}\"`,\n path: `permissions[${i}].objects.${objName}.readScope`,\n message:\n `\"${objName}\" is private (OWD) and this set grants allowRead without a readScope — ` +\n `holders see ONLY records they own (plus explicit shares).`,\n hint:\n `If that is intended (personal data), ignore this. Otherwise add readScope: ` +\n `'own_and_reports' | 'unit' | 'unit_and_below' | 'org', or widen the object's sharingModel.`,\n });\n }\n }\n }\n }\n\n return findings;\n}\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * [ADR-0090 D6] Access-matrix snapshot — authoring-time companion to the\n * runtime explain engine.\n *\n * `buildAccessMatrix(stack)` derives, PURELY from metadata, one row per\n * (permission set × object) the stack declares: the CRUD/VAMA bits, the\n * depth axes, and the object's OWD for context. The matrix is snapshotted to\n * `access-matrix.json` and diffed on every compile: an unchanged matrix\n * auto-passes; a changed one fails the build until the snapshot is updated —\n * so every capability change becomes a REVIEWABLE, semantic diff\n * (\"`crm_admin` gains delete on `crm_lead`\") instead of a buried JSON hunk.\n * This is the publish-gate substrate the AI-authoring safety story needs:\n * AI may draft grants freely; it cannot silently change who can do what.\n */\n\nimport type { AccessMatrix, AccessMatrixEntry } from '@objectstack/spec/security';\n\ntype AnyRec = Record<string, unknown>;\n\nfunction asArray(v: unknown): AnyRec[] {\n if (Array.isArray(v)) return v as AnyRec[];\n if (v && typeof v === 'object') {\n return Object.entries(v as AnyRec).map(([name, def]) => ({ name, ...(def as AnyRec) }));\n }\n return [];\n}\n\n/** Build the sorted access matrix for a normalized stack. */\nexport function buildAccessMatrix(stack: AnyRec): AccessMatrix {\n const entries: AccessMatrixEntry[] = [];\n if (!stack || typeof stack !== 'object') return { version: 1, entries };\n\n const owdByObject = new Map<string, string>();\n for (const obj of asArray(stack.objects)) {\n const name = typeof obj.name === 'string' ? obj.name : '';\n if (!name) continue;\n const owd = (obj.sharingModel ?? (obj.security as AnyRec | undefined)?.sharingModel) as string | undefined;\n if (typeof owd === 'string') owdByObject.set(name, owd);\n }\n\n for (const ps of asArray(stack.permissions)) {\n const psName = typeof ps.name === 'string' ? ps.name : '';\n if (!psName) continue;\n const objects = (ps.objects && typeof ps.objects === 'object' ? ps.objects : {}) as AnyRec;\n for (const [objName, rawPerm] of Object.entries(objects)) {\n const p = (rawPerm ?? {}) as AnyRec;\n const entry: AccessMatrixEntry = {\n permissionSet: psName,\n object: objName,\n create: p.allowCreate === true,\n read: p.allowRead === true || p.viewAllRecords === true || p.modifyAllRecords === true,\n edit: p.allowEdit === true || p.modifyAllRecords === true,\n delete: p.allowDelete === true || p.modifyAllRecords === true,\n viewAllRecords: p.viewAllRecords === true,\n modifyAllRecords: p.modifyAllRecords === true,\n };\n if (typeof p.readScope === 'string') entry.readScope = p.readScope;\n if (typeof p.writeScope === 'string') entry.writeScope = p.writeScope;\n const owd = owdByObject.get(objName);\n if (owd) entry.sharingModel = owd;\n entries.push(entry);\n }\n }\n\n entries.sort((a, b) =>\n a.permissionSet === b.permissionSet\n ? a.object.localeCompare(b.object)\n : a.permissionSet.localeCompare(b.permissionSet),\n );\n return { version: 1, entries };\n}\n\nconst BIT_LABELS: Array<[keyof AccessMatrixEntry, string]> = [\n ['create', 'create'],\n ['read', 'read'],\n ['edit', 'edit'],\n ['delete', 'delete'],\n ['viewAllRecords', 'View All Data'],\n ['modifyAllRecords', 'Modify All Data'],\n];\n\n/**\n * Semantic diff between two matrices — human-review lines, empty = identical.\n * Ordered: removals, additions, then per-entry bit/scope changes.\n */\nexport function diffAccessMatrix(before: AccessMatrix, after: AccessMatrix): string[] {\n const lines: string[] = [];\n const key = (e: AccessMatrixEntry) => `${e.permissionSet}\u0000${e.object}`;\n const beforeMap = new Map((before?.entries ?? []).map((e) => [key(e), e]));\n const afterMap = new Map((after?.entries ?? []).map((e) => [key(e), e]));\n\n for (const [k, b] of beforeMap) {\n if (!afterMap.has(k)) {\n lines.push(`'${b.permissionSet}' loses ALL access to '${b.object}' (entry removed)`);\n }\n }\n for (const [k, a] of afterMap) {\n const b = beforeMap.get(k);\n if (!b) {\n const grants = BIT_LABELS.filter(([bit]) => a[bit] === true).map(([, label]) => label);\n lines.push(`'${a.permissionSet}' gains access to '${a.object}' (${grants.join(', ') || 'no bits set'})`);\n continue;\n }\n for (const [bit, label] of BIT_LABELS) {\n if (b[bit] !== a[bit]) {\n lines.push(`'${a.permissionSet}' ${a[bit] ? 'gains' : 'loses'} ${label} on '${a.object}'`);\n }\n }\n if ((b.readScope ?? 'own') !== (a.readScope ?? 'own')) {\n lines.push(`'${a.permissionSet}' read depth on '${a.object}': ${b.readScope ?? 'own'} → ${a.readScope ?? 'own'}`);\n }\n if ((b.writeScope ?? 'own') !== (a.writeScope ?? 'own')) {\n lines.push(`'${a.permissionSet}' write depth on '${a.object}': ${b.writeScope ?? 'own'} → ${a.writeScope ?? 'own'}`);\n }\n if ((b.sharingModel ?? '') !== (a.sharingModel ?? '')) {\n lines.push(`'${a.object}' record baseline (OWD): ${b.sharingModel ?? '(unset)'} → ${a.sharingModel ?? '(unset)'} (affects every principal)`);\n }\n }\n return lines;\n}\n"],"mappings":"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","names":["asArray","asArray","asArray","asArray","asArray","createRequire","asArray","asArray","asArray","asArray","asArray","asArray","asArray","asArray"]}
|