Skip to content

Wrap informal definitions/theorems in individual crossref divs - #78

Open
d-morrison wants to merge 5 commits into
mainfrom
claude/def-theorem-divs-77
Open

Wrap informal definitions/theorems in individual crossref divs#78
d-morrison wants to merge 5 commits into
mainfrom
claude/def-theorem-divs-77

Conversation

@d-morrison

@d-morrison d-morrison commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Closes #77

Summary

Every chapter had prose that stated a definition, theorem-like result, or named
algorithm with real defining precision but never wrapped it in the book's formal
crossref div (::: {#def-...}, {#thm-...}, {#alg-...}, etc. --- see
.github/copilot-instructions.md's "Theorems and Proofs" section), so it rendered
as a plain numbered subsection instead of a boxed, numbered Definition N /
Theorem N / Algorithm N environment like its sibling definitions.

Confirmed example that prompted this: ch. 19's "Dynamic Strategies" ---
before
rendered as plain subsection 2.2; now renders as Definition 4 (Dynamic Strategies).

Two passes, at two different standards

This PR went through two full audit passes:

  1. First pass: boxed the clear cases across all 23 chapters, using a
    confirmation checklist that filtered out anything judged "too thin" or "just
    an instance of an already-defined concept."
  2. Second pass, after review feedback: that filter was wrong. The standard
    is now "any term being introduced for the first time should get boxed --
    same with new results ... err on the side of more boxing, not less."
    Every
    chapter (including two judged "no changes needed" in pass 1) was re-audited
    under this permissive bar, adding ~140 more divs -- among them the book's
    2nd and 3rd #alg- (Algorithm) environments, and all five named
    selection-bias subtypes in ch. 8 (healthy worker bias, differential loss to
    follow-up, etc.) individually boxed.

Combined: ~240 definition/theorem/algorithm divs added across 21 of 23
chapters
(ch. 2 and 14 needed real fixes only in the second pass; every
chapter has real fixes now).

Verification

  • Every new div id checked against the whole-book id list for uniqueness;
    one real collision the two independent batches produced (#alg-g-estimation
    claimed by both ch. 14 and ch. 21) was caught and disambiguated.
  • Scripted checks: all ::: fences balanced per file, no theorem-family div
    nested inside another, no theorem-family div nested inside a .callout-note
    (a genuine Quarto rendering constraint --- fatal at render time even though
    raw pandoc parses the nesting as valid markdown; three ch. 17 instances found
    and fixed).
  • Content-preservation: every file's word count grew (never shrank) relative
    to main, and every diff line that looked like a deletion was checked to be
    legitimate reflow/copyediting, not lost content.
  • Full quarto render (all 23 chapters x 3 formats: HTML, RevealJS, PDF
    handout) completes clean; spot-checked rendered HTML repeatedly to confirm
    new divs actually render as boxed, numbered environments.
  • No new {#exm-...} example divs added (26 before, 26 after), and no
    @def-... crossref links introduced --- neither pattern exists anywhere
    else in the book yet, so adding either now would be scope creep beyond this
    pass's ask.

Follow-ups filed separately

  • #79 --- two pre-existing
    duplicate crossref ids (#def-positivity in ch. 2 & 3; #def-standardization
    in ch. 2 & 13), unrelated to this pass.
  • #80 --- the Claude Code Review
    workflow failed to produce a verdict on this PR three times in a row (two
    quota-skips, one "no verdict" job failure); a self-review is posted below in
    lieu of the automated one.
  • #81 --- ch. 5's "Four Response
    Types" heading actually lists five, noticed in passing while boxing that
    section.

Both subsections stated a definitional-precision claim ("A **static
strategy** assigns...", "A **dynamic strategy** adapts...") but rendered
as plain numbered subsections instead of boxed Definition environments,
unlike every other definition in the chapter.

Part of #77.
Chapters 1, 3-13, 15-18, 20-23: 53 additional definitions, theorems,
and one algorithm were stated with definitional precision (a bolded
term plus defining language, or a formula-naming sentence) but never
wrapped in the book's `::: {#def-...}` / `{#thm-...}` / etc. crossref
div, so they rendered as plain numbered subsections instead of boxed,
numbered environments like their sibling definitions.

Each fix wraps only the core defining statement, leaving surrounding
motivation, bullet-list examples, and "why this matters" commentary
as plain prose outside the div, matching the existing convention
(see ch19's Static/Dynamic Strategies from the prior commit). No new
`{#exm-...}` divs were added and no `@def-...` crossref links were
introduced, since neither pattern exists anywhere else in the book.

Chapter 14 needed no changes (already fully boxed); chapter 2 likewise.

Closes #77.
@d-morrison
d-morrison marked this pull request as ready for review August 20, 2026 19:26
@github-actions

Copy link
Copy Markdown

Warning

Claude review skipped — API credential or quota unavailable. No CLAUDE_CODE_OAUTH_TOKEN or ANTHROPIC_API_KEY secret is configured, or account API quota is exhausted. Re-trigger the review by pushing a new commit or re-running the workflow once configured/reset. View run

@d-morrison

Copy link
Copy Markdown
Collaborator Author

Self-review (Claude review was skipped — quota/credential unavailable per the automated notice above)

I've independently reviewed this diff at the same standard the automated reviewer would apply, since it didn't produce a verdict this round.

Content-preservation check (the highest-risk failure mode for a "wrap existing prose in a div" change): diffed every removed line against every added line across all 20 files. All "orphan" removals (lines that don't reappear byte-identical) were verified to be legitimate reformatting only — mainly inline math converted to display math to match the existing div convention (e.g. $Y = Y^A$ inline → $$Y = Y^A.$$ display, matching how every pre-existing definition in the book already formats its equations). Spot-checked several of these directly against the resulting files (ch01 Consistency, ch13 ATT, ch16 Wald Estimator, ch23's two mediation divs, ch21's sequential censoring exchangeability) — no semantic content was dropped or altered in any of them.

Structural checks (scripted, not eyeballed):

  • All 55 new ::: div fences balanced (open == close) in every touched file.
  • No theorem-family div ({#def-...}/{#thm-...}/etc.) nested inside another.
  • No new id collides with any existing id book-wide (the two pre-existing collisions, def-positivity and def-standardization, predate this PR and are tracked separately in Duplicate crossref div ids: #def-positivity and #def-standardization #79).
  • Exactly 55 new theorem-family divs added (matches the PR description), 1 of which is #alg-2sls — the book's first use of the Algorithm environment.

Build verification: full quarto render (23 chapters × 3 formats) completes with exit 0 and produces all 69 expected output files, non-empty. (First attempt falsely appeared to succeed because a background-logging echo "exit=$?" masked the real failure — caught by checking the log's actual exit line rather than trusting the wrapper; the real cause was a missing ggdag R package unrelated to this diff, now installed.) Spot-checked rendered HTML output directly to confirm several new divs actually render as boxed Definition N/Theorem N/Algorithm N environments, not just that the build didn't error.

Scope check: confirmed no new {#exm-...} example divs were added and no @def-... crossref links were introduced anywhere, since grepping the whole book before starting showed neither pattern exists yet — adding either now would have been scope creep beyond fixing the specific "unboxed definition" gap this PR targets.

No findings. Requesting a human look given the automated review didn't run this round — happy to address anything raised.

@d-morrison

Copy link
Copy Markdown
Collaborator Author

/review

@github-actions

Copy link
Copy Markdown

👀 Claude Review Dispatchedrun reviewing PR #78 at 1024746.

@github-actions

Copy link
Copy Markdown

Warning

Claude review skipped — API credential or quota unavailable. No CLAUDE_CODE_OAUTH_TOKEN or ANTHROPIC_API_KEY secret is configured, or account API quota is exhausted. Re-trigger the review by pushing a new commit or re-running the workflow once configured/reset. View run

@d-morrison

Copy link
Copy Markdown
Collaborator Author

/review

@github-actions

Copy link
Copy Markdown

👀 Claude Review Dispatchedrun reviewing PR #78 at 1024746.

Both were stated with defining precision (naming sentence + display
equation) but never boxed, despite "treatment history" and "covariate
history" being cited by name throughout the rest of Part III.

Found via a second, more targeted sweep of the whole book for bolded
terms with defining language sitting outside any theorem div. Every
other candidate from that sweep was already covered (boxed nearby,
inside a deliberately-informal .notes div, a pedagogical label like
"Step 1"/"Setting", or a comparison-list restatement of an
already-defined term) -- consistent with the judgment the original
six auditing passes already applied.

Part of #77.
@d-morrison

Copy link
Copy Markdown
Collaborator Author

Follow-up pass: swept the whole book again for bolded terms with defining language sitting outside any theorem div, per a request to look for anything the first pass missed. Found and fixed one genuine gap — ch. 19's Treatment History ($\bar{A}_k$) and Covariate History ($\bar{L}_k$), both cited by name throughout the rest of Part III but never boxed.

Everything else in that sweep (~100 raw candidates, mostly false positives from a broad regex) was already accounted for: boxed nearby, sitting inside a deliberately-informal .notes div (e.g. ch. 1's "sharp causal null hypothesis"), a pedagogical label ("Step 1", "Setting", "Question"), or a comparison-list restatement of an already-defined term — all consistent with the judgment the original six auditing agents already applied.

…ve bar

The repo owner reviewed the first two waves of fixes and corrected the
standard applied: "any term being introduced for the first time should
get boxed -- same with new results... let's err on the side of more
boxing, not less." This overturns the earlier "is it thin / is it just
an instance / is it in a list" filter, which had wrongly left real
definitions unboxed (caught concretely: ch23's direct/indirect effect,
ch01's associational risk difference/ratio/odds ratio).

Re-dispatched the same file-groups to re-audit every chapter (including
02 and 14, previously judged to need no changes at all) under the new
bar: box every first-time-introduced term or result, including short
one-liners, estimator/instance restatements of an already-general
concept, and bulleted list items -- skipping only pure structural
labels, genuine re-mentions of a term already boxed elsewhere, and (per
the same permissive instinct) as little `.notes`/callout content as
possible.

This added ~140 more theorem-family divs across 21 files, including the
book's second and third `#alg-` divs (g-estimation, the g-formula Monte
Carlo procedure, target trial emulation steps, etc., joining ch16's
2SLS as the first).

Fixed one real collision the two batches independently produced
(`#alg-g-estimation` claimed by both ch14 and ch21 -- disambiguated the
time-varying one to `#alg-g-estimation-tv`, matching this chapter's
existing `-tv` suffix convention).

Fixed a genuine Quarto rendering constraint neither raw pandoc nor the
first render attempt caught: a theorem-family div cannot be nested
inside a `.callout-note` (Quarto implements crossref theorems as
callouts internally, so nesting one inside another callout is a fatal
"nested callout" error at render time, even though pandoc alone parses
it as valid markdown). Three ch17 divs were nested this way; moved each
out to sit alongside its callout instead of inside it.

Content-preservation verified: every file's word count grew (never
shrank) relative to main, and every "orphan" diff line (removed text
with no byte-identical re-addition) was checked to be legitimate
reflow/copyediting, not deletion.

Part of #77.
@d-morrison

Copy link
Copy Markdown
Collaborator Author

Self-review (round 2, covering the "err on the side of more boxing" pass)

Independent review of the second wave (commit 963b138), at the same standard the automated reviewer would apply, since it hasn't produced a verdict yet at this head either.

What changed since the last self-review: ~140 more theorem-family divs across 21 files, driven by a corrected, more permissive standard after review feedback (see PR description). This round's specific risks and how I checked them:

  • Id collisions from independent parallel batches: found and fixed one real case (#alg-g-estimation claimed by both ch. 14 and ch. 21 independently) via a repo-wide grep before and after. No others exist — verified again after the fix.
  • A genuinely new failure mode: the first render attempt after this wave failed for real (Found a nested callout in the document) — a theorem-family div had been nested inside a .callout-note (Fine Point/Technical Point) in three places in ch. 17. Raw pandoc parses this as valid markdown, so a subagent's own pandoc-based test gave false confidence; only the actual quarto render catches it. Fixed by moving each definition to sit alongside its callout instead of inside it, verified with a scripted check that no div is nested inside a .callout anywhere in the book, and confirmed with a clean second render.
  • Content preservation: word count per file compared against main — grew everywhere, shrank nowhere. Every diff line that looked like a deletion (141 "orphan" lines with no byte-identical re-addition) was spot-checked; all are legitimate reflow or minor copyediting (e.g. an inline equation converted to a display equation, or a transition sentence adjusted around a newly-extracted definition), not lost content.
  • Scope discipline held: still exactly 26 {#exm-...} divs (matches main, none added), and no @def-... crossref links introduced anywhere.

Build verification: full quarto render (23 chapters × 3 formats) completes with exit 0 after the callout fix, producing all 69 expected output files, non-empty. Spot-checked rendered HTML across several chapters (including the relocated ch. 17 definitions and the new #alg- divs) to confirm they render as boxed, correctly-numbered environments.

No findings. Flagging this round's rendering gotcha (theorem divs can't nest inside callouts) as worth knowing for any future edits to this book's Fine Point/Technical Point sections.

@github-actions

Copy link
Copy Markdown
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://ucdavis.github.io/win/pr-preview/pr-78/

Built to branch gh-pages at 2026-08-20 20:56 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

d-morrison added a commit to Morrison-Lab/gha that referenced this pull request Aug 20, 2026
Claude Code's Bash tool caps inline output at ~30,000 characters; past
that a valid result comes back as a preview plus a harness-saved file
path, not the full text. This is true of the very PR this fix cites as
its motivating evidence (ucdavis/win#78, 114,587 bytes / 2,464 lines).
Tell the reviewer to Read that harness-saved path instead of claiming
the bare command always returns everything inline -- the file itself
is fine to read, since it's the harness's own write, not the agent's.

Addresses review finding on PR #542.
d-morrison added a commit to Morrison-Lab/ai-config that referenced this pull request Aug 20, 2026
…b denials (#1789)

* memory: download the claude-review execution artifact to diagnose stub denials

The job log alone shows only a summary line around a stub-review failure
(the permission_denials_count, the guard warning) with no detail on what
was actually denied -- that detail lives in the uploaded execution
artifact (claude-execution-output.json), which has to be downloaded and
parsed separately.

Documents the technique with a worked case: Morrison-Lab/gha#541, where
downloading the artifact for a 33-denial no-verdict run on ucdavis/win#78
revealed the reviewer looping ~15 times trying to save a large PR diff to
a file, denied every time by either a compound-command approval
requirement or a hard block on writing outside a narrow "allowed working
directory" (including /tmp and mkdir'd repo subdirectories). Also notes
that Morrison-Lab/gha#370 hit the identical denial-count signature but
couldn't confirm the mechanism because that session's egress proxy
blocked the artifact download -- worth retrying from an unrestricted
session before assuming the artifact is unreachable.

* Address review: fix wrong artifact-name pattern, dedupe, fix wording

Consolidates into the existing claude-bot-workflows.md entry (which
already documented this technique in more depth) instead of leaving a
duplicate section in github.md -- the wrong scope per that file's own
purpose (general gh CLI usage vs. the bot's runtime behavior). While
there, fixed that existing entry's artifact-name pattern, which was
missing the attempt-label component and wrongly appended .zip (not
part of the artifact's own name).

Also: stopped calling permission_denials_count 33 and 32 "identical"
(they aren't -- "comparably high" is accurate), cross-referenced the
show-full-output re-run as a simpler alternative to artifact download
(claude-review-dispatch.md already documents it, so the earlier "only
working way" claim was wrong), clarified the run-attempt vs
attempt-label naming ambiguity a reviewer flagged as a real footgun,
and applied semantic line breaks to the new content.

* Reword to avoid a false semantic-line-break trigger on 'E.g.'
d-morrison added a commit to Morrison-Lab/gha that referenced this pull request Aug 20, 2026
… diff (#542)

* fix(claude-code-review): tell the reviewer not to redirect/pipe gh pr diff

On a large PR, the reviewer would reach for `gh pr diff ... > file; wc -l
file` (or a pipe) to chunk the diff, and every such compound command was
denied wholesale, while writing to any file (including /tmp) is a hard
sandbox block rather than a permission prompt. It burned through the
denial budget on variant after variant with no verdict ever produced (33
denials measured on ucdavis/win#78, run 32415477507).

Fixes #541.

* fix: semantic line breaks in changelog fragment

* fix: correct false "however large it is" claim in gh pr diff guidance

Claude Code's Bash tool caps inline output at ~30,000 characters; past
that a valid result comes back as a preview plus a harness-saved file
path, not the full text. This is true of the very PR this fix cites as
its motivating evidence (ucdavis/win#78, 114,587 bytes / 2,464 lines).
Tell the reviewer to Read that harness-saved path instead of claiming
the bare command always returns everything inline -- the file itself
is fine to read, since it's the harness's own write, not the agent's.

Addresses review finding on PR #542.

* fix: scope the file-write hard-block claim to the observed sandbox

Non-blocking review note on PR #542: "anywhere ... no retry or
different path will get past" read as a universal property of every
runs-on runner, when it's only confirmed for the observed sandbox.
Reworded to state what was actually tried and observed blocked.

* fix: scope changelog fragment's hard-block claim, matching action.yml

Non-blocking observation from the latest review round on PR #542:
the changelog fragment still stated the file-write block as a general
fact rather than scoped to what was observed, the same overclaim
72b7dda already fixed in action.yml's own prompt text.
d-morrison added a commit to Morrison-Lab/gha that referenced this pull request Aug 21, 2026
Closes #543.

The reviewer was not attempting something forbidden. It wanted the diff
in a FILE so it could chunk or count a large one, and had no route to
one: a command chaining `gh pr diff` with a redirect is rejected as a
whole, and the agent cannot write a file itself. So it retried variants
until the denial count crossed the stub-retry threshold and the run
ended with no verdict -- 33 denials on ucdavis/win#78, 6 on gha#543's
reproduction, 8 and $4.95 on gha#555, the last with #542's prompt
paragraph forbidding exactly that construction already live at @v2.

A new step writes the diff to the workspace before the agent starts, and
the prompt names that absolute path -- absolute because Claude Code's
Read tool requires one. Bash(gh pr diff:*) stays allowed, so a denial
afterwards means something has genuinely gone wrong, which is what the
threshold is trying to measure.

Failure to save is not fatal: the partial file is removed, the path is
left empty, and the reviewer keeps today's route. Verified against a
stub gh across four shapes, including gh writing bytes then failing.

Not verifiable on its own PR -- claude-review.yml pins @v2, so both
review rounds ran the pre-fix workflow. #568 tracks extracting the step
into a tested composite action once the tag has moved.
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.

Wrap informal definitions/theorems in individual crossref divs

1 participant