Slice 1 of #14130 (Slice B's gatherer). The primitive-first half — buildable off dev because both inputs are already there.
Scope (this ticket)
gatherDimensionConsistencyDiagnosis({collections, expectedDimension, serviceId, observedAt, sampleSize, auditFn}) (ai/daemons/orchestrator/services/dimensionConsistencyGatherer.mjs): runs auditCollectionVectorDimensions (#14113, pure/embedder-free) across the supplied live collections → per-collection samples → buildDimensionConsistencyDiagnosis (#14104, detect-only/samples-injected) → a recovery-diagnosis (null when all match). auditFn injectable for tests. Degrade-not-throw; not embed-canary-gated. + 4 unit tests.
Why off-dev / interface-stable
The gatherer emits a standard recovery-diagnosis regardless of the runner's escalate-vs-heal routing, and both auditCollectionVectorDimensions + buildDimensionConsistencyDiagnosis are on dev with exactly-matching sample shapes — so the FUNCTION needs nothing from #14184.
Out of scope (#14130 slice-2)
The runner injection — wiring this gatherer into DataIntegrityDiagnosisService's evidence seam — targets #14184's post-cutover runner and is gated on its 8am merge.
Refs #14130 (parent), #14113 (the audit primitive), #14104 (the producer), #14184 (the runner cutover, slice-2 gate). Self-assigned. Authored by Ada (@neo-opus-ada · Claude Opus 4.8, Claude Code).
Slice 1 of #14130 (Slice B's gatherer). The primitive-first half — buildable off dev because both inputs are already there.
Scope (this ticket)
gatherDimensionConsistencyDiagnosis({collections, expectedDimension, serviceId, observedAt, sampleSize, auditFn})(ai/daemons/orchestrator/services/dimensionConsistencyGatherer.mjs): runsauditCollectionVectorDimensions(#14113, pure/embedder-free) across the supplied live collections → per-collection samples →buildDimensionConsistencyDiagnosis(#14104, detect-only/samples-injected) → arecovery-diagnosis(null when all match).auditFninjectable for tests. Degrade-not-throw; not embed-canary-gated. + 4 unit tests.Why off-dev / interface-stable
The gatherer emits a standard
recovery-diagnosisregardless of the runner's escalate-vs-heal routing, and bothauditCollectionVectorDimensions+buildDimensionConsistencyDiagnosisare on dev with exactly-matching sample shapes — so the FUNCTION needs nothing from #14184.Out of scope (#14130 slice-2)
The runner injection — wiring this gatherer into
DataIntegrityDiagnosisService's evidence seam — targets #14184's post-cutover runner and is gated on its 8am merge.Refs #14130 (parent), #14113 (the audit primitive), #14104 (the producer), #14184 (the runner cutover, slice-2 gate). Self-assigned. Authored by Ada (@neo-opus-ada · Claude Opus 4.8, Claude Code).