Files
LinkedIn-Analytics-Dashboard/monthly_report_notes.py
T
beantownbabe 03e6d7287e Wire CTA Campaign phases into Reports as real computable periods
CUSTOM_PERIODS in report.py now drives _filtered/_period_label/
compute_period_stats for the 3 CTA phases (date ranges from the
proposed plan), and the campaign-report title treatment applies to
them the same way it does for July-September. Removed the app.py
placeholder guards (reports tab + docx download) now that real period
computation exists instead of an alert box, and fixed the docx
filename label lookup to check all campaigns' periods, not just the
old single flat list. Added Core Message (reused) and Roadmap
(per-phase) abstracts to monthly_report_notes.py for the 3 phases -
no executive_summary yet since the campaign hasn't run and isn't
approved, so KPI/chart cards render on real, currently-empty data
rather than fabricated findings.
2026-10-26 12:22:40 +01:00

551 lines
36 KiB
Python

"""Curated, hand-written narrative for each month of the 3-month LinkedIn campaign
(July, August, September 2026, plus an end-of-campaign report). Growth numbers are
computed live from the exports elsewhere (see report.compute_period_stats), this file
only holds the "why", which lives in git history and project context, not in any
dataframe. Keyed by the same "YYYY-MM" strings report.report_month_options() produces.
Add August's and September's entries here as those months are written up, no other
code changes are needed for the Reports tab or PDF to pick them up.
"""
# TXproducts' central value proposition doesn't change month to month, unlike the
# Roadmap abstract (a different campaign stage each month, per "LinkedIn Branding
# Campaign Roadmap.pdf") — factored out to one place so every month's entry reuses
# the identical text instead of N copies that could quietly drift apart.
_CORE_MESSAGE_ABSTRACT = [
("\"We reveal the processes inside your materials,\"", True),
("", "br"),
(" This defines TXproducts' central value proposition. It's the foundation "
"of all outreach and content.", False),
]
NOTES = {
"2026-07": {
"executive_summary": {
"goal_line": "July's Campaign: Stage One: Find the Voice - Establish a "
"consistent brand voice and discover which posts and formats "
"drove the most engagement.",
"goal_met": "Yes",
"growth_note": "Page grew from 85 to 107 followers (+22, +25.9%).",
"engagement_question": "Which post drove most engagement?",
"engagement_findings": [
"Traction by Format: Carousels and a personal, emotional-register story "
"outperformed everything else.",
"Emotional/personal-voice posts averaged 21.8% Real Eng % vs. Rational "
"posts' 8.1%.",
"Best single post hit 45.0% Real Eng %, the clear #1 all month.",
],
"trilogy_intro": "The 14/07-28/07-30/07 trilogy outperformed everything "
"else, giving a concrete, audited answer to what resonates "
"with this audience.",
"trilogy_posts": [
"14/07 — introduces the problem (operation modes, frustration of waiting)",
"28/07 — deepens it with the Ferris wheel analogy, ends on a cliffhanger CTA",
"30/07 — delivers the solution, in Daniel's own voice, closing the loop",
],
"trilogy_closing": "The trilogy of three posts brings in honesty in a way "
"that matters for credibility, further underlined by "
"technical substance delivered through a personal-voice "
"format.",
"best_posting_day_note": "Best Posting Day: Thursday shows the highest "
"average engagement this month.",
"best_posting_day_caveat": "Note: Every single Carousel was posted on a "
"Thursday, and every Video/Poll was posted on a "
"Tuesday, so this month's data can't isolate a "
"real day-of-week effect from a format effect.",
"validation_gap": "The one validation attempt (21/07 poll) got zero "
"responses. Whether this audience engages with "
"interactive formats at all is still unanswered.",
"audience_composition_line": "AUDIENCE COMPOSITION: Academia/Research "
"Institute is the largest single sector this "
"month.",
"audience_dimensions": [
("Prior Knowledge and Language", "This cohort is mostly Academic and "
"Engineering/Technical and understands the underlying science."),
("Decision Context", "Most of this cohort do not have a budget-holding "
"role, so they're not positioned to act on a rational business case."),
("Trust and Reservations", "Emotional posts outperformed the rational "
"ones. Leading with a human touch to a skeptical audience wins."),
],
},
"core_message_abstract": _CORE_MESSAGE_ABSTRACT,
"roadmap_abstract": [
("Find the Voice.", True),
(" Establish a consistent brand voice and discover the tone that resonates. "
"Identify which posts and formats drove the most engagement.", False),
],
"features_shipped": [
"Initial dashboard build (Jul 21): Overview, Content, Followers, Visitors, "
"Competitors, and Growth tabs, weekly-pace tracking, PDF report generation, "
"data upload with live refresh, and a static HTML export builder for sharing "
"via NextCloud.",
"Posts table made scrollable instead of growing indefinitely, and the file "
"finder hardened to ignore non-export files sitting in the same folder (Jul 22).",
"Follower Directory and Follower Study linked directly from the Followers tab "
"hero banner (Jul 31).",
"Followers by Country map expanded from 14 hardcoded country centroids to a "
"near-complete world table, with a console warning for any country still "
"missing one (Jul 31).",
"Calendar month drill-down tiles, a follower-breakdown expand toggle, a CTR "
"explainer, and manual post title overrides added across the Followers and "
"Content tabs (Jul 31).",
"Real Eng % (Audience-only, Team excluded, hand-audited, Clicks included) "
"rolled out everywhere a per-post engagement rate is shown, Reports pages and "
"the live Content/Overview dashboard alike, replacing LinkedIn's raw reported "
"number as the figure every table/chart/KPI actually uses (Aug 11). The audit "
"data and Real Eng % calculation moved into a new shared module "
"(engagement_audit.py) so the live app and the PDF/NextCloud export can't "
"drift apart. Traction by Format's separate 'Reported Avg Eng %' column was "
"dropped entirely rather than shown side by side with the real one, the same "
"reasoning already applied to Clicks: one number, one meaning, everywhere. "
"Correcting an earlier internal claim from this same audit: 09/07 does NOT "
"drop to near-bottom under Real Eng %, it remains the clear #1 post (45.0% "
"real vs. 47.9% raw) because its large Click volume (195) dominates the "
"calculation. The Core Message 'Emotional posts outperformed Rational ones' "
"finding was re-checked against the real numbers, not just re-labeled, and "
"holds: Emotional posts average 21.8% Real Eng % vs. Rational's 8.1%, a wider "
"gap than under raw numbers.",
"Audience Composition and Follower Study were raw pivot-table dumps with no "
"interpretation — a reader had to notice everything themselves. Both now lead "
"with real, dynamically-computed findings instead (Aug 31): Audience "
"Composition names the month's dominant sector, country concentration, and any "
"notable new followers; Follower Study leads with what changed that specific "
"month (new Notable Contacts, Account Clusters that grew, annotated inline) "
"ahead of the cumulative bimodal-seniority/shallow-network picture, rather than "
"repeating a near-identical all-time table every month with no monthly story.",
],
"data_quality": [
"File finder no longer crashes when a stray non-export file, a manual roster "
"or an Office lock file, sits in the same folder as the real LinkedIn exports.",
"Country map no longer silently drops a country if it is missing a centroid, "
"it now warns in the console instead, and the on-screen country count is "
"computed from the same rollup as the map so the two can never disagree.",
"Visitors category breakdown (Location, Seniority, Company size) is no longer "
"lost month to month. LinkedIn only reports a category once it clears a "
"per-export minimum-visits threshold, so a single-snapshot approach was "
"silently losing real categories that dipped below the threshold one week and "
"reappeared the next. Replaced with an append-only running-total log "
"(visitor_history.py).",
"Conversion Rate chart no longer silently drops days with zero tracked "
"visitors but a real follower change (LinkedIn lets people follow a Page "
"directly from a feed post, with no page visit at all). Every day now shows, "
"with those days flagged instead of hidden.",
"Decided against the deeper 3-7 day attribution-window/weekly-bucket idea "
"discussed Jul 28: at current follow/visit volumes, a week can have as few "
"as 1-3 real follows, too small for weekly aggregation to meaningfully "
"reduce noise over daily data. Revisit if monthly volumes grow enough for "
"the technique to actually pay off.",
],
"follower_study": [
"Grew and was actively reclassified throughout July as new followers were "
"screenshotted and profiled by hand.",
"A seniority and sector classification fix landed Jul 31 (backup preserved as "
"follower_directory_BACKUP-before-student-sector-fix.html), plus several "
"individual profile confirmations (Dominique Elser, Anna Bujak, Emma Xia, "
"Marten Edwards, Mudabar Ahmad Mubashar, Martin Schroter) that corrected "
"taglines into real titles and employers.",
"Not yet brought under git version control during July itself, that happened "
"Aug 3 and falls outside this report.",
],
"outstanding": [
"Real Eng % audit coverage, corrected 2026-09-21 (prior wording was stale): "
"with pre-campaign (19/06, 24/06) and non-campaign (02/09) posts properly "
"excluded and the repost (10/07) already excluded, the only real remaining "
"gap is 27/08, a genuine campaign post that was missed and still needs "
"auditing, plus 08/09, the newest post, not yet sent over. This was never "
"a large historical-backfill question, just two small posts to catch up on.",
"'Avg. Eng. Rate' stays on LinkedIn's raw daily Content Tracking Stats "
"number, resolved 2026-09-30: it's a page-level daily aggregate with no "
"name-level breakdown, unlike Real Eng %'s per-post hand audit, so there's "
"nothing to audit it against, Team can't be excluded from a single blended "
"daily number the way it can from a specific post's own Reactions list. Not "
"a pending decision anymore, just two genuinely different metrics shown side "
"by side, labeled 'raw, unaudited' everywhere it appears so the distinction "
"is explicit rather than assumed.",
],
},
"2026-08": {
"executive_summary": {
"goal_line": "August's Campaign: Stage Two: Find the Audience - Confirm "
"who is listening. Analyze follower demographics and which "
"job titles are visiting the profile.",
"goal_met": "Yes",
"growth_note": "Page grew from 107 to 126 followers (+19, +17.8%), the "
"largest single-month gain of the campaign so far.",
"engagement_question": "Who is actually listening?",
"engagement_findings": [
"Academia/Research Institute dominates the audience: 11 of 19 "
"profiled followers this month (58%), overwhelmingly based in "
"Germany (11 of 19).",
"Researcher/Scientist is the single largest seniority group — a "
"technical, research-facing audience, not a commercial/business one.",
"Carousel (04/08) repeated July's pattern, topping the month at "
"50.8% Real Eng %, but a plain Text/Image post with a crisp "
"value-prop statement (13/08, 'measurement at a fraction of the "
"cost') nearly matched it at 48.7% — format alone doesn't explain "
"the gap to the rest of the month's posts (2-8%); message clarity "
"matters just as much.",
],
"trilogy_intro": "The month's six Text/Image posts (11/08 through "
"27/08) form a single TXServices launch arc, not "
"isolated posts:",
"trilogy_posts": [
"11/08 — introduces TXServices, the measurement service itself",
"13/08 — the cost argument (measurement at a fraction of the cost)",
"18/08 — proof: the first real TXServices test run at Beamline P08, DESY",
"20/08 & 25/08 — the standardized workflow and what a first run "
"actually takes",
"27/08 — the standardized sample environment, closing the technical case",
],
"trilogy_closing": "Only the cost-argument post (13/08) broke out of "
"the 2-8% range the rest of the arc sat in — "
"introducing a new service needs more than one post "
"to land, but this month's data doesn't yet show "
"which specific angle (if any beyond cost) actually "
"moves this audience.",
"best_posting_day_note": "Best Posting Day: Tuesday averaged 22.7% Real "
"Eng % vs. Thursday's 15.4%.",
"best_posting_day_caveat": "Note: that gap is entirely the one "
"Carousel's doing — strip it out and "
"Thursday's plain Text/Image posts actually "
"averaged higher (13.3% vs 15.4%), the same "
"format/day confound flagged in July, still "
"unresolved.",
"validation_gap": "The second Poll attempt (06/08) got zero real "
"follower responses, same as July's — the only "
"reaction and comment were the Page's own, and "
"the only vote was internal (Daniel). The 5.2% "
"Real Eng % figure is entirely unaudited Clicks, "
"not engagement with the poll itself. Decision: "
"the Poll/Wildcard format is removed from the "
"campaign after two straight zero-response "
"attempts.",
"audience_composition_line": "AUDIENCE COMPOSITION: Academia/Research "
"Institute and Germany both dominate more "
"heavily than in July — the audience is "
"narrowing, not broadening.",
"audience_dimensions": [
("Prior Knowledge and Language", "Same as July: mostly Academic "
"and Engineering/Technical, understands the underlying science "
"without needing it simplified."),
("Decision Context", "A services launch (TXServices) speaks "
"directly to this cohort's day-to-day work, unlike July's more "
"abstract brand introduction — but the arc's flat engagement "
"suggests the pitch itself still needs sharpening."),
("Trust and Reservations", "The one post that broke out (13/08) "
"led with a concrete number (cost), not a feature list — "
"specificity, not just honesty, is what earned attention this "
"month."),
],
},
"core_message_abstract": _CORE_MESSAGE_ABSTRACT,
"roadmap_abstract": [
("Find the Audience.", True),
(" Confirm who is listening. Analyze follower demographics and which job "
"titles are visiting the profile.", False),
],
"features_shipped": [
"Reports tab built from scratch: Core Message, Roadmap, and Monthly Notes "
"cards with cross-page navigation, then split into 7 distinct insights pages "
"(Core Message, Roadmap, All Posts, Follower Growth, Audience Composition, "
"Follower Study, Monthly Notes) as the section list grew (Aug 5-7). All 7 "
"sections were then mirrored into both the PDF export and the static "
"NextCloud export, so the live dashboard, PDF, and shared snapshot read from "
"the same data instead of drifting apart (Aug 8).",
"GOTO Messaging page added: a cut-and-paste outreach building-block Handbook "
"of the Rules, with a Board callout, neutralized wording, and pale-yellow "
"styling instead of anything that reads as a hard sell (Aug 6).",
"Engagement Composition table polish: Impressions/Clicks/CTR % regrouped "
"ahead of Real Eng %, the redundant chart dropped so the table takes full "
"width, a Most Reach medallion badge added for the post with the highest "
"combined Audience Likes+Comments+Reposts (renaming Read's 'Reach' to "
"'Amplification' to resolve a naming collision), the callout rewritten to "
"lead with the hand-audited fact first, and every per-post table sorted "
"chronologically for consistent cross-referencing across tabs (Aug 11).",
"Real Eng % and CTR % formulas spelled out explicitly in every callout that "
"references them, instead of assuming the reader already knows the math "
"(Aug 26).",
],
"data_quality": [
"Follower Directory and Follower Study brought under git version control for "
"the first time (Aug 3) — from this point on, every addition and correction "
"has a real commit history instead of living only in the hand-edited HTML "
"file with no audit trail of its own.",
"Corrected follow dates for 3 followers using cross-referenced export data "
"(Aug 3), and separately corrected Sabine E. Herlitschka's follow date from "
"August to July 2026 (Aug 5).",
"Fixed a wrong title on the 13/08 post that had been falling back to a "
"generic placeholder instead of its real text (Aug 19).",
"Corrected 04/08's repost audit: Mihail Petev had been counted as an "
"audience repost of the original post, but he'd only liked a separate "
"company-page reshare surface (already excluded from the Real Eng % audit "
"for a different reason, a mismatched Impressions denominator) — the "
"incorrect repost credit was removed (Aug 27).",
"Fixed the unaudited-post fallback in Engagement Composition when Impressions/"
"Clicks/CTR % were added alongside Real Eng % (Aug 11).",
],
"follower_study": [
"Grew from 107 to 126 followers over the month (the largest single-month "
"gain of the campaign so far), added and profiled in near real time as each "
"batch came in: Alexander Rack, Tina Schmidt, and Sinan Bubik (Aug 5), 5 more "
"on Aug 19, 3 more on Aug 24, and Sourav Kumar on Aug 26, each addition "
"triggering a full chart/prose recompute rather than a batched end-of-month "
"catch-up.",
"This was the first month tracked in git from day one (see Data Quality "
"above), so every one of these additions has its own commit instead of being "
"reconstructable only from the live file's current state.",
],
"outstanding": [],
},
"2026-09": {
"executive_summary": {
"goal_line": "September's Campaign: Stage Three: Find the Trigger - What "
"made people act — reactions, reposts, and new connections.",
"goal_met": "Partial",
"growth_note": "Page grew from 126 to 142 followers (+16, +12.7%), the "
"slowest month of the campaign so far (July +25.9%, "
"August +17.8%).",
"engagement_question": "What actually triggered real engagement, not "
"just a passive like?",
"engagement_findings": [
"08/09 ('Power electronics fail because materials change under "
"stress') was the only post this month with genuine back-and-forth "
"comments, a real discussion thread, and the month's highest Real "
"Eng % (19.2%).",
"That 19.2% ceiling is the lowest 'best post' of the campaign so "
"far (July 45.0%, August 50.8%), and the month's own average "
"(12.8%) is roughly half August's (20.0%) — whatever triggered "
"08/09's discussion didn't repeat.",
"The month's Carousel (29/09) finally ran, and did NOT repeat "
"July/August's winning pattern — it scored 10.0%, below even "
"17/09's and 22/09's plain Text/Image posts, and nowhere near "
"July's 45.0% or August's 50.8%. Carousel is not a guaranteed "
"win; whatever made it work before didn't carry over here.",
],
"trilogy_intro": "September's six posts don't form a single arc like "
"July's trilogy or August's TXServices launch — "
"they're six different jobs done in six different "
"posts:",
"trilogy_posts": [
"03/09 — announces SNIB2026 attendance (event promo)",
"08/09 — a technical pain point (materials under stress) — the "
"month's only real discussion",
"15/09 — recaps SNIB2026 after the fact",
"17/09 — a direct ask for pilot partners",
"22/09 — a team photo (#MeetTheTeam)",
"29/09 — 'The two pillars of TXservices' (Carousel), the "
"month's one format test — and its lowest-scoring post",
],
"trilogy_closing": "Only the pain-point post (08/09) generated real "
"comments; everything else, including the "
"Carousel, landed flat — a trigger was found "
"once, not built into a repeatable pattern, and "
"the one format lever that worked twice before "
"didn't work a third time.",
"best_posting_day_note": "Best Posting Day: Tuesday averaged 10.9% "
"Real Eng % vs. Thursday's 6.4%.",
"best_posting_day_caveat": "Note: this month actually separates the "
"two variables for the first time — "
"Tuesday had both the campaign's weakest "
"Carousel (29/09, 10.0%) and its best "
"post (08/09, 19.2%), so the day itself "
"isn't doing the work; the specific post "
"still is.",
"validation_gap": "17/09's direct pilot-partner ask, the clearest "
"conversion CTA of the campaign, underperformed "
"(8.0%) — this isn't a validation test like "
"July's poll (that's about whether the audience "
"responds to a format at all), it's a direct "
"business ask, and a plain pain-point post still "
"beat it by more than double.",
"audience_composition_line": "AUDIENCE COMPOSITION: Academia/Research "
"Institute still leads (10 of 17), but "
"seniority spread out — Engineer/"
"Developer, Director/Head/Principal, "
"Postdoc/PhD Researcher, and Student/"
"Trainee are now tied at 3 each, a "
"broader mix than August's Researcher/"
"Scientist-heavy audience.",
"audience_dimensions": [
("Prior Knowledge and Language", "Still mostly Academic/"
"Engineering/Technical, but the seniority spread (students "
"through Director-level) means the same post now reaches very "
"different levels of context."),
("Decision Context", "Director/Head/Principal now ties for the "
"largest seniority group — the first month with a real "
"budget-holding presence, a different decision context than "
"July/August's mostly non-budget-holding cohort."),
("Trust and Reservations", "08/09's pain-point framing, not a "
"product pitch or a format choice, is what earned the month's "
"only real conversation — naming a real problem beat both the "
"direct ask (17/09) and the Carousel (29/09)."),
],
},
"core_message_abstract": _CORE_MESSAGE_ABSTRACT,
"roadmap_abstract": [
("Find the Trigger.", True),
(" What made people act — reactions, reposts, and new connections.", False),
],
},
"campaign-end": {
"executive_summary": {
"goal_line": "3-Month Campaign: Find the Voice (July) -> Find the "
"Audience (August) -> Find the Trigger (September).",
"goal_met": "Partial",
"growth_note": "Page grew from 85 to 142 followers (+57, +67.1% "
"cumulative) — but the monthly pace decelerated every "
"single month (July +25.9%, August +17.8%, September "
"+12.7%).",
"engagement_question": "What did the campaign actually prove, stage "
"by stage?",
"engagement_findings": [
"Carousel ran 7 times across the whole campaign (4 in July, 2 "
"in August, 1 in September) and averages 29.1% Real Eng %, "
"clearly the best of any format — Text/Image averages 9.1% by "
"comparison. Carousel still has real range (6.0% to 50.8%), not "
"a guaranteed result, but the campaign's #2 post (13/08, 48.7%) "
"proves the format works even better paired with a concrete "
"claim: that post combined Carousel with a specific cost "
"argument.",
"A real trigger was found once (September's 08/09 pain-point "
"post, the only genuine discussion thread of the whole campaign, "
"and still the highest Real Eng % of the month even against the "
"month's own Carousel) but never repeated or turned into a "
"system.",
],
"trilogy_intro": "Three stages, three different kinds of answer:",
"trilogy_posts": [
"July — Find the Voice: Carousel averaged best across its 4 "
"posts this month (range 6.0%-45.0%). Separately, the 14/07-"
"28/07-30/07 trilogy (Video, Video, Carousel) worked as a "
"sequential narrative arc, independent of format.",
"August — Find the Audience: a clear demographic answer "
"(Academia/Research, Germany, Researcher/Scientist), the "
"6-post TXServices launch arc, and 2 Carousels this month — "
"04/08 (50.8%, the campaign's #1 post) and 13/08 (48.7%, #2, "
"the cost-argument post from the TXServices arc)",
"September — Find the Trigger: one real trigger found (08/09's "
"pain-point post, beating even the month's own Carousel, 10.0%), "
"but not repeated — growth and engagement both decelerated",
],
"trilogy_closing": "Each stage answered its own question, but the "
"campaign never closed the loop between them.",
"best_posting_day_note": "Best Posting Day: Tuesday won in August and "
"September; July's Thursday win was itself "
"Carousel-driven (every July Carousel ran "
"on a Thursday), not a real day effect.",
"best_posting_day_caveat": "Note: September finally separated the "
"two variables (Tuesday held both the "
"campaign's weakest Carousel and its best "
"post) — the day was never what mattered, "
"the specific post always was. July and "
"August's day findings were confounded by "
"format and should be read with that in "
"mind.",
"validation_gap": "The Poll format was tried twice as a validation "
"test (21/07, 06/08) — does this audience respond "
"to an interactive format at all — and got zero "
"real follower responses both times (06/08's only "
"vote was internal). The format was removed from "
"the campaign after the second attempt. Separately, "
"17/09's pilot-partner ask (a direct conversion "
"CTA, not a validation test) got 8.0% — both kinds "
"of direct ask lost to organic storytelling or a "
"named pain point every time.",
"audience_composition_line": "AUDIENCE COMPOSITION (campaign-wide): "
"Academia/Research Institute and "
"Germany dominate in every single month "
"profiled — the most stable finding of "
"the entire campaign.",
"audience_dimensions": [
("Prior Knowledge and Language", "Consistently Academic and "
"Engineering/Technical across all 3 months — content never "
"needs simplifying for this audience, in July, August, or "
"September alike."),
("Decision Context", "This shifted over the campaign: July and "
"August's cohort was mostly non-budget-holding, but September "
"brought the first real budget-holding presence (Director/"
"Head/Principal tied for the largest seniority group) — the "
"audience's buying power grew as the campaign went on, worth "
"re-approaching now that it has."),
("Trust and Reservations", "Specificity built trust more "
"reliably than honesty alone — a concrete claim consistently "
"outperformed a vague or feature-list one, the throughline "
"behind both the format findings above and the failed direct "
"asks below."),
],
"insights": [
"Carousel ran 7 times across the campaign and averages 29.1% "
"Real Eng %, clearly the best format — Text/Image averages "
"9.1%.",
"13/08 is the campaign's #2 post (48.7%), a Carousel paired "
"with a concrete cost claim.",
"A specific claim beats vague content every time it's been "
"tried, in any format.",
"The audience is stable: Academia/Research Institute, "
"Germany-based, Researcher/Scientist-heavy in all 3 months.",
"Direct asks (2 polls, 1 pilot-partner CTA) got zero or weak "
"response every time, across all 3 months.",
"One real engagement trigger was found (08/09's pain-point "
"post) but never repeated.",
"Growth decelerated every month (July +25.9%, August +17.8%, "
"September +12.7%) even as total followers grew 85 to 142.",
],
"recommendations": [
"Make Carousel the default format and keep pairing it with a "
"concrete claim — 13/08 already proved this works (Carousel + "
"a cost argument, 48.7%, the campaign's #2 post). The one "
"combination still untried is specifically Carousel + a named "
"pain point (September's trigger finding, so far only tried "
"as Text/Image).",
"Move the 'ask' out of the public post and into direct "
"outreach: 21 people who engaged with a post without following "
"are already sitting in outreach_contacts.py, unconverted — a "
"warmer list than any public CTA has reached so far.",
"Treat conversion as a separate funnel from engagement. This "
"campaign never tracked whether a like or comment turned into "
"a pilot partner or a meeting. October needs its own metric "
"for that, such as DM replies, calls booked, or pilot "
"sign-ups, since Real Eng % only measures attention. This can "
"also be tracked through Twenty CRM.",
"Source content from real conversations, like 08/09's, instead "
"of assumed pain points. October doesn't need a new "
"audience-discovery push, since the audience hasn't moved. It "
"needs content built for what that audience has actually "
"affirmed.",
],
},
},
# CTA Campaign phases (Nov 2026 - Feb 2027), pending approval. Core Message is
# the same constant every other campaign reuses (TXproducts' value proposition
# doesn't change); the Roadmap abstract is what changes per phase, drawn
# directly from the proposed plan's own theme framing. No executive_summary yet
# - that would mean reporting findings from a campaign that hasn't run, so the
# KPI table and charts render on real (currently empty) data instead until
# there's something real to write up, same as any other not-yet-run period.
"cta-phase-1": {
"core_message_abstract": _CORE_MESSAGE_ABSTRACT,
"roadmap_abstract": [
("Failure Analysis.", True),
(" Power electronics fail under real operating stress, and time "
"resolution shows the failure as it happens.", False),
],
},
"cta-phase-2": {
"core_message_abstract": _CORE_MESSAGE_ABSTRACT,
"roadmap_abstract": [
("Standardization.", True),
(" Failure results are only useful when they're comparable: same "
"stress, same measurement, same pipeline on every sample.", False),
],
},
"cta-phase-3": {
"core_message_abstract": _CORE_MESSAGE_ABSTRACT,
"roadmap_abstract": [
("WaveGate.", True),
(" The technology that makes standardized, time-resolved failure "
"analysis possible.", False),
],
},
}