{"repo":"NousResearch/hermes-agent","public_id":"3907","display_label":"read_file line counting bugs and fixes","summary":"Multiple bug reports and fix attempts addressing two related read_file issues: undercounting total_lines for files without a trailing newline, and displaying a phantom empty last line for files that do end with a newline. One unrelated microphone device selector feature is also present.","subsystem":"agent","counts":{"members":13,"open_issues":0,"open_issues_distinct":0,"open_prs":5,"closed_issues":3,"merged_prs":1,"attempt_prs":9},"landed_fix":{"status":"merged_to_main","basis":"structural","pr":107798,"merged_at":"2026-09-13T03:52:50+00:00"},"resolution":{"state":"unresolved","by":null},"freshness":{"state":"verified","last_verified_at":"2026-09-13T03:52:50+00:00","is_stale":false},"grouping":{"backbone":"STRUCTURAL_PARTIAL","link_density":0.15487179487179484},"fix_edges":[{"issue_number":3907,"pr_number":107798,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false,"pr_merged_at":"2026-09-13T03:52:50+00:00"},{"issue_number":49451,"pr_number":107798,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false,"pr_merged_at":"2026-09-13T03:52:50+00:00"},{"issue_number":55697,"pr_number":107798,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false,"pr_merged_at":"2026-09-13T03:52:50+00:00"}],"members":[{"kind":"issue","number":3907,"title":"[Bug]: read_file() undercounts total_lines for files without trailing newline","url":null,"state":"closed"},{"kind":"issue","number":55697,"title":"read_file undercounts total_lines and can silently drop the last line of a file without a trailing newline","url":null,"state":"closed"},{"kind":"issue","number":59999,"title":"[Bug] read_file total_lines is inaccurate — uses wc -l which counts newlines, not lines","url":null,"state":"closed"},{"kind":"pr","number":3908,"title":"tools/file_operations: fix wc -l undercounting for files without trailing newline (#3907)","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#3908","number":3908}],"category":"duplicate_of","implication":"duplicate"},"merged":false},{"kind":"pr","number":3927,"title":"fix(tools): read_file() undercounts total_lines for files without trailing newline","url":null,"state":"open","close_reason":{"category":"uncategorized","implication":"needs_llm"},"merged":false},{"kind":"pr","number":20814,"title":"fix(file_operations): correct total_lines for files without trailing newline","url":null,"state":"open","close_reason":{"refs":[{"kind":"pr","value":"#3927","number":3927},{"kind":"pr","value":"#3908","number":3908},{"kind":"pr","value":"#3907","number":3907}],"category":"duplicate_of","implication":"duplicate"},"merged":false},{"kind":"pr","number":22945,"title":"fix(file): count unterminated final line in read_file","url":null,"state":"open","close_reason":{"refs":[{"kind":"pr","value":"#3927","number":3927},{"kind":"pr","value":"#3908","number":3908},{"kind":"pr","value":"#3907","number":3907},{"kind":"pr","value":"#20814","number":20814}],"category":"duplicate_of","implication":"duplicate"},"merged":false},{"kind":"pr","number":42929,"title":"fix(tools): count file lines newline-agnostically in read_file","url":null,"state":"open","close_reason":{"refs":[{"kind":"pr","value":"#3907","number":3907},{"kind":"pr","value":"#3927","number":3927},{"kind":"pr","value":"#3908","number":3908},{"kind":"pr","value":"#20814","number":20814},{"kind":"pr","value":"#22945","number":22945}],"category":"duplicate_of","implication":"duplicate"},"merged":false},{"kind":"pr","number":55696,"title":"fix(tools): read_file undercounts (and can drop) a final line without a trailing newline","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#107798","number":107798},{"kind":"pr","value":"#106888","number":106888},{"kind":"pr","value":"#49453","number":49453}],"category":"implemented_elsewhere","implication":"superseded"},"merged":false},{"kind":"pr","number":55757,"title":"fix(file): count unterminated final line in read_file","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#42929","number":42929},{"kind":"pr","value":"#55697","number":55697},{"kind":"pr","value":"#55696","number":55696},{"kind":"pr","value":"#22945","number":22945}],"category":"duplicate_of","implication":"duplicate"},"merged":false},{"kind":"pr","number":74372,"title":"feat(desktop): add microphone device selector for voice mode","url":null,"state":"open","close_reason":{"refs":[{"kind":"pr","value":"#55697","number":55697},{"kind":"pr","value":"#111234","number":111234}],"category":"uncategorized","implication":"needs_llm"},"merged":false},{"kind":"pr","number":106888,"title":"fix(tools): count final unterminated line in read_file total_lines","url":null,"state":"closed","close_reason":{"refs":[{"kind":"commit","value":"6f62aff7f2bf","number":0},{"kind":"pr","value":"#107798","number":107798}],"category":"merged_via","implication":"superseded"},"merged":false},{"kind":"pr","number":107798,"title":"fix(tools): read_file counts unterminated final lines and stops rendering a phantom trailing line (salvage #106888, #49453)","url":null,"state":"merged","close_reason":{"category":"merged"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["tests/tools/test_file_operations.py","tests/tools/test_file_operations_edge_cases.py","tests/tools/test_file_ops_single_roundtrip.py","tools/file_operations.py"]}],"trust":{"default_tier":"verified","includes_suggested":false}}