fix(skill): absent claim term -> INCONCLUSIVE hint; note surge-tuning (final-review minors #3,#4)
- gsc_signal_delta.py: extract `found` local var; add first branch in verdict_hint chain so a term absent from both GSC windows yields INCONCLUSIVE (not ARTIFACT). Existing ARTIFACT / CONFIRMED-PARTIAL / PARTIAL branches unchanged (elif chain). - test_gsc_signal_delta.py: add test_absent_claim_term_inconclusive asserting found=False and "INCONCLUSIVE" in verdict_hint for a term in neither fixture. - code/CLAUDE.md: one-line surge-tuning note — verdict_hint/in_top_movers are calibrated for upward claims; for drops, inspect top_decliners directly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KuT3W81t88QQFaxY2ruWv2
This commit is contained in:
@@ -12,6 +12,8 @@ python3 scripts/gsc_signal_delta.py \
|
|||||||
Returns day-normalized site totals, top gainers/decliners, and a `verdict_hint`
|
Returns day-normalized site totals, top gainers/decliners, and a `verdict_hint`
|
||||||
(heuristic only — the final verdict is the skill's job, after L2/L3).
|
(heuristic only — the final verdict is the skill's job, after L2/L3).
|
||||||
|
|
||||||
|
**Surge-tuning note**: `verdict_hint` and `in_top_movers` are calibrated for upward "surge" claims (movers ranked by click gain). For a claimed *drop*, inspect `top_decliners` directly rather than relying on the hint.
|
||||||
|
|
||||||
## Getting the exports
|
## Getting the exports
|
||||||
`mcp__dda__gsc_fetch_performance` (property pinned per workspace, e.g. JHR
|
`mcp__dda__gsc_fetch_performance` (property pinned per workspace, e.g. JHR
|
||||||
`sc-domain:josunhotel.com`) → save the query-dimension rows to a file → run the
|
`sc-domain:josunhotel.com`) → save the query-dimension rows to a file → run the
|
||||||
|
|||||||
@@ -106,9 +106,10 @@ def compute_delta(recent, prior, recent_days, prior_days,
|
|||||||
gainer_terms = {g["query"] for g in gainers}
|
gainer_terms = {g["query"] for g in gainers}
|
||||||
rc, pc = r_by.get(claim_term, {}), p_by.get(claim_term, {})
|
rc, pc = r_by.get(claim_term, {}), p_by.get(claim_term, {})
|
||||||
in_movers = claim_term in gainer_terms
|
in_movers = claim_term in gainer_terms
|
||||||
|
found = bool(rc or pc)
|
||||||
share = (rc.get("clicks", 0.0) / rt["clicks"] * 100) if rt["clicks"] else 0.0
|
share = (rc.get("clicks", 0.0) / rt["clicks"] * 100) if rt["clicks"] else 0.0
|
||||||
out["claim_term"] = {
|
out["claim_term"] = {
|
||||||
"term": claim_term, "found": bool(rc or pc),
|
"term": claim_term, "found": found,
|
||||||
"recent": {"clicks": rc.get("clicks", 0.0),
|
"recent": {"clicks": rc.get("clicks", 0.0),
|
||||||
"impressions": rc.get("impressions", 0.0),
|
"impressions": rc.get("impressions", 0.0),
|
||||||
"position": rc.get("position")},
|
"position": rc.get("position")},
|
||||||
@@ -118,7 +119,12 @@ def compute_delta(recent, prior, recent_days, prior_days,
|
|||||||
"in_top_movers": in_movers,
|
"in_top_movers": in_movers,
|
||||||
"click_share_pct": round(share, 2),
|
"click_share_pct": round(share, 2),
|
||||||
}
|
}
|
||||||
if not in_movers and share < 1.0:
|
if not found:
|
||||||
|
out["verdict_hint"] = (
|
||||||
|
f"'{claim_term}' is absent from both GSC windows (no impressions / "
|
||||||
|
f"likely anonymized) -> INCONCLUSIVE, not refuted; confirm via live "
|
||||||
|
f"SERP + entity layer.")
|
||||||
|
elif not in_movers and share < 1.0:
|
||||||
out["verdict_hint"] = (
|
out["verdict_hint"] = (
|
||||||
f"'{claim_term}' contributes {share:.2f}% of recent clicks and is "
|
f"'{claim_term}' contributes {share:.2f}% of recent clicks and is "
|
||||||
f"absent from top movers -> claimed impact likely ARTIFACT; real "
|
f"absent from top movers -> claimed impact likely ARTIFACT; real "
|
||||||
|
|||||||
@@ -40,6 +40,12 @@ def test_day_normalization():
|
|||||||
assert out["site_totals"]["prior"]["clicks_per_day"] == 6.93 # 208/30
|
assert out["site_totals"]["prior"]["clicks_per_day"] == 6.93 # 208/30
|
||||||
|
|
||||||
|
|
||||||
|
def test_absent_claim_term_inconclusive():
|
||||||
|
out = compute_delta(RECENT, PRIOR, 28, 30, claim_term="존재하지않는검색어")
|
||||||
|
assert out["claim_term"]["found"] is False
|
||||||
|
assert "INCONCLUSIVE" in out["verdict_hint"]
|
||||||
|
|
||||||
|
|
||||||
def test_positive_days_required():
|
def test_positive_days_required():
|
||||||
try:
|
try:
|
||||||
compute_delta(RECENT, PRIOR, 0, 30)
|
compute_delta(RECENT, PRIOR, 0, 30)
|
||||||
|
|||||||
Reference in New Issue
Block a user