Skip to content

Commit e652ab8

Browse files
os-billclaude
andcommitted
fix(spec): address contract review — card id out of the refusal string, prescription module-private, docblock adjacency (#17296)
R1: `check:doc-authoring` reds on an internal issue id inside a customer-facing string. The refusal now reads `(ADR-0049 enforce-or-remove)`, matching how driver-memory's twin already spells it. No pin asserted the id. R2: `timeUpdateIntervalRefusalMessage` had zero consumers outside its own error map, so it is module-private now — the `CRYPTO_HASH_RETIRED` shape an enum-value narrowing takes. `RETIRED_SUB_DAY_INTERVALS` stays exported; it has real cross-package readers. Both inventories regenerated. R3: the new conversion had been inserted between an existing docblock and the symbol it documents. It moves below `metricFiltersRemoved`; the `CONVERSIONS_BY_MAJOR` order is unchanged. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH
1 parent f32f16a commit e652ab8

4 files changed

Lines changed: 86 additions & 78 deletions

File tree

‎packages/spec/api-surface/data.json‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -827,7 +827,6 @@
827827
"suggestDefaultValueToken (function)",
828828
"suggestFieldTypeForSqlType (function)",
829829
"textOperatorDoorVerdict (function)",
830-
"timeUpdateIntervalRefusalMessage (function)",
831830
"unprovisionedInjectedColumns (function)",
832831
"urlCredentialQueryParams (function)",
833832
"urlUserinfoPassword (function)",

‎packages/spec/export-origins/data.json‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -814,7 +814,6 @@
814814
"suggestDefaultValueToken": "src/data/default-value-shape.ts#suggestDefaultValueToken (function)",
815815
"suggestFieldTypeForSqlType": "src/data/type-compat.ts#suggestFieldTypeForSqlType (function)",
816816
"textOperatorDoorVerdict": "src/data/filter-text-operator-declared-type.ts#textOperatorDoorVerdict (function)",
817-
"timeUpdateIntervalRefusalMessage": "src/data/analytics.zod.ts#timeUpdateIntervalRefusalMessage (function)",
818817
"unprovisionedInjectedColumns": "src/data/injected-system-column-provenance.ts#unprovisionedInjectedColumns (function)",
819818
"urlCredentialQueryParams": "src/data/driver/common.zod.ts#urlCredentialQueryParams (function)",
820819
"urlUserinfoPassword": "src/data/driver/common.zod.ts#urlUserinfoPassword (function)",

‎packages/spec/src/conversions/registry.ts‎

Lines changed: 74 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -7391,6 +7391,80 @@ const fieldColumnListsCanonicalized: MetadataConversion = {
73917391
* cube's `measures` RECORD (keyed by name), one level below the collection
73927392
* item, so the top-level-only `stripKeys` runs per metric, not per cube.
73937393
*/
7394+
const metricFiltersRemoved: MetadataConversion = {
7395+
id: 'metric-filters-removed',
7396+
toMajor: 18,
7397+
retiredFromLoadPath: true,
7398+
surface: 'analyticsCubes[].measures.<metric>.filters',
7399+
summary:
7400+
"cube metric key 'filters' removed (#10414, ADR-0049 — no strategy ever read it: the "
7401+
+ 'authored raw-SQL condition was parsed and dropped, and the query returned the '
7402+
+ "unfiltered aggregate. Filter at query time with `where`, fold the condition into the "
7403+
+ "metric's own `sql` expression, or use an ADR-0021 dataset measure's structured `filter`)",
7404+
apply(stack, emit) {
7405+
return mapCollection(stack, 'analyticsCubes', (cube, path) => {
7406+
const measures = cube.measures;
7407+
if (!isDict(measures)) return cube;
7408+
let touched = false;
7409+
const nextMeasures: Record<string, unknown> = { ...measures };
7410+
for (const [name, metric] of Object.entries(measures)) {
7411+
if (!isDict(metric)) continue;
7412+
const stripped = stripKeys(metric, ['filters'], emit, `${path}.measures.${name}`);
7413+
if (stripped === metric) continue;
7414+
nextMeasures[name] = stripped;
7415+
touched = true;
7416+
}
7417+
if (!touched) return cube;
7418+
return { ...cube, measures: nextMeasures };
7419+
});
7420+
},
7421+
fixture: {
7422+
before: {
7423+
analyticsCubes: [{
7424+
name: 'orders',
7425+
sql: 'orders',
7426+
measures: {
7427+
// The card's measured shape: parsed, registered, returned unfiltered.
7428+
closed_won_revenue: {
7429+
name: 'closed_won_revenue',
7430+
label: 'Closed-Won Revenue',
7431+
type: 'sum',
7432+
sql: 'amount',
7433+
filters: [{ sql: "stage = 'closed_won'" }],
7434+
},
7435+
// A metric WITHOUT the key rides through untouched — the strip
7436+
// dispatches on key presence, and the copy-on-write contract keeps
7437+
// the reference.
7438+
order_count: { name: 'order_count', label: 'Orders', type: 'count', sql: 'id' },
7439+
},
7440+
dimensions: {
7441+
stage: { name: 'stage', label: 'Stage', type: 'string', sql: 'stage' },
7442+
},
7443+
}],
7444+
},
7445+
after: {
7446+
analyticsCubes: [{
7447+
name: 'orders',
7448+
sql: 'orders',
7449+
measures: {
7450+
closed_won_revenue: {
7451+
name: 'closed_won_revenue',
7452+
label: 'Closed-Won Revenue',
7453+
type: 'sum',
7454+
sql: 'amount',
7455+
},
7456+
order_count: { name: 'order_count', label: 'Orders', type: 'count', sql: 'id' },
7457+
},
7458+
dimensions: {
7459+
stage: { name: 'stage', label: 'Stage', type: 'string', sql: 'stage' },
7460+
},
7461+
}],
7462+
},
7463+
// One notice: the single metric carrying `filters`.
7464+
expectedNotices: 1,
7465+
},
7466+
};
7467+
73947468
/**
73957469
* `dimensions.<dim>.granularities` — the three sub-day names `TimeUpdateInterval`
73967470
* declared until protocol 18 (#17296, ADR-0049 enforce-or-remove).
@@ -7497,80 +7571,6 @@ const cubeSubDayGranularitiesRemoved: MetadataConversion = {
74977571
},
74987572
};
74997573

7500-
const metricFiltersRemoved: MetadataConversion = {
7501-
id: 'metric-filters-removed',
7502-
toMajor: 18,
7503-
retiredFromLoadPath: true,
7504-
surface: 'analyticsCubes[].measures.<metric>.filters',
7505-
summary:
7506-
"cube metric key 'filters' removed (#10414, ADR-0049 — no strategy ever read it: the "
7507-
+ 'authored raw-SQL condition was parsed and dropped, and the query returned the '
7508-
+ "unfiltered aggregate. Filter at query time with `where`, fold the condition into the "
7509-
+ "metric's own `sql` expression, or use an ADR-0021 dataset measure's structured `filter`)",
7510-
apply(stack, emit) {
7511-
return mapCollection(stack, 'analyticsCubes', (cube, path) => {
7512-
const measures = cube.measures;
7513-
if (!isDict(measures)) return cube;
7514-
let touched = false;
7515-
const nextMeasures: Record<string, unknown> = { ...measures };
7516-
for (const [name, metric] of Object.entries(measures)) {
7517-
if (!isDict(metric)) continue;
7518-
const stripped = stripKeys(metric, ['filters'], emit, `${path}.measures.${name}`);
7519-
if (stripped === metric) continue;
7520-
nextMeasures[name] = stripped;
7521-
touched = true;
7522-
}
7523-
if (!touched) return cube;
7524-
return { ...cube, measures: nextMeasures };
7525-
});
7526-
},
7527-
fixture: {
7528-
before: {
7529-
analyticsCubes: [{
7530-
name: 'orders',
7531-
sql: 'orders',
7532-
measures: {
7533-
// The card's measured shape: parsed, registered, returned unfiltered.
7534-
closed_won_revenue: {
7535-
name: 'closed_won_revenue',
7536-
label: 'Closed-Won Revenue',
7537-
type: 'sum',
7538-
sql: 'amount',
7539-
filters: [{ sql: "stage = 'closed_won'" }],
7540-
},
7541-
// A metric WITHOUT the key rides through untouched — the strip
7542-
// dispatches on key presence, and the copy-on-write contract keeps
7543-
// the reference.
7544-
order_count: { name: 'order_count', label: 'Orders', type: 'count', sql: 'id' },
7545-
},
7546-
dimensions: {
7547-
stage: { name: 'stage', label: 'Stage', type: 'string', sql: 'stage' },
7548-
},
7549-
}],
7550-
},
7551-
after: {
7552-
analyticsCubes: [{
7553-
name: 'orders',
7554-
sql: 'orders',
7555-
measures: {
7556-
closed_won_revenue: {
7557-
name: 'closed_won_revenue',
7558-
label: 'Closed-Won Revenue',
7559-
type: 'sum',
7560-
sql: 'amount',
7561-
},
7562-
order_count: { name: 'order_count', label: 'Orders', type: 'count', sql: 'id' },
7563-
},
7564-
dimensions: {
7565-
stage: { name: 'stage', label: 'Stage', type: 'string', sql: 'stage' },
7566-
},
7567-
}],
7568-
},
7569-
// One notice: the single metric carrying `filters`.
7570-
expectedNotices: 1,
7571-
},
7572-
};
7573-
75747574
/**
75757575
* `record:highlights` highlight-field `icon` — a declared, advertised key with
75767576
* zero read points (#10054, ADR-0049 enforce-or-remove; maintainer ruling

‎packages/spec/src/data/analytics.zod.ts‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,23 @@ export const RETIRED_SUB_DAY_INTERVALS = ['second', 'minute', 'hour'] as const;
9898
* - a RETIRED sub-day name is a value this enum used to declare, so the
9999
* prescription is the retirement — what replaced it and the migrate line;
100100
* - anything else was never declared, so the prescription is the vocabulary.
101+
*
102+
* **Module-private**, which is the shape this kind of retirement takes:
103+
* `hook-body.zod.ts`'s `CRYPTO_HASH_RETIRED` is the matching precedent — a
104+
* prescription an enum's own error map consumes and nothing else does. The
105+
* sibling {@link analyticsDateRangeRefusalMessage} is exported because a
106+
* cross-file pin asserts `toBe(...)` against it, so the export IS the single
107+
* source of that expected string; this one has no such consumer, and
108+
* `driver-memory`'s door deliberately words its own sentence for its own
109+
* surface rather than re-emitting this one. An export with no reader is a
110+
* published surface the next narrowing has to keep.
101111
*/
102-
export function timeUpdateIntervalRefusalMessage(input: unknown): string {
112+
function timeUpdateIntervalRefusalMessage(input: unknown): string {
103113
const received = typeof input === 'string' ? `'${input}'` : JSON.stringify(input) ?? String(input);
104114
const declared = DateGranularity.options.join(', ');
105115
if (typeof input === 'string' && (RETIRED_SUB_DAY_INTERVALS as readonly string[]).includes(input)) {
106116
return (
107-
`Time interval ${received} was retired in protocol 18 (#17296, ADR-0049 enforce-or-remove). `
117+
`Time interval ${received} was retired in protocol 18 (ADR-0049 enforce-or-remove). `
108118
+ 'No backend ever bucketed it and none could advertise it: the canonical bucket-key '
109119
+ 'vocabulary and `supports.queryDateGranularity` both stop at '
110120
+ `${declared}, so the name resolved to a refusal or to one group per distinct timestamp. `

0 commit comments

Comments
 (0)