background-fields.ts2.4 KBView on GitHub
/**
 * Frontend background-field (sub-event taxonomy) visibility helpers.
 *
 * Org custom fields can be flagged `background === true`. Those are internal
 * sub-event taxonomy "moments" (discovery questions, objections, MEDDPICC
 * signals) extracted for analysis — they must NEVER surface in normal
 * field-display UI: CRM/canvas/sidebar columns, group-by and field-mapping
 * pickers, the conversation overview grid, or the working-memory card.
 *
 * The dedicated taxonomy editor (IntelligenceFieldsEditor) is the one surface
 * that deliberately shows background fields; it reads them directly rather than
 * through these helpers.
 *
 * Mirrors the server-side source of truth in
 * `apps/server/src/services/field-values/background-fields.ts`.
 */

/** A field definition is "background" (hidden taxonomy moment) when `background === true`. */
export function isBackgroundField(field: { background?: boolean } | null | undefined): boolean {
  return field?.background === true;
}

/**
 * Strip background (sub-event taxonomy) fields from a field-definitions map,
 * returning only the user-visible definitions. Preserves the key → definition
 * shape so every column/picker/overview consumer can drop this in where it
 * currently reads `aop.customFieldDefinitions`.
 */
export function getVisibleFieldDefinitions<T extends { background?: boolean }>(
  defs: Record<string, T> | null | undefined,
): Record<string, T> {
  const out: Record<string, T> = {};
  for (const [id, field] of Object.entries(defs ?? {})) {
    if (!isBackgroundField(field)) out[id] = field;
  }
  return out;
}

/**
 * Collect the set of background field IDs across many AOPs.
 *
 * Working-memory *values* (`WorkingMemoryEntry`) carry no `background` flag, so
 * they can only be identified via a field definition. When a given
 * conversation's own AOP defs are unavailable (no `aopId`, or an other-org AOP
 * whose minimal fetch failed), this org-wide set — background taxonomy IDs are
 * canonical and shared across an org's AOPs — still lets callers keep background
 * values hidden instead of falling back to showing everything.
 */
export function collectBackgroundFieldIds(
  aops: Array<{ customFieldDefinitions?: Record<string, { background?: boolean }> | null }>,
): Set<string> {
  const ids = new Set<string>();
  for (const aop of aops) {
    for (const [id, def] of Object.entries(aop.customFieldDefinitions ?? {})) {
      if (isBackgroundField(def)) ids.add(id);
    }
  }
  return ids;
}