Skip to content

fix(core): false-positive fixes from two site scans - #109

Merged
k2kirov merged 68 commits into
mainfrom
staging/false-positive-fixes
Oct 6, 2026
Merged

k2kirov merged 68 commits into
mainfrom
staging/false-positive-fixes

Conversation

@k2kirov

@k2kirov k2kirov commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

False-positive fixes found by scanning a large retail site, then a small marketing site. Each fix landed in this branch through its own PR, with failing tests first, a dossier update and a patch changeset. No audit id, grade, tier, weight or schema changes.

Merged fix PRs

Re-scan of the same site, before and after

Overall score: 60 to 76.

Audit Before After
14 crawler audits (gptbot, ccbot, claude-*, perplexitybot, ...) warn pass
access-crawl-control/ai-bot-directives warn pass
access-crawl-control/no-bot-detection warn pass
access-crawl-control/ai-usage-signal-coherence-across-channels warn na
access-crawl-control/rsl-licensing-terms-conformance fail na
agent-interfaces/webmcp-declarative-forms fail na
agentic-commerce/acp-policy-link-surface fail warn
agentic-commerce/cart-handoff-reachability fail pass
answer-readiness/text-fragment-addressability fail pass
answer-readiness/unique-data fail na
content-extraction/section-headings fail warn
machine-discovery/discovery-index-coverage fail na
machine-discovery/root-text-file-resolution-integrity fail pass
machine-discovery/rss-feed fail na
operability-safety/form-autofill-token-coverage fail na

Count-only changes, verdict unchanged (other real defects remain):

  • css-hidden-ghost-content: 2846 to 2329 hidden tokens
  • extraction-determinism: overlap 0.00 to 0.56
  • extractor-survival-recall: 14/14 to 2/11 spans lost
  • agent-commerce-feed-parity: remaining defects are a dangling seller @id and no target-country signal

No other verdict moved.

Checks

Every fix PR ran the full gate: build, test, typecheck, lint, check:dossiers, check:requires, check:audit-map, format:check. Last run: 5585 tests passed.

Round 2: a small marketing site

A second report listed 12 suspected false positives. Each was checked against the audit code and its dossier; 10 held fully or in part, and each fix below landed through its own PR.

Rejected after review (no change): CSS display:block on spans (no layout engine, documented), token-ratio's Readability numerator (documented), sitemap-lastmod coverage (Bing documents lastmod as a recrawl signal, so omission is a real cost). Recorded under Deferred: hidden text in the shared semantic/density extractors; section-split's Evidence list cites unrelated sources.

Re-scan of the marketing site, before and after round 2

Overall score: 93 to 97.

Audit Before After
answer-readiness/text-fragment-addressability fail pass
content-extraction/fake-headings fail pass
answer-readiness/section-split-risk-profile warn pass
content-extraction/json-ld-duplication-mass warn pass
operability-safety/aria-layer-injection-scan warn pass
operability-safety/ghost-clickable-element-ratio warn pass
operability-safety/ugc-trust-boundary-markers warn na
operability-safety/contact-form fail na

Count-only changes: survival recall 12/29 to 8/26 spans lost (the rest are visible homepage sections Readability drops); semantic-lists 3 to 1 pseudo-list; websub now reports only the missing hub. No other verdict moved.

Last full gate: 5638 tests passed, plus typecheck, lint, check:dossiers, check:requires, check:audit-map and format:check.

k2kirov and others added 30 commits October 6, 2026 09:17
The sitemap walk caps entries at 500 and child sitemaps at 10. A page
missing from the part it read may be listed in the part it skipped, so
discovery-index-coverage now returns notApplicable instead of failing.
Found on a large retail site whose 2455-URL product sitemap filled the
cap before the one-URL sitemap that lists the homepage.
Nested Review, Comment, Answer and Question dates record when someone
else wrote, not when the page changed. Reading them as page signals
reported product pages that publish no page date as divergent instead
of unverifiable.

Count lastmods within one hour as one build stamp. A generator that
writes the clock per URL spreads one run over seconds, and exact
string matching missed it.
The 14 per-bot robots.txt audits warned at 0.5 when a bot was allowed
only through User-agent: *. Under RFC 9309 section 2.2.1 that is the
same access a named group grants, and no vendor documents a
difference. They now pass and name the group that applied. A blocked
bot still fails. A missing or unreadable robots.txt is not applicable.
Control-token copy no longer says Google-Extended or Applebot-Extended
crawl.
fix(core): pass crawler bots allowed through the catch-all group
The audit warned when YouBot or AI2Bot was allowed through User-agent: *.
Its only reason was that the policy could flip under a later blanket
block; no source documents a difference, and RFC 9309 section 2.2.1
grants the same access. The dossier is corrected first. Inherited access
now passes and names the rule that applied; a block still fails. A
missing or soft-404 robots.txt is not applicable.
…allow

fix(core): pass ai-bot-directives when bots inherit the catch-all
The audit reports contradictions between channels; a site with no
signal in any channel has nothing to contradict. The dossier called
silence a real cost with no source, while its own sources read absence
as unknown or no preference. Dossier corrected first; notes stay in
details.
fix(core): treat AI-usage silence as not applicable in coherence audit
When nothing advertises an RSL licence, the audit guesses /license.xml
and /rsl.xml. A site that redirects both to its homepage got four
conformance errors about the homepage HTML. A guessed path is now kept
only when its body has an <rsl> element; otherwise the audit returns
notApplicable.
fix(core): ignore RSL path guesses that return no RSL document
Random root .txt paths that 301 to the homepage were reported as an SPA
catch-all, because the audit counted the homepage's final 200. A probe
whose final path differs from the requested one now counts as absent.
An HTML 200 at the requested path still fails.
fix(core): read a redirected root .txt probe as absent
A readable storefront that loads the Turnstile api.js for its forms
still drew three findings. cart-handoff-reachability now fails only a
cart that is a challenge page or only a widget. no-bot-detection passes
a loader on a page the scan could read. no-blocking-captcha matches
vendor script src and widget elements instead of the vendor name, so
inline config, CSP lists and prose no longer match.
fix(core): stop reading a form Turnstile loader as a bot wall
The semantic extractor took the first <article>. On a page with many, that was a promo strip, and extraction determinism reported 0.00 agreement. It now takes the article with the most text, and falls back to the body when none holds a fifth of the page.
…article

fix(core): read the largest article in the semantic extractor
The aggressive extractor dropped any element whose class contained a blocklisted word, which deleted a page wrapper named page-content--banner-enabled. It now tests whole class tokens and ids, and keeps an element holding most of the page. Script contents no longer count as prose, so JSON-LD URLs stop being key spans.
…tokens

fix(core): match stripper class tokens, not substrings
The span after an h2/h3 was whatever text followed it. A tile grid became one answer crossing every block, and a one-word button repeated under each tile became an ambiguous answer. Heading spans now have to be sentences of three or more words; a sentence split across sibling blocks is still reported.
fix(core): take only sentences as text-fragment answer spans
Image arrays and ImageObjects were read as no image. A ProductGroup's
AggregateOffer range and variant offer prices were read as no price,
and productGroupID did not count as an item group. Resolve seller @id
references on the page; a dangling reference still fails.
fix(core): read every JSON-LD shape in feed parity
A store locator's 'City or postcode' box matched the postal-code
keyword and failed the audit. Query forms take a keyword or place, not
profile data. Skip them, and skip location fields whose name offers a
choice between concepts.
fix(core): skip search and locator forms in autofill coverage
Page builders emit whitespace-only <section> row slots. They have
nothing to label and dragged a homepage to fail. Skip them, and return
not applicable when no section has content, as the dossier requires.
fix(core): skip empty layout sections in section-headings
A feed is optional and the dossier says the audit informs rather than
penalises. Return not applicable when no feed answers and no page
advertises one. An advertised feed that does not answer still fails.
fix(core): rss-feed is not applicable without a feed
k2kirov and others added 24 commits October 6, 2026 11:47
…ectioned

fix(core): skip values, chrome and hidden text in fake-headings
…ards

fix(core): match text fragments over nearest-block runs
fix(core): skip @id references in JSON-LD duplicate count
fix(core): read namespaced atom:link in feed WebSub discovery
…control

fix(core): skip wrappers and inner labels of native controls in ghost scan
…e-only

fix(core): compare aria-label with visible text on controls only
fix(core): treat FAQPage entries as editorial in UGC boundary scan
fix(core): decline contact-form when a contact page was not sampled
fix(core): skip hidden regions and keycaps in semantic-lists
…tional

fix(core): report THIN sections without warning on them
…hidden

fix(core): count title-kept h1 and skip hidden spans in survival recall
fix(core): let Last-Modified corroborate but not contradict lastmod
@k2kirov k2kirov changed the title fix(core): false-positive fixes from a large retail site scan fix(core): false-positive fixes from two site scans Oct 6, 2026
@k2kirov
k2kirov merged commit c677b51 into main Oct 6, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant