shipped@di-atomic/competitor-watch · v0.1.1 · beta

A competitor snapshot is not a competitor diff.

Most competitor reports describe the present in change-flavoured language, and nothing inside them tells you which one you are reading. competitor-watch makes changed a fact the storage layer proves rather than a claim a writer makes: snapshots land in a content-addressed store, an identical week creates no revision at all, and every change ships with the revision pair and the add and delete counts behind it.

For founders, operators and agencies who get a weekly competitor update and cannot tell which lines in it are news — and who would rather be told “we could not look this week” than be quietly handed a re-description.

A dark chalkboard with two identical hand-drawn rectangles side by side. The left is an empty white chalk outline labelled SNAPSHOT; the right is filled solid gold and contains plus four slash minus three, labelled DIFF.
Built by Di-Atomic Marketing & compliance agency 32 live production probes before authoring 7-language team Clients incl. ONYX Radiance, Pamit Group
32live production reads run before a line was authored
0 of 30Meta commercial ads that disclose a spend figure
5verdicts, so “could not look” never reads as “no change”
4scripts that print PASS or FAIL with numbers
Installopvs-skills install @di-atomic/competitor-watch

Then say: “run the weekly competitor scan” or “did anyone change pricing?”.

Why a weekly competitor report drifts

What a normal scan produces
re-read their pricing page
describe what it says now
write it up as this week's update

→ did any of this actually move?
→ the crawl timed out; is that "no change"?
→ their LinkedIn dates are blank — stopped?
→ four ads vanished off page one — pulled?
→ what is their impressions index? (-1)

(send it Monday, sound certain)

Every one of those is a place a report prints a confident number that is wrong. None of them are visible to the reader, or to the person who wrote it.

What competitor-watch produces
set      declared per call, never inferred
store    content-addressed; same bytes,
         no revision, so unchanged is free
changed  from_rev → to_rev, +4 / -3
timeout  queued, a first-class verdict
blank    not_disclosed (EU-only field)
sample   labelled 30 of 377, appearances only
spend    never emitted, on any platform
demand   who ranks for "them + alternative"

A claim you can check without trusting the writer, because the evidence is what produced the claim in the first place.

If a claim can only be checked by the person making it, it will drift.

Five verdicts, and the last three never collapse into the second

changedCarries a revision pair and its additions and deletions counts. It cannot be written without them.
unchangedThe store created no new revision from an identical write. A server-side fact, and free.
queuedThe crawl is async and had not returned. Not the same as nothing having happened.
not_disclosedThe platform publishes this to nobody. A US advertiser’s blank LinkedIn dates are lawful, not broken.
unavailableI tried and failed. Recorded as a failure to look, never as a finding.

What you actually get

🔄

A diff, not a re-snapshot

Snapshots go to a content-addressed store. Writing the same bytes back creates no revision, so “nothing moved” costs nothing and is decided by the substrate. A real change reports the revision pair and the counts between them.

🚫

It refuses to invent a number

No ad library discloses commercial spend, so none is ever emitted. A field can also be filled and still empty: impressions_with_index came back non-null on 30 of 30 ads, every one holding minus one. Sentinels are read at the leaf, never at the wrapper.

🎯

It sees who buys no ads at all

Searching a competitor plus “alternative” costs one credit and returned five rivals in the top eight, each publishing content to intercept that search. An ad library shows what someone pays for. This shows who is hunting their unhappy customers.

One competitor, one week, start to finish

> "run the weekly competitor scan"

  set ............ 4 competitors, declared, resolved
                   credit cost printed FIRST: 63/competitor
                   for a full paginated ad sweep

  pricing ........ changed    from_rev fec68254 → 6fab9dc9
                              +4 / -3   (Starter 19 → 24)
  changelog ...... unchanged  identical write, no revision
  website ........ queued     async crawl, worker_id null
                              NOT reported as "no change"

  meta ads ....... 30 of 377 sampled (8%)
                   appearances claimed, absences NOT
  linkedin ads ... 19 of 24 disclosed  (EU-targeted)
                   5 not_disclosed, not "stopped"
  google ads ..... volume + timing only; copy costs
                   25 credits/creative, so not sourced
  spend .......... never emitted

  demand ......... 5 of top 8 "alternative" results
                   are rivals; 2 absent from every
                   ad library we just read

  verify-competitor-set-declared ....... PASS
  lint-non-attributable-claims ......... PASS  0 uncited
  verify-diff-vs-prior-week ............ PASS  real parent
  verify-parse-tolerance ............... PASS

The credit cost is printed before the scan starts, and a scan that cannot be finished is refused rather than half-run — a partially paginated sweep silently corrupts the following week’s diff, which is worse than not scanning at all.

Two things it refuses to get wrong

A dark chalkboard showing a large empty white chalk rectangle labelled 30 slash 30 FILLED, with an arrow pointing right to a small solid gold box containing minus one.
A field can be filled on every record and still hold nothing. Completeness is judged on the leaf value against a sentinel list, never on the presence of the wrapper.
A dark chalkboard showing a row of exactly eight small squares, five filled solid gold and three empty white outlines, under the heading THEM ALTERNATIVE and above the caption 5 OF 8 ARE RIVALS.
The rivals an ad library cannot see. One credit on the alternative-to search returned five competitors in the top eight, two of which buy no ads at all.

What it will tell you it cannot do

  • Ad spend: unavailable everywhere. Meta publishes it for political ads only. It is never estimated, and never prefixed with a tilde.
  • LinkedIn dates: EU-targeted ads only. 19 of 24 disclosed for one advertiser, 0 of 24 for two others. Per-ad targeting decides it, not the company’s address.
  • Ad lists are samples. Meta returned 30 of 377, Google 40 of about 2,000. Set subtraction on page one manufactures churn that never happened.
  • Google ad copy is not sourced. It is absent from the list response and costs 25 credits per creative. Google is a volume and timing signal only.
  • LinkedIn post engagement does not exist. The response carries four keys and none of them is a like. Cadence only.
  • Website reads are asynchronous. A crawl can still be queued when the report is due, and that is reported as queued.
Why this exists

I got tired of competitor reports I could not check.

competitor-watch is one skill in the system behind Di-Atomic — the marketing and compliance agency that runs cognitoAI, SpiderIQ and OPVS. If you want a weekly read on your market that tells you what moved, in any of our seven languages and including regulated categories, that is the day job.

Book a 30-min call with Di-Atomic

Just want the skill? Get @di-atomic/competitor-watch free.