|
| 1 | +--- |
| 2 | +name: audit-comparisons |
| 3 | +description: Re-verify every claim on the comparison pages against its own citations, fix what is wrong, refresh the check dates, and report what could not be verified. Runs end to end with no input. Use when comparison data may be stale, before publishing comparison pages, or when asked to fact-check, re-verify, or refresh /comparisons. |
| 4 | +--- |
| 5 | + |
| 6 | +# Audit comparisons |
| 7 | + |
| 8 | +Re-checks `apps/sim/lib/compare/data/` — 20 competitor profiles plus Sim's own — against the |
| 9 | +sources each claim already cites. Wrong or unsupported wording gets corrected, check dates move |
| 10 | +to today for sources that were actually read, and anything unreadable is reported instead of |
| 11 | +being quietly asserted or quietly dropped. |
| 12 | + |
| 13 | +Run it with no arguments. It needs one thing from the user, once, before any work starts: a |
| 14 | +working browser. Everything after that is automatic. |
| 15 | + |
| 16 | +## What this protects |
| 17 | + |
| 18 | +These pages exist to be read by answer engines and LLMs. The long-form text IS the product. |
| 19 | +Earlier audits destroyed value by "tidying" — they cut 456 KB of sourced detail, dropped 250 |
| 20 | +`detail` fields, and reshaped the schema. That is the single worst outcome of a run. |
| 21 | + |
| 22 | +1. **Never shorten `value` or `detail`.** They are long on purpose. `shortValue` (3-10 words) is |
| 23 | + the only short field; it is a compression of `value` that introduces no new claim. If a |
| 24 | + correction makes a claim narrower, the text stays long — it gets *more* precise, not smaller. |
| 25 | + A run that reduces total bytes of `apps/sim/lib/compare/data/competitors/` without a |
| 26 | + correction to justify each cut has failed. |
| 27 | +2. **Never change shape.** No new fields, no renamed keys, no new files, no edits outside |
| 28 | + `apps/sim/lib/compare/data/`. The audit updates language and dates in files that already exist. |
| 29 | +3. **Absence of evidence is not evidence of absence.** If a capability cannot be confirmed, say |
| 30 | + it is not documented and set `confidence: 'unknown'`. Never write that a product lacks a |
| 31 | + feature because the docs could not be found. |
| 32 | +4. **Cite only pages actually read in this run,** and only where the page really contains the |
| 33 | + claim. A 200 response is not support. |
| 34 | +5. **Preserve qualifications.** Plan gating, report scope and NDA conditions, preview/beta |
| 35 | + labels, region limits, self-hosted-vs-cloud splits. Losing a qualification is a factual error. |
| 36 | +6. **No artifacts.** No reports, notes, manifests or scratch files in the repo. Findings travel |
| 37 | + in agent messages. The tree ends PR-ready. |
| 38 | + |
| 39 | +## Step 0 — Preflight (before spawning anything) |
| 40 | + |
| 41 | +Fail here, loudly, rather than halfway through 21 profiles. |
| 42 | + |
| 43 | +1. `git status --porcelain` in the repo. If `apps/sim/lib/compare/data/` already has uncommitted |
| 44 | + edits, tell the user and stop — the audit needs a clean baseline to diff against. |
| 45 | +2. **Static fetch:** WebFetch `https://docs.sim.ai/platform/enterprise/scim`. Expect real prose. |
| 46 | +3. **Client-rendered fetch:** WebFetch `https://trust.sim.ai/`. This one is expected to come back |
| 47 | + as a bare title — that is the failure mode the browser exists for, not a problem. |
| 48 | +4. **Browser:** navigate to `https://trust.sim.ai/`, wait ~3s for the client render, then read the |
| 49 | + page text. It must list the compliance certifications. If the browser pane is unavailable, the |
| 50 | + navigation is refused, or the text stays empty: |
| 51 | + |
| 52 | + > Stop. Tell the user the audit needs browser access, name what failed, and ask them to enable |
| 53 | + > it. Do not start the checkers — without the browser fallback every JavaScript-rendered |
| 54 | + > pricing page and trust centre in the set becomes "unverifiable", which is a useless run. |
| 55 | +
|
| 56 | +Only when all four pass, continue. Say so in one line and keep going — do not ask permission. |
| 57 | + |
| 58 | +## Step 1 — Units |
| 59 | + |
| 60 | +One unit per profile file: every `apps/sim/lib/compare/data/competitors/*.ts` plus |
| 61 | +`apps/sim/lib/compare/data/sim.ts`. A unit is roughly 85 claims and 50-90 URLs, which is the |
| 62 | +largest chunk one agent can check without losing precision. Never batch two profiles into one |
| 63 | +checker. |
| 64 | + |
| 65 | +`sim.ts` is cited by every competitor page, so audit it too — its claims are load-bearing |
| 66 | +everywhere. |
| 67 | + |
| 68 | +## Step 2 — Check (bounded, read-only) |
| 69 | + |
| 70 | +Spawn checkers in batches of 5. Each gets the verbatim prompt in |
| 71 | +`agents/checker.md` with `{{PROFILE_PATH}}` replaced. The checker reads one file, opens every |
| 72 | +cited URL, and returns two things: a per-URL verdict list, and flags for claims that are wrong, |
| 73 | +unsupported, over-stated, or unverifiable. It edits nothing. |
| 74 | + |
| 75 | +## Step 3 — Fix (fresh eyes, flags only) |
| 76 | + |
| 77 | +For each profile that came back with flags, spawn a *fresh* agent with the verbatim prompt in |
| 78 | +`agents/fixer.md`. It receives only the file path and that profile's flags plus per-URL verdicts — |
| 79 | +no checker reasoning, no conversation history, nothing about the other profiles. It re-opens the |
| 80 | +cited page itself, decides whether it agrees, and only then edits. |
| 81 | + |
| 82 | +The split is the point: the checker is free to be suspicious because it cannot change anything, |
| 83 | +and the fixer is a genuine second opinion because it never sees the argument, only the claim. |
| 84 | +Roughly a quarter of flags are false positives — usually a retrieval that got truncated or a |
| 85 | +second attached source that already supported the claim — and the fixer is what catches them. |
| 86 | + |
| 87 | +## Step 4 — Dates |
| 88 | + |
| 89 | +The page's "verified as of" line is derived from the citation dates in the data |
| 90 | +(`getLatestVerifiedDate`, and the page review date from the oldest citation), so there is no |
| 91 | +separate date to maintain. The fixer sets `asOf` to **today** for every source it or the checker |
| 92 | +actually read and confirmed supports its claim, and leaves `asOf` untouched for any source that |
| 93 | +came back unverifiable. That way a refreshed date always means "a machine read this page today |
| 94 | +and the claim still stood". |
| 95 | + |
| 96 | +## Step 5 — Verify the tree |
| 97 | + |
| 98 | +After every fixer returns: |
| 99 | + |
| 100 | +```bash |
| 101 | +cd apps/sim && bun run type-check # expect 0 errors |
| 102 | +cd apps/sim && bunx vitest run "app/(landing)/comparisons" "lib/compare" |
| 103 | +bunx biome check $(git diff --name-only | grep -E '\.tsx?$' | tr '\n' ' ') |
| 104 | +git status --porcelain # MUST contain no '??' lines |
| 105 | +git diff --stat # MUST touch only lib/compare/data |
| 106 | +``` |
| 107 | + |
| 108 | +Then compare size: `cat apps/sim/lib/compare/data/competitors/*.ts | wc -c` against the same |
| 109 | +command at `git stash`-free HEAD. A large drop means someone truncated long-form text — find it |
| 110 | +and restore it before reporting success. |
| 111 | + |
| 112 | +## Step 6 — Report |
| 113 | + |
| 114 | +Print to the conversation only. No files. |
| 115 | + |
| 116 | +- One line per profile: claims checked, URLs read, flags raised, fixes applied, flags rejected. |
| 117 | +- **Unverifiable list** — every page that could not be read after both WebFetch and the browser, |
| 118 | + and every cell whose claim now rests on one. This is the most important section; surface it |
| 119 | + even when it is long. |
| 120 | +- Anything a fixer disagreed with, with its reason. |
| 121 | +- Confirmation that the tree has no new files and no changes outside `lib/compare/data`. |
| 122 | + |
| 123 | +## Known-hard sources |
| 124 | + |
| 125 | +Lessons from previous runs — these are traps, not edge cases: |
| 126 | + |
| 127 | +- **Trust centres and status pages** (`trust.sim.ai` and most vendor equivalents) are client |
| 128 | + rendered. WebFetch returns a bare title. Always browser. |
| 129 | +- **Pricing pages with interval toggles** (make.com, pipedream.com) hide the other interval's |
| 130 | + prices behind a control. Read them in the browser and operate the toggle. |
| 131 | +- **Plan matrices with tick marks** (Zapier SSO/SCIM) list every plan name in text while the |
| 132 | + ticks restrict the feature to two of them. Text extraction reads the names and loses the |
| 133 | + restriction. Browser, and look at the marks. |
| 134 | +- **Docs that carry two generations of guidance** (CrewAI's agent docs kept old Docker examples |
| 135 | + beside an explicit deprecation notice). Prefer the explicit deprecation or "current" section, |
| 136 | + and never "correct" a claim to match a stale example. |
| 137 | +- **OpenAI help-centre and product pages** return 403 to automated browsers. Expect |
| 138 | + unverifiable; say so rather than guessing. |
| 139 | +- **A flag may be wrong because the fact already cites a second source** that supports it. Check |
| 140 | + every attached source before agreeing with a flag. |
0 commit comments