marketing + seo: the three-week tester campaign, schedule-post --link, the not-indexed audit
gates / gates (push) Successful in 6m15s
gates / gates (push) Successful in 6m15s
COPY.md section 7: five Hungarian posts for Tue/Thu 19:00 over three weeks, each with a source comment per claim and one link. The Monday post (2026-10-12, 6.2) is untouched and no slot shares its day. fb_probe.py gains --link (default unchanged). Every scheduled post used to attach the home page's preview card whatever its text said, so a post about /teszteles would have sent the people who clicked its card to the home page. build_parser() split out of main() so a test can parse argv. Red-proved: both new tests fail with "Namespace object has no attribute link" without the flag. Search Console audit (seo-2026-10-10/not-indexed.md): all seven not-indexed URLs with a verdict each - four expected by design, two waiting on Google's crawl queue, one fault on our side. That one is /api/contact, the contact form's POST endpoint crawled as a page; robots.txt now disallows /api/. The performance baseline (0 clicks, 47 impressions, position 73, nine queries) is recorded there to compare against in a month.
This commit is contained in:
@@ -516,9 +516,9 @@ def scenario_sched_dry(g, page):
|
||||
return 0, res
|
||||
|
||||
|
||||
def scenario_sched_post(g, page, message, when):
|
||||
def scenario_sched_post(g, page, message, when, link=POST_LINK):
|
||||
pid, ptok = page["id"], page["token"]
|
||||
c = g.call("P1-create", "POST", pid + "/feed", ptok, form=schedule_form(message, when))
|
||||
c = g.call("P1-create", "POST", pid + "/feed", ptok, form=schedule_form(message, when, link=link))
|
||||
if not c.ok:
|
||||
log("P REFUSED: %s" % json.dumps(c.err, ensure_ascii=False))
|
||||
return 6, {"created": False, "error": c.err}
|
||||
@@ -543,8 +543,8 @@ def scenario_sched_post(g, page, message, when):
|
||||
|
||||
# ---------------------------------------------------------------- main
|
||||
|
||||
def main(argv=None):
|
||||
global VERBOSE
|
||||
def build_parser():
|
||||
"""The CLI surface, separate from main() so a test can parse argv without running a command."""
|
||||
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
||||
ap.add_argument("-v", action="store_true", help="print each call: method, path (no query), status, error")
|
||||
ap.add_argument("--version", default="v26.0", help="Graph API version (default v26.0)")
|
||||
@@ -555,9 +555,18 @@ def main(argv=None):
|
||||
help="COPY.md section to post, e.g. 6.1 or 6.2 (schedule-post)")
|
||||
ap.add_argument("--at", default=None,
|
||||
help="when to publish, 'YYYY-MM-DD HH:MM' in Europe/Budapest (schedule-post)")
|
||||
ap.add_argument("--link", default=POST_LINK,
|
||||
help="schedule-post: the URL whose preview card is attached (default %s). "
|
||||
"The card is what a reader clicks, so a post about one page names that page "
|
||||
"here, not just in its text." % POST_LINK)
|
||||
ap.add_argument("--dry", action="store_true",
|
||||
help="schedule-post: the throwaway link+schedule check, then delete it")
|
||||
a = ap.parse_args(argv)
|
||||
return ap
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
global VERBOSE
|
||||
a = build_parser().parse_args(argv)
|
||||
VERBOSE = a.v
|
||||
try:
|
||||
token = load_key(a.credentials)
|
||||
@@ -607,9 +616,9 @@ def run(cmd, g, token, a=None):
|
||||
except (ValueError, OSError) as e:
|
||||
log("REFUSED: %s" % e)
|
||||
return 2
|
||||
log("P section %s: %d characters, publishing at %s (epoch %d)"
|
||||
% (a.section, len(message), a.at, when))
|
||||
rc, _ = scenario_sched_post(g, page, message, when)
|
||||
log("P section %s: %d characters, link %s, publishing at %s (epoch %d)"
|
||||
% (a.section, len(message), a.link, a.at, when))
|
||||
rc, _ = scenario_sched_post(g, page, message, when, link=a.link)
|
||||
log("schedule-post: done (rc=%d)" % rc)
|
||||
return rc
|
||||
rc, _ = scenario_d(g, page, 0)
|
||||
|
||||
@@ -107,6 +107,23 @@ class ScheduleForm(unittest.TestCase):
|
||||
f = fb_probe.schedule_form("x", fb_probe.time.time() + 3600, link=None)
|
||||
self.assertNotIn("link", f)
|
||||
|
||||
def test_a_per_post_link_reaches_the_form(self):
|
||||
"""2026-10-10: the campaign posts each point at their OWN page, and the preview CARD is what
|
||||
a reader clicks. Before --link existed, every scheduled post attached https://felhom.eu/ no
|
||||
matter what its text said, so a post about /teszteles sent its readers to the home page.
|
||||
This pins the whole path: the CLI flag must reach the form."""
|
||||
a = fb_probe.build_parser().parse_args(
|
||||
["schedule-post", "--section", "7.1", "--at", "2026-10-13 19:00",
|
||||
"--link", "https://felhom.eu/teszteles"])
|
||||
self.assertEqual(a.link, "https://felhom.eu/teszteles")
|
||||
f = fb_probe.schedule_form("x", fb_probe.time.time() + 3600, link=a.link)
|
||||
self.assertEqual(f["link"], "https://felhom.eu/teszteles")
|
||||
self.assertEqual(f["published"], "false") # still unreachable, even with a link set
|
||||
|
||||
def test_link_defaults_to_the_home_page_when_the_flag_is_absent(self):
|
||||
a = fb_probe.build_parser().parse_args(["schedule-post", "--at", "2026-10-13 19:00"])
|
||||
self.assertEqual(a.link, "https://felhom.eu/")
|
||||
|
||||
|
||||
class ScheduleWindow(unittest.TestCase):
|
||||
NOW = 1_760_000_000
|
||||
|
||||
Reference in New Issue
Block a user