Thomas Piacentini
← Workshop

Cheat sheet

Paper Writer, Critic and Iteration

Original text · English

Schedule experiments with UCB, iterate a draft with a five-score critic, and emit LaTeX, BibTeX and a manifest.

End-to-end research demo

dispatchResultUCB statspaper.triggerMiniPapermini_to_full_papermanifestSeed hypothesesalpha, beta, gammaclientIterationSchedulerUCB pickerprocess3 parallel slotsasyncio tasksprocessResult busreward per branchqueuepick_best_branchhighest mean rewardprocessCriticLoopfive scores per roundmodelPaperWritertex, bib, manifestprocessDemoReportstop_reasonstore
Nodes and connections
NodeRoleKind
Seed hypothesesalpha, beta, gammaclient
IterationSchedulerUCB pickerprocess
3 parallel slotsasyncio tasksprocess
Result busreward per branchqueue
pick_best_branchhighest mean rewardprocess
CriticLoopfive scores per roundmodel
PaperWritertex, bib, manifestprocess
DemoReportstop_reasonstore
FromToConnection
Seed hypothesesIterationScheduler
IterationScheduler3 parallel slotsdispatch
3 parallel slotsResult busResult
Result busIterationSchedulerUCB stats
Result buspick_best_branchpaper.trigger
pick_best_branchCriticLoopMiniPaper
CriticLoopPaperWritermini_to_full_paper
PaperWriterDemoReportmanifest
Sources

Run the lessons

CommandWhat it does
python3 code/main.py (54)Writes paper.tex, references.bib, manifest.json to a temp dir
python3 code/main.py (55)Prints the critic loop result and per-round trace
python3 code/main.py (56)Prints stop_reason, paper triggers and branch stats
python3 code/main.py (57)Prints best branch, critic status and paper sections
Sources

Calls in code

TaskCode
Figures from experiment outputsfigs = read_experiment_manifest(experiments, out_dir)
Render LaTeX onlyrender_latex(paper)
Fill prose and write three filesmanifest = PaperWriter(prose=prose).write(paper, out_dir)
Pair critic and revisercritic, reviser = make_deterministic_critic_pair()
Iterate a draftCriticLoop(critic=critic, reviser=reviser, max_rounds=6, target_score=8.0)
Mock experimentsmake_deterministic_runner(base_rewards, noise=0.04, delay_ms=2.0, seed=seed)
Schedule and waitreport = await sched.run(seed)
Pick and promotepick_best_branch(sched_report), then mini_to_full_paper(critic_result.paper, branch)
Sources

Declare the paper skeleton

paper = Paper(
title="<title>", authors=["Lab Bot"], abstract="<abstract>",
sections=[
Section(id="method", title="Method", cites=["jones2021"],
figure_refs=[figs[0].id]),label sec:method
],
figures=figs,label fig:<id>
bibliography=[
BibEntry(key="jones2021", entry_type="article",
fields={"title": "On loops", "author": "Jones", "year": "2021"}),
],
)
prose = MockProseGenerator(outlines={"method": "<outline>"})
writer = PaperWriter(prose=prose)gates run before any file
Sources

Run the UCB scheduler

seed = [Hypothesis(id="h-a-1", branch="branch-a"),
Hypothesis(id="h-b-1", branch="branch-b")]
runner = make_deterministic_runner(
base_rewards={"branch-a": 0.85, "branch-b": 0.55},
seed=7, delay_ms=2.0,
)reward is base + N(0, noise)
sched = IterationScheduler(
runner=runner, slots=3, max_experiments=20,
paper_threshold=0.7, prune_floor=0.25, prune_after_runs=3,
expander=deterministic_expander,two follow-ups per high reward
)
report = asyncio.run(sched.run(seed))SchedulerReport
report.to_dict()stop_reason, paper_triggers
Sources

Critic round and stop rules

  1. Critic scores clarity, novelty, evidence, methodology and related_work from 0 to 10.
  2. Critic emits one suggestion for each dimension below 8.0.
  3. Harness all five at or above target_score stops with reason target.
  4. Harness mean gain at most plateau_epsilon for 2 rounds stops with plateau.
  5. Reviser applies each edit, for example expand-body or add-method-section.
  6. Harness after max_rounds the status is stopped with reason budget.
  7. Order target wins over plateau. Plateau wins over budget.
Sources

Formulas and scores

UCB1
mean reward + c times sqrt(ln(total_runs) / runs).
Untried branch
ucb_score returns float("inf"), so it runs first.
Prune
mean below prune_floor after prune_after_runs trials.
Paper trigger
branch mean at or above paper_threshold, once per branch.
Clarity
min(10.0, 3.0 + avg_body / 50.0).
Evidence
min(10.0, 2.0 + 2.0 * fig_refs + 1.5 * cites).
Novelty
9.0 for high, 6.0 for medium, 3.0 for low originality_tag.
Demo originality
high at reward 0.8 or more, medium at 0.6 or more.
Sources

Loop defaults

SettingDefaultNote
max_rounds5Critic budget. Below 1 raises ValueError
target_score8.0Every dimension, not the mean
plateau_epsilon0.1For plateau_window 2 rounds
slots3Parallel asyncio tasks
max_experiments50max_seconds is 30.0
exploration_csqrt(2)UCB exploration weight
paper_threshold0.7Fires paper.trigger
prune_floor0.2After prune_after_runs 3 trials
Sources

Errors and fixes

SymptomCauseFix
PaperValidationError: cites unknown bibliography keySection cite has no BibEntryAdd the entry to bibliography
PaperValidationError: references unknown figure idfigure_refs names a missing figureAdd the figure first
NoTriggerErrorNo branch reached paper_thresholdCheck branch rewards against the threshold
Five flat rounds, verdict budgetSuggestions never raise the scoreFix the critic, not the draft
Branch never scheduled againBranch is prunedCheck prune_floor and prune_after_runs
Trace event kind errorRunner task raisedRead the repr of the exception in the trace
Sources

Questions

Why a skeleton first?
Gates check figures, cites and sections before any prose.
What does the critic read?
manifest.json. It does not parse LaTeX.
Why UCB?
Greedy never explores. Uniform never exploits.
Why import, not copy?
The demo adjusts sys.path and composes the earlier lessons.
Sources
Original source
---
id: research-agent-writing
title: Paper Writer, Critic and Iteration
code: PW
subtitle: Schedule experiments with UCB, iterate a draft with a five-score critic, and emit LaTeX, BibTeX and a manifest.
hue: 280
sources: phases/19-capstone-projects/54-paper-writer, phases/19-capstone-projects/55-critic-loop, phases/19-capstone-projects/56-iteration-scheduler, phases/19-capstone-projects/57-end-to-end-research-demo
source_hash: 68a4188a61fb9e49
---

## End-to-end research demo
type: architecture
from: phases/19-capstone-projects/57-end-to-end-research-demo/docs/en.md, phases/19-capstone-projects/57-end-to-end-research-demo/code/main.py, phases/19-capstone-projects/56-iteration-scheduler/docs/en.md

```arch
node | seed | 1,1 | Seed hypotheses | alpha, beta, gamma | client
node | sched | 2,1 | IterationScheduler | UCB picker | process
node | slots | 3,1 | 3 parallel slots | asyncio tasks | process
node | bus | 4,1 | Result bus | reward per branch | queue
node | pick | 4,2 | pick_best_branch | highest mean reward | process
node | critic | 3,2 | CriticLoop | five scores per round | model
node | writer | 2,2 | PaperWriter | tex, bib, manifest | process
node | report | 1,2 | DemoReport | stop_reason | store
edge | seed | sched |
edge | sched | slots | dispatch
edge | slots | bus | Result
edge | bus | sched | UCB stats
edge | bus | pick | paper.trigger
edge | pick | critic | MiniPaper
edge | critic | writer | mini_to_full_paper
edge | writer | report | manifest
```

## Run the lessons
type: command-table
span: 2
from: phases/19-capstone-projects/54-paper-writer/code/main.py, phases/19-capstone-projects/55-critic-loop/code/main.py, phases/19-capstone-projects/56-iteration-scheduler/code/main.py, phases/19-capstone-projects/57-end-to-end-research-demo/code/main.py

| Command | What it does |
|---|---|
| `python3 code/main.py` (54) | Writes paper.tex, references.bib, manifest.json to a temp dir |
| `python3 code/main.py` (55) | Prints the critic loop result and per-round trace |
| `python3 code/main.py` (56) | Prints stop_reason, paper triggers and branch stats |
| `python3 code/main.py` (57) | Prints best branch, critic status and paper sections |

## Calls in code
type: task-table
span: 2
from: phases/19-capstone-projects/54-paper-writer/code/main.py, phases/19-capstone-projects/55-critic-loop/code/main.py, phases/19-capstone-projects/56-iteration-scheduler/code/main.py, phases/19-capstone-projects/57-end-to-end-research-demo/code/main.py

| Task | Code |
|---|---|
| Figures from experiment outputs | `figs = read_experiment_manifest(experiments, out_dir)` |
| Render LaTeX only | `render_latex(paper)` |
| Fill prose and write three files | `manifest = PaperWriter(prose=prose).write(paper, out_dir)` |
| Pair critic and reviser | `critic, reviser = make_deterministic_critic_pair()` |
| Iterate a draft | `CriticLoop(critic=critic, reviser=reviser, max_rounds=6, target_score=8.0)` |
| Mock experiments | `make_deterministic_runner(base_rewards, noise=0.04, delay_ms=2.0, seed=seed)` |
| Schedule and wait | `report = await sched.run(seed)` |
| Pick and promote | `pick_best_branch(sched_report)`, then `mini_to_full_paper(critic_result.paper, branch)` |

## Declare the paper skeleton
type: annotated-code
lang: python
from: phases/19-capstone-projects/54-paper-writer/code/main.py, phases/19-capstone-projects/54-paper-writer/docs/en.md

```python
paper = Paper(
    title="<title>", authors=["Lab Bot"], abstract="<abstract>",
    sections=[
        Section(id="method", title="Method", cites=["jones2021"],
                figure_refs=[figs[0].id]),     # label sec:method
    ],
    figures=figs,                              # label fig:<id>
    bibliography=[
        BibEntry(key="jones2021", entry_type="article",
                 fields={"title": "On loops", "author": "Jones", "year": "2021"}),
    ],
)
prose = MockProseGenerator(outlines={"method": "<outline>"})
writer = PaperWriter(prose=prose)              # gates run before any file
```

## Run the UCB scheduler
type: annotated-code
lang: python
from: phases/19-capstone-projects/56-iteration-scheduler/code/main.py

```python
seed = [Hypothesis(id="h-a-1", branch="branch-a"),
        Hypothesis(id="h-b-1", branch="branch-b")]
runner = make_deterministic_runner(
    base_rewards={"branch-a": 0.85, "branch-b": 0.55},
    seed=7, delay_ms=2.0,
)                                              # reward is base + N(0, noise)
sched = IterationScheduler(
    runner=runner, slots=3, max_experiments=20,
    paper_threshold=0.7, prune_floor=0.25, prune_after_runs=3,
    expander=deterministic_expander,           # two follow-ups per high reward
)
report = asyncio.run(sched.run(seed))          # SchedulerReport
report.to_dict()                               # stop_reason, paper_triggers
```

## Critic round and stop rules
type: flow
from: phases/19-capstone-projects/55-critic-loop/docs/en.md, phases/19-capstone-projects/55-critic-loop/code/main.py

1. **Critic**: scores clarity, novelty, evidence, methodology and related_work from 0 to 10.
2. **Critic**: emits one suggestion for each dimension below 8.0.
3. **Harness**: all five at or above `target_score` stops with reason target.
4. **Harness**: mean gain at most `plateau_epsilon` for 2 rounds stops with plateau.
5. **Reviser**: applies each edit, for example `expand-body` or `add-method-section`.
6. **Harness**: after `max_rounds` the status is stopped with reason budget.
7. **Order**: target wins over plateau. Plateau wins over budget.

## Formulas and scores
type: concepts
from: phases/19-capstone-projects/56-iteration-scheduler/docs/en.md, phases/19-capstone-projects/56-iteration-scheduler/code/main.py, phases/19-capstone-projects/55-critic-loop/code/main.py, phases/19-capstone-projects/57-end-to-end-research-demo/code/main.py

- **UCB1**: mean reward + c times sqrt(ln(total_runs) / runs).
- **Untried branch**: `ucb_score` returns `float("inf")`, so it runs first.
- **Prune**: mean below `prune_floor` after `prune_after_runs` trials.
- **Paper trigger**: branch mean at or above `paper_threshold`, once per branch.
- **Clarity**: `min(10.0, 3.0 + avg_body / 50.0)`.
- **Evidence**: `min(10.0, 2.0 + 2.0 * fig_refs + 1.5 * cites)`.
- **Novelty**: 9.0 for high, 6.0 for medium, 3.0 for low `originality_tag`.
- **Demo originality**: high at reward 0.8 or more, medium at 0.6 or more.

## Loop defaults
type: defaults
from: phases/19-capstone-projects/55-critic-loop/code/main.py, phases/19-capstone-projects/55-critic-loop/docs/en.md, phases/19-capstone-projects/56-iteration-scheduler/code/main.py, phases/19-capstone-projects/56-iteration-scheduler/docs/en.md

| Setting | Default | Note |
|---|---|---|
| `max_rounds` | 5 | Critic budget. Below 1 raises ValueError |
| `target_score` | 8.0 | Every dimension, not the mean |
| `plateau_epsilon` | 0.1 | For `plateau_window` 2 rounds |
| `slots` | 3 | Parallel asyncio tasks |
| `max_experiments` | 50 | `max_seconds` is 30.0 |
| `exploration_c` | sqrt(2) | UCB exploration weight |
| `paper_threshold` | 0.7 | Fires `paper.trigger` |
| `prune_floor` | 0.2 | After `prune_after_runs` 3 trials |

## Errors and fixes
type: troubleshooting
from: phases/19-capstone-projects/54-paper-writer/code/main.py, phases/19-capstone-projects/55-critic-loop/docs/en.md, phases/19-capstone-projects/56-iteration-scheduler/code/main.py, phases/19-capstone-projects/57-end-to-end-research-demo/code/main.py, phases/19-capstone-projects/57-end-to-end-research-demo/docs/en.md

| Symptom | Cause | Fix |
|---|---|---|
| `PaperValidationError`: cites unknown bibliography key | Section cite has no `BibEntry` | Add the entry to `bibliography` |
| `PaperValidationError`: references unknown figure id | `figure_refs` names a missing figure | Add the figure first |
| `NoTriggerError` | No branch reached `paper_threshold` | Check branch rewards against the threshold |
| Five flat rounds, verdict budget | Suggestions never raise the score | Fix the critic, not the draft |
| Branch never scheduled again | Branch is pruned | Check `prune_floor` and `prune_after_runs` |
| Trace event kind error | Runner task raised | Read the `repr` of the exception in the trace |

## Questions
type: qa
span: 2
from: phases/19-capstone-projects/54-paper-writer/docs/en.md, phases/19-capstone-projects/55-critic-loop/docs/en.md, phases/19-capstone-projects/56-iteration-scheduler/docs/en.md, phases/19-capstone-projects/57-end-to-end-research-demo/docs/en.md

- **Why a skeleton first?** Gates check figures, cites and sections before any prose.
- **What does the critic read?** `manifest.json`. It does not parse LaTeX.
- **Why UCB?** Greedy never explores. Uniform never exploits.
- **Why import, not copy?** The demo adjusts `sys.path` and composes the earlier lessons.
Code and artifacts 1
What you take away

Saved in your notebook on this device.

Sources and limits

Reading checkpoints are self-reported. Test results are recorded separately and apply to the executed cases.

AI Engineering from Scratch · 3f9715c · MIT

Download this file ↓