Skip to content

Assessment domain: GA evidence appendix renderer (PRD-0016) + implementation sketch#129

Merged
tieguy merged 23 commits into
mainfrom
claude/sp42-wikipedia-ga-reviews-xlwxej
Jul 10, 2026
Merged

Assessment domain: GA evidence appendix renderer (PRD-0016) + implementation sketch#129
tieguy merged 23 commits into
mainfrom
claude/sp42-wikipedia-ga-reviews-xlwxej

Conversation

@tieguy

@tieguy tieguy commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

Docs only — the assessment domain's second PRD and its implementation sketch, following on from #124.

  • docs/domains/assessment/prd/0016-ga-evidence-appendix-renderer.md (Discussion) — a pure renderer from the existing report contracts (PageVerificationReport, ADR-0011; StabilitySignal staged behind PRD-0015) to the pasteable Talk:Article/GAn wikitext evidence appendix: the GA review-assist design sketch's first build step and the future sp42-assessment crate's first code. All three open questions were resolved with the Editor, then the document went through a full paragraph-by-paragraph review. What the review settled:
    • primary persona is the on-ramp reader — zero SP42 context, reading a pasted appendix cold — which drove cold-reader legibility invariants (no raw contract identifiers; copy-module vocabulary; human-facing citation markers), a what-is-this explainer link in the provenance footer, and number-and-name criterion headings with the GA criteria keyed at first use
    • criterion-2 sublists ordered by consequence for the review (claim–source disagreements lead; link rot follows; honesty arms and books close), with supported findings as a compact one-line spot-check record and unconfirmed (unlocated-grounding) supports in their own sublist
    • the honesty line inverted to state the assessed set positively ("evidence for 2b only") — the drafted complement enumeration was wrong and would re-drift
    • two contract collisions found and resolved: the stats arm lacks a grounded/unconfirmed split (renderer derives it; additive supported_unlocated counter noted upstream for the references domain), and the report carries no run timestamp (determinism pinned via shell-injected rendered_at; additive verified_at noted upstream)
    • plain wikitext restated for its real reason (dependency failure mode, not renderer trust), with the {{GAList}} native-idiom question explicitly routed to alpha copy review with real GA reviewers
  • docs/design-plans/2026-07-10-ga-appendix-renderer.md — the implementation sketch, written in parallel with the PRD and grounded in the tree (it corrected the PRD three times before review even started: grounding axis, staged stability DoD, saved-report mode as the core surface). Four phases: crate + pure builder, CLI surfaces (render-report + ga-appendix format), fixture realism with a sandbox paste, and a staged stability phase landing with PRD-0015's implementation. Synced with every review-time change.
  • Assessment README gains the PRD-0016 entry.

Type

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Build, CI, or release
  • Security-sensitive change

Validation Required

Docs-only change — no code paths touched. Cross-references checked against the tree (PageVerificationReport/CitationFinding fields, ReportDocument shape, CLI OutputFormat, workspace layout) while writing the implementation sketch.

Risk

  • Touches auth/session/cookies/CSRF
  • Touches deployment/runtime configuration
  • Touches desktop packaging
  • Touches scoring or Wikimedia action behavior
  • Needs an ADR

No ADR: the renderer is pure composition over existing contracts, and the new sp42-assessment crate follows ADR-0013 via the adding-a-domain.md turnkey path (rationale recorded in the PRD header).

Notes For Reviewers

  • The PRD is in Discussion: resolved questions carry the Editor's decided answers, open to reviewer reaction until acceptance.
  • Two small upstream suggestions for the references domain are recorded (not gated on): additive supported_unlocated on PageVerificationStats, and additive verified_at on PageVerificationReport — both close gaps the renderer works around today.
  • Places most worth scrutiny: the on-ramp persona's consequences (Problem + wording invariants), the consequence ordering of the criterion-2 section spec, and the plain-wikitext vs {{GAList}} deferral.

🤖 Generated with Claude Code

https://claude.ai/code/session_01ATEQwdt8J9mVb94EcgRFY3


Generated by Claude Code

claude added 13 commits July 10, 2026 18:59
Thin PRD for the design sketch's first build step: a pure renderer from
PageVerificationReport (+ optional StabilitySignal) to the pasteable
Talk:Article/GAn wikitext evidence appendix. Wording invariants as contract
(no pass/fail, PRD-0014 mismatch framing), plain wikitext with nowiki-
escaped quotes, stable ordering for hold-loop comparability, provenance
footer, assessment-domain placement per the layering rule. Three open
questions with proposed answers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ATEQwdt8J9mVb94EcgRFY3
…aced

Four-phase plan grounded in the tree: sp42-assessment crate with a pure
wikitext builder over PageVerificationReport (bypassing ReportDocument,
whose flat-string shape carries none of the appendix's invariants), CLI
ga-appendix format plus a pure render-report subcommand, fixture realism,
and a staged stability phase landing with PRD-0015's implementation.

Feeds three learnings back into PRD-0016: the grounding axis joins the
wording invariants (Unlocated support renders as unconfirmed), the
stability DoD items are staged so the citations-only appendix is the MVP
gate, and the saved-report mode is the core surface (no bridge, session,
or network) with the verify-page flag as convenience.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ATEQwdt8J9mVb94EcgRFY3
Both surfaces ship (saved-report render as the core, verify-page flag as
convenience); supported findings render as a compact one-line-each
spot-check record rather than counts-only, with unconfirmed supports in
their own sublist; the not-assessed line stays, with criterion 5 leaving it
exactly when a StabilitySignal renders.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ATEQwdt8J9mVb94EcgRFY3
The default reader has zero SP42 context — a pasted appendix is read cold
by reviewers, nominators, and watchers, and is most readers' first SP42
artifact. Consequences: cold-reader legibility joins the wording invariants
(no raw contract identifiers, copy-module vocabulary, human-facing citation
markers), the provenance footer gains a what-is-this explainer link with a
DoD assertion, and the copy-drift risk is reweighted as first impression.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ATEQwdt8J9mVb94EcgRFY3
…-first sublists

Criterion numbering is now defined at first use with the GA-criteria link;
appendix section headings carry number and name for the cold reader; the
criterion-2 bullet becomes a numbered section spec ordered by consequence
for the review (claim-source disagreements lead, link rot follows, honesty
arms and books close), with refs addressed by their human-facing citation
markers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ATEQwdt8J9mVb94EcgRFY3
…target; criterion-5 heading

The complement enumeration (1a, 2c, 3, 4, 6) was wrong — it omitted 1b, 2a,
and 2d — and re-drifts as evidence lanes land, so the line now states the
tiny assessed set positively (2b only; plus 5 when a StabilitySignal
renders). Explainer link gets an MVP target (repo docs via the platform
public_documents surface; on-wiki essay as the eventual home). Criterion 5
heading carries its name.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ATEQwdt8J9mVb94EcgRFY3
…noted

The stats arm lacks a grounded/unconfirmed split within supported verdicts,
so the summary line derives it deterministically from findings rather than
blending them; an additive supported_unlocated counter on
PageVerificationStats is noted as the clean upstream fix for the references
domain, not gated on here.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ATEQwdt8J9mVb94EcgRFY3
…d, placement corrected

Plain wikitext is the dependency-failure-mode choice, not renderer trust;
the native GAList idiom counterargument is recorded and routed to the alpha
copy review. Sublist categories order by consequence while findings keep
report order within each. Placement corrected: PageVerificationReport lives
in sp42-citation (domain-to-domain dependency), StabilitySignal slated for
sp42-core, crate flat per the actual workspace layout.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ATEQwdt8J9mVb94EcgRFY3
…r wording

The report contract carries no run timestamp, so rendered_at is a
shell-injected Clock input pinned in the replay test, the footer labels its
date as the render date, and an additive verified_at on the report is the
second noted upstream fix. Resolved Q1 gains its DoD binding (both CLI
surfaces tested, saved-report render byte-identical).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ATEQwdt8J9mVb94EcgRFY3
…ationale

Phase 1's section spec now matches the reviewed PRD (consequence order,
supported compact list, assessed-by line, headings, legibility scan,
injected rendered_at); phase 3 carries the GAList question to reviewers; a
review-time sync section records the flow-back and the two upstream notes.
The sp42-reporting alternative's rationale corrected: it hosts shared
report primitives, not patrolling-only reporting.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ATEQwdt8J9mVb94EcgRFY3
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ATEQwdt8J9mVb94EcgRFY3
@tieguy tieguy requested a review from schiste as a code owner July 10, 2026 20:21
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ATEQwdt8J9mVb94EcgRFY3

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4a2d12cb80

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +187 to +188
are addressed by their human-facing citation markers (`[1]`, named refs),
which is what `ref_id` already carries (ADR-0011).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Correct the citation-marker contract assumption

For the saved-report renderer, this assumption is not true: the extractor has BlockRef::ref_text for the visible marker, but extract_use_sites only copies ref_id into CitationFinding/SkippedRef, and ref_id is the stable cite id (e.g. cite_ref-smith_3-0), not [1] or the rendered named-ref marker. Since this PRD also commits to rendering from a stored PageVerificationReport with no page fetch, the renderer cannot recover the human-facing marker unless the report contract carries ref_text (or the output requirement is changed), and following the current text would violate the cold-reader/no-raw-identifier invariant.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed against the code and fixed in b9e537dref_id is indeed the stable cite id and BlockRef::ref_text never reaches the report. The PRD now specifies a derived reader-facing ref label for the MVP (ref name parsed from the cite id when present, else a stable per-report index; raw cite_ref-… ids join the no-raw-identifiers DoD scan), with an additive ref_text on CitationFinding/SkippedRef recorded as an upstream note for the references domain.


Generated by Claude Code

Comment on lines +135 to +136
2. *Dead links* — unreachable sources, with their `archive_of` repair
handles. Mechanical and actionable.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Separate unrecovered dead links from archive fallbacks

In the current report contract, archive_of is only populated when a dead live URL was successfully verified through an archive fallback; unresolved SourceUnavailable(Unreachable) findings generally have archive_of = None, and the citation's fallback archive URLs are not preserved in CitationFinding or PageVerificationReport. With this spec, a saved-report renderer cannot make every dead-link line carry archive_of repair handles, and it risks mixing recovered-via-archive citations with unrecovered link rot; either require a report field for fallback candidates or scope archive_of rendering to findings that actually came from an archive fallback.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed and fixed in b9e537darchive_of only exists on findings actually recovered through an archive fallback, and unrecovered Unreachable findings carry no archive candidates (those stay on the extractor's use-site). The spec now splits the sublists: recovered-via-archive (supported, with the archive_of repair handle, pulled out of the supported list because they're actionable) vs. unrecovered dead links (dead URL only), and an additive candidate-archives field on unreachable findings is recorded as an upstream note.


Generated by Claude Code

ref_id is the stable cite id, not the rendered marker: the MVP derives a
reader-facing ref label (raw cite_ref ids join the no-raw-identifiers
scan) and an additive ref_text on CitationFinding/SkippedRef is noted
upstream. archive_of exists only on findings recovered through an archive
fallback: the dead-links sublist splits into recovered-via-archive (repair
handles) and unrecovered (dead URL only), with an additive candidate-
archives field noted upstream. Sketch synced; upstream notes now number
four.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ATEQwdt8J9mVb94EcgRFY3

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b9e537d0a2

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

wording invariants (incl. `Unlocated` rendering as unconfirmed support and
a no-raw-contract-identifiers scan), nowiki escaping over a
malicious-quote fixture, determinism with a pinned timestamp.
2. **CLI surface.** `OutputFormat::GaAppendix` accepted by `verify-page`; new

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the advertised ga-appendix CLI value

When this phase adds OutputFormat::GaAppendix, the current sp42-cli/src/main.rs enum is annotated #[value(rename_all = "lowercase")], so a bare variant addition will expose gaappendix, while the PRD/DoD asks reviewers to type --format ga-appendix. Please call out an explicit value name or a rename_all change here; otherwise the advertised CLI and the planned CLI tests will not match the parser.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified (main.rs:37 carries #[value(rename_all = "lowercase")]) and fixed in 0973da5: the sketch's CLI phase now pins an explicit #[value(name = "ga-appendix")] on the new variant, leaving the existing single-word values untouched.


Generated by Claude Code

Comment on lines +156 to +158
5. *Unconfirmed supports* — supported/partial verdicts whose quote could not
be re-located: the panel's judgment without evidence in hand, never
blended into the supported list.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Resolve the unlocated-partial bucket collision

A Partial finding with grounding_status = Unlocated currently fits two mutually exclusive buckets: the earlier disagreement bucket includes every Partial, while this bucket also includes supported/partial verdicts whose quote could not be re-located. The verifier can produce that exact combination when a winning partial/support quote does not locate, so an implementation can either duplicate the finding or hide a claim-source disagreement under “unconfirmed supports”; please make the precedence explicit.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Real ambiguity — fixed in 0973da5 with explicit precedence: verdict partitions the sublists, grounding annotates. Every NotSupported/Partial finding renders in the disagreements bucket regardless of grounding status (a Partial+unlocated carries an unlocated annotation on its line there — hiding a claim–source disagreement is the worse failure), the unconfirmed-supports sublist narrows to Supported+unlocated only, and the DoD now asserts both combinations plus every-finding-in-exactly-one-sublist.


Generated by Claude Code

answer was revised during discussion: the GA spot-check's purpose is to
document that sources *support* the text, and a reviewer's record must say
*which* refs were checked — counts alone don't serve that. Supported
findings render one line each (`ref_id`, claim prefix, grounding marker),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Replace the remaining raw ref_id output requirement

Fresh evidence after the earlier ref-label review is this remaining Q2 summary: it still says supported entries render ref_id, even though the main body now says CitationFinding.ref_id is only the stable cite id and raw cite_ref-… ids must not appear. If implementers follow this resolved-question text, supported findings will violate the cold-reader/no-raw-identifier invariant and the DoD scan, so this should say the derived reader-facing ref label instead.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct — a residual from the earlier ref-label fix. Q2's resolution text now says "derived reader-facing ref label" (0973da5).


Generated by Claude Code

…, CLI value name

Verdict partitions the criterion-2 sublists and grounding annotates: a
Partial+unlocated finding stays in the disagreements bucket with an
annotation (hiding a disagreement is the worse failure), Supported+unlocated
goes to unconfirmed supports, and every finding appears in exactly one
sublist, with the DoD testing both combinations. Q2's resolution text drops
its residual raw ref_id. The sketch pins an explicit ga-appendix value name
against OutputFormat's lowercase rename_all.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ATEQwdt8J9mVb94EcgRFY3

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0973da56e5

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +146 to +148
1. *Claim–source disagreements* — `NotSupported`/`Partial` findings, each
line carrying the claim, its reader-facing ref label, the reader-facing
verdict, the verbatim located quote, and the source link. These can sink

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Do not require located quotes for ungrounded findings

The saved-report renderer cannot satisfy this for all disagreement findings: GroundingStatus::NotApplicable is explicitly used when no supporting quote is expected for NotSupported, and assemble_citation_finding returns a no_quote_finding(..., GroundingStatus::NotApplicable, ...) for non-support winners, so CitationFinding.passage is absent and the report does not retain panel votes. For NotSupported and unlocated Partial inputs, requiring a verbatim located quote will either make the renderer tests impossible to satisfy or push implementers to present source_excerpt as if it were grounded evidence; scope the quote requirement to findings that actually carry passage and define the fallback wording for the rest.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed (no_quote_finding with NotApplicable at verify.rs:562 — ADR-0007's no-quote verdict semantics) and fixed in 92ca05b: the quote requirement is scoped to findings carrying passage; a no-quote NotSupported line states that no supporting passage was found; and source_excerpt may only ever render as labeled context (what the panel read), never presented as grounded evidence — with a DoD item asserting exactly that.


Generated by Claude Code

Comment on lines +156 to +160
2. *Recovered via archive* — findings whose claim was verified through an
archive fallback: supported, but the live URL is dead, and `archive_of`
(which the contract populates **only** in this case) is the repair
handle — "update the citation to the archive." Pulled out of the
supported list because they are actionable.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve archive repair handles on archived disagreements

Because the PRD says the disagreements bucket takes every NotSupported/Partial finding, archive-backed disagreements will never reach the recovered-via-archive bucket, but try_archive_fallback stamps archive_of on any archive result whose verdict is not SourceUnavailable, including Partial and NotSupported. In that scenario the appendix would show the archive source link while losing the dead live URL repair handle, so require archive_of to render on any line that carries it, not only on supported recovered-via-archive entries.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed (try_archive_fallback accepts any non-SourceUnavailable archive verdict) and fixed in 92ca05b: archive_of now renders on any line that carries it, in every bucket — archive-backed disagreements keep their dead-live-URL repair handle in the disagreements bucket, recovered-via-archive narrows to Supported, and a DoD item covers the archive-backed-disagreement case.


Generated by Claude Code

Comment on lines +169 to +172
5. *Unconfirmed supports* — `Supported` verdicts whose quote could not be
re-located: the panel's judgment without evidence in hand, never blended
into the supported list. (`Partial`+unlocated stays in the disagreements
bucket, annotated — see its precedence rule.)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Handle fuzzy-located support in the grounding split

This only defines the unconfirmed bucket for Supported+Unlocated, but LocatedFuzzy is also a real grounding status and is explicitly not groundable (is_groundable_support only accepts exact Located); the existing presentation helper groups Supported | Partial with either Unlocated or LocatedFuzzy as Unverified. If the renderer follows this text, a supported fuzzy-only quote can be counted/rendered with ordinary supported findings rather than in the non-grounded split (or a separate fuzzy/caution treatment), understating the evidence caveat the report carries.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed (LocatedFuzzy at verify.rs:136; is_groundable_support accepts exact Located only) and fixed in 92ca05b: the non-exact-grounding treatment now covers Unlocated and LocatedFuzzy alike — Supported with either renders in the unconfirmed-supports sublist annotated with which, Partial with either stays annotated in the disagreements bucket, and the DoD matrix covers all four verdict×status combinations.


Generated by Claude Code

claude and others added 2 commits July 10, 2026 20:42
…ywhere, LocatedFuzzy

The quote requirement scopes to findings carrying passage: NotSupported is
typically a no-quote verdict (NotApplicable) whose line states no
supporting passage was found, and source_excerpt only renders as labeled
context. archive_of renders on any line carrying it — the contract stamps
it on archive-backed disagreements too, which keep their repair handle in
the disagreements bucket while recovered-via-archive narrows to Supported.
LocatedFuzzy joins Unlocated in the non-exact-grounding treatment, matching
the exact-Located-only grounding gate, with the DoD matrix covering all
four verdict-by-status combinations.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ATEQwdt8J9mVb94EcgRFY3

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8309366d58

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +339 to +341
- [ ] Quoted evidence containing wikitext markup (templates, refs, links) is
`<nowiki>`-escaped so the appendix never transcludes or breaks page
markup, verified by a malicious-quote fixture.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Cover nowiki terminators in quote escaping

Because quoted evidence is arbitrary source text, a quote containing a literal </nowiki> closes a naive nowiki wrapper and lets any following {{template}}, <ref>, or link markup execute when pasted. This DoD only requires fixtures with templates/refs/links, so an implementation can pass while still being vulnerable to the terminator case; please require the escaping helper or malicious fixture to handle </nowiki> specifically.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — the classic wrapper-terminator breakout, and the fixture requirement would indeed have let a vulnerable implementation pass. Fixed in 67d7c3f: the escaping helper entity-encodes nowiki terminators (and markup-significant angle brackets) inside quoted content rather than trusting the wrapper, and the DoD's malicious-quote fixture now includes a literal </nowiki> with the assertion that markup following it renders inert.


Generated by Claude Code

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Replying on the round-5 finding about unusable_reason here is wrong thread — see the dedicated reply on that comment.)


Generated by Claude Code

A quote containing a literal </nowiki> closes a naive wrapper and lets
following markup execute; the escaping helper entity-encodes terminators
inside quoted content and the malicious-quote fixture must assert the
breakout case renders inert. Codex round 4 on PR #129.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ATEQwdt8J9mVb94EcgRFY3

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 67d7c3ff71

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +190 to +191
4. *Unreadable sources* — fetched but not machine-readable (PDF, viewer
shells), honestly framed as a tool limitation: the citation may be fine.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Render specific unusable-source reasons

For SourceUnavailableReason::Unusable findings, the report can carry CitationFinding.unusable_reason (PdfBody, ViewerShell, NavChromePaywall, etc.), and the existing page renderer already surfaces that detail so reviewers can distinguish a PDF from a viewer shell or paywall. This bucket only requires generic unreadable-source wording, and the DoD never asserts the specific reason, so an implementation can pass while dropping a report disclosure despite the earlier “every disclosure renders” invariant; require each unreadable line to include a reader-facing reason when the field is present.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed — unusable_reason is a report disclosure and the existing page renderer already surfaces it, so the generic wording quietly violated the every-disclosure rule. Fixed in 4f9388f: each unreadable line renders the specific reader-facing reason when the field is present (PDF vs viewer shell vs paywall, via the copy module — the reviewer's next move differs by which), with a DoD item over fixtures carrying distinct reasons. (Apologies for the stray reply on the round-4 thread pointing here.)


Generated by Claude Code

The field is a report disclosure (PDF vs viewer shell vs paywall) and the
reviewer's next move differs by which; dropping it violated the
every-disclosure-renders rule. Codex round 5 on PR #129.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ATEQwdt8J9mVb94EcgRFY3

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4f9388f410

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +180 to +184
2. *Recovered via archive* — findings whose claim was **supported** through
an archive fallback: the live URL is dead and `archive_of` is the repair
handle — "update the citation to the archive." Pulled out of the
supported list because they are actionable. (The contract stamps
`archive_of` on any non-unavailable archive verdict, including archive-

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Define precedence for archive-backed unconfirmed supports

For an archive fallback whose panel verdict is Supported but whose grounding is Unlocated or LocatedFuzzy, this bucket and the later unconfirmed-supports bucket both match. Fresh evidence from the code is that try_archive_fallback stamps archive_of on any non-SourceUnavailable archive verdict (crates/sp42-citation/src/citation/page.rs:223-227), while the grounding contract explicitly allows Supported with non-exact grounding (crates/sp42-citation/src/citation/verify.rs:117-139); a renderer following these bullets can therefore either hide the grounding caveat under “recovered via archive” or duplicate the finding despite the exactly-one-sublist invariant. Please define the precedence and test that combined case.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Real collision — fixed in a18d9df with the same shape as the round-2 precedence rule, extended into the Supported buckets: grounding exactness partitions, archive_of annotates. An archive-backed Supported with Unlocated/LocatedFuzzy grounding renders in the unconfirmed-supports sublist carrying its repair handle (filing it under "recovered" would overstate the evidence; the handle renders anywhere), recovered-via-archive narrows to Supported+exactly-Located, and the DoD tests both combinations with the never-twice assertion.


Generated by Claude Code

Comment on lines +105 to +108
2. **CLI surface.** `OutputFormat::GaAppendix` accepted by `verify-page` —
with an explicit `#[value(name = "ga-appendix")]`, because the enum's
existing `#[value(rename_all = "lowercase")]` would otherwise expose
`gaappendix` and break the advertised flag and the CLI tests; new

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep ga-appendix out of the shared format enum

Under the current CLI wiring, FormatArg is the shared --format parser and is flattened into multiple rendering commands (crates/sp42-cli/src/main.rs:260-265, plus verify, verify-page, bare-url preview, and preview args), so adding GaAppendix to OutputFormat here makes Clap accept and advertise --format ga-appendix for non-page-report commands too. Unless those commands really produce a GA appendix, users will get either nonsensical output or late “unsupported format” failures; use a command-local page-report format enum or wrapper so only verify-page and render-report expose this value.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct — FormatArg is flattened into verify, bare-url preview, and preview as well, so a shared-enum variant would advertise ga-appendix on commands that can't produce one. Fixed in a18d9df: the sketch's CLI phase now specifies a command-local page-report format enum (Text | Json | Markdown | GaAppendix, explicit value name) for verify-page and render-report only.


Generated by Claude Code

…nd-local format enum

Within Supported, grounding exactness partitions and archive_of annotates:
an archive-backed Supported with non-exact grounding renders in unconfirmed
supports with its repair handle, never in recovered-via-archive and never
twice, with both combinations in the DoD. The CLI phase moves ga-appendix
off the shared OutputFormat (flattened into unrelated commands) onto a
command-local page-report format enum for verify-page and render-report.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ATEQwdt8J9mVb94EcgRFY3

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a18d9df104

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +373 to +377
- [ ] Quoted evidence containing wikitext markup (templates, refs, links,
**and a literal `</nowiki>` terminator**) is escaped so the appendix
never transcludes or breaks page markup — the terminator case asserts
that markup *following* an embedded `</nowiki>` still renders inert —
verified by a malicious-quote fixture covering all four shapes.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Escape all rendered verbatim fields

When a rendered claim or source_excerpt contains literal wikitext (for example an article sentence discussing {{Infobox}} or source text containing </nowiki>), this acceptance item still passes because it only requires the malicious fixture for quoted evidence. The renderer also outputs claims and optional context above, and the implementation sketch says every verbatim field should be escaped, so please bind the PRD/DoD to escaping those fields too; otherwise a pasted appendix can still transclude or break markup outside passage.quote.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right — claims are article wikitext by construction and source_excerpt is arbitrary source text, so scoping the fixture to quotes left both unbound (the sketch said "every verbatim field" but the PRD's DoD didn't). Fixed in 1ec3ffe: the escaping rule and DoD item now bind every rendered verbatim field, with the malicious fixture carrying hostile content in each field kind (a claim discussing {{Infobox}}, an excerpt embedding a </nowiki> terminator, a quote with a ref tag).


Generated by Claude Code

Claims are article wikitext by construction and source_excerpt is
arbitrary source text; the DoD's malicious fixture now carries hostile
content in each field kind. Codex round 7 on PR #129.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ATEQwdt8J9mVb94EcgRFY3

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1ec3ffe50b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +222 to +225
6. *Supported findings* — a compact one-line-each spot-check record
(ref label, claim prefix, grounding marker); the reviewing guide
expects the reviewer to say what they checked, and counts alone are not a
record. Quotes stay in the CLI/structured rendering.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include source URLs in supported spot-check lines

When a single ref bundles multiple cited URLs, extract_use_sites emits one finding per URL while cloning the same ref_id (crates/sp42-citation/src/citation/extract.rs:119-132). In that scenario two supported entries can share the same derived ref label and claim prefix, so the proposed compact line cannot tell reviewers which cited source was spot-checked; require the provenance/source link or another per-use-site discriminator here as well.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed — bundled refs clone ref_id across per-URL use-sites (ADR-0011's one-use-site-per-cited-source decision), so ref label + claim prefix alone can be ambiguous. Fixed in 8f1134c: the supported line gains the source link as a required discriminator (load-bearing, not decoration), with a bundled-ref fixture in the DoD asserting two same-ref_id supported lines render distinguishably.


Generated by Claude Code

Comment on lines +390 to +394
- [ ] No raw contract identifiers (`NotSupported`, `SourceUnavailable`, enum
variant names generally, and raw `cite_ref-…` ids) appear in the
appendix; all verdict/status vocabulary comes from the reader-facing
copy module and ref labels are derived, verified by a renderer
assertion scanning output over a fixture exercising every verdict and

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Extend the no-raw-id check to failure records

When extraction or verification fails, the saved report can carry raw cite IDs inside BlockFailure.reason (extract.rs:106-110, page.rs:471-477), and the renderer also must render failures as first-class lists. Because this acceptance check only scans a fixture exercising verdicts/statuses, a renderer can pass while leaking cite_ref-… from failure text; include skipped/extraction-failure records in this no-raw-id fixture or require the renderer to rewrite those reasons.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed — BlockFailure.reason embeds raw cite ids (extract.rs formats ref {ref_id} has no resolvable claim text). Fixed in 8f1134c: failure and skip reasons render through the copy module with embedded cite ids rewritten to derived labels, and the no-raw-identifiers DoD fixture now includes skipped and extraction-failure records.


Generated by Claude Code

…n covers failure reasons

A bundled ref emits one finding per URL sharing the same ref_id, so the
compact supported line requires the source link to say which source was
spot-checked; and BlockFailure.reason strings embed raw cite ids today, so
failure/skip lines render through the copy module with ids rewritten and
join the no-raw-identifiers fixture. Codex round 8 on PR #129.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ATEQwdt8J9mVb94EcgRFY3
@tieguy tieguy merged commit 3892a8b into main Jul 10, 2026
4 checks passed
@tieguy tieguy deleted the claude/sp42-wikipedia-ga-reviews-xlwxej branch July 10, 2026 21:13

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8f1134ce32

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +492 to +493
findings render one line each (derived reader-facing ref label, claim
prefix, grounding marker),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include the source link in the Q2 summary

Fresh evidence after the bundled-ref fix is that the main section and DoD now require the source link as the per-URL discriminator, but this resolved-question summary still says supported lines contain only the ref label, claim prefix, and grounding marker. If implementers follow this decision summary, bundled refs with multiple URLs can again produce indistinguishable supported spot-check lines, so the summary should include the source link too.

Useful? React with 👍 / 👎.

Comment on lines +103 to +104
a no-raw-contract-identifiers scan), nowiki escaping over a
malicious-quote fixture, determinism with a pinned timestamp.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Test escaping across all verbatim fields

Fresh evidence after the verbatim-field escaping fix is that this phase still only calls for a malicious quote fixture. Claims and source_excerpt are rendered verbatim too, and the PRD now requires those fields to handle templates/refs/</nowiki> safely; if this sketch drives implementation, claim or excerpt breakout cases can ship untested while satisfying the phase checklist.

Useful? React with 👍 / 👎.

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.

2 participants