> ## Documentation Index
> Fetch the complete documentation index at: https://docs.siftstack.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Naming rules and limits

> Character limits, allowed characters, and mutability rules for Asset, Channel, Run, and other Sift entity names.

export const MintTable = ({columns = [], rows = [], columnWidths = []}) => {
  const pushTextWithLineBreaks = (parts, text, keyBase) => {
    const segments = String(text).split(/\\n|\n/);
    segments.forEach((segment, idx) => {
      if (segment) {
        parts.push(<span key={`${keyBase}-text-${idx}`}>{segment}</span>);
      }
      if (idx < segments.length - 1) {
        parts.push(<br key={`${keyBase}-br-${idx}`} />);
      }
    });
  };
  const parseMarkdown = text => {
    if (text === null || text === undefined) return "";
    const str = String(text);
    const parts = [];
    let lastIndex = 0;
    const pattern = /(`[^`]+`|\*\*[^*]+\*\*|\*[^*]+\*|\[([^\]]+)\]\(([^)]+)\))/g;
    let match;
    while (true) {
      match = pattern.exec(str);
      if (match === null) {
        break;
      }
      if (match.index > lastIndex) {
        pushTextWithLineBreaks(parts, str.substring(lastIndex, match.index), `before-${lastIndex}`);
      }
      const fullMatch = match[0];
      if (fullMatch.startsWith("`") && fullMatch.endsWith("`")) {
        parts.push(<code key={match.index}>{fullMatch.slice(1, -1)}</code>);
      } else if (fullMatch.startsWith("**") && fullMatch.endsWith("**")) {
        parts.push(<strong key={match.index}>{fullMatch.slice(2, -2)}</strong>);
      } else if (fullMatch.startsWith("*") && fullMatch.endsWith("*")) {
        parts.push(<em key={match.index}>{fullMatch.slice(1, -1)}</em>);
      } else if (fullMatch.startsWith("[")) {
        const linkText = match[2];
        const linkUrl = match[3];
        parts.push(<a key={match.index} href={linkUrl} className="text-black-600 dark:text-black-400">
            {linkText}
          </a>);
      }
      lastIndex = pattern.lastIndex;
    }
    if (lastIndex < str.length) {
      pushTextWithLineBreaks(parts, str.substring(lastIndex), `tail-${lastIndex}`);
    }
    if (parts.length > 0) {
      return parts;
    }
    const plainParts = [];
    pushTextWithLineBreaks(plainParts, str, "plain");
    return plainParts.length ? plainParts : str;
  };
  const safeColumns = Array.isArray(columns) ? columns : [];
  const safeRows = Array.isArray(rows) ? rows : [];
  const safeColumnWidths = Array.isArray(columnWidths) ? columnWidths : [];
  const hasColumnWidths = safeColumnWidths.some(w => w !== null && w !== undefined && w !== "");
  const toCssWidth = width => typeof width === "number" ? `${width}px` : String(width);
  const getColumnStyle = idx => {
    const rawWidth = safeColumnWidths[idx];
    if (rawWidth === null || rawWidth === undefined || rawWidth === "") {
      return undefined;
    }
    const width = toCssWidth(rawWidth);
    return {
      width,
      minWidth: width
    };
  };
  const containerStyle = hasColumnWidths ? undefined : {
    overflowX: "auto"
  };
  const tableStyle = hasColumnWidths ? {
    tableLayout: "fixed",
    width: "100%"
  } : {
    width: "max-content",
    minWidth: "100%"
  };
  if (!Array.isArray(columns) || !Array.isArray(rows) || !Array.isArray(columnWidths)) {
    console.warn("MintTable received invalid props:", {
      columns,
      rows,
      columnWidths
    });
  }
  if (!safeColumns.length && !safeRows.length) {
    return null;
  }
  return <div className="mint-table-container" style={containerStyle}>
      <table style={tableStyle}>
        {hasColumnWidths && <colgroup>
            {safeColumns.map((_, idx) => {
    const style = getColumnStyle(idx);
    return <col key={idx} style={style} />;
  })}
          </colgroup>}
        <thead>
          <tr>
            {safeColumns.map((col, idx) => <th key={idx} className="text-left" style={getColumnStyle(idx)}>
                <b>{parseMarkdown(col)}</b>
              </th>)}
          </tr>
        </thead>
        <tbody>
          {safeRows.map((row, rIdx) => {
    const safeRow = Array.isArray(row) ? row : [];
    return <tr key={rIdx}>
                {safeRow.map((cell, cIdx) => <td key={cIdx} style={getColumnStyle(cIdx)}>
                    {parseMarkdown(cell)}
                  </td>)}
              </tr>;
  })}
        </tbody>
      </table>
    </div>;
};

Names in Sift are often used as identifiers in the API and workflow pipelines, not just as display labels. Understanding the constraints for each entity type helps you avoid failures and plan for changes.

## General behaviors

### Case sensitivity

Asset names are stored with their original casing. Sift maintains a lowercase index to support case-insensitive lookups, and the filtering API supports both `caseSensitive: true` and `caseSensitive: false` modes.

### Name reuse after archiving

For most entities, uniqueness constraints apply only to non-archived entities. Once an entity is archived, its name can be reused by a new entity.

Channel names are scoped per Asset, meaning two different Assets can have a Channel with the same name. Within a single Asset, a Channel is uniquely identified by the combination of name, data type, and unit. A Channel with the same name but a different data type or unit is treated as a distinct Channel.

### Whitespace trimming

Asset and Tag names have leading and trailing whitespace trimmed before storage.

## Assets

<MintTable
  columns={['Rule', 'Detail']}
  rows={[
['Max length', '128 characters'],
['Allowed characters', 'Any printable Unicode letter, mark, number, punctuation character, symbol, or space is allowed.'],
['Prohibited characters', '`/` (forward slash) and non-printing characters'],
['Whitespace', 'Leading and trailing whitespace is trimmed before storage'],
['Mutability', 'Immutable: name cannot be changed after creation']
]}
/>

`asset_name` is a required field in the ingestion API, data import API, and Channel schema API. If you create an Asset under one name, every external system sending data to that Asset by name must use that exact name.

## Channels

| Rule                  | Detail                                                                                                                                         |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| Max length            | 255 bytes                                                                                                                                      |
| Allowed characters    | ASCII only: no Unicode                                                                                                                         |
| Prohibited characters | `"` `\` `` ` `` `~` `\|` and the ASCII Information Separator characters: File Separator, Group Separator, Record Separator, and Unit Separator |
| Spaces                | Allowed                                                                                                                                        |
| Mutability            | Immutable: only description, units, metadata, and active status can be updated                                                                 |

Channel names function as identifiers in the ingestion pipeline. Like Asset names, changing a Channel name is not supported. Any external system referencing the Channel by name would require updates.

## Calculated Channels

<MintTable
  columns={['Rule', 'Detail']}
  rows={[
['Max length', '253 bytes'],
['Uniqueness', 'Must be unique within the organization'],
['Mutability', 'Mutable: name can be changed. Uniqueness is re-validated on update']
]}
/>

## Runs

<MintTable
  columns={['Rule', 'Detail']}
  rows={[
['Uniqueness', 'No uniqueness constraint'],
['Character restrictions', 'None'],
['Mutability', 'Mutable']
]}
/>

## Annotations

<MintTable
  columns={['Rule', 'Detail']}
  rows={[
['Character restrictions', 'None'],
['Mutability', 'Mutable']
]}
/>

## Campaigns

<MintTable
  columns={['Rule', 'Detail']}
  rows={[
['Mutability', 'Mutable']
]}
/>

## Tags

<MintTable
  columns={['Rule', 'Detail']}
  rows={[
['Whitespace', 'Names cannot contain whitespace'],
['Mutability', 'Immutable']
]}
/>

## Flows

<MintTable
  columns={['Rule', 'Detail']}
  rows={[
['Mutability', 'Immutable']
]}
/>
