feat: fold Google Analytics into the SEO report (lib/ga.sh) #329
Labels
No labels
Agent
Compat/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No assignees
1 participant
Notifications
Total time spent: 6 minutes 1 second
Due date
igor
6 minutes 1 second
No due date set.
Dependencies
No dependencies set
Reference
joshtronic/igor#329
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Goal (re-scoped for the agent's turn budget — see Execution notes)
GA client + SEO report fold-in. Follow-on to #309 (GA access — done: the service account
reads GSC + 7 GA properties). The CEO digest fold-in has been split into a separate follow-up
(it depends on
lib/ga.shfrom this ticket), so each PR completes inside the agent's 50-turnbudget — this ticket ran out of turns twice trying to do both at once.
Principle: "GSC and/or GA — whatever's available." GA is additive and OPTIONAL: a domain with
no GA property must render exactly as it does today.
Part A —
lib/ga.sh(new; mirrorlib/gsc.sh)Pure-ish, scripted (no LLM), authing through the existing
lib/google-auth.sh:ga_access_token— wrapgoogle_sa_access_token "https://www.googleapis.com/auth/analytics.readonly".Empty + rc=1 on failure.
ga_property_for_domain <domain>— resolve the numeric property id dynamically: GEThttps://analyticsadmin.googleapis.com/v1beta/accountSummaries?pageSize=200, return thepropertySummaries[].property(stripproperties/) whosedisplayName == <domain>. Empty ifnone. No static map — mirrors GSC's zero-config enumeration.
ga_run_report <property_id> <start> <end> <dimensions_csv> <metrics_csv>— POSThttps://analyticsdata.googleapis.com/v1beta/properties/<id>:runReport; echo raw JSON; matchgsc_query's error posture (empty-rows JSON + rc on failure).Reference — properties the SA can read (do NOT hardcode; sanity-check only):
certifiedtradejobs.com 535124688, vpsshowdown.com 487911904, sharktank.co 404967917, scenekids.com 535254606, thatgirljen.com 371484954, debtmom.com 526352480, holidayapi.com 387040916.Part B — SEO report fold-in (
lib/seo-analysis.sh,bin/tick.shdo_seo_tick)When the analyzed domain resolves to a GA property, fetch GA for the same 28-day window
(
seo_window) and add an "On-site behavior (GA)" section to the report:sessions,engagedSessions,engagementRate,totalUsers,keyEventsif present. Thread throughseo_build_reportand BOTH renderers (seo_render_markdown,seo_render_html). Optionality ismandatory: no GA property → renders exactly as today (GSC-only). No new env knob.
Tests — REQUIRED (top code-review finding)
bin/test-ga.shagainst fixture JSON:ga_property_for_domainmatch/no-match,ga_run_reportparsing. Skip-safe (exit 0 + notice ifjq/python3absent), likebin/test-ceo.sh.it minimal — extend an existing test rather than a large new suite if that's cheaper.
bash bin/check-sync.shgreen.Execution notes (turn budget — this ticket failed twice on these)
("done"). Both prior attempts wrote everything correctly but ran out of turns re-running the
test suite, so nothing committed. Build, verify once, then STOP. Don't re-run the full
suite repeatedly or re-explore.
bash bin/test-ga.sh/bash bin/check-sync.sh— no>redirects, no&&/;compound commands, no./relativeexecution. Those forms trip the permissionprofile, get denied, and waste turns.
Constraints
set -euo pipefail; 2-space indent; check-then-act;logfor logging.agent-settings.json,systemd/,.forgejo/workflows/.Acceptance criteria
lib/ga.shwith the three functions; dynamic property resolution (no static map).bin/test-ga.sh+ SEO branch coverage;bash bin/check-sync.shgreen.The agent completed with no work produced and no blocker reported. Investigate. (claude exit: 1, elapsed 515s)
last bytes of claude output
The agent produced no work on this issue twice. The issue is probably unclear, requires context Claude can't reach, or has a setup problem. Investigate, then remove
Status/Blockedto re-queue.feat: fold Google Analytics into the SEO report and CEO digest (lib/ga.sh)to feat: fold Google Analytics into the SEO report (lib/ga.sh)Re-scoped + re-queued (CoS Igor). This ran out of the agent's 50-turn budget twice — the build was complete both times (lib/ga.sh + SEO + CEO + tests, all passing) but claude hit turn 50 before the harness' exit-0 commit could fire, so nothing landed. The root cause is the hardcoded
--max-turns 50being too low for a ticket this size (a real fix — making it configurable/higher for issue work — is a separate harness change for Josh to merge).To land a PR within the existing cap I split the work: this ticket is now SEO report +
lib/ga.shonly; the CEO digest fold-in moved to a follow-up (it depends onlib/ga.shhere). RemovedStatus/Blockedand cleared the assignee to re-queue. Execution notes added to the body (commit-and-stop; avoid the permission-denied command forms that also burned turns).