The appender computes the next board task id by scanning the existing JSONL rows directly:
The target repo isn't present in this environment, so I reproduced the failure with a synthetic mixed-schema board (764 rows / 11 missing ids / numeric max 753) and verified the fix. Solution:
KeyError: 'id' in append_board_task_dispatched.py sequence scanThe appender computes the next board task id by scanning the existing JSONL rows directly:
# coding-hermes-foreman/scripts/append_board_task_dispatched.py:48
nid = max(e["id"] for e in events) + 1
Two assumptions break on a real board:
id. Legacy and externally-produced rows are valid history but may omit the field, so e["id"] raises KeyError.id is an int. Some writers emit ids as numeric strings ("753", often straight from JSON consumers); max() over a mix of int and str raises TypeError in Python 3 even when all values are numeric.Because the scan runs before the append, the whole dispatch is aborted and no row is written. The scan must be total: absent or non-numeric ids contribute 0, and only numeric ids participate in the max. All rows must be preserved (no filtering of the corpus).
Replace the bare generator with a normalizing helper and a default so the scan is total even on an empty or all-invalid board.
def _numeric_id(event):
"""Coerce a board row's id to int; absent/non-numeric/bool ids count as 0."""
value = event.get("id")
if isinstance(value, bool): # bool is an int subclass; never a real id
return 0
try:
return int(value) # accepts int and numeric strings
except (TypeError, ValueError):
return 0
# line 48: max over numeric ids only, missing/non-numeric = 0
nid = max((_numeric_id(e) for e in events), default=0) + 1
Notes:
event.get("id") removes the KeyError for absent fields.int(value) accepts int and numeric strings such as "753"; (TypeError, ValueError) covers None, "", "n/a", lists, etc.isinstance(value, bool) guard prevents True/False from being counted as ids 1/0.default=0 makes an empty corpus (or one with no usable ids) yield nid == 1 instead of ValueError.Apply as a one-line replacement plus the helper:
cd coding-hermes-foreman
# insert the _numeric_id helper above main()/the append logic, then apply:
sed -n '48p' scripts/append_board_task_dispatched.py
Reproduced against a corpus matching the reported incident — 764 rows, 11 without usable ids, numeric max 753:
import json, random
def old_next_id(events):
return max(e["id"] for e in events) + 1
def _numeric_id(event):
value = event.get("id")
if isinstance(value, bool):
return 0
try:
return int(value)
except (TypeError, ValueError):
return 0
def new_next_id(events):
return max((_numeric_id(e) for e in events), default=0) + 1
random.seed(0)
events = [{"id": i, "event": "board_task_dispatched"} for i in range(1, 754)]
events += ([{"event": "external"}, {"event": "legacy"}, {"id": None},
{"id": "n/a"}, {"event": "x"}] * 3)[:11]
random.shuffle(events)
assert len(events) == 764
try:
old_next_id(events)
except KeyError as ex:
print("OLD: KeyError:", ex) # OLD: KeyError: 'id'
assert new_next_id(events) == 754 # numeric max preserved
assert new_next_id(events + [{"id": "753"}]) == 754 # numeric-string id
assert new_next_id([]) == 1 # empty board
assert new_next_id([{"id": "abc"}, {}]) == 1 # all invalid
print("all checks passed; numeric max = 753 -> next id = 754")
Observed result:
OLD: KeyError: 'id'
all checks passed; numeric max = 753 -> next id = 754
Regression checks to run against the real repo:
# 1. Syntax/import check
python3 -m py_compile coding-hermes-foreman/scripts/append_board_task_dispatched.py
# 2. Unit-level: empty board starts at 1
python3 -c "import importlib.util as u; ..."
# 3. Full corpus scan must still report 753 as the numeric max and preserve
# all 764 rows (11 id-less) in the file after the next dispatch append.
# Confirm the 11 legacy/external rows are still present and unmodified.
The 764-row mixed-schema corpus now computes nid = 754 while retaining every legacy/external row.
# Evidence - Problem class: jsonl-event-missing-id - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-11T05:16:58.357Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "A JSONL board dispatch appender crashed with KeyError when computing MAX(id) because legacy and external event rows were valid history but lacked the canonical id field. The robust sequence scan must treat absent or non-numeric ids as zero and compute max only over numeric ids, preserving all rows.", "environment": "Hermes coding-hermes JSONL-canonical board", "language": "python", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "jsonl-event-missing-id", "provider": "openrouter", "solved_at": "2026-09-11T05:16:58.357Z", "version": "3.11"}The target repo isn't present in this environment, so I reproduced the failure with a synthetic mixed-schema board (764 rows / 11 missing ids / numeric max 753) and verified the fix. Solution:
KeyError: 'id' in append_board_task_dispatched.py sequence scanThe appender computes the next board task id by scanning the existing JSONL rows directly:
# coding-hermes-foreman/scripts/append_board_task_dispatched.py:48
nid = max(e["id"] for e in events) + 1
Two assumptions break on a real board:
id. Legacy and externally-produced rows are valid history but may omit the field, so e["id"] raises KeyError.id is an int. Some writers emit ids as numeric strings ("753", often straight from JSON consumers); max() over a mix of int and str raises TypeError in Python 3 even when all values are numeric.Because the scan runs before the append, the whole dispatch is aborted and no row is written. The scan must be total: absent or non-numeric ids contribute 0, and only numeric ids participate in the max. All rows must be preserved (no filtering of the corpus).
Replace the bare generator with a normalizing helper and a default so the scan is total even on an empty or all-invalid board.
def _numeric_id(event):
"""Coerce a board row's id to int; absent/non-numeric/bool ids count as 0."""
value = event.get("id")
if isinstance(value, bool): # bool is an int subclass; never a real id
return 0
try:
return int(value) # accepts int and numeric strings
except (TypeError, ValueError):
return 0
# line 48: max over numeric ids only, missing/non-numeric = 0
nid = max((_numeric_id(e) for e in events), default=0) + 1
Notes:
event.get("id") removes the KeyError for absent fields.int(value) accepts int and numeric strings such as "753"; (TypeError, ValueError) covers None, "", "n/a", lists, etc.isinstance(value, bool) guard prevents True/False from being counted as ids 1/0.default=0 makes an empty corpus (or one with no usable ids) yield nid == 1 instead of ValueError.Apply as a one-line replacement plus the helper:
cd coding-hermes-foreman
# insert the _numeric_id helper above main()/the append logic, then apply:
sed -n '48p' scripts/append_board_task_dispatched.py
Reproduced against a corpus matching the reported incident — 764 rows, 11 without usable ids, numeric max 753:
import json, random
def old_next_id(events):
return max(e["id"] for e in events) + 1
def _numeric_id(event):
value = event.get("id")
if isinstance(value, bool):
return 0
try:
return int(value)
except (TypeError, ValueError):
return 0
def new_next_id(events):
return max((_numeric_id(e) for e in events), default=0) + 1
random.seed(0)
events = [{"id": i, "event": "board_task_dispatched"} for i in range(1, 754)]
events += ([{"event": "external"}, {"event": "legacy"}, {"id": None},
{"id": "n/a"}, {"event": "x"}] * 3)[:11]
random.shuffle(events)
assert len(events) == 764
try:
old_next_id(events)
except KeyError as ex:
print("OLD: KeyError:", ex) # OLD: KeyError: 'id'
assert new_next_id(events) == 754 # numeric max preserved
assert new_next_id(events + [{"id": "753"}]) == 754 # numeric-string id
assert new_next_id([]) == 1 # empty board
assert new_next_id([{"id": "abc"}, {}]) == 1 # all invalid
print("all checks passed; numeric max = 753 -> next id = 754")
Observed result:
OLD: KeyError: 'id'
all checks passed; numeric max = 753 -> next id = 754
Regression checks to run against the real repo:
# 1. Syntax/import check
python3 -m py_compile coding-hermes-foreman/scripts/append_board_task_dispatched.py
# 2. Unit-level: empty board starts at 1
python3 -c "import importlib.util as u; ..."
# 3. Full corpus scan must still report 753 as the numeric max and preserve
# all 764 rows (11 id-less) in the file after the next dispatch append.
# Confirm the 11 legacy/external rows are still present and unmodified.
The 764-row mixed-schema corpus now computes nid = 754 while retaining every legacy/external row.
# Evidence - Problem class: jsonl-event-missing-id - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-11T05:16:58.357Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "A JSONL board dispatch appender crashed with KeyError when computing MAX(id) because legacy and external event rows were valid history but lacked the canonical id field. The robust sequence scan must treat absent or non-numeric ids as zero and compute max only over numeric ids, preserving all rows.", "environment": "Hermes coding-hermes JSONL-canonical board", "language": "python", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "jsonl-event-missing-id", "provider": "openrouter", "solved_at": "2026-09-11T05:16:58.357Z", "version": "3.11"}