feat(seo-data): W1 — surface rich_results, the data inspect already threw away
google_seo.py:129 read only indexStatusResult out of the URL Inspection
response and discarded the rest. richResultsResult was already on the wire:
same call, same OAuth scope (webmasters.readonly), same quota. Google's own
structured-data verdict on the live indexed URL was being downloaded and
binned.
Plan correction: the TODO said "richresults verb". Wrong — a new verb means
a second POST to the same endpoint for a payload already received, on a
per-site quota, and nobody wants rich results without index status. Extended
inspect() instead; fetch.sh unchanged, no new verb, no new scope.
Design driven by the published schema, not by guesswork — two details I
would have got wrong:
- richResultsResult is OMITTED when Google detects none ("absent if none
found"). Surfaced as synthetic verdict ABSENT rather than a missing key: a
caller cannot tell an absent key from a check that never ran. ABSENT means
"none detected", never "invalid". The KeyError path is the real risk here,
so it has its own fixture dir (fixtures-norich/) and its own tests.
- PARTIAL is "Reserved, unused" per the API docs. The draft emitted it. It
never emits it now, and a test asserts the absence.
issues[] deduped (the same issueMessage repeats across every affected item),
errors/warnings count instances — scale from the counter, cause from the
message.
seo-analyzer STEP 4 consumes it as the system's only programmatic JSON-LD
validation, bounded honestly: index:inspect is per-URL, quota'd, and needs a
verified property, so its reach is the STEP 9 COVERAGE ratio, not the site.
Replacing a fake validator with a fake coverage promise would be no better.
This is what beats claude-seo: their README's "dual validator (Rich Results
Test + Schema Markup Validator)" is two hyperlinks a human clicks — grep of
their .py finds zero calls. This is Google's verdict, via auth already held.
Note: the new dedupe assertion trips SC2015 (A && B || C), same as the
pre-existing line 27; ok() ends on an assignment so it cannot fail. Kept for
house-style consistency — lib/seo-data/*.sh is outside the lib/*.sh
shellcheck glob anyway.
Verified: seo-data 85 -> 95 pass, 0 fail; both paths exercised end-to-end
and output inspected by hand; make test 35 GREEN / 0 RED; py_compile clean.
This commit is contained in:
@@ -57,6 +57,24 @@ has "queries position field" "$Q" '"position": 6.3'
|
||||
I="$(SEO_DATA_MOCK_DIR="$MOCK" python3 "$SD/google_seo.py" inspect \
|
||||
--store "$S2" --account client-a --property sc-domain:ex.com --url https://ex.com/x)"
|
||||
has "inspect indexed true" "$I" '"indexed": true'
|
||||
# rich_results rides the same URL-Inspection response (no extra call/quota)
|
||||
has "rich verdict surfaced" "$I" '"verdict": "FAIL"'
|
||||
has "rich type breadcrumbs" "$I" '"type": "Breadcrumbs"'
|
||||
has "rich type faq" "$I" '"type": "FAQ"'
|
||||
has "rich counts error severity" "$I" '"errors": 2'
|
||||
has "rich counts warn severity" "$I" '"warnings": 1'
|
||||
has "rich keeps issue message" "$I" "Missing field 'acceptedAnswer'"
|
||||
# same issueMessage repeats across items — the rollup must collapse it to one
|
||||
NMSG="$(printf '%s' "$I" | grep -cF "Missing field 'acceptedAnswer'")"
|
||||
[ "$NMSG" = "1" ] && ok "rich dedupes issue messages" \
|
||||
|| no "rich dedupes issue messages" "got $NMSG occurrences"
|
||||
# Google OMITS richResultsResult when it detects none — absence is data, and
|
||||
# must not KeyError nor vanish into a missing key
|
||||
NR="$(SEO_DATA_MOCK_DIR="$SD/fixtures-norich" python3 "$SD/google_seo.py" inspect \
|
||||
--store "$S2" --account client-a --property sc-domain:ex.com --url https://ex.com/x)"
|
||||
has "no-rich → synthetic ABSENT" "$NR" '"verdict": "ABSENT"'
|
||||
has "no-rich keeps index status" "$NR" '"indexed": true'
|
||||
hasnt "no-rich emits no PARTIAL" "$NR" 'PARTIAL'
|
||||
DEG="$(env -u SEO_DATA_MOCK_DIR python3 "$SD/google_seo.py" queries \
|
||||
--store "$TMP2/none.json" --account nobody --property sc-domain:ex.com)"
|
||||
has "gsc degrades w/o creds" "$DEG" '"status": "degraded"'
|
||||
|
||||
Reference in New Issue
Block a user