Skip to content

[codex] Improve Slack insight digest markdown#496

Merged
izadoesdev merged 3 commits into
stagingfrom
codex/slack-insights-markdown-evals
Jun 26, 2026
Merged

[codex] Improve Slack insight digest markdown#496
izadoesdev merged 3 commits into
stagingfrom
codex/slack-insights-markdown-evals

Conversation

@izadoesdev

@izadoesdev izadoesdev commented Jun 26, 2026

Copy link
Copy Markdown
Member

Summary

  • Rework Slack insight digests into a markdown-only operator flow: label, title, evidence, why it matters, and next action.
  • Include the website name in digest headers as Name (domain) and fall back to the domain when no name exists.
  • Redact UUID-like internal IDs from visible Slack copy and add regression coverage for the final markdown contract.
  • Tighten insight prompt/schema guidance so investigations use calm wording, keep visible suggestions human-readable, and reserve raw IDs for action params.

Validation

  • bun test src/delivery.test.ts
  • cd apps/insights && bun run check-types
  • cd apps/insights && bun test src
  • bunx ultracite check apps/insights/src/delivery.ts apps/insights/src/delivery.test.ts apps/insights/src/generation.ts apps/insights/src/prompts.ts packages/ai/src/ai/schemas/smart-insights-output.ts
  • dotenv -- bun run --cwd packages/evals src/cli.ts --surface slack --tag digest --limit 2 --skip-judge --no-save --concurrency 1
  • Commit hooks ran full check-types; push hook ran repo test successfully.

@vercel

vercel Bot commented Jun 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
databuddy-status Ready Ready Preview, Comment Jun 26, 2026 6:56pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
dashboard Skipped Skipped Jun 26, 2026 6:56pm
documentation Skipped Skipped Jun 26, 2026 6:56pm

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: e3348168-eaea-45ab-9978-f59c8778fd7a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/slack-insights-markdown-evals

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@unkey-deploy

unkey-deploy Bot commented Jun 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Unkey Deploy

Name Status Preview Inspect Updated (UTC)
api (preview) Ready Visit Preview Inspect Jun 26, 2026 6:56pm

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 5 files

Confidence score: 4/5

  • In apps/insights/src/delivery.ts, the fallback Slack text uses an unescaped website label, so names containing mrkdwn or mention tokens can trigger unintended mentions/links and noisy notifications for users—escape/sanitize the label before assigning text to de-risk before merge.
Architecture diagram
sequenceDiagram
    participant Scheduler as Insight Scheduler
    participant Gen as generateWebsiteInsights
    participant Prompt as Build System Prompt
    participant AI as AI Model
    participant Delivery as deliverInsightDigests
    participant Blocks as buildBlocks
    participant Slack as Slack API

    Note over Scheduler,Slack: Insight generation and Slack digest delivery

    Scheduler->>Gen: generateWebsiteInsights(organizationId, websiteId)
    Gen->>Gen: fetch site details (id, domain, name)
    Gen->>Prompt: buildSystemPrompt()
    Prompt-->>Gen: prompt with "calm analyst" wording rules
    Gen->>AI: invoke AI model with insight schema
    AI-->>Gen: insights array (title, description, impactSummary, suggestion, type, sentiment, actions)
    alt insight has impactSummary
        Gen->>Gen: use impactSummary for "why it matters"
    else impactSummary missing
        Gen->>Gen: fallbackWhyItMatters() based on type/sentiment
    end
    alt action labels available
        Gen->>Gen: extract plain label for "Next" action
    else actions empty
        Gen->>Gen: fallbackNextAction() based on type
    end
    Gen->>Delivery: deliverInsightDigests(organizationId, websiteId, websiteDomain, websiteName, insights, chains)
    
    Note over Delivery,Blocks: Redact internal IDs from visible copy
    Delivery->>Blocks: buildBlocks(websiteName, websiteDomain, insights, chains)
    Blocks->>Blocks: formatWebsiteLabel(websiteName, websiteDomain)
    alt name exists and differs from domain
        Blocks->>Blocks: "Name (domain)"
    else no name or name matches domain
        Blocks->>Blocks: use domain only
    end
    loop for each insight
        Blocks->>Blocks: digestLabel() based on type + sentiment
        Blocks->>Blocks: userVisibleCopy() redacts UUIDs → "the affected item"
        Blocks->>Blocks: redacts code snippets (e.g., document.execCommand)
        Blocks->>Blocks: escapeMrkdwn() escapes HTML chars
        Blocks->>Blocks: compose markdown: label, title, Evidence, Why it matters, Next
        alt chain site count > 1
            Blocks->>Blocks: append "Also found on N other sites"
        end
    end
    Blocks-->>Delivery: SlackBlock[] with header + card blocks
    Delivery->>Slack: postToSlack(token, channelId, blocks, text)
    Slack-->>Delivery: 200 OK

    Note over Gen,Slack: Key branching for copy and schema enforcement
    alt insight type is referrer_change and sentiment positive
        Blocks->>Blocks: label = "Opportunity · Acquisition"
    else type is conversion_leak
        Blocks->>Blocks: label = "Fix · Goal tracking"
    else type is funnel_regression
        Blocks->>Blocks: label = "Cleanup · Funnel config"
    else default
        Blocks->>Blocks: label based on severity
    end
Loading

Shadow auto-approve: would not auto-approve because issues were found.

Re-trigger cubic

Comment thread apps/insights/src/delivery.ts Outdated
@izadoesdev izadoesdev marked this pull request as ready for review June 26, 2026 18:29
@greptile-apps

greptile-apps Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR reworks Slack insight digest blocks into a structured five-line operator card (label → title → evidence → why it matters → next action), adds UUID redaction for visible copy, and includes the website name in the digest header. It also tightens AI schema guidance and prompt wording to steer the model toward cleaner, human-readable output.

  • delivery.ts introduces digestLabel, userVisibleCopy, fallbackWhyItMatters, and fallbackNextAction to replace the old flat title/description/suggestion layout. buildBlocks is now exported and gains websiteName as a new first parameter.
  • The suggestion field remains required in DigestInsight but is never read during rendering — nextAction() uses actions[0].label or a generic type-based fallback, so insights without explicit actions always emit generic "Next:" copy even when a specific suggestion exists.
  • Schema .describe() strings and prompt guidance instruct the model to keep suggestion human-readable and ID-free, but this guidance has no effect on Slack delivery because suggestion is silently ignored in the rendering path.

Confidence Score: 3/5

Safe to merge for header and UUID-redaction changes; the "Next:" field will show generic fallback text for any insight that has a specific suggestion but no actions array.

The nextAction() function skips insight.suggestion entirely and falls through to type-based generic strings whenever actions is absent. Because actions is optional in the schema and many insights may not carry it, a meaningful fraction of real digests will show copy like "Add an annotation so future weeks have context." instead of the AI-generated specific suggestion. The new schema guidance was added specifically to make suggestion clean enough to display, but the delivery code was not updated to leverage it. The rest of the changes — header format, UUID redaction, fallback labels — are straightforward and well-tested.

apps/insights/src/delivery.ts — specifically the nextAction function and the DigestInsight interface.

Important Files Changed

Filename Overview
apps/insights/src/delivery.ts Core rework of Slack block rendering: adds UUID redaction, website name in header, structured label/title/evidence/impact/action card format. suggestion is now a required-but-ignored field and nextAction() skips it entirely in favour of generic fallbacks when actions is absent.
apps/insights/src/delivery.test.ts New regression suite for the Slack markdown contract; covers header format, card structure, UUID redaction, and domain-only fallback. The document.execCommand assertion passes because suggestion is never rendered rather than because it was sanitised.
apps/insights/src/generation.ts Single-line change: passes site.name into deliverInsightDigests as websiteName. Straightforward and low-risk.
apps/insights/src/prompts.ts Prompt guidance updated: calmer title tone, human-readable suggestions with IDs reserved for action params, description reframed as evidence. Prompt-only change with no runtime impact.
packages/ai/src/ai/schemas/smart-insights-output.ts Schema .describe() strings tightened to reinforce human-readable suggestion and calm title wording. No runtime behaviour change.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[deliverInsightDigests] --> B[buildBlocks]
    B --> C[formatWebsiteLabel]
    B --> D[Header block plain_text]
    B --> E{For each insight}
    E --> F[digestLabel - type plus sentiment]
    E --> G[userVisibleCopy - UUID redaction]
    E --> H{impactSummary present?}
    H -->|yes| I[Use impactSummary]
    H -->|no| J[fallbackWhyItMatters]
    E --> K{actions present?}
    K -->|yes| L[Use actions label]
    K -->|no| M[fallbackNextAction - generic]
    L --> N[Section block mrkdwn]
    M --> N
    I --> N
    J --> N
    note1[suggestion field required but never read] -.-> K
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[deliverInsightDigests] --> B[buildBlocks]
    B --> C[formatWebsiteLabel]
    B --> D[Header block plain_text]
    B --> E{For each insight}
    E --> F[digestLabel - type plus sentiment]
    E --> G[userVisibleCopy - UUID redaction]
    E --> H{impactSummary present?}
    H -->|yes| I[Use impactSummary]
    H -->|no| J[fallbackWhyItMatters]
    E --> K{actions present?}
    K -->|yes| L[Use actions label]
    K -->|no| M[fallbackNextAction - generic]
    L --> N[Section block mrkdwn]
    M --> N
    I --> N
    J --> N
    note1[suggestion field required but never read] -.-> K
Loading

Comments Outside Diff (1)

  1. apps/insights/src/delivery.ts, line 21-31 (link)

    P2 suggestion is required in DigestInsight but never read

    buildBlocks (and every helper it calls) never accesses insight.suggestion. The field is required — callers must provide it — yet it is silently discarded at render time. Future maintainers reading the interface will expect it drives some output. Marking it optional (or removing it) would signal clearly that delivery ignores it, and would also surface any callers who might be computing its value unnecessarily.

Reviews (1): Last reviewed commit: "chore(insights): tighten investigation c..." | Re-trigger Greptile

Comment thread apps/insights/src/delivery.ts
Comment thread apps/insights/src/delivery.ts Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 2 files (changes from recent commits).

Shadow auto-approve: would auto-approve. Refines Slack insight digest formatting, redaction, and prompt guidance. UI-only changes covered by new tests; no core logic or infrastructure risk.

Re-trigger cubic

@izadoesdev izadoesdev merged commit 87ca8c0 into staging Jun 26, 2026
18 checks passed
@izadoesdev izadoesdev deleted the codex/slack-insights-markdown-evals branch June 26, 2026 21:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant