> ## 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.

# Annotation reference

> Status definitions, valid transitions, and file attachment limits for Annotations

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>;
};

This page covers the status workflow and file attachment behavior for Data Review Annotations. Phase Annotations do not have states or file attachment support; this reference applies only to Data Review Annotations.

## Statuses

<MintTable
  columns={['State', 'Meaning', 'When to use it']}
  rows={[
['Open', 'The Annotation has not been reviewed. This is the default state when an Annotation is created.', 'Before any review has taken place.'],
['Failed', 'The Annotation was reviewed and the underlying telemetry represents a real problem that must be addressed.', 'When the finding requires follow-up action; for example, a sensor anomaly or a rule violation that cannot be accepted.'],
['Accepted', 'The Annotation was reviewed and determined to be valid or not requiring action.', 'When the finding is understood, expected, or otherwise does not require corrective action.']
]}
/>

## Transitioning between states

Use the status control in the Annotation details panel to transition an Annotation between **Open**, **Failed**, and **Accepted**. All state transitions are recorded in the Annotation's activity log with a timestamp and the user who made the change.

## How Annotation states appear in Reports

When a Rule is evaluated in a Report, the status displayed for that Rule is derived from the states of its Annotations:

* If all Annotations are **Open**: the Rule shows as Open.
* If at least one Annotation is **Failed**: the Rule shows as Failed, regardless of other Annotation states.
* If all Annotations are **Accepted**: the Rule shows as Accepted.
* If the Rule generated no Annotations: the Rule shows as **Passed**. Passed Rules are not shown in the Report by default; filter for Passed Rules to see them.

Changing an Annotation's state immediately updates the Rule's displayed status in the Report.

## File attachments

Files can be attached to Annotations and to individual comments on Annotations.

### Supported file types

<MintTable
  columns={['Type', 'Formats', 'In-platform viewing']}
  rows={[
['Image', '`.png`, `.jpg`, `.jpeg`', 'Yes; viewable directly in Sift'],
['Video', '`.mp4`, `.webm`', 'Yes; viewable directly in Sift'],
['All other file types', 'Any format', 'No; files can be uploaded and downloaded but must be opened externally']
]}
/>

### Size limits

<MintTable
  columns={['Limit', 'Value']}
  rows={[
['Maximum file size per upload', '30 GB'],
['Maximum number of files per Annotation', 'No enforced limit']
]}
/>

## Behavior

<MintTable
  columns={['Area', 'Details']}
  rows={[
['Archiving', 'Archiving an Annotation removes it from the active view but does not change its state. Archived Annotations can be restored.'],
['Phase Annotations', 'Phase Annotations cannot be transitioned. They have no state field and cannot be assigned or resolved.'],
['Attachments and archiving', 'Attachments are stored alongside their Annotation or comment and remain associated with it even if the Annotation is archived.'],
['Attachments and behavior', 'Attachments do not alter the content or behavior of the Annotation or comment they are added to.'],
['File size limit', 'Files that exceed 30 GB cannot be uploaded; the upload will fail.'],
['Rules excluded from evaluation', 'A Rule that was not included in the Report evaluation does not appear in the Report at all; not even as Passed.'],
['Live Rules and Reports', 'Live Rules that did not generate an Annotation during the original evaluation are not linked to the Report and will not be included if the Report is rerun. To evaluate them, generate a new Report.'],
['Re-running Rule evaluation', 'Re-running Rule evaluation against a Run creates new Annotations rather than updating or deduplicating the ones from a prior evaluation. When comparing Annotation output across repeated evaluations, deduplicate the results yourself.']
]}
/>

## Related workflows

* [Detect and review issues in a Run](/documentation/review/detect-and-review-issues-in-a-run)
* [Triage and close out flagged issues](/documentation/review/triage-and-close-out-flagged-issues)
