# SPEC — Reproduce the Debian GR (LLM usage) ballot comparison

## Goal

Reproduce the two output artifacts:

1. `comparison.md` — a Markdown comparison of the ballot options.
2. `comparison.html` — an interactive HTML table with JavaScript to reorder columns **and** to auto-generate a filled ballot.

> ⚠️ **The comparison analysis itself was produced with AI assistance and may contain errors.** Both `comparison.md` and `comparison.html` must display a prominent warning to this effect — that the page was auto-generated with AI assistance, may contain errors or mischaracterizations, and that voters should read and understand each proposal's full text (linked from the vote page) before casting their ballot. This warning appears near the top of both outputs and is not optional.

## Sources

The vote being described is the Debian General Resolution **"LLM usage in Debian"**, published at:

> https://www.debian.org/vote/2026/vote_002

That page lists every published proposal (proposals **A–H**) plus proposers/seconds and full text. Fetch it to obtain the full text and metadata of all options to compare.

The corrected ballot (with the authoritative choice numbering, choice titles, and exact voting-form template used by Devotee) is:

> https://lists.debian.org/debian-vote/2026/08/msg00279.html
> ("General resolution: LLM usage in Debian: First call for votes: corrected ballot", Debian Project Secretary, 2026-08-15)

### Option mapping

There are 8 policy options to analyze (Choices 1–8) plus a 9th ballot choice ("None of the above") that is not a policy option. Their numbering is taken from both the vote page and the corrected ballot. The Debian GR number–letter mapping is fixed:

| Ballot # | Letter | Title (as printed on the corrected ballot)              | Proposer          |
|---------:|:------:|---------------------------------------------------------|-------------------|
| 1        | A      | Ban LLM contributions from Debian via Social Contract    | Matthias Geiger   |
| 2        | B      | Allow AI-Assisted Contributions with conditions         | Lucas Nussbaum   |
| 3        | C      | Reject LLMs as far as practical, update Code of Conduct | Ian Jackson      |
| 4        | D      | Accept AI contributions for Debian specific work         | Pierre-Elliott Bécue |
| 5        | E      | Responsible Use of Generative AI                         | Marc Haber        |
| 6        | F      | A cautious approach to generative AI                    | Tobias Frost      |
| 7        | G      | Debian is created by humans                             | Gard Spreemann    |
| 8        | H      | Avoid the use of LLM: climate destruction is a deal breaker | Holger Levsen |
| 9        | —      | None of the above                                         | *(not a proposal)* |

(Note: the vote page prints Choice 1 as "No LLM contributions to Debian via Social Contract", while the corrected ballot prints "Ban LLM contributions from Debian via Social Contract". The two refer to the same proposal; the **corrected-ballot wording** is used as the canonical title here because that is the exact text the voter will see and rank.)

Ballot Choice **9** ("None of the above") is part of the ballot. It is **not** a policy option, so it is not analyzed in the 13 comparison rows; in the comparison table it appears as a column whose every cell is `—` (N/A). It **does** participate in column reordering and in ballot generation, so a voter can position it among the other choices to rank it.

## Analysis to perform

For **each option** (Choices 1–8, letters A–H), determine, by reading the option's text, the position on each of these comparison points:

1. **Overall stance** — ban / permit-with-conditions / discourage / accept / neutral / cautious-avoid.
2. **Binding mechanism** — e.g. new Social Contract point, §4.1(5) statement, CoC supplement, project guidelines. The row also records whether the statement is framed as an evolving "current position" (changeable without a new GR) vs. a static foundation-document amendment.
3. **Scope** — Debian-specific only (excl. upstream) vs. all contributions; whether messages-to-humans are covered; whether upstream is addressed.
4. **Disclosure** — required / expected / encouraged / N/A, plus any detail (Git trailer, lightweight-tool carve-outs, etc.).
5. **Maintainer can refuse AI contributions** — explicit yes / not addressed / N/A, with the mechanism (CoC-enforceable vs. collaborative processes).
6. **Maintainer can accept AI contributions** — explicit yes (project-level allow) / implicit (not prohibited) / N/A (ban moots acceptance). Symmetric to point 5.
7. **Bulk / automated changes** — addressed (prior discussion / human oversight) or not.
8. **Confidentiality / privacy** — whether it covers embargoed info, keys, credentials, personal data, etc.
9. **Legal / copyright treatment** — central rationale vs. addressed vs. deferred vs. listed-only.
10. **Enforcement** — good-faith intent / contributor accountability / CoC disciplinary action / etc.
11. **Environmental / climate impact** — whether the proposal acknowledges or condemns the AI industry's environmental and ecological harms (energy/resource consumption in training and inference, data-center footprint, hardware/resource waste) as motivating rationale, or stays silent.
12. **Broader-ethical impact** — whether the proposal acknowledges or condemns the AI industry's wider non-environmental ethical harms (aggressive web-scraping for training data causing DoS-like load on Debian's own infrastructure, disregard for license/copyright conventions such as robots.txt, exploitation of authors, corporate ethics of AI vendors, etc.) as motivating rationale, or stays silent.
13. **Community sustainability / knowledge transfer** — whether the proposal addresses the impact of LLM adoption on Debian's contributor community (reviewer burnout, new contributors failing to learn, disruption of knowledge transfer / skill atrophy).

## Output 1 — `comparison.md`

A Markdown document containing:

- A short header noting the source URLs (vote page **and** the corrected ballot).
- A **prominent AI-assistance warning** (see the warning in the Goal section): the analysis was produced with AI assistance, may contain errors, and voters should read each proposal's full text before deciding. Place it immediately after the header, styled as a blockquote.
- A **full comparison table** with one column per ballot choice (Choices 1–9) and one row per comparison point above. Keep cells short. Use `**Yes — explicit**` / `**Required**` / `**Yes**` bolding to aid scanning; `N/A` where a ban moots the question. The "None of the above" column's cells are all `—` (N/A) because it is not a policy option.
- **Column labels use the ballot choice number prominently**, followed by the letter and the **ballot option title** (the exact title as printed on the corrected ballot), e.g. `1 (A) · Ban LLM contributions from Debian via Social Contract`; for Choice 9 the letter is omitted: `9 · None of the above`. The proposers appear in the option-mapping table at the top of the document (and in the HTML as a tooltip), not in the column header.
- **Row 1 ("Overall stance")** shows the bold stance badge followed by a short quoted fragment (with `…` ellipses) of the most telling phrases from the proposal text that justify the stance, e.g. `Ban — "expressly forbid any contributions…"; "prohibited from inclusion"`. Keep only the most important terms; do not reproduce whole sentences.
- A legend/notes section reproducing the stance-order definition (ban → discourage → cautious-avoid → permit-with-conditions → accept → neutral) used by the "Progressive order" button, and the binding-mechanism evolving/static distinction.

## Output 2 — `comparison.html`

A single self-contained HTML file (no external CSS/JS) implementing an interactive comparison table plus a ballot auto-fill panel:

- A **prominent AI-assistance warning banner** near the top of the page (before or within the lead paragraph, clearly visible without scrolling): the comparison was auto-generated with AI assistance, may contain errors or mischaracterizations, and voters must read and understand each proposal's full text (linked from the vote page) before casting their ballot. Style it distinctly (e.g. a left-bordered warning box with an amber/magenta accent).

### Table interactivity

- Same data as `comparison.md` — 9 option columns (Choices 1–9) plus the fixed row-label column. The column header text is the **ballot option title** (exact wording from the corrected ballot); the proposer is shown in the header's `title` tooltip, not in the visible header.
- **Column headers** show the ballot choice number prominently (`1`…`9`) with the letter shown secondary/smaller (e.g. `1` big, `A` in a muted or smaller span) followed by the ballot title. For Choice 9 ("None of the above") there is no letter. Tooltip/lead text uses both the number and the letter where present, plus the proposer.
- **Row 1 ("Overall stance")** shows the colored stance badge followed by a short quoted fragment (with `…` ellipses) of the most telling phrases from the proposal text, mirroring `comparison.md`. Keep only the most important terms.
- **Column reorder via drag-and-drop (insert, not swap)**: drag a `<th>` (except the fixed label column) and drop it onto/over another column to **insert** it at the destination, shifting the intervening columns — do *not* merely swap the two. The drop position is decided by the pointer's horizontal position over the target header: landing on the left half inserts *before* the target, the right half inserts *after* the target (so dropping on the right half of the last column makes the dragged column last).
- **All columns always visible**: all 9 option columns are always shown (every choice is always ranked in the generated ballot).
- **No horizontal scrolling**: the table must fit the page width (use `table-layout: fixed; width: 100%` and let cell and header content **wrap** via `overflow-wrap: anywhere` so long text never forces a scrollbar). Vertical (page) scrolling is fine; the header row remains sticky.
- **State persistence**: persist column order in `localStorage` under a single key; gracefully handle schema changes (drop unknown keys, append missing ones).
- **Action buttons**:
  - **"Ballot order"** — arrange columns in ballot order (Choice 1 → Choice 9, left to right).
  - **"Progressive order (ban → permissive)"** — arrange columns from most restrictive to most permissive based on each option's overall stance. "None of the above" sorts last (it is not on the ban→permissive spectrum).
  - **"Reverse progressive order (permissive → ban)"** — the reverse of Progressive order (most permissive → most restrictive), **except** that "None of the above" remains last.
- **Styling**: Debian magenta (#d70751) sticky header row, zebra-striped body, accessible labels/legends, full-width page layout (table fills the viewport width, no horizontal scroll). Mark the label column as non-draggable and add a `title` hint on draggable headers.
- Provide a `<title>` and a lead paragraph that links back to both the vote page and the corrected ballot.

### Ballot auto-fill panel

A clearly delimited panel (e.g. a `<section>`) below the comparison table. **The ballot is generated directly from the column order — there are no separate rank input fields or UUID input field.** The panel contains:

- Help text explaining: drag the comparison columns above to rank the choices (leftmost column = rank 1, next = rank 2, …); the ballot text below updates automatically.
- A live **read-only `<textarea>`** whose contents are regenerated whenever the column order changes. It renders the email-ready ballot body, **exactly** matching the corrected-ballot template layout, with the `:` separator (not `=`) between "Choice N" and the title:

  ```
  -=-=-=-=-=- Don't Delete Anything Between These Lines =-=-=-=-=-=-=-=-
  d69f9187-ed2f-40b6-a2eb-4211d3f84d86
  [<rank>] Choice 1: Ban LLM contributions from Debian via Social Contract
  [<rank>] Choice 2: Allow AI-Assisted Contributions with conditions
  [<rank>] Choice 3: Reject LLMs as far as practical, update Code of Conduct
  [<rank>] Choice 4: Accept AI contributions for Debian specific work
  [<rank>] Choice 5: Responsible Use of Generative AI
  [<rank>] Choice 6: A cautious approach to generative AI
  [<rank>] Choice 7: Debian is created by humans
  [<rank>] Choice 8: Avoid the use of LLM: climate destruction is a deal breaker
  [<rank>] Choice 9: None of the above
  -=-=-=-=-=- Don't Delete Anything Between These Lines =-=-=-=-=-=-=-=-
  ```

  - `<rank>` is derived from the current **column order**: all 9 columns are always visible, so the i-th column from the left (1-based) gets rank `i`, as a single digit 1–9. Because all 9 columns are shown, every choice is always ranked 1–9 and duplicates are impossible by construction.
  - The UUID line is always the literal `d69f9187-ed2f-40b6-a2eb-4211d3f84d86` (never empty, never user-edited).
- A **ties warning** shown next to the `<textarea>`: the generated ballot gives each choice a **distinct** rank 1–9 based on column order; it does **not** support ranking several options at the same rank (equal rankings / ties). To express ties, the user must manually edit the generated text (Debian/Devotee accepts equal rankings, e.g. two choices both ranked `[1]`). The warning makes this limitation explicit so the user does not assume the output is ready to send unchanged when they want ties.
- A **"Copy to clipboard"** button next to the `<textarea>`.

## Verification

- `comparison.md` opens in any Markdown viewer and contains the full comparison table (one column per option × 13 rows): columns labeled by ballot number (1–9) plus the letter sub-label and proposer for Choices 1–8, and a Choice 9 "None of the above" column whose cells are all `—`.
- Opening `comparison.html` in a browser:
  - **Dragging a header and dropping onto another *inserts* the dragged column at the destination** (left half of target = before, right half = after), shifting intervening columns — not a two-column swap; reloading the page preserves state; "Ballot order" resets to Choice 1 → Choice 9. There are no checkboxes or hide/show controls.
  - The page has **no horizontal scrollbar** at any viewport width: all 9 option columns + the label column are always shown, with cell content wrapping.
  - "Progressive order" arranges columns from most restrictive (ban) to most permissive (neutral), with Choice 9 last.
  - "Reverse progressive order" arranges columns from most permissive (neutral) to most restrictive (ban), with Choice 9 still last.
  - The ballot panel:
    - It regenerates automatically as columns are reordered; the `<textarea>` always shows a valid ballot body matching the corrected-ballot format exactly (`:` separator, two `=-=-=-=-=- Don't Delete …` delimiter lines, Choice 1–9).
    - The leftmost column's option is rank 1, the next is rank 2, …, the rightmost (9th) is rank 9.
    - Copying the text and signing/mailing it to `gr_llm@vote.debian.org` would be a valid ballot (given a correct GPG signature on the mail).
    - State (column order) survives a page reload; "Ballot order" resets the column order to Choice 1 → Choice 9.