Competitor scan always re-runs; report numbers refresh when the report is rewritten
- Skill: a "Find competitors" click always does the full scan and rewrites this month's report (the run had skipped because one already existed) - Frozen <report>.data.json is reused only while the .md is older, so a new run's report gets fresh numbers without deleting files by hand Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
9238b8c77a
commit
2e0b28f2a2
@ -5,6 +5,8 @@ description: Find a client's real competitors (local rivals and niche benchmarks
|
|||||||
|
|
||||||
Goal: tell the client who they're actually up against, who's winning and *why*, and the 3–5 openings nobody in their market is using. Numbers come from Instagram via the tools, never from memory or guesses.
|
Goal: tell the client who they're actually up against, who's winning and *why*, and the 3–5 openings nobody in their market is using. Numbers come from Instagram via the tools, never from memory or guesses.
|
||||||
|
|
||||||
|
**Always run the full scan, even if this month's report already exists.** Someone started this run on purpose (new data sources, tracked accounts changed, or the last report was wrong). Use the old report only as a starting point, then rewrite `competitors-YYYY-MM.md` in place and re-export the PDF. Re-suggesting an account doesn't duplicate it: `competitor_suggest` replaces the existing suggestion and skips tracked or dismissed accounts.
|
||||||
|
|
||||||
1. **Know the client.** Read `clients/<slug>/client.json`, `brand.md`, `goals.md`, `constraints.md` and any `audit-*` file. Note: niche, exact offer, city/area (and radius that matters: a clinic competes within ~10 km, an online brand nationally), price level, ideal customer. Call `competitors` to see who's already tracked, so you don't suggest them again.
|
1. **Know the client.** Read `clients/<slug>/client.json`, `brand.md`, `goals.md`, `constraints.md` and any `audit-*` file. Note: niche, exact offer, city/area (and radius that matters: a clinic competes within ~10 km, an online brand nationally), price level, ideal customer. Call `competitors` to see who's already tracked, so you don't suggest them again.
|
||||||
|
|
||||||
2. **Search for candidates** (8–15 searches in total, no more):
|
2. **Search for candidates** (8–15 searches in total, no more):
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
// Visual report blocks: the AI writes small fenced markers, this file draws them as inline SVG/HTML.
|
// Visual report blocks: the AI writes small fenced markers, this file draws them as inline SVG/HTML.
|
||||||
// Charts are drawn from the stored account numbers (never from figures typed by the AI) and frozen
|
// Charts are drawn from the stored account numbers (never from figures typed by the AI) and frozen
|
||||||
// next to the report as <report>.data.json the first time it renders, so a re-export shows the same numbers.
|
// next to the report as <report>.data.json the first time it renders, so a re-export shows the same numbers
|
||||||
|
// (until the .md is rewritten, which takes a fresh copy).
|
||||||
//
|
//
|
||||||
// Data blocks: ```mc:kpis ```mc:reach ```mc:funnel ```mc:followers ```mc:formats ```mc:rhythm ```mc:top-posts
|
// Data blocks: ```mc:kpis ```mc:reach ```mc:funnel ```mc:followers ```mc:formats ```mc:rhythm ```mc:top-posts
|
||||||
// Written blocks: ```mc:score (Area | 6/10 | why) ```mc:actions (Action | Owner | When)
|
// Written blocks: ```mc:score (Area | 6/10 | why) ```mc:actions (Action | Owner | When)
|
||||||
@ -90,7 +91,8 @@ function competitionData(slug, snap) {
|
|||||||
|
|
||||||
export function reportData(mdPath) {
|
export function reportData(mdPath) {
|
||||||
const frozen = resolve(mdPath).replace(/\.md$/i, ".data.json");
|
const frozen = resolve(mdPath).replace(/\.md$/i, ".data.json");
|
||||||
if (existsSync(frozen)) return readJson(frozen);
|
// Frozen until the report itself is rewritten (a new run or an edit): then its text and numbers move together.
|
||||||
|
if (existsSync(frozen) && statSync(frozen).mtimeMs >= statSync(mdPath).mtimeMs) return readJson(frozen);
|
||||||
const slug = slugFor(mdPath);
|
const slug = slugFor(mdPath);
|
||||||
const data = slug && freshData(slug);
|
const data = slug && freshData(slug);
|
||||||
if (data) try { writeFileSync(frozen, JSON.stringify(data)); } catch { /* read-only folder: render live */ }
|
if (data) try { writeFileSync(frozen, JSON.stringify(data)); } catch { /* read-only folder: render live */ }
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user