export const meta = {
  name: 'modemwars-annotate',
  description: 'Phase 2: arbitrate variable names, then write detailed line-by-line comments for every chunk',
  phases: [
    { title: 'Variables', detail: 'one arbiter agent decides zero-page and global variable names' },
    { title: 'Rebuild', detail: 'rebuild the listing with the arbitrated names applied' },
    { title: 'Annotate', detail: 'one agent per chunk writes annotations/20_<chunk>.json' },
    { title: 'Verify', detail: 'rebuild, reassemble and compare every unit' },
  ],
}

const chunks = args.chunks
const RESULT = {
  type: 'object',
  properties: {
    path: { type: 'string' },
    linesCommented: { type: 'integer' },
    routines: { type: 'integer' },
    problems: { type: 'array', items: { type: 'string' } },
  },
  required: ['path', 'linesCommented', 'routines', 'problems'],
}

const common = `
You are annotating a reverse-engineered disassembly of "Modem Wars" (Commodore 64, Electronic Arts / Ozark
Softscape, Dan Bunten, 1988): a two-player real-time strategy game played over a modem or null-modem link, with a
solo trainer, "game film" record/playback, a console with STATS / REPAIR / MISC panels, and a 40x40 battlefield
map.  Work in /home/scott/claude/modemwars.

Read first: docs/overview.md (disk, boot, loader protocol, memory map, overlays, game concepts) and the section of
docs/knowledgeBase.md for your unit (every routine and data block found by the survey pass).  disassembly/XREF.txt
lists callers/readers/writers of every label and of every zero-page location.  disassembly/zeropage.inc holds the
variable names.

The listing is ca65 syntax; every instruction line ends with "; XXXX" (its address) and then the comment text.
Each file starts with a Contents table of its routines.  Labels are unit-scoped: the same address holds different
code in the other overlay variant.  Hardware registers are named (VIC_*, SID_*, CIA1_*, CIA2_*).  The game runs
with $01=$35 (no ROMs, I/O visible) and scans the keyboard and joystick itself.  Strings end with a character
whose bit 7 is set.  Graphics data is rendered as bit art in the comments.

Facts established by the survey pass - use these names and do not re-derive them:
 * Units: 100 records in parallel 100-byte arrays starting at $F640, each array $64 apart - column, row,
   flags/facing, type (0 GRUNT 1 RIDER 2 BOOMER 3 SPY 4 COMCEN, bit 7 = dead), destination column/row,
   secondary target, cloak, blitz, stun/dug-in, energy (0-50), move state, draw flags, terrain hidden under
   the unit, group id.  Units 0-49 are player 0, 50-99 player 1; unit 49 and unit 99 are the comcens.
 * Map: $F000-$F63F, one byte per cell of the 40x40 battlefield.  A cell holding $80|index means that unit
   stands there and the terrain it covers is kept in the per-unit "terrain under" array.
 * Screen: multicolour bitmap, VIC bank 2 - bitmap $A000, video matrix $8C00, colour RAM $D800.  Text is
   drawn into the bitmap with the game's own font, through the text engine in game/textEngineC000.s.
   Left panel = whole map at 4x4 pixels per cell; right panel = 7x5 cells at 16x16; console below it.
 * Opponent: one jump table at $E000 backed by EITHER game/modemDriverE000.s (a real software modem) OR
   game/trainerAiE000.s (the solo trainer's computer opponent).  $E000 per-frame poll, $E003 open/close,
   $E006 get byte, $E009 send byte, $E00C per-frame, $E015 get key.
 * Commands: single bytes $80-$A6 plus 0-3 argument bytes, queued in a ring and dispatched through
   commandHandlerTable at $4D2A.  The same stream is what a "game film" records and replays.
 * Side-dependent branches are self-modified: several "cpy #$32" tests are followed by a BCC/BCS whose
   opcode byte is written at run time from the player's side.  Treat that opcode byte as a variable.

Annotation JSON format (the build merges all annotations/*.json; everything is unit-scoped):
{
 "chunk": "<id>", "unit": "<unit>",
 "unitLabels": { "<unit>": { "XXXX": "camelCaseName" } },
 "notes": { "XXXX": { "unit": "<unit>",
                      "routine": ["name - what it does", "In:  ...", "Out: ...", "Called from: ..."],
                      "block":   ["comment block printed before this address"],
                      "line":    "end-of-line comment for the instruction or data at this address" } },
 "dataTypes": { "XXXX": ["text"|"addr"|"word"|"byte"|"grid"|"bitmap"|"sprite", length, optionalRowWidth] },
 "zpComments": { "XX": "better description of a zero-page variable (do not rename)" }
}
Addresses: uppercase hex, 4 digits (2 for zero page), no "$".  Plain ASCII only - no accented characters, arrows
or box-drawing characters.

HARD RULES
 * Write ONLY your own file annotations/20_<chunk>.json.  Never edit disassembly/*.s, tools/*, docs/* or another
   agent's annotation file, and never edit the generated files annotations/05_*, 06_*, 10_*, 11_*, 15_*.
 * Do NOT run tools/build.py or disassembly/verify.sh - other agents are running in parallel and the build
   rewrites the whole disassembly directory.  A separate verification agent runs it at the end.
 * Do not rename anything outside your own address range.  You MAY rename labels inside your range when you have a
   better name (camelCase, specific: waitForRasterBottom, unitHealthTable, isFilmPlaying).
 * Never invent facts.  Mark uncertainty in the comment itself ("probably", "?").
`

phase('Variables')
const arb = await agent(`${common}
TASK: you are the naming arbiter for variables.  survey/variableProposals.json lists, per address, every name and
meaning proposed by the survey agents (often several per address, sometimes contradictory).  The zero-page section
at the end of disassembly/XREF.txt shows every reader and writer.  Decide ONE final camelCase name and a one-line
description for:
  (a) every zero-page address that has a proposal or is used by the game (keep "zp_XX" only when nothing can be
      inferred - but read the readers/writers in the listing before giving up);
  (b) absolute RAM variables that live outside the code units: $8A00-$8BFF (sprite shapes), $9000-$92FF (VIC
      shadow registers, buffers, game state), $F640-$FBB7 (unit record arrays and work RAM), $FFD2-$FFFF;
  (c) the well-known flags inside the main program: $0B7D-$0BB4 (the settings block), $87FF, $90B7, $90EA, $90FB.
Resolve conflicts by reading the code, not by counting votes.  Names must be unique across the whole program and
must not collide with routine names in docs/knowledgeBase.md.  Prefer the plural/array form for the per-unit
arrays (unitColTable, unitRowTable, unitTypeTable, ...).

Write /home/scott/claude/modemwars/annotations/15_variables.json:
{ "zp": { "XX": ["name", "description"] },
  "labels": { "XXXX": "name" },                                   <- addresses outside every code unit range
  "unitLabels": { "game/mainProgram0800": { "0BA5": "isSoloTrainer" } },  <- variables inside a unit range
  "notes": { "XXXX": { "unit": "game/mainProgram0800", "line": "description" } }
}
You MAY run "python3 tools/build.py 2>&1 | grep -i warning" and "./disassembly/verify.sh | grep -c OK" (expect 24)
because you are the only agent running in this phase; fix any duplicate-name warning it reports.
Return path, number of zp names decided (linesCommented), number of absolute variables (routines), problems.`,
  { label: 'arbiter:variables', phase: 'Variables', schema: RESULT })

phase('Rebuild')
const rebuilt = await agent(`Work in /home/scott/claude/modemwars.  Run:
  python3 tools/build.py 2>&1 | grep -iE "warning|error|traceback"
  ./disassembly/verify.sh | grep -c OK          (must print 24)
  python3 tools/chunks.py 700 > /dev/null
If verify does not print 24, show the failing unit and its first ca65 error
(./disassembly/verify.sh 2>&1 | grep -B2 -A2 Error | head -30), trace it to the offending entry in
annotations/15_variables.json (bad label name, a text run crossing a label, a non-ASCII character) and fix that
annotation file - never edit disassembly/*.s or tools/*.  Repeat until it verifies.
Return path="disassembly", linesCommented=0, routines=0, problems=[what you fixed].`,
  { label: 'rebuild', phase: 'Rebuild', schema: RESULT })

phase('Annotate')
const results = await pipeline(chunks, (c) => agent(`${common}
YOUR CHUNK: unit "${c.unit}", file disassembly/${c.file}, addresses $${c.startAddr}-$${c.endAddr}.
Locate it with:  grep -n "; ${c.startAddr}" disassembly/${c.file}   and   grep -n "; ${c.endAddr}" disassembly/${c.file}
then read the whole range with sed -n.  Read it all before writing anything.

TASK: write the detailed annotation for this chunk to /home/scott/claude/modemwars/annotations/20_${c.id}.json
(format above).  Requirements:
 1. Every routine that starts in your range gets a "routine" header: what it does (1-3 sentences), "In:" the
    registers and variables it consumes, "Out:" the results and side effects, and "Called from:" its callers taken
    from XREF.txt when there are only a few.  Improve the survey's wording where you understand it better; keep
    its name unless it is clearly wrong.
 2. A "line" comment on essentially EVERY instruction, explaining intent rather than the mnemonic ("start at the
    left edge of the viewport", not "load 0 into X").  In every compare/branch name the thing being tested
    ("branch if the unit is dead").  Explain every magic number: screen offsets, colours, screen codes, sprite
    pointers, VIC/SID/CIA bit meanings, raster lines, timer values, table strides, unit-array offsets ($64 apart).
 3. "block" comments before each logical section and loop: what it iterates over and what it maintains.
 4. Data inside your range: label it and describe the structure (element size, what the index means).  Use
    dataTypes "text" for strings (exact length, including the terminator byte), "addr" for tables of 16-bit
    addresses, "grid" with a row width for tables read as rows, "bitmap"/"sprite" for graphics.
 5. Self-modifying code: say exactly which instruction is patched, by whom, and with what (labels look like
    L_1234+1 for the operand byte).
 6. Note anything that looks like dead or leftover code, and say why you think so.
Work top to bottom; do not skip routines.  Follow calls into other files when the meaning of a call matters.
When done, validate with: python3 -c "import json;json.load(open('annotations/20_${c.id}.json'))"
Return: path, number of line comments written, number of routine headers, problems (mis-traced code, survey names
you corrected, unresolved questions).`,
  { label: `annotate:${c.id}`, phase: 'Annotate', schema: RESULT }))

phase('Verify')
const verified = await agent(`Work in /home/scott/claude/modemwars.  You are the only agent running now.
 1. grep -lP '[^\\x00-\\x7F]' annotations/*.json docs/*.md 2>/dev/null   - replace any non-ASCII character found.
 2. python3 -c "import json,glob;[json.load(open(f)) for f in glob.glob('annotations/*.json')]"  - fix invalid JSON.
 3. python3 tools/build.py 2>&1 | grep -iE "warning|error|traceback"
 4. ./disassembly/verify.sh | grep -v "^OK"      - every one of the 24 units must reassemble byte-exact.
If a unit fails, find the first ca65 error (./disassembly/verify.sh 2>&1 | grep -B2 -A2 Error | head -30), trace it
to the annotation entry that caused it and fix THAT annotation file.  Never edit disassembly/*.s or tools/*.
Duplicate-name warnings from build.py are auto-resolved but ugly: fix the annotation that caused each one.
Repeat until verify reports 24 OK and build.py prints no warnings.
Return path="disassembly", linesCommented=0, routines=0, problems=[everything you had to fix].`,
  { label: 'verify', phase: 'Verify', schema: RESULT })

return { arbiter: arb, rebuilt, chunks: results.filter(Boolean), verified }
